4点和椭圆

22

我有4个点... 我可以使用这段代码绘制多边形

var p = new Polygon();
p.Points.Add(new Point(0, 0));
p.Points.Add(new Point(70, 0));
p.Points.Add(new Point(90, 100));
p.Points.Add(new Point(0, 80));

如何使用Silverlight绘制适合此多边形的“椭圆”?

输入图像描述

问题仍未得到解答!!!


3
如果您无法立即找到任何可为您完成此操作的函数或代码(可能有,我只是不知道),则可以阅读此链接(http://chrisjones.id.au/Ellipses/ellipse.html)以提供如何解决此问题的思路。请注意不要更改原意并使内容更加易懂。 - Jeff Mercado
非常感谢提供链接,我数学不是很好,但我会尝试从这篇文章中“获取一些东西”。 - obenjiro
4
重要信息缺失:这个“椭圆”是否应该轴对齐,还是轴可以自由对齐?(根据您的示例图像,人们会得出它应该是轴对齐的印象。) - Dan Byström
1
+1. 这是一个非常有趣的问题。 - Todd Main
1
@Otaku,完全同意。 :-) +1。 - Stephen Chung
显示剩余3条评论
4个回答

9

一种方法是使用 QuadraticBezierSegment 或者 BezierSegment

例如,像这样:

    <Path Stroke="Red" StrokeThickness="2" >
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigureCollection>
                    <PathFigure StartPoint="0,40">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                <BezierSegment Point1="0,93"
                                           Point2="90,117"
                                           Point3="80,50"
                                           />                                       
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathFigureCollection>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
</Path>
<Path Stroke="Red" StrokeThickness="2" >
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigureCollection>
                    <PathFigure StartPoint="0,40">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                <BezierSegment Point1="0,-13"
                                           Point2="70,-17"
                                           Point3="80,50"
                                           />                                       
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathFigureCollection>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
</Path>
<Polygon Points="0,0 70,0 90,100 0,80"></Polygon>

它看起来像这样

这不是完美的解决方案,要想得到精确的结果,您必须计算曲线上的精确点并使用4个QuadraticBezierSegment

编辑: QuadraticBezierSegment的示例

<Path Stroke="Red" StrokeThickness="1">
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigureCollection>
                    <PathFigure StartPoint="0,40">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                    <QuadraticBezierSegment Point1="6,79"
                                           Point2="45,90"
                                           />                                       
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathFigureCollection>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
</Path>
    <Path Stroke="Red" StrokeThickness="1">
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure StartPoint="45,90">
                            <PathFigure.Segments>
                                <PathSegmentCollection>
                                    <QuadraticBezierSegment Point1="80,91"
                                           Point2="80,50"
                                           />
                                </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>
        </Path.Data>
    </Path>
    <Path Stroke="Red" StrokeThickness="1">
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigureCollection>
                    <PathFigure StartPoint="0,40">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                    <QuadraticBezierSegment Point1="2,3"
                                           Point2="35,0"
                                           />                                       
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathFigureCollection>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
</Path>
    <Path Stroke="Red" StrokeThickness="1">
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure StartPoint="35,0">
                            <PathFigure.Segments>
                                <PathSegmentCollection>
                                    <QuadraticBezierSegment Point1="72,8"
                                           Point2="80,50"
                                           />
                                </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>
        </Path.Data>
    </Path>
    <Polygon Name="pol"  Points="0,0 70,0 90,100 0,80" Stroke="Red" StrokeThickness="1"</Polygon>

这是一个示例图片

这还是一个实验性的算法,不过它非常准确。

编辑2: 您可以使用此图像和我的注释计算曲线的点:

输入图像描述

曲线有起始点、中间点和终点。在此图像中,起点和终点为L、M、N、O;中间点为W、X、Y、Z

例如,我们如何计算点L

通过直线方程y = k * x + b找到直线AB、DC、AC、DB、AD的方程。交叉点ACDB得到R。交叉点ABDC得到E。然后找到直线ER的方程,交叉点ERAD得到L

我们如何计算点W

通过长度公式l = sqrt(sqr(x2 - x1) + sqr(y2 - y1))找到AR的长度。使用公式AW = AR/(4*pi)和此系数,以及直线方程和长度公式,解方程组后得到W

其他点的计算方式类似。

这个算法不仅适用于具有平行线的多边形,而且在这种情况下,算法更加简单。长度系数也是相同的。

通过这个算法,我找到了您示例中3条曲线的点:

<Path Stroke="Red" StrokeThickness="1">
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigureCollection>
                    <PathFigure StartPoint="0,36">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                    <QuadraticBezierSegment Point1="4.7,74.6"
                                           Point2="39.9,88.9"
                                           />                                       
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathFigureCollection>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
</Path>
    <Path Stroke="Red" StrokeThickness="1">
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure StartPoint="39.9,88.9">
                            <PathFigure.Segments>
                                <PathSegmentCollection>
                                    <QuadraticBezierSegment Point1="83.43,92.7"
                                           Point2="78.8,43.9"
                                           />
                                </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>
        </Path.Data>
    </Path>
    <Path Stroke="Red" StrokeThickness="1">
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigureCollection>
                    <PathFigure StartPoint="0,36">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                    <QuadraticBezierSegment Point1="3.55,3.94"
                                           Point2="31.8,0"
                                           />                                       
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathFigureCollection>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
</Path>

这个曲线和椭圆线完全相同。如下图:

enter image description here

您可以将此算法转化为“公式”,从而找到您的解决方案。

您需要4个函数来完成这个过程:

1)从2个点的坐标中查找直线系数

2)从它的系数中找到与2条线交叉的点的坐标

3)从2个点的坐标中找到线段的长度

4)从该起始点的系数和坐标以及您在前一个函数中找到的长度(除以(4*pi))中找到位于该直线上的点的坐标

Edit3: 您可以优化这个解决方案,它有一些缺陷,比如平行线等。但它很快,如果您优化它可能满足您的要求。

Xaml:

<Path Stroke="Red" StrokeThickness="1">
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigureCollection>
                        <PathFigure x:Name="pathleftdown" StartPoint="0,0">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                    <QuadraticBezierSegment x:Name="bezleftdown" Point1="0,0"
                                           Point2="0,0"
                                           />                                       
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathFigureCollection>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
</Path>
    <Path Stroke="Red" StrokeThickness="1">
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure x:Name="pathrigthdown" StartPoint="0,0">
                            <PathFigure.Segments>
                                <PathSegmentCollection>
                                    <QuadraticBezierSegment x:Name="bezrigthdown" Point1="0,0"
                                           Point2="0,0"
                                           />
                                </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>
        </Path.Data>
    </Path>
    <Path Stroke="Red" StrokeThickness="1">
    <Path.Data>
        <PathGeometry>
            <PathGeometry.Figures>
                <PathFigureCollection>
                        <PathFigure x:Name="pathleftup"  StartPoint="0,0">
                        <PathFigure.Segments>
                            <PathSegmentCollection>
                                    <QuadraticBezierSegment x:Name="bezleftup" Point1="0,0"
                                           Point2="0,0"
                                           />                                       
                            </PathSegmentCollection>
                        </PathFigure.Segments>
                    </PathFigure>
                </PathFigureCollection>
            </PathGeometry.Figures>
        </PathGeometry>
    </Path.Data>
</Path>
    <Path Stroke="Red" StrokeThickness="1">
        <Path.Data>
            <PathGeometry>
                <PathGeometry.Figures>
                    <PathFigureCollection>
                        <PathFigure x:Name="pathrigthup"  StartPoint="0,0">
                            <PathFigure.Segments>
                                <PathSegmentCollection>
                                    <QuadraticBezierSegment x:Name="bezrigthup" Point1="0,0"
                                           Point2="0,0"
                                           />
                                </PathSegmentCollection>
                            </PathFigure.Segments>
                        </PathFigure>
                    </PathFigureCollection>
                </PathGeometry.Figures>
            </PathGeometry>
        </Path.Data>
    </Path>

    <Polygon Name="pol"  Points="0,0 250,0 251,340 0,341" Stroke="Red" StrokeThickness="1"></Polygon>
    <Button Content="Generate" Width ="80" Height="30" HorizontalAlignment="Right" VerticalAlignment="Top"  Click="Button_Click"></Button>

和代码:

private class pointXY
    {
        public double x;
        public double y;
    }
    private class lineKB
    {
        public double k;
        public double b;
        public bool flagXconst = false;
        public double xConst = 0;
    }

    private lineKB GetLineFromPonts(pointXY A, pointXY B)
    {
        lineKB line = new lineKB();
        if ((B.x - A.x) != 0)
        {
            line.k = (B.y - A.y) / (B.x - A.x);
            line.b = A.y - A.x * line.k;
        }
        else
        {
            line.xConst = A.x;
            line.flagXconst = true;
        }
        return line;
    }

    private pointXY GetPointFromLines(lineKB a, lineKB b)
    {
        pointXY point = new pointXY();
        if (a.flagXconst)
        {
            point.x = a.xConst;
            point.y = a.xConst * b.k + b.b;
        }else
            if (b.flagXconst)
            {
                point.x = b.xConst;
                point.y = b.xConst * a.k + a.b;
            }
            else
            {
                point.x = (a.b - b.b) / (b.k - a.k);
                point.y = a.k * point.x + a.b;
            }
        return point;
    }

    private double LengthOfLine(pointXY A, pointXY B)
    {
        return Math.Sqrt((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y));
    }

    private pointXY GetMidlePoint(pointXY S, double l, lineKB line, bool leftright)
    {
        double b = -2 * S.x - 2 * line.k * (-line.b + S.y);
        double a = (1 + line.k * line.k);
        double c = (S.x * S.x - l * l + (-line.b + S.y) * (-line.b + S.y));
        double d = b*b - 4 * a * c;
        double x1 = (-b + Math.Sqrt(d)) / (2 * a);
        double x2 = (-b - Math.Sqrt(d)) / (2 * a);
        pointXY ret = new pointXY();
        if (leftright)
            if (x1 > S.x) ret.x = x1;
            else ret.x = x2;
        else
            if (x1 < S.x) ret.x = x1;
            else ret.x = x2;
        ret.y = line.k * ret.x + line.b;
        return ret;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        pointXY A = new pointXY();
        A.x = pol.Points[0].X;
        A.y = pol.Points[0].Y;
        pointXY B = new pointXY();
        B.x = pol.Points[1].X;
        B.y = pol.Points[1].Y;
        pointXY C = new pointXY();
        C.x = pol.Points[2].X;
        C.y = pol.Points[2].Y;
        pointXY D = new pointXY();
        D.x = pol.Points[3].X;
        D.y = pol.Points[3].Y;
        lineKB AC = GetLineFromPonts(A, C);
        lineKB BD = GetLineFromPonts(B, D);
        pointXY R = GetPointFromLines(AC, BD);

        lineKB AB = GetLineFromPonts(A, B);
        lineKB BC = GetLineFromPonts(B, C);
        lineKB CD = GetLineFromPonts(C, D);
        lineKB DA = GetLineFromPonts(D, A);

        pointXY E = GetPointFromLines(AB, CD);
        lineKB ER = GetLineFromPonts(E, R);
        pointXY L = GetPointFromLines(ER, DA);
        pointXY N = GetPointFromLines(ER, BC);

        pointXY F = GetPointFromLines(BC, DA);
        lineKB FR = GetLineFromPonts(F, R);
        pointXY M = GetPointFromLines(FR, AB);
        pointXY O = GetPointFromLines(FR, CD);

        pointXY W = GetMidlePoint(A, (LengthOfLine(A, R) / (4 * Math.PI)), AC, true);
        pointXY X = GetMidlePoint(B, (LengthOfLine(B, R) / (4 * Math.PI)), BD, false);
        pointXY Y = GetMidlePoint(C, (LengthOfLine(C, R) / (4 * Math.PI)), AC, false);
        pointXY Z = GetMidlePoint(D, (LengthOfLine(D, R) / (4 * Math.PI)), BD, true);

        pathleftup.StartPoint = new Point(L.x, L.y);
        bezleftup.Point1 = new Point(W.x, W.y);
        bezleftup.Point2 = new Point(M.x, M.y);

        pathleftdown.StartPoint = new Point(L.x, L.y);
        bezleftdown.Point1 = new Point(Z.x, Z.y);
        bezleftdown.Point2 = new Point(O.x, O.y);

        pathrigthdown.StartPoint = new Point(O.x, O.y);
        bezrigthdown.Point1 = new Point(Y.x, Y.y);
        bezrigthdown.Point2 = new Point(N.x, N.y);

        pathrigthup.StartPoint = new Point(M.x, M.y);
        bezrigthup.Point1 = new Point(X.x, X.y);
        bezrigthup.Point2 = new Point(N.x, N.y);

    }

你能否用QuadraticBezierSergemts制作一个简单的例子,我自己试过,但结果不是很好:( - obenjiro
@Ai_boy 好的,我稍后添加,并在您的帖子中添加注释。 - Sonorx
@Ai_boy 我会尽力帮助你,如果我找到了,就会添加到我的答案中。 - Sonorx
3
你在这方面付出了_相当_多的努力,感谢你尽最大努力为我们做好了这件事 :) - Tim Post
@Tim Post 感谢您撤销了Wiki的更改。 - Sonorx
显示剩余2条评论

5

根据Jeff M提供的信息,我创建了一个函数,该函数返回适合于多边形内的椭圆:

Ellipse FitEllipse(Polygon poly)
    {
        double W0 = poly.Points[0].X;
        double W1 = poly.Points[0].Y;
        double X0 = poly.Points[1].X;
        double X1 = poly.Points[1].Y;
        double Y0 = poly.Points[2].X;
        double Y1 = poly.Points[2].Y;
        double Z0 = poly.Points[3].X;
        double Z1 = poly.Points[3].Y;

        double A =  X0 * Y0 * Z1 - W0 * Y0 * Z1 - X0 * Y1 * Z0 + W0 * Y1 * Z0 - W0 * X1 * Z0 + W1 * X0 * Z0 + W0 * X1 * Y0 - W1 * X0 * Y0;
        double B =  W0 * Y0 * Z1 - W0 * X0 * Z1 - X0 * Y1 * Z0 + X1 * Y0 * Z0 - W1 * Y0 * Z0 + W1 * X0 * Z0 + W0 * X0 * Y1 - W0 * X1 * Y0;
        double C =  X0 * Y0 * Z1 - W0 * X0 * Z1 - W0 * Y1 * Z0 - X1 * Y0 * Z0 + W1 * Y0 * Z0 + W0 * X1 * Z0 + W0 * X0 * Y1 - W1 * X0 * Y0;
        double D =  X1 * Y0 * Z1 - W1 * Y0 * Z1 - W0 * X1 * Z1 + W1 * X0 * Z1 - X1 * Y1 * Z0 + W1 * Y1 * Z0 + W0 * X1 * Y1 - W1 * X0 * Y1;
        double E = -X0 * Y1 * Z1 + W0 * Y1 * Z1 + X1 * Y0 * Z1 - W0 * X1 * Z1 - W1 * Y1 * Z0 + W1 * X1 * Z0 + W1 * X0 * Y1 - W1 * X1 * Y0;
        double F =  X0 * Y1 * Z1 - W0 * Y1 * Z1 + W1 * Y0 * Z1 - W1 * X0 * Z1 - X1 * Y1 * Z0 + W1 * X1 * Z0 + W0 * X1 * Y1 - W1 * X1 * Y0;
        double G =  X0 * Z1 - W0 * Z1 - X1 * Z0 + W1 * Z0 - X0 * Y1 + W0 * Y1 + X1 * Y0 - W1 * Y0;
        double H =  Y0 * Z1 - X0 * Z1 - Y1 * Z0 + X1 * Z0 + W0 * Y1 - W1 * Y0 - W0 * X1 + W1 * X0;
        double I =  Y0 * Z1 - W0 * Z1 - Y1 * Z0 + W1 * Z0 + X0 * Y1 - X1 * Y0 + W0 * X1 - W1 * X0;

        double detT = A * E * I + B * F * G + C * D * H - A * F * H - B * D * I - C * E * G;

        double J = (E * I - F * H) / detT;
        double K = (C * H - B * I) / detT;
        double L = (B * F - C * E) / detT;
        double M = (F * G - D * I) / detT;
        double N = (A * I - C * G) / detT;
        double O = (C * D - A * F) / detT;
        double P = (D * H - E * G) / detT;
        double Q = (B * G - A * H) / detT;
        double R = (A * E - B * D) / detT;

        double a = J * J + M * M + P * P;
        double b = J * K + M * N - P * Q;
        double c = K * K + N * N - Q * Q;
        double d = J * L + M * O - P * R;
        double f = K * L + N * O - Q * R;
        double g = L * L + O * O - R * R;

        double Ex = (c * d - b * f) / (b * b - a * c);
        double Ey = (a * f - b * d) / (b * b - a * c);

        double Ea = Math.Sqrt(2.0 * (a * f * f + c * d * d + g * b * b - 2.0 * b * d * f - a * c * g) / ((b * b - a * c) * (Math.Sqrt((a - c) * (a - c) + 4.0 * b * b) - (a + c))));
        double Eb = Math.Sqrt(2.0 * (a * f * f + c * d * d + g * b * b - 2.0 * b * d * f - a * c * g) / ((a * c - b * b) * (Math.Sqrt((a - c) * (a - c) + 4.0 * b * b) + (a + c))));

        double phi = 0;

        if (b == 0 && a < c) {
            phi = 0;
        } else if (b == 0 && a > c) {
            phi = Math.PI / 2;
        } else if (b != 0 && a < c) {
            phi = (Math.PI / 2 - Math.Atan((a - c) / (2 * b))) / 2;
        } else if (b != 0 && a > c) {
            phi = (Math.PI / 2 - Math.Atan((a - c) / (2 * b))) / 2 + Math.PI / 2;
        }

        Ellipse el = new Ellipse();
        el.Height = Ea * 2;
        el.Width  = Eb * 2;

        el.RenderTransform = new RotateTransform(phi * 180 / Math.PI);

        return el;
    }

哇,你做了很多工作。伙计,你太棒了 :) 但在我看来这有点“过度杀伤力”.. 还有“渲染变换”.. 我不认为浏览器能处理这种大量的“椭圆”。 - obenjiro
4
我一次只能追踪4个无意义的变量名称。 - BlueRaja - Danny Pflughoeft
+1 @Ai_boy 我一点也不认为这样做过度,看起来正好符合你的需求,而RenderTransforms应该足够便宜。 - Patrick Klug
如果我每秒绘制5000个“椭圆”,它会快速呈现吗?讽刺你的解决方案很完美..但对我来说不是,抱歉... - obenjiro

2

虽然使用四条Bezier曲线就可以很好地解决这个问题(而且可能是最简单的解决方案),但我在这里提出了一种不同的方法,仅仅是为了好玩。 :-)

这样考虑你的问题:给定一个常规的矩形,在内部画一个椭圆,然后将矩形“变形”为最终形状。

我认为你的变形转换不是线性的,因此你可能不能简单地找到一个矩阵来表示它(注意:我可能是错的,并且很想被证明是错的;这里有数学专家吗?)。 请参见下面的编辑。

其中一种方法是:首先画出椭圆,然后逐个拉伸/压缩四个角落之一。通过仅变形形状的一个角落,您始终可以保持左右两个角之间的对角线不变地插值椭圆曲线上的任何点到其新位置。

编辑:变换

从正方形开始(并且有一个内部的圆)。

  1. 将其旋转45度,使对角线成为轴
  2. 同时缩放轴线,使其匹配新形状的两条对角线的相对长度
  3. 将一个轴线倾斜到新形状的两条对角线之间的角度
  4. 平移一个轴线,使原点匹配新形状的对角线交叉点

请注意,所有四个变换都是纯线性或仿射(即线性+平移),因此它们均可用变换矩阵来表示。最终结果是另一种仿射变换,也可以由矩阵表示。

因此,这个矩阵将圆形形状转换为新形状。

希望我的数学没有错误...


这可能是一个解决方案..但我认为矩阵变换不会那么快..无论如何,你在这里有一个有趣的想法,我会尝试实现它,但我不擅长数学。 - obenjiro
1
+1 它不是线性的,而是投影的;因此你仍然可以找到一个(4x4)矩阵。 - BlueRaja - Danny Pflughoeft
真的吗?我认为投影变换不能处理所有四个角的任意平移...即四个变换后的角必须仍然遵守某些数学关系... :-) - Stephen Chung
但是GPU并不总是在Silverlight中工作(取决于硬件),而且现在Moonlight 2绝对没有GPU支持,我不能使用在任何地方都无法工作的解决方案。 - obenjiro
3
@Ai_boy,当GPU不可用时,Silverlight会退回到软件渲染。因此你不需要担心这个问题。任何可以在GPU上运行的东西都可以在没有GPU的情况下运行。矩阵操作仍然是最快的,因为Silverlight中的软件渲染仍然基于向量/矩阵。此外,它还利用了CPU的SIMD指令。 - Stephen Chung
显示剩余2条评论

1

卡斯滕的代码中有一个小错误

} else if (b != 0 && a < c) {
    phi = (Math.PI / 2 - Math.Atan((a - c) / (2 * b))) / 2;
} else if (b != 0 && a > c) {       

当a==c时,它返回phi = 0,这是不正确的。相反,上述行应该是

} else if (b != 0 && a < c) {
    phi = (Math.PI / 2 - Math.Atan((a - c) / (2 * b))) / 2;
} else if (b != 0 && a >= c) {

或者

} else if (b != 0 && a <= c) {
     phi = (Math.PI / 2 - Math.Atan((a - c) / (2 * b))) / 2;
} else if (b != 0 && a > c) {

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接