I'm using the Color.FromArgb to for determining the brush color. Using this for examplePen p= new Pen(new SolidColorBrush(Color.FromArgb(95, 255, 0, 0)), 6); the problem with this is that I want to use 4 colors of the brushes (red, orange, yellow and green). And I have a condition where depending on the value in this condition the color is chosen with a certain transparency. The problem with this is the transition between the two different colors, for example from green to yellow or from orange to red, the color changes suddenly and I don't want this. I want to transition to be smooth between different colors so for example from orange to red I want it to take the different degrees of oranges till it becomes reddish till it becomes red.
The below is a snapshot of my code trying to clarify what I did, so if anyone could please advise, and please let me know if any more clarification needed. So as shown below depending of the value of X the color is determined with a certain intensity, but the problem is in if the last value of X was 10 which means Green and the current is 11 which means the color is Yellow, this makes the view not smooth because the color changed from Green to Yellow without any degrees of smoothness. And I thought that may be using HSV can solve this problem. So if anyone could please advise.
for(X=0; X<=40; X++)
//this is green phase
if (X == 0)
P = new Pen(new SolidColorBrush(Color.FromArgb(75, 0, 255, 0)), 6);
else if (X == 1)
P = new Pen(new SolidColorBrush(Color.FromArgb(77, 0, 255, 0)), 6);
else if (X == 2)
P = new Pen(new SolidColorBrush(Color.FromArgb(79, 0, 255, 0)), 6);
else if (X == 3)
P = new Pen(new SolidColorBrush(Color.FromArgb(81, 0, 255, 0)), 6);
else if (X == 4)
P = new Pen(new SolidColorBrush(Color.FromArgb(83, 0, 255, 0)), 6);
else if (X == 5)
P = new Pen(new SolidColorBrush(Color.FromArgb(85, 0, 255, 0)), 6);
else if (X == 6)
P = new Pen(new SolidColorBrush(Color.FromArgb(87, 0, 255, 0)), 6);
else if (X == 7)
P = new Pen(new SolidColorBrush(Color.FromArgb(89, 0, 255, 0)), 6);
else if (X == 8)
P = new Pen(new SolidColorBrush(Color.FromArgb(91, 0, 255, 0)), 6);
else if (X == 9)
P = new Pen(new SolidColorBrush(Color.FromArgb(93, 0, 255, 0)), 6);
else if (X == 10)
P = new Pen(new SolidColorBrush(Color.FromArgb(95, 0, 255, 0)), 6);
// this is yellow phase
else if (X == 11)
P = new Pen(new SolidColorBrush(Color.FromArgb(75, 255, 255, 0)), 6);
else if (X == 12)
P = new Pen(new SolidColorBrush(Color.FromArgb(77, 255, 255, 0)), 6);
else if (X == 13)
P = new Pen(new SolidColorBrush(Color.FromArgb(79, 255, 255, 0)), 6);
else if (X == 14)
P = new Pen(new SolidColorBrush(Color.FromArgb(81, 255, 255, 0)), 6);
else if (X == 15)
P = new Pen(new SolidColorBrush(Color.FromArgb(83, 255, 255, 0)), 6);
else if (X == 16)
P = new Pen(new SolidColorBrush(Color.FromArgb(85, 255, 255, 0)), 6);
else if (X == 17)
P = new Pen(new SolidColorBrush(Color.FromArgb(87, 255, 255, 0)), 6);
else if (X == 18)
P = new Pen(new SolidColorBrush(Color.FromArgb(89, 255, 255, 0)), 6);
else if (X == 19)
P = new Pen(new SolidColorBrush(Color.FromArgb(91, 255, 255, 0)), 6);
else if (X == 20)
P = new Pen(new SolidColorBrush(Color.FromArgb(93, 255, 255, 0)), 6);
// this is orange phase
else if (X == 21)
P = new Pen(new SolidColorBrush(Color.FromArgb(75, 255, 127, 0)), 6);
else if (X == 22)
P = new Pen(new SolidColorBrush(Color.FromArgb(77, 255, 127, 0)), 6);
else if (X == 23)
P = new Pen(new SolidColorBrush(Color.FromArgb(79, 255, 127, 0)), 6);
else if (X == 24)
P = new Pen(new SolidColorBrush(Color.FromArgb(81, 255, 127, 0)), 6);
else if (X == 25)
P = new Pen(new SolidColorBrush(Color.FromArgb(83, 255, 127, 0)), 6);
else if (X == 26)
P = new Pen(new SolidColorBrush(Color.FromArgb(85, 255, 127, 0)), 6);
else if (X == 27)
P = new Pen(new SolidColorBrush(Color.FromArgb(87, 255, 127, 0)), 6);
else if (X == 28)
P = new Pen(new SolidColorBrush(Color.FromArgb(89, 255, 127, 0)), 6);
else if (X == 29)
P = new Pen(new SolidColorBrush(Color.FromArgb(91, 255, 127, 0)), 6);
else if (X == 30)
P = new Pen(new SolidColorBrush(Color.FromArgb(93, 255, 127, 0)), 6);
//this is red phase
else if (X == 31)
P = new Pen(new SolidColorBrush(Color.FromArgb(75, 255, 0, 0)), 6);
else if (X == 32)
P = new Pen(new SolidColorBrush(Color.FromArgb(77, 255, 0, 0)), 6);
else if (X == 33)
P = new Pen(new SolidColorBrush(Color.FromArgb(79, 255, 0, 0)), 6);
else if (X == 34)
P = new Pen(new SolidColorBrush(Color.FromArgb(81, 255, 0, 0)), 6);
else if (X == 35)
P = new Pen(new SolidColorBrush(Color.FromArgb(83, 255, 0, 0)), 6);
else if (X == 36)
P = new Pen(new SolidColorBrush(Color.FromArgb(85, 255, 0, 0)), 6);
else if (X == 37)
P = new Pen(new SolidColorBrush(Color.FromArgb(87, 255, 0, 0)), 6);
else if (X == 38)
P = new Pen(new SolidColorBrush(Color.FromArgb(89, 255, 0, 0)), 6);
else if (X == 39)
P = new Pen(new SolidColorBrush(Color.FromArgb(91, 255, 0, 0)), 6);
else if (X == 40)
P = new Pen(new SolidColorBrush(Color.FromArgb(93, 255, 0, 0)), 6);
Maybe you should take a look into this answer. It helps you to use the methods GetHue(), GetSaturation() and GetBrightness() from the color class and create a new color from these parameters.
By using this you can simply get out the hue of your start and end color and depending on your step size get as much intermediate colors as needed.
Wouldn't it be great to have a method:
int numberOfIntermediateColors = 8;
IEnumerable<Colors> colorPalette = Color.Red.Range(Color.Green, numberOfIntermediateColors);
And here it is:
public static IEnumerable<Color> Range(this Color firstColor, Color lastColor, int count)
{
float stepHueClockwise = GetStepping(firstColor.GetHue(), lastColor.GetHue(), count, Direction.Clockwise);
float stepHueCounterClockwise = GetStepping(firstColor.GetHue(), lastColor.GetHue(), count, Direction.CounterClockwise);
if (Math.Abs(stepHueClockwise) >= Math.Abs(stepHueCounterClockwise))
return Range(firstColor, lastColor, count, Direction.Clockwise);
else
return Range(firstColor, lastColor, count, Direction.CounterClockwise);
}
public static IEnumerable<Color> Range(this Color firstColor, Color lastColor, int count, Direction hueDirection)
{
var color = firstColor;
if (count <= 0)
yield break;
if (count == 1)
yield return firstColor;
float startingHue = color.GetHue();
float stepHue = GetStepping(firstColor.GetHue(), lastColor.GetHue(), count - 1, hueDirection);
var stepSaturation = (lastColor.GetSaturation() - firstColor.GetSaturation()) / (count - 1);
var stepBrightness = (lastColor.GetBrightness() - firstColor.GetBrightness()) / (count - 1);
var stepAlpha = (lastColor.A - firstColor.A) / (count - 1.0);
for (int i = 1; i < count; i++)
{
yield return color;
var hueValue = startingHue + stepHue * i;
if (hueValue > 360)
hueValue -= 360;
if (hueValue < 0)
hueValue = 360 + hueValue;
color = FromAhsb(
Clamp((int)(color.A + stepAlpha), 0, 255),
hueValue,
Clamp(color.GetSaturation() + stepSaturation, 0, 1),
Clamp(color.GetBrightness() + stepBrightness, 0, 1));
}
yield return lastColor;
}
public enum Direction
{
Clockwise = 0,
CounterClockwise = 1
}
private static float GetStepping(float start, float end, int count, Direction direction)
{
var hueDiff = end - start;
switch (direction)
{
case Direction.CounterClockwise:
if (hueDiff >= 0)
hueDiff = (360 - hueDiff) * -1;
break;
default:
if (hueDiff <= 0)
hueDiff = 360 + hueDiff;
break;
}
return hueDiff / count;
}
private static int Clamp(int value, int min, int max)
{
if (value < min)
return min;
if (value > max)
return max;
return value;
}
private static float Clamp(float value, float min, float max)
{
if (value < min)
return min;
if (value > max)
return max;
return value;
}
To get your list of pens without any transparency you can take this simple approach:
var startColor = Color.Green;
var endColor = Color.Red;
var penWidth = 6;
var rainbow = startColor.Range(endColor, 40, bla.Direction.CounterClockwise);
var pens = rainbow.Select(color => new Pen(color, penWidth))
.ToList();
// Somewhere else...
int x = RetrieveDesiredCondition();
var neededPen = pens[x];
As far as i can see in your example you like to let the transparency iterate from 75 - 95 for each block of ten colors and a total of four blocks. In that case maybe this algorithm may help:
var startColor = Color.Green;
var endColor = Color.Red;
var penWidth = 6;
var lowerTransparency = 75;
var higherTransparency = 95;
var stepsPerSection = 10;
var sections = 4;
var stepsNeeded = stepsPerSection * sections;
var transparencyRange = higherTransparency - lowerTransparency;
var stepSize = transparencyRange / stepsPerSection;
var rainbow = startColor.Range(endColor, stepsNeeded, Direction.CounterClockwise);
var rainbowWithTransparency = rainbow.Select((color, index) =>
{
var step = (index % stepsPerSection) * stepSize;
var neededTransparency = lowerTransparency + step;
return Color.FromArgb(neededTransparency, color);
});
var pens = rainbowWithTransparency.Select(color => new Pen(color, penWidth))
.ToList();
// Somewhere else...
int x = RetrieveDesiredCondition();
var neededPen = pens[x];
Related
All good times of day!
Faced with the following task: you need to find the shapes in the image, cut them out and save them in jpg or png.
Find the shapes worked out (attached the image), but how do I get their extreme coordinates?
I find shapes with EMGU CV.
I'm taking Image it out of PictureBox.
// - was like the idea to find the distance from the center to the edge of the figure through Moments, but did not understand how they work
Image<Gray, byte> grayImage = inputImage.SmoothMedian(1).Convert<Gray, byte>().ThresholdBinaryInv(new Gray(230), new Gray(255));
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
Mat hierarchy = new Mat();
for (int i = 0; i < contours.Size; i++)
{
double perimetr = CvInvoke.ArcLength(contours[i], true);
VectorOfPoint approximation = new VectorOfPoint();
CvInvoke.ApproxPolyDP(contours[i], approximation, 0.04 * perimetr, true);
if (approximation.Size >= 3 && perimetr > 100 && approximation.Size != 5)
{
CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
}
Moments moments = CvInvoke.Moments(contours[i]);
int x = (int)(moments.M10 / moments.M00);
int y = (int)(moments.M01 / moments.M00);
if (perimetr > 100)
{
if (approximation.Size == 3)
{
CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
CvInvoke.PutText(inputImage, "Triangle", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
new MCvScalar(0, 0, 255), 1);
}
if (approximation.Size == 4)
{
Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);
double aspectRatio = (double)rect.Width / (double)rect.Height;
if (aspectRatio >= 0.95 && aspectRatio <= 1.05)
{
CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
CvInvoke.PutText(inputImage, "Square", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
new MCvScalar(0, 0, 255), 1);
}
else
{
CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
CvInvoke.PutText(inputImage, "Rectangle", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
new MCvScalar(0, 0, 255), 1);
}
}
if (approximation.Size == 5)
{
CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
CvInvoke.PutText(inputImage, "Pentagon", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
new MCvScalar(0, 0, 255), 1);
}
if (approximation.Size == 6)
{
CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
CvInvoke.PutText(inputImage, "Hexagon", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
new MCvScalar(0, 0, 255), 1);
}
if (approximation.Size > 6)
{
var R = (double)perimetr / (3.14 * 2);
if (R > (Math.Min(inputImage.Width, inputImage.Height) / 3) * 0.1 && R < (Math.Min(inputImage.Width, inputImage.Height) / 2))
{
CvInvoke.DrawContours(inputImage, contours, i, new MCvScalar(0, 255, 0), 2);
CvInvoke.PutText(inputImage, "Circle", new Point(x, y), Emgu.CV.CvEnum.FontFace.HersheyPlain, 1,
new MCvScalar(0, 0, 255), 1);
}
}
}
}
Thank you for your attention.
Input image
Output image
I found a solution to my question. There is a method that returns a description of the contour with an array of points.
Point[] contour = contours[i].ToArray();
I've got a 2D rpg-ish thing going on, where I want my character to swing a sword when I press a certain key, the sword swing is made out of 3 sprites.
This is the code I got going on so far:
EDIT: Upon request I've copypasted the entire class in where my attack-animation-code is in.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace RPGJensLomanderV2
{
class Player : Characters
{
KeyboardState ks;
Camera camera;
KeyboardState oldKs;
int attackTime;
Vector2 origin = Vector2.Zero;
bool isAnimationRunning = false;
public Player(GameScreen gameScreen, Camera camera)
: base(gameScreen)
{
health = 10;
this.camera = camera;
direction = Vector2.Zero;
movementSpeed = 1;
currentSprite = new Rectangle(229, 30, 14, 16);
}
public override void Load(ContentManager content)
{
spawnPoint = gameScreen.destSourceRecISE.Where(t => t.Value.X == 78 && t.Value.Y == 26).First().Key;
position = spawnPoint;
gameScreen.destSourceRecISE.Remove(spawnPoint);
base.Load(content);
}
public override void Update(GameTime gameTime)
{
ks = Keyboard.GetState();
timeSprite += gameTime.ElapsedGameTime.Milliseconds;
Attack(gameTime);
attackTime = 0;
Movement(gameTime);
camera.Position = position;
oldKs = ks;
}
private void Movement(GameTime gameTime)
{
if (ks.IsKeyDown(Keys.Right) && ks.IsKeyDown(Keys.Up))
{
direction = new Vector2(1, -1);
directionPointer = 1;
if (currentSprite.X != 140 && currentSprite.X != 154)
currentSprite = new Rectangle(140, 30, 14, 16);
if (timeSprite >= 100)
{
if (currentSprite.X == 140)
currentSprite = new Rectangle(154, 30, 14, 16);
else if (currentSprite.X == 154)
currentSprite = new Rectangle(140, 30, 14, 16);
timeSprite = 0;
}
}
else if (ks.IsKeyDown(Keys.Right) && ks.IsKeyDown(Keys.Down))
{
direction = new Vector2(1, 1);
directionPointer = 2;
if (currentSprite.X != 229 && currentSprite.X != 245)
currentSprite = new Rectangle(229, 30, 16, 16);
if (timeSprite >= 100)
{
if (currentSprite.X == 229)
currentSprite = new Rectangle(245, 30, 16, 16);
else if (currentSprite.X == 245)
currentSprite = new Rectangle(229, 30, 16, 16);
timeSprite = 0;
}
}
else if (ks.IsKeyDown(Keys.Left) && ks.IsKeyDown(Keys.Up))
{
direction = new Vector2(-1, -1);
directionPointer = 1;
if (currentSprite.X != 140 && currentSprite.X != 154)
currentSprite = new Rectangle(140, 30, 14, 16);
if (timeSprite >= 100)
{
if (currentSprite.X == 140)
currentSprite = new Rectangle(154, 30, 14, 16);
else if (currentSprite.X == 154)
currentSprite = new Rectangle(140, 30, 14, 16);
timeSprite = 0;
}
}
else if (ks.IsKeyDown(Keys.Left) && ks.IsKeyDown(Keys.Down))
{
direction = new Vector2(-1, 1);
directionPointer = 2;
if (currentSprite.X != 229 && currentSprite.X != 245)
currentSprite = new Rectangle(229, 30, 16, 16);
if (timeSprite >= 100)
{
if (currentSprite.X == 229)
currentSprite = new Rectangle(245, 30, 16, 16);
else if (currentSprite.X == 245)
currentSprite = new Rectangle(229, 30, 16, 16);
timeSprite = 0;
}
}
else if (ks.IsKeyDown(Keys.Left))
{
direction = new Vector2(-1, 0);
directionPointer = 3;
if (currentSprite.X != 198 && currentSprite.X != 214)
currentSprite = new Rectangle(198, 30, 16, 16);
if (timeSprite >= 100)
{
if (currentSprite.X == 198)
currentSprite = new Rectangle(214, 30, 15, 16);
else if (currentSprite.X == 214)
currentSprite = new Rectangle(198, 30, 16, 16);
timeSprite = 0;
}
}
else if (ks.IsKeyDown(Keys.Right))
{
direction = new Vector2(1, 0);
directionPointer = 4;
if (currentSprite.X != 168 && currentSprite.X != 184)
currentSprite = new Rectangle(168, 30, 16, 16);
if (timeSprite >= 100)
{
if (currentSprite.X == 168)
currentSprite = new Rectangle(184, 30, 16, 16);
else if (currentSprite.X == 184)
currentSprite = new Rectangle(168, 30, 16, 16);
timeSprite = 0;
}
}
else if (ks.IsKeyDown(Keys.Up))
{
direction = new Vector2(0, -1);
directionPointer = 1;
if (currentSprite.X != 140 && currentSprite.X != 154)
currentSprite = new Rectangle(140, 30, 14, 16);
if (timeSprite >= 100)
{
if (currentSprite.X == 140)
currentSprite = new Rectangle(154, 30, 14, 16);
else if (currentSprite.X == 154)
currentSprite = new Rectangle(140, 30, 14, 16);
timeSprite = 0;
}
}
else if (ks.IsKeyDown(Keys.Down))
{
direction = new Vector2(0, 1);
directionPointer = 2;
if (currentSprite.X != 229 && currentSprite.X != 245)
currentSprite = new Rectangle(229, 30, 16, 16);
if (timeSprite >= 100)
{
if (currentSprite.X == 229)
currentSprite = new Rectangle(245, 30, 16, 16);
else if (currentSprite.X == 245)
currentSprite = new Rectangle(229, 30, 16, 16);
timeSprite = 0;
}
}
else
{
direction = Vector2.Zero;
timeSprite = 0;
}
position += movementSpeed * direction;
}
private void Attack(GameTime gameTime)
{
if (ks.IsKeyDown(Keys.A) /*&& oldKs.IsKeyUp(Keys.A)*/)
{
isAnimationRunning = true;
}
while (isAnimationRunning && directionPointer == 1)
{
attackTime += gameTime.ElapsedGameTime.Milliseconds;
if (attackTime > 1 && attackTime < 100)
{
currentSprite = new Rectangle(3, 46, 32, 16);
}
if (attackTime < 200 && attackTime > 100)
{
currentSprite = new Rectangle(33, 61, 32, 32);
}
if (attackTime > 200 && attackTime < 300)
{
currentSprite = new Rectangle(61, 65, 16, 32);
}
if (attackTime > 300)
{
attackTime = 0;
currentSprite = new Rectangle(140, 30, 14, 16);
isAnimationRunning = false;
}
}
if (directionPointer == 2 && isAnimationRunning)
{
attackTime += gameTime.ElapsedGameTime.Milliseconds;
if (attackTime < 100)
{
currentSprite = new Rectangle(4, 67, 32, 16);
}
else if (attackTime < 200 && attackTime > 100)
{
currentSprite = new Rectangle(35, 66, 32, 32);
}
else if (attackTime > 200 && attackTime < 300)
{
currentSprite = new Rectangle(69, 66, 16, 32);
}
else if (attackTime > 300)
{
attackTime = 0;
isAnimationRunning = false;
currentSprite = new Rectangle(229, 30, 16, 16);
}
}
if (directionPointer == 3 && isAnimationRunning)
{
attackTime += gameTime.ElapsedGameTime.Milliseconds;
if (attackTime < 100)
{
currentSprite = new Rectangle(5, 138, 16, 32);
}
else if (attackTime < 200 && attackTime > 100)
{
currentSprite = new Rectangle(20, 138, 32, 32);
}
else if (attackTime > 200 && attackTime < 300)
{
currentSprite = new Rectangle(53, 154, 32, 16);
}
else if (attackTime > 300)
{
attackTime = 0;
isAnimationRunning = false;
currentSprite = new Rectangle(198, 30, 16, 16);
}
}
if (directionPointer == 4 && isAnimationRunning)
{
attackTime += gameTime.ElapsedGameTime.Milliseconds;
if (attackTime < 100)
{
currentSprite = new Rectangle(5, 102, 16, 32);
}
else if (attackTime < 200 && attackTime > 100)
{
currentSprite = new Rectangle(20, 102, 32, 32);
}
else if (attackTime > 200 && attackTime < 300)
{
currentSprite = new Rectangle(51, 118, 32, 16);
}
else if (attackTime > 300)
{
attackTime = 0;
currentSprite = new Rectangle(168, 30, 16, 16);
isAnimationRunning = false;
}
}
}
public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, currentSprite, Color.White, 0f, origin, 1f, SpriteEffects.None, 0f);
}
}
}
Right now, it does not go past the first sprite of the attack when I swing, and I am not totally sure how to make it happen. I'd be grateful if someone could give me a tip or the like of how I could make it go through the entire code so that a full swing will be done on the press of a button? Thanks on beforehand!
Define a global variable
bool isAnimationRunning = false;
and then change your code like this:
if (ks.IsKeyDown(Keys.A) && directionPointer == 1 && oldKs.IsKeyUp(Keys.A))
{
isAnimationRunning = true;
}
if(isAnimationRunning)
{
attackTime += gameTime.ElapsedGameTime.Milliseconds;
if (attackTime > 1 && attackTime < 100)
{
currentSprite = new Rectangle(3, 46, 32, 16);
}
else if (attackTime < 200 && attackTime > 100)
{
currentSprite = new Rectangle(33, 61, 32, 32);
}
else if (attackTime > 200 && attackTime < 300)
{
currentSprite = new Rectangle(61, 65, 16, 32);
}
else if (attackTime > 300)
{
attackTime = 0;
isAnimationRunning = false;
}
}
Give point within the region with a color to fill the region, similar to the "drawing" in the paint bucket function.
The. NET Framework, there is no direct equivalent.
but i hope use C# to do it.
is it possible?
Here's a very naive flood fill algorithm that should get you started
void Form1_Paint(object sender, PaintEventArgs e)
{
using (Bitmap bitmap = new Bitmap(500, 500))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.Clear(Color.White);
List<Point> points = new List<Point>();
for (double i = 0; i < 10; i++)
{
double dist = (i % 2 == 0) ? 100 : 50;
double x = 200 + Math.Cos(i / 10d * Math.PI * 2d) * dist;
double y = 200 + Math.Sin(i / 10d * Math.PI * 2d) * dist;
points.Add(new Point((int)x, (int)y));
}
g.DrawPolygon(Pens.Black, points.ToArray());
}
FloodFill(bitmap, 200, 200, Color.Red);
e.Graphics.DrawImage(bitmap, 0, 0);
}
}
void FloodFill(Bitmap bitmap, int x, int y, Color color)
{
BitmapData data = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
int[] bits = new int[data.Stride / 4 * data.Height];
Marshal.Copy(data.Scan0, bits, 0, bits.Length);
LinkedList<Point> check = new LinkedList<Point>();
int floodTo = color.ToArgb();
int floodFrom = bits[x + y * data.Stride / 4];
bits[x + y * data.Stride / 4] = floodTo;
if (floodFrom != floodTo)
{
check.AddLast(new Point(x, y));
while (check.Count > 0)
{
Point cur = check.First.Value;
check.RemoveFirst();
foreach (Point off in new Point[] {
new Point(0, -1), new Point(0, 1),
new Point(-1, 0), new Point(1, 0)})
{
Point next = new Point(cur.X + off.X, cur.Y + off.Y);
if (next.X >= 0 && next.Y >= 0 &&
next.X < data.Width &&
next.Y < data.Height)
{
if (bits[next.X + next.Y * data.Stride / 4] == floodFrom)
{
check.AddLast(next);
bits[next.X + next.Y * data.Stride / 4] = floodTo;
}
}
}
}
}
Marshal.Copy(bits, 0, data.Scan0, bits.Length);
bitmap.UnlockBits(data);
}
Given two simple, rectangles:
class Rectangle
{
int x;
int y;
int width;
int height;
}
Rectangle a;
Rectangle b;
and the following enumeration:
[Flags]
enum Edges
{
None,
Top,
Bottom,
Left,
Right,
Inside,
}
What is the quickest way to detect the edges on rectangle a which are collided with by rectangle b?
Edges e = EdgeDetect(a, b);
public Edges DetectEdge(Rect A, Rect B) {
rectC = rectA.Intersect(rectB);
if(rectC.IsEmpty) return Edges.None;
Edge edge = Edges.Inside;
if(rectA.X+rectA.Width == rectB.X || rectA.X == rectB.X){
edge = Edges.Left;
}
if(rectA.Y+rectA.Height == rectB.Y || rectA.Y == rectB.Y){
edge = edge | Edges.Top;
}
if(rectA.X == rectB.X + rectB.Width
|| rectA.X + rectA.Width == rectB.X + rectB.Width){
edge = edge | Edges.Right;
}
if(rectA.Y == rectB.Y + rectB.Heigth
|| rectA.Y + rectA.Height == rectB.Y + rectB.Height){
edge = edge | Edges.Bottom;
}
return edge;
}
First of all, you have to defines explicitly values of your enum in order to have flags working correctly. In you case Left == Top + Bottom + None. Here is a possible declaration :
[Flags]
public enum Edges
{
None = 0,
Top = 1,
Bottom = 2,
Left = 4,
Right = 8,
Identical = Top + Bottom + Left + Right,
Inside = 16,
Covers = 32
}
Next, a possible implementation of edge collision detection. Note that I use the builtin System.Drawing.Rectangle instead of rewriting the class. The immediate advantage is the availability of the Intersect method. :
public static Edges DetectEdgesCollision(Rectangle a, Rectangle b)
{
var result = Edges.None;
if (a == b) return Edges.Identical;
b.Intersect(a);
if (b.IsEmpty) return Edges.None;
if (a == b) return Edges.Covers;
if (a.Top == b.Top && (a.Right >= b.Right && a.Left<=b.Left ))
result |= Edges.Top;
if (a.Bottom == b.Bottom && (a.Right >= b.Right && a.Left<=b.Left ))
result |= Edges.Bottom;
if (a.Left == b.Left && (a.Bottom >= b.Bottom && a.Top <= b.Top))
result |= Edges.Left;
if (a.Right == b.Right && (a.Bottom >= b.Bottom && a.Top <= b.Top))
result |= Edges.Right;
return result == Edges.None ? Edges.Inside : result;
}
Here is a set of tests that validates this implementation :
[TestMethod]
public void RectDoesNotIntersect()
{
var a = new Rectangle(0, 0, 10, 10);
var b = new Rectangle(20, 20, 10, 10);
var result = Program.DetectEdgesCollision(a, b);
Assert.AreEqual<Edges>(Edges.None, result);
}
[TestMethod]
public void RectAreNested()
{
var a = new Rectangle(0, 0, 30,30);
var b = new Rectangle(10, 10, 10, 10);
var result = Program.DetectEdgesCollision(a, b);
Assert.AreEqual<Edges>(Edges.Inside, result);
}
[TestMethod]
public void RectCollidesOnTopAndLeft()
{
var a = new Rectangle(10, 10, 10, 10);
var b = new Rectangle(0, 0, 10, 10);
var result = Program.DetectEdgesCollision(a, b);
Assert.AreEqual<Edges>(Edges.Left | Edges.Top, result);
}
[TestMethod]
public void RectCollidesOnBottom()
{
var a = new Rectangle(0, 0, 20, 20);
var b = new Rectangle(10, 10, 5, 50);
var result = Program.DetectEdgesCollision(a, b);
Assert.AreEqual<Edges>(Edges.Bottom , result);
}
[TestMethod]
public void RectAreIdenticals()
{
var a = new Rectangle(10, 10, 10, 10);
var b = new Rectangle(10, 10, 10, 10);
var result = Program.DetectEdgesCollision(a, b);
Assert.AreEqual<Edges>(Edges.Identical, result);
}
[TestMethod]
public void RectBCoversA()
{
var a = new Rectangle(10, 10, 10, 10);
var b = new Rectangle(0, 0, 30, 30);
var result = Program.DetectEdgesCollision(a, b);
Assert.AreEqual<Edges>(Edges.Covers, result);
}
I want to create a bitmap of size 160*160 and split it into four squares with each square filled with one color. How can this be done?
Just in case anyone needs a method solving this specific problem in a more general way, I wrote an extension method, taking colors and an integer that states how many tiles it should split off in x and y direction:
public static void FillImage(this Image img, int div, Color[] colors)
{
if (img == null) throw new ArgumentNullException();
if (div < 1) throw new ArgumentOutOfRangeException();
if (colors == null) throw new ArgumentNullException();
if (colors.Length < 1) throw new ArgumentException();
int xstep = img.Width / div;
int ystep = img.Height / div;
List<SolidBrush> brushes = new List<SolidBrush>();
foreach (Color color in colors)
brushes.Add(new SolidBrush(color));
using (Graphics g = Graphics.FromImage(img))
{
for (int x = 0; x < div; x++)
for (int y = 0; y < div; y++)
g.FillRectangle(brushes[(y * div + x) % colors.Length],
new Rectangle(x * xstep, y * ystep, xstep, ystep));
}
}
The four squares, the OP wanted would be produced with:
new Bitmap(160, 160).FillImage(2, new Color[]
{
Color.Red,
Color.Blue,
Color.Green,
Color.Yellow
});
You can try something like
using (Bitmap b = new Bitmap(160, 160))
using (Graphics g = Graphics.FromImage(b))
{
g.FillRectangle(new SolidBrush(Color.Blue), 0, 0, 79, 79);
g.FillRectangle(new SolidBrush(Color.Red), 79, 0, 159, 79);
g.FillRectangle(new SolidBrush(Color.Green), 0, 79, 79, 159);
g.FillRectangle(new SolidBrush(Color.Yellow), 79, 79, 159, 159);
b.Save(#"c:\test.bmp");
}