2

Ellipse を C# の配列にレンダリングするコードを知っている人はいますか? 私は見回しましたが、私の問題を解決するものは何も見つかりませんでした。

次の配列があるとします。

bool[,] pixels = new bool[100, 100];

長方形の領域内に中空と塗りつぶされた楕円の両方をレンダリングする関数を探しています。例えば:

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));

どんな助けでも大歓迎です。

4

4 に答える 4

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;
                    }
                }
            }
        }
    }
}
于 2012-06-28T09:29:59.227 に答える
2

ソース コードとこの質問に対する完全に有効な回答が既にあるようですが、 WriteableBitmapExプロジェクトには、さまざまな種類のポリゴン (楕円など) を描画および塗りつぶすための効率的なソース コードも多数含まれていることを指摘したいと思います。いわゆるWriteableBitmapオブジェクト。

このコードは、2D 配列 (または 2D 配列の 1D 表現) をさまざまな方法でレンダリングする必要がある一般的なシナリオに簡単に適用できます。

楕円の場合は、WriteableBitmapShapeExtensions.cs ファイルのメソッドと WriteableBitmapFillExtensions.cs ファイルのメソッドに特に注意してくださいこれらDrawEllipse...すべて、trunk/Source/WriteableBitmapExサブフォルダーにあります。FillEllipse...

于 2012-06-29T11:58:46.030 に答える
1

これは一般的にすべての言語に当てはまります。既存のグラフィックス ライブラリ (宿題?) を使用するのではなく、特にこのようなものを探している理由はわかりませんが、楕円を描画するには、使用することをお勧めします楕円(円にも)に適応できる中点線描画アルゴリズム:

http://en.wikipedia.org/wiki/Midpoint_circle_algorithm

これが Bresenham のアルゴリズムの一般化であることに完全に同意するかどうかはわかりません (確かに、Bresenham のアルゴリズムと Midpoint のアルゴリズムは異なるが、同じ結果を生成することが証明されていると教えられました)。楕円に固有のアルゴリズムについては、下部にある論文へのリンクを参照してください。

楕円の塗りつぶしに関しては、スキャンライン アプローチを採用することをお勧めします。各行を順番に見て、左右の線がどのピクセルにあるかを調べ、その間のすべてのピクセルを塗りつぶします。

于 2012-06-23T02:28:29.833 に答える
0

最も簡単な方法は、行列の各要素を反復処理し、楕円方程式がtrueと評価されるかどうかを確認することです。

ここに画像の説明を入力してください

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;
            }

楕円が逆になっている場合は、をに変更するだけではありません><

(x / a) * (x / a) + (y / b) * (y / b)中空のものの場合、との差が1特定のしきい値内にあるかどうかを確認できます。不等式を方程式に変更するだけでは、おそらくいくつかのピクセルが失われます。

さて、これを実際に完全にテストしていないので、方程式が正しく適用されているかどうかはわかりませんが、概念を説明したいと思います。

于 2012-06-27T21:46:34.003 に答える