XNA Draw a filled circle - c#

In another thread on XNA, Callum Rogers wrote some code which creates a texture with the outline of a circle, but I'm trying to create a circle filled with a color. What I have to modify on this code to fill the circle with color?
public Texture2D CreateCircle(int radius)
{
int outerRadius = radius*2 + 2; // So circle doesn't go out of bounds
Texture2D texture = new Texture2D(GraphicsDevice, outerRadius, outerRadius);
Color[] data = new Color[outerRadius * outerRadius];
// Colour the entire texture transparent first.
for (int i = 0; i < data.Length; i++)
data[i] = Color.Transparent;
// Work out the minimum step necessary using trigonometry + sine approximation.
double angleStep = 1f/radius;
for (double angle = 0; angle < Math.PI*2; angle += angleStep)
{
// Use the parametric definition of a circle: http://en.wikipedia.org/wiki/Circle#Cartesian_coordinates
int x = (int)Math.Round(radius + radius * Math.Cos(angle));
int y = (int)Math.Round(radius + radius * Math.Sin(angle));
data[y * outerRadius + x + 1] = Color.White;
}
texture.SetData(data);
return texture;
}

Don't use a texture for stuff like this (especially for things being in one single color!) - also don't try to do it pixel by pixel. You've got 3D acceleration for a reason.
Just draw the circle similar to a pie using a triangle fan. You'll need the following vertices.
Center of the circle
x points on the circle's border.
The first two points will define a line between the center of the circle and its border. The third vertex will define the first polygon. Vertices 1, 3 and 4 will then define the second polygon, etc.
To get the points on the circle's border use the formulas from your example. The first angle will be 0°, the following ones multiples of (360° / points on circle). To get a full circle you'll need one additional point that matches the second point (the first point on the border).
Depending on the number of vertices on the circle you'll get different n-gons. The more vertices you use the rounder the shape will look (at some performance cost):
(Less than 2 vertices aren't possible as a polygon requires at least 3 vertices to be drawn.)
Total of 4 points (3 points on circle) will result in a triangle.
Total of 5 points (4 point on circle) will result in a square.
Total of 6 points (5 points on circle) will result in a pentagon
...
Actually the XNA example for drawing primites show how to draw a circle (or n-gon) using a triangle fan.

well for anyone who wants to do it pixel by pixel ... i made a solution based on the information given. In your 2d texture method add the following code to fill the circle. I'm making a game and wanted to be able to make circles different colors and sizes. So inside CreateCircle(int radius) method, add the following code after the outline has been created :
bool finished = false;
int firstSkip = 0;
int lastSkip = 0;
for (int i = 0; i <= data.Length - 1; i++)
{
if (finished == false)
{
//T = transparent W = White;
//Find the First Batch of Colors TTTTWWWTTTT The top of the circle
if ((data[i] == Color.White) && (firstSkip == 0))
{
while (data[i + 1] == Color.White)
{
i++;
}
firstSkip = 1;
i++;
}
//Now Start Filling TTTTTTTTWWTTTTTTTT
//circle in Between TTTTTTW--->WTTTTTT
//transaparent blancks TTTTTWW--->WWTTTTT
// TTTTTTW--->WTTTTTT
// TTTTTTTTWWTTTTTTTT
if (firstSkip == 1)
{
if (data[i] == Color.White && data[i + 1] != Color.White)
{
i++;
while (data[i] != Color.White)
{
//Loop to check if its the last row of pixels
//We need to check this because of the
//int outerRadius = radius * 2 + -->'2'<--;
for (int j = 1; j <= outerRadius; j++)
{
if (data[i + j] != Color.White)
{
lastSkip++;
}
}
//If its the last line of pixels, end drawing
if (lastSkip == outerRadius)
{
break;
finished = true;
}
else
{
data[i] = Color.White;
i++;
lastSkip = 0;
}
}
while (data[i] == Color.White)
{
i++;
}
i--;
}
}
}
}
// Set the data when finished
//-- don't need to paste this part, already given up above
texture.SetData(data);
return texture;

If you need to do it from scratch (though I'm guessing there are easier ways), change the way you perform the rendering. Instead of iterating through angles and plotting pixels, iterate through pixels and determine where they are relative to the circle. If they are <R, draw as fill color. If they are ~= R, draw as border color.

I know that I'm a little late, but I modified your code to fill in the center
public static Texture2D CreateCircle(GraphicsDevice importedGraphicsDevice, int radius)
{
int outerRadius = radius * 2 + 2; // So circle doesn't go out of bounds
Texture2D texture = new Texture2D(importedGraphicsDevice, outerRadius, outerRadius);
Color[] data = new Color[outerRadius * outerRadius];
// Colour the entire texture transparent first.
for (int i = 0; i < data.Length; i++)
data[i] = Color.Transparent;
// Work out the minimum step necessary using trigonometry + sine approximation.
double angleStep = 1f / radius;
for (double angle = 0; angle < Math.PI * 2; angle += angleStep)
{
// Use the parametric definition of a circle: http://en.wikipedia.org/wiki/Circle#Cartesian_coordinates
int x = (int)Math.Round(radius + radius * Math.Cos(angle));
int y = (int)Math.Round(radius + radius * Math.Sin(angle));
data[y * outerRadius + x + 1] = Color.White;
}
//width
for (int i = 0; i < outerRadius; i++)
{
int yStart = -1;
int yEnd = -1;
//loop through height to find start and end to fill
for (int j = 0; j < outerRadius; j++)
{
if (yStart == -1)
{
if (j == outerRadius - 1)
{
//last row so there is no row below to compare to
break;
}
//start is indicated by Color followed by Transparent
if (data[i + (j * outerRadius)] == Color.White && data[i + ((j + 1) * outerRadius)] == Color.Transparent)
{
yStart = j + 1;
continue;
}
}
else if (data[i + (j * outerRadius)] == Color.White)
{
yEnd = j;
break;
}
}
//if we found a valid start and end position
if (yStart != -1 && yEnd != -1)
{
//height
for (int j = yStart; j < yEnd; j++)
{
data[i + (j * outerRadius)] = new Color(10, 10, 10, 10);
}
}
}
texture.SetData(data);
return texture;
}

Related

Mapping PerlinNoise to a Grid

I am trying to generate a grid across my map and add nodes depending on the perlin noise value. Depending on the value obtained from the perlin noise at a location, I will add a new Node which will be of a certain type e.g. Mountain, Water etc to represent terrian. Here I am trying to make it so that if the value is > 0.5, this mean it's only mountains and so a black coloured cubes should surround the mountain areas, However, my black cubes do not match the mountain areas from the perlin noise and I cannot seem to figure out why I am going wrong. Would appreciate any insight into how I could go about achieving this.
private void LocateWalkableCells()
{
for(int z = 0; z < Height; z++)
{
for(int x = 0; x < Width; x++)
{
noise = GetNoiseValue(x, z);
if(noise > 0.5) {
grid[x,z] = new Node(new Vector3(x, 0, z), TerrainType.Mountain, 1);
}
else {
grid[x,z] = new Node(new Vector3(x, 0, z), TerrainType.Grass, 1);
}
}
}
}
private float GetNoiseValue(int x, int z)
{
int pos = (x * Width) + z;
return Mathf.Round(terrainGenerator.noiseArray[pos] * 10) / 10;
}
// Draw gizmos to visualize colour
void OnDrawGizmos()
{
Gizmos.DrawWireCube(transform.position, new Vector3(Width, 1, Height));
if(grid != null)
{
foreach(Node n in grid)
{
if(n.TerrainType == TerrainType.Grass)
{
Gizmos.color = Color.green;
}
else if(n.TerrainType == TerrainType.Mountain)
{
Gizmos.color = Color.black;
}
Gizmos.DrawCube(n.Position, Vector3.one * (nodeDiameter - .1f));
}
}
}
noiseArray is used for the vertices of the terrain in the following code:
vertices = new Vector3[(Width + 1) * (Depth + 1)];
noiseArray = PerlinNoise();
int i = 0;
for(int z = 0; z <= Depth; z++)
{
for(int x = 0; x <= Width; x++)
{
var currentHeight = noiseArray[i];
if(currentHeight > HeightThreshold)
{
currentHeight *= HeightMultiplier;
}
vertices[i] = new Vector3(x, currentHeight, z);
i++;
}
}
Output
Result from suggested answer
Still seems to miss some mountain areas, colouring green instead of black.
It think the issue is in
var pos = (x * Width) + z;
since x is you index on the width of the grid you would probably rather want
var pos = z * Width + x;
in other words you want to
skip z rows
each row has Width elements
then from there take the xth element
assuming your terrain is laid out row-wise.
Or if it is laid out column-wise (which is rather unusual but possible)
var pos = x * Height + z;
or in other words
skip x columns
each column has Height elements
then from there take the zth element
See also Converting index of one dimensional array into two dimensional array i. e. row and column
Update
Now that you have showed the terrain generation code it needs to be
var pos = z * (Width + 1) + x;
since the terrain array has actually Width + 1 elements per row.

Animation isn't working because the picbox doesn't reset and the task doesn't sleep

I have this code right here:
EDIT: Source Code:
private void btnAnimate_Click(object sender, EventArgs e)
{
Bitmap[] circle = new Bitmap[300];
for (int i = 0; i < circle.Length; i++)
{
circle[i] = new Bitmap(260, 266);
}
double r = 25; // radius
double rr = Math.Pow(r, 2); // r^2
int h = 25;
// x value of centre of circle is represented with h and y value is represented with k
for (int k = 25; k <= 100; k += 25) // y value of center moves down 1 pixel every iteration
{
for (int x = -h; x <= h + r; x++)
{
for (int y = -k; y <= k + r; y++)
{
if (Math.Abs(Math.Pow(x - h, 2) + Math.Pow(y - k, 2)) <= rr)
// if: |(x-h)^2 + (y - h)^2| <= r^2, then draw the pixel
{
circle[k - 25].SetPixel(x, y, Color.Red);
}
}
}
}
for (int l = 25; l <= 100; l+= 25)
{
picBox.Image = circle[l - 25];
btnAnimate.Text = "circle" + (l/25);
System.Threading.Thread.Sleep(1000);
}
}
(it use to be k++ but I made it k+= 25 so it would make it easier to trouble shoot, it will only draw 4 circles instead of the original 75.)
and I want it to draw a circle on a picture box (I've tested it and it can do that), but afterwards I want it to sleep for a while, then clear the picture box, draw a new circle only 1 pixel below it and repeat until the circle hits the ground. The problem with this is that the program is sleeping but it isn't showing the action done in between sleeps. i.e it says to show circle 1 then sleep until it reaches circle 4, but it will not show circles 1 through 3 though it will sleep, it will just show the final circle. It's not even just the pic box
you can see that I wrote
btnAnimate.Text = "circle" + (l/25);
System.Threading.Thread.Sleep(1000);
I want it to change the button text to 1, 2, 3, and 4 to count each iteration but it doesn't do that either. it will just show 4 at the end.
What do you think the problem is?
Solution:
double r = 25; // radius
double rr = Math.Pow(r, 2); // r^2
int h = 25;
// x value of centre of circle is represented with h and y value is represented with k
for (int k = 25; k <= 100; k += 25) // y value of center moves down 1 pixel every iteration
{
Bitmap circle = new Bitmap(260, 266);
for (int x = -h; x <= h + r; x++)
{
for (int y = -k; y <= k + r; y++)
{
if (Math.Abs(Math.Pow(x - h, 2) + Math.Pow(y - k, 2)) <= rr)
// if: |(x-h)^2 + (y - h)^2| <= r^2, then draw the pixel
{
circle.SetPixel(x, y, Color.Red);
}
}
}
picBox.Image = circle;
picBox.Update();
System.Threading.Thread.Sleep(100);
}
You have two problems:
You are not clearing the Bitmap circle drawn circle on each iteration, so you are building upon the previous drawn circle, so it looks like a falling circle with trails. You can fix this by defining your Bitmap circle inside of the first for loop, instead of outside.
It is failing to show the new image inbetween Thread sleeps because you are not telling the control to refresh itself visually. Do this by calling picBox.Update() or picBox.Refresh() after you set picBox.Image = circle.

Color resemblance for motion detection

Given 2 consecutive frames, how can I search for pixels that changed?
I tried the following:
if (old != null)
{
for (int i = 0; i < b.Width; i++)
{
for (int j = 0; j < b.Height; j++)
{
if (!b.GetPixel(i, j).Equals(old.GetPixel(i, j)))
s.SetPixel(i, j, b.GetPixel(i, j));
else
s.SetPixel(i, j, Color.White);
}
}
}
Where "old" is the previous frame and "s" is the new frame. The code basically paints the pixels that didn't change in white.
But since the webcam produces a very low quality frame almost all of the pixels change.
How can I eliminate the pixels that didn't change "greatly"?
A very basic approach is to convert your Color pixel to an 0 - 255 based grey value.
So you can compare your pixels as an integer and make some delta error difference.
Consider this method which convert a color to a integer grayscale value
private static int GreyScaleRange(Color originalColor)
{
return (int)((originalColor.R * .3) + (originalColor.G * .59)
+ (originalColor.B * .11));
}
So instead of doing equal function, you should do
int deltadifference = 5 ;
if (Math.abs((GreyScaleRange(b.GetPixel(i, j)) - (GreyScaleRange(old.GetPixel(i, j)) > deltadifference)
s.SetPixel(i, j, b.GetPixel(i, j));
else
s.SetPixel(i, j, Color.White);

Algorithm to find rectangles

I have the following code:
int width = 10;
int height = 7;
bool[,] array1 = new bool[width, height];
string values =
"1100000000" +
"1100000011" +
"0001100011" +
"0001100000" +
"0001110000" +
"0000000110" +
"0000000110";
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
array1[x, y] = (values[x + y * width] == '1');
}
}
im looking for a algorithm that would extract Ranges where we have a 1.
so from this data we would get rectangles
(0,0,2,2),
(8,1,2,2),
(3,2,3,3),
(7,5,2,2)
the order of the rectangles do not matter!
But i have no idea how to do this any one got any pointers?
After reading Rusty Weber answer i came up with the following:
private static List<Rectangle> GetRectangles(bool[,] array)
{
List<Rectangle> rectangles = new List<Rectangle>();
for (int x = 0; x < array.GetLength(0); x++)
{
for (int y = 0; y < array.GetLength(1); y++)
{
if (array[x, y])
{
rectangles.Add(GetRectangle(array, new Point(x, y)));
}
}
}
return rectangles;
}
static Rectangle GetRectangle(bool[,] array, Point startLocation)
{
int maxX = int.MinValue;
int minX = int.MaxValue;
int maxY = int.MinValue;
int minY = int.MaxValue;
HashSet<Point> visitedLocations = new HashSet<Point>();
Stack<Point> pointsToGo = new Stack<Point>();
Point location;
pointsToGo.Push(startLocation);
while (pointsToGo.Count > 0)
{
location = pointsToGo.Pop();
if (!location.X.IsBetween(0, array.GetLength(0) - 1))
continue;
if (!location.Y.IsBetween(0, array.GetLength(1) - 1))
continue;
if (!array[location.X, location.Y])
continue;
if (visitedLocations.Contains(location))
continue;
visitedLocations.Add(location);
pointsToGo.Push(new Point(location.X + 1, location.Y));
pointsToGo.Push(new Point(location.X, location.Y + 1));
pointsToGo.Push(new Point(location.X - 1, location.Y));
pointsToGo.Push(new Point(location.X, location.Y - 1));
}
foreach (Point location2 in visitedLocations)
{
array[location2.X, location2.Y] = false;
if (location2.X > maxX)
maxX = location2.X;
if (location2.X < minX)
minX = location2.X;
if (location2.Y > maxY)
maxY = location2.Y;
if (location2.Y < minY)
minY = location2.Y;
}
return new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
}
public static bool IsBetween<T>(this T item, T start, T end)
{
return Comparer<T>.Default.Compare(item, start) >= 0
&& Comparer<T>.Default.Compare(item, end) <= 0;
}
COMMENT :: It might help me to answer your question if you have better defined coordinates. (0,0,2,2) isn't exactly Cartesian and it may need some explaining. Is this the top left corner followed by the widths?
Ok. The easiest to program way, in my opinion at least, to extract all possible rectangles from the graph is to have a recursively defined method that searches in a specific direction for the symmetric rectangle pattern. This however could end up being really slow so I hope that speed isn't a constraint for you. Looking at the style of code, I would say that this is a school assignment for either recursion or dynamic programming.
something along the lines of the following pseudocode
`
for i in width
{
for j in height
{
if(point[i,j] == 1)
{
potentials = searh_in_direction(i,j,graph,width,height,RIGHT,[[i,j]] )
listOfAllRects.append(potentials)
}
}
}
list_of_rectangle searh_in_direction(i,j,graph,width,height,direction, listofpoints )
{
nextdirection = direction.nextdirection; //Right -> down -> left-> up
//DEVELOP METHOD FOR RECURSION HERE THAT RETURNS ALL SETS OF 4 POINTS THAT
for every point in the direction of travel
if the point is the origional point and we have 4 points including the point we are looking at, we have a rectangle and we need to return
if point on direction of travel is a one travel on the next direction
posiblerects.append(searh_in_direction(i,j,graph,width,height,nextdirection , listofpoints.append(currentpoint)))
//after all points in direction have bee searched
return posiblerects.
}
`
I know that this code could be very confusing but that is the gist of what you need as a recursive element.
I will also note that I can already see several bugs in this code but I have run out of the 15 minutes that I said that I was going to spend on this post so you might have to pick them out yourself.
This gives you the same results you're looking for:
static void Main(string[] args)
{
string values =
"1100000000" +
"1100000011" +
"0001100011" +
"0001100000" +
"0001110000" +
"0000000110" +
"0000000110";
int width = 10;
int height = 7;
bool[,] array = new bool[width, height];
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
array[x, y] = (values[x + y * width] == '1');
List<Rectangle> rectangles = new List<Rectangle>();
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
if (array[x, y] && !Used(rectangles, x, y))
{
int rHeight = 1;
for (int rX = x + 1; rX < width && array[rX, y] && !Used(rectangles, rX, y); ++rX)
for (int rY = y + 1; rY < height && array[rX, rY] && !Used(rectangles, rX, rY); ++rY)
if (rY - y >= rHeight)
rHeight = rY - y + 1;
int rWidth = 1;
for (int rY = y + 1; rY < height && rY - y <= rHeight && array[x, rY] && !Used(rectangles, x, rY); ++rY)
for (int rX = x + 1; rX < width && array[rX, rY] && !Used(rectangles, rX, rY); ++rX)
if (rX - x >= rWidth)
rWidth = rX - x + 1;
rectangles.Add(new Rectangle(x, y, rWidth, rHeight));
}
}
}
foreach (Rectangle rect in rectangles)
Console.WriteLine(rect);
}
private static bool Used(IEnumerable<Rectangle> rectangles, int x, int y)
{
return rectangles.Any(r => r.Contains(x, y));
}
I made an adhoc Rectangle struct since I didn't reference System.Drawing, but you can pass a System.Drawing.Point to the System.Drawing.Rectangle.Contains() and get the same results.
Also, notice that the width of your array should actually be 10 and your indexing math was wrong. You should be multiplying y by the width, not the height.
It is not clear from the question if you really want rectangles that cover the 1's exactly, or if you want bounding volumes that can contain zeroes, but will cover all the 1's with a reasonably small number of rectangles.
Assuming you want rectangles to cover the 1's, and you don't need a perfect solution:
Make a temporary copy of the array.
Iterate over the temporary looking for 1's
When you hit a 1, begin a new rectagle that starts as 1x1, offset to that location ( e.g. covers just that 1 )
Expand that rectangle rightward so long as there is a 1 in the next cell
Expand that rectangle downards so long as the row below has 1's matching the width
of the current rectangle.
ONce you can't expand down any more, emit that recgantle, and clear all the 1's covered by that rectangle from the temporary
continue scanning for 1's starting with the cell directly after the top right corner of the current rectangle.
This will produce a decent covering - but by no means ideal. If you need a perfect covering - e.g. the guaranteed minimum number of rectangles then it is harder.

Render points of Both a filled and unfilled Ellipse to Array in C#

Does anyone know of any code to render an Ellipse to an array in C#? I had a look about, I couldn't find anything that answered my problem.
Given the following array:
bool[,] pixels = new bool[100, 100];
I'm looking for functions to render both a hollow and filled ellipse within a rectangular area. e.g:
public void Ellipse(bool[,] pixels, Rectangle area)
{
// fill pixels[x,y] = true here for the ellipse within area.
}
public void FillEllipse(bool[,] pixels, Rectangle area)
{
// fill pixels[x,y] = true here for the ellipse within area.
}
Ellipse(pixels, new Rectangle(20, 20, 60, 60));
FillEllipse(pixels, new Rectangle(40, 40, 20, 20));
Any help would be greatly appreciated.
Something like this should do the trick
public class EllipseDrawer
{
private static PointF GetEllipsePointFromX(float x, float a, float b)
{
//(x/a)^2 + (y/b)^2 = 1
//(y/b)^2 = 1 - (x/a)^2
//y/b = -sqrt(1 - (x/a)^2) --Neg root for upper portion of the plane
//y = b*-sqrt(1 - (x/a)^2)
return new PointF(x, b * -(float)Math.Sqrt(1 - (x * x / a / a)));
}
public static void Ellipse(bool[,] pixels, Rectangle area)
{
DrawEllipse(pixels, area, false);
}
public static void FillEllipse(bool[,] pixels, Rectangle area)
{
DrawEllipse(pixels, area, true);
}
private static void DrawEllipse(bool[,] pixels, Rectangle area, bool fill)
{
// Get the size of the matrix
var matrixWidth = pixels.GetLength(0);
var matrixHeight = pixels.GetLength(1);
var offsetY = area.Top;
var offsetX = area.Left;
// Figure out how big the ellipse is
var ellipseWidth = (float)area.Width;
var ellipseHeight = (float)area.Height;
// Figure out the radiuses of the ellipses
var radiusX = ellipseWidth / 2;
var radiusY = ellipseHeight / 2;
//Keep track of the previous y position
var prevY = 0;
var firstRun = true;
// Loop through the points in the matrix
for (var x = 0; x <= radiusX; ++x)
{
var xPos = x + offsetX;
var rxPos = (int)ellipseWidth - x - 1 + offsetX;
if (xPos < 0 || rxPos < xPos || xPos >= matrixWidth)
{
continue;
}
var pointOnEllipseBoundCorrespondingToXMatrixPosition = GetEllipsePointFromX(x - radiusX, radiusX, radiusY);
var y = (int) Math.Floor(pointOnEllipseBoundCorrespondingToXMatrixPosition.Y + (int)radiusY);
var yPos = y + offsetY;
var ryPos = (int)ellipseHeight - y - 1 + offsetY;
if (yPos >= 0)
{
if (xPos > -1 && xPos < matrixWidth && yPos > -1 && yPos < matrixHeight)
{
pixels[xPos, yPos] = true;
}
if(xPos > -1 && xPos < matrixWidth && ryPos > -1 && ryPos < matrixHeight)
{
pixels[xPos, ryPos] = true;
}
if (rxPos > -1 && rxPos < matrixWidth)
{
if (yPos > -1 && yPos < matrixHeight)
{
pixels[rxPos, yPos] = true;
}
if (ryPos > -1 && ryPos < matrixHeight)
{
pixels[rxPos, ryPos] = true;
}
}
}
//While there's a >1 jump in y, fill in the gap (assumes that this is not the first time we've tracked y, x != 0)
for (var j = prevY - 1; !firstRun && j > y - 1 && y > 0; --j)
{
var jPos = j + offsetY;
var rjPos = (int)ellipseHeight - j - 1 + offsetY;
if(jPos == rjPos - 1)
{
continue;
}
if(jPos > -1 && jPos < matrixHeight)
{
pixels[xPos, jPos] = true;
}
if(rjPos > -1 && rjPos < matrixHeight)
{
pixels[xPos, rjPos] = true;
}
if (rxPos > -1 && rxPos < matrixWidth)
{
if(jPos > -1 && jPos < matrixHeight)
{
pixels[rxPos, jPos] = true;
}
if(rjPos > -1 && rjPos < matrixHeight)
{
pixels[rxPos, rjPos] = true;
}
}
}
firstRun = false;
prevY = y;
var countTarget = radiusY - y;
for (var count = 0; fill && count < countTarget; ++count)
{
++yPos;
--ryPos;
// Set all four points in the matrix we just learned about
// also, make the indication that for the rest of this row, we need to fill the body of the ellipse
if(yPos > -1 && yPos < matrixHeight)
{
pixels[xPos, yPos] = true;
}
if(ryPos > -1 && ryPos < matrixHeight)
{
pixels[xPos, ryPos] = true;
}
if (rxPos > -1 && rxPos < matrixWidth)
{
if(yPos > -1 && yPos < matrixHeight)
{
pixels[rxPos, yPos] = true;
}
if(ryPos > -1 && ryPos < matrixHeight)
{
pixels[rxPos, ryPos] = true;
}
}
}
}
}
}
Although there already seems to be a perfectly valid answer with source code and all to this question, I just want to point out that the WriteableBitmapEx project also contains a lot of efficient source code for drawing and filling different polygon types (such as ellipses) in so-called WriteableBitmap objects.
This code can easily be adapted to the general scenario where a 2D-array (or 1D representation of a 2D-array) should be rendered in different ways.
For the ellipse case, pay special attention to the DrawEllipse... methods in the WriteableBitmapShapeExtensions.cs file and FillEllipse... methods in the WriteableBitmapFillExtensions.cs file, everything located in the trunk/Source/WriteableBitmapEx sub-folder.
This more applies to all languages in general, and I'm not sure why you're looking for things like this in particular rather than using a pre-existing graphics library (homework?), but for drawing an ellipse, I would suggest using the midpoint line drawing algorithm which can be adapted to an ellipse (also to a circle):
http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
I'm not sure I fully agree that it's a generalisation of Bresenham's algorithm (certainly we were taught that Bresenham's and the Midpoint algorithm are different but proved to produce identical results), but that page should give you a start on it. See the link to the paper near the bottom for an algorithm specific to ellipses.
As for filling the ellipse, I'd say your best bet is to take a scanline approach - look at each row in turn, work out which pixels the lines on the left and right are at, and then fill every pixel inbetween.
The simplest thing to do would do is iterate over each element of your matrix, and check whether some ellipse equation evaluates to true
taken from http://en.wikipedia.org/wiki/Ellipse
What I would start with is something resembling
bool[,] pixels = new bool[100, 100];
double a = 30;
double b = 20;
for (int i = 0; i < 100; i++)
for (int j = 0; j < 100; j++ )
{
double x = i-50;
double y = j-50;
pixels[i, j] = (x / a) * (x / a) + (y / b) * (y / b) > 1;
}
and if your elipse is in reverse, than just change the > to <
For a hollow one, you can check whether the difference between (x / a) * (x / a) + (y / b) * (y / b) and 1 is within a certain threshold. If you just change the inequality to an equation, it will probably miss some pixels.
Now, I haven't actually tested this fully, so I don't know if the equation being applied correctly, but I just want to illustrate the concept.

Categories

Resources