如何在CF中绘制部分椭圆? (完整框架中的Graphics.DrawArc)

时间:2012-08-27 15:51:06

标签: graphics drawing compact-framework system.drawing compact-framework2.0

我希望会有一个简单的答案,因为有时候,从Compact Framework中删除的东西有一种以看似迂回的方式执行的方式,但是效果与完整的框架一样(或者可以提高效率) )。

简单地说,我希望能够在Compact Framework 2.0中执行类似于System.Drawing.Graphics.DrawArc(...)的功能。

用于UserControl的OnPaint覆盖,在我已经填充的椭圆内绘制弧。

基本上(关闭伪代码,请忽略参数中的缺陷):

FillEllipse(ellipseFillBrush, largeEllipseRegion);
DrawArc(arcPen, innerEllipseRegion, startAngle, endAngle); //not available in CF

我只在90度空间中绘制弧线,因此椭圆弧的右下角或左上角。如果任何角度的答案真的是迂回,困难或低效,而对于只做只是椭圆的一个角落的简单解决方案,我对后者很好,尽管前者会有所帮助其他有类似问题的人。

3 个答案:

答案 0 :(得分:4)

我使用此代码,然后将FillPolygon或DrawPolygon与输出点一起使用:

private Point[] CreateArc(float StartAngle, float SweepAngle, int PointsInArc, int Radius, int xOffset, int yOffset, int LineWidth)
{
    if(PointsInArc < 0)
        PointsInArc = 0;

    if(PointsInArc > 360)
        PointsInArc = 360;

    Point[] points = new Point[PointsInArc * 2];
    int xo;
    int yo;
    int xi;
    int yi;
    float degs;
    double rads;

    for(int p = 0 ; p < PointsInArc ; p++)
    {
        degs = StartAngle + ((SweepAngle / PointsInArc) * p);

        rads = (degs * (Math.PI / 180));

        xo = (int)(Radius * Math.Sin(rads));
        yo = (int)(Radius * Math.Cos(rads));
        xi = (int)((Radius - LineWidth) * Math.Sin(rads));
        yi = (int)((Radius - LineWidth) * Math.Cos(rads));

        xo += (Radius + xOffset);
        yo = Radius - yo + yOffset;
        xi += (Radius + xOffset);
        yi = Radius - yi + yOffset;

        points[p] = new Point(xo, yo);
        points[(PointsInArc * 2) - (p + 1)] = new Point(xi, yi);
    }

    return points;
}

答案 1 :(得分:1)

我确实遇到了这个问题,我和我的团队解决了为紧凑框架图形类创建扩展方法的问题;

我希望我可以帮助别人,因为我花了很多精力来获得这个好的解决方案

Mauricio de Sousa Coelho

嵌入式软件工程师

public static class GraphicsExtension
{
    // Implements the native Graphics.DrawArc as an extension
    public static void DrawArc(this Graphics g, Pen pen, float x, float y, float width, float height, float startAngle, float sweepAngle)
    {
        //Configures the number of degrees for each line in the arc
        int degreesForNewLine = 5;

        //Calculates the number of points in the arc based on the degrees for new line configuration
        int pointsInArc = Convert.ToInt32(Math.Ceiling(sweepAngle / degreesForNewLine)) + 1;

        //Minimum points for an arc is 3
        pointsInArc = pointsInArc < 3 ? 3 : pointsInArc;

        float centerX = (x + width) / 2;
        float centerY = (y + height) / 2;

        Point previousPoint = GetEllipsePoint(x, y, width, height, startAngle);

        //Floating point precision error occurs here
        double angleStep = sweepAngle / pointsInArc;

        Point nextPoint;
        for (int i = 1; i < pointsInArc; i++)
        {
            //Increments angle and gets the ellipsis associated to the incremented angle
            nextPoint = GetEllipsePoint(x, y, width, height, (float)(startAngle + angleStep * i));

            //Connects the two points with a straight line
            g.DrawLine(pen, previousPoint.X, previousPoint.Y, nextPoint.X, nextPoint.Y);

            previousPoint = nextPoint;
        }

        //Garantees connection with the last point so that acumulated errors cannot
        //cause discontinuities on the drawing
        nextPoint = GetEllipsePoint(x, y, width, height, startAngle + sweepAngle);
        g.DrawLine(pen, previousPoint.X, previousPoint.Y, nextPoint.X, nextPoint.Y);
    }

    // Retrieves a point of an ellipse with equation:
    private static Point GetEllipsePoint(float x, float y, float width, float height, float angle)
    {
        return new Point(Convert.ToInt32(((Math.Cos(ToRadians(angle)) * width + 2 * x + width) / 2)), Convert.ToInt32(((Math.Sin(ToRadians(angle)) * height + 2 * y + height) / 2)));
    }

    // Converts an angle in degrees to the same angle in radians.
    private static float ToRadians(float angleInDegrees)
    {
        return (float)(angleInDegrees * Math.PI / 180);
    }
}

答案 2 :(得分:0)

跟随@ ctacke的响应,它为圆形(高度==宽度)创建了一个弧形多边形,我进一步编辑它并创建了一个函数,用于为曲线创建一个Point数组,而不是多边形,以及任何椭圆。

注意:StartAngle在这里是NOON位置,90度是3点钟位置,所以StartAngle = 0和SweepAngle = 90从中午到3点位置产生弧线。
原始的DrawArc方法将3点设置为0度,将90度设置为6点钟位置。只需注意用CreateArc替换DrawArc,然后用生成的Point []数组替换DrawLine 我会更进一步改变这一点,但为什么要打破一些有用的东西呢?

private Point[] CreateArc(float StartAngle, float SweepAngle, int PointsInArc, int ellipseWidth, int ellipseHeight, int xOffset, int yOffset)
{
    if (PointsInArc < 0)
        PointsInArc = 0;

    if (PointsInArc > 360)
        PointsInArc = 360;

    Point[] points = new Point[PointsInArc];
    int xo;
    int yo;
    float degs;
    double rads;

    //could have WidthRadius and HeightRadius be parameters, but easier
    // for maintenance to have the diameters sent in instead, matching closer
    // to DrawEllipse and similar methods
    double radiusW = (double)ellipseWidth / 2.0;
    double radiusH = (double)ellipseHeight / 2.0;

    for (int p = 0; p < PointsInArc; p++)
    {
        degs = StartAngle + ((SweepAngle / PointsInArc) * p);

        rads = (degs * (Math.PI / 180));

        xo = (int)Math.Round(radiusW * Math.Sin(rads), 0);
        yo = (int)Math.Round(radiusH * Math.Cos(rads), 0);

        xo += (int)Math.Round(radiusW, 0) + xOffset;
        yo = (int)Math.Round(radiusH, 0) - yo + yOffset;

        points[p] = new Point(xo, yo);
    }

    return points;
}