有没有人知道在C#中将Ellipse渲染到数组的任何代码?我看了一下,找不到能解决问题的任何东西。
给出以下数组:
bool[,] pixels = new bool[100, 100];
我正在寻找在矩形区域内渲染空心和填充椭圆的函数。 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));
非常感谢任何帮助。
答案 0 :(得分:2)
这样的事情可以解决问题
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;
}
}
}
}
}
}
答案 1 :(得分:2)
虽然似乎已经有perfectly valid answer的源代码和所有这个问题,但我只想指出WriteableBitmapEx项目还包含很多高效的source code在所谓的WriteableBitmap
对象中绘制和填充不同的多边形类型(如椭圆)。
此代码可以很容易地适应一般场景,其中2D阵列(或2D阵列的1D表示)应以不同方式呈现。
对于椭圆情况,请特别注意 WriteableBitmapShapeExtensions.cs 文件中的DrawEllipse...
方法和 WriteableBitmapFillExtensions.cs中的FillEllipse...
方法文件,一切都位于 trunk / Source / WriteableBitmapEx 子文件夹中。
答案 2 :(得分:1)
这更适用于所有语言,而且我不确定为什么你会特别寻找这样的东西,而不是使用预先存在的图形库(作业?),而是用于绘图一个椭圆,我建议使用中点线绘制算法,它可以适应椭圆(也是一个圆):
http://en.wikipedia.org/wiki/Midpoint_circle_algorithm
我不确定我是否完全同意它是Bresenham算法的概括(当然我们被告知Bresenham&Midpoint算法不同但被证明产生相同的结果),但该页面应该为您提供一个开始。有关省略号的算法,请参阅底部附近纸张的链接。
至于填充椭圆,我说你最好的选择是采用扫描线方法 - 依次查看每一行,找出左右两侧的线条所在的像素,然后填写每一行像素中间。
答案 3 :(得分:0)
最简单的做法是迭代矩阵的每个元素,并检查一些椭圆方程是否计算为真
取自http://en.wikipedia.org/wiki/Ellipse
我开始的是类似于
的东西 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;
}
如果您的elipse正好相反,那么只需将>
更改为<
对于空心的,您可以检查(x / a) * (x / a) + (y / b) * (y / b)
和1
之间的差异是否在特定阈值之内。如果你只是将不等式改为等式,它可能会遗漏一些像素。
现在,我还没有完全测试过,所以我不知道方程是否正确应用,但我只想说明这个概念。