public void CircleLineCross() {
            //  DisplayGeometryGraph.SetShowFunctions();

            const double chordLen = 1.5;
            const int cy = 3;
            const double cx = chordLen / 2;
            var r = Math.Sqrt(cy * cy + cx * cx);
            var center = new Point(cx, cy);
            var circle = new Ellipse(r, r, center);
            var a = new Point(-10, 0);
            var b = new Point(10, 0);
            var ca = a - center;
            var cb = b - center;
            const double angle = Math.PI / 6;
            ca = ca.Rotate(angle);
            cb = cb.Rotate(angle);
            a = center + ca;
            b = center + cb;
            var lineSeg = new LineSegment(a, b);
            var ii = Curve.GetAllIntersections(lineSeg, circle, true);
            //            DisplayGeometryGraph.ShowDebugCurves(new DebugCurve(100,0.01,"black", lineSeg), new DebugCurve(100,0.01,"blue", circle));
            Assert.IsTrue(ii.Count == 2);

            var roundedRect = new RoundedRect(new Rectangle(0, 100, 200, 0), 10, 10);
            lineSeg = new LineSegment(0, 0, 200, 100);
            //   DisplayGeometryGraph.ShowDebugCurves(new DebugCurve(100, 0.01, "black", lineSeg), new DebugCurve(100, 0.01, "blue", roundedRect));
            ii = Curve.GetAllIntersections(lineSeg, roundedRect, true);
            Assert.IsTrue(ii.Count == 2);

            lineSeg = new LineSegment(0, 100, 200, 0);
            // DisplayGeometryGraph.ShowDebugCurves(new DebugCurve(100, 0.01, "black", lineSeg), new DebugCurve(100, 0.01, "blue", roundedRect));            
            ii = Curve.GetAllIntersections(lineSeg, roundedRect, true);
            Assert.IsTrue(ii.Count == 2);

            lineSeg = new LineSegment(-2.05, 92.9, 8.27, 103.0);
            // DisplayGeometryGraph.ShowDebugCurves(new DebugCurve(100, 0.01, "black", lineSeg), new DebugCurve(100, 0.01, "blue", roundedRect));
            ii = Curve.GetAllIntersections(lineSeg, roundedRect, true);
            Assert.IsTrue(ii.Count == 0);

            var d = 10 * (Math.Sqrt(2) - 1) * Math.Sqrt(2);

            lineSeg = new LineSegment(d, 0, 0, d);
            var seg =
                roundedRect.Curve.Segments.Where(s => s is Ellipse).Select(s => (Ellipse)s).Where(
                    e => e.Center.X < 11 && e.Center.Y < 11).First();
            // DisplayGeometryGraph.ShowDebugCurves(new DebugCurve(100, 0.01, "black", lineSeg), new DebugCurve(100, 0.01, "blue", seg));
            ii = Curve.GetAllIntersections(lineSeg, seg, true);

            Assert.IsTrue(ii.Count == 1);


        }
Beispiel #2
0
        static void Main(string[] args)
        {
            #if TEST
            Microsoft.Msagl.GraphViewerGdi.DisplayGeometryGraph.SetShowFunctions();
            #endif

            //define a polygone
            var polygon=new Polyline(new []{new Point(0,0), new Point(7,8), new Point(7,7), new Point(8,8), new Point(5,0)}){Closed=true};
            var point = new Point(3, 3);

            var ellipse = new Ellipse(0.5, 0.5, point);//just to show the point

            //showing the polygon and the ellipse with the center at the point
            #if TEST
            LayoutAlgorithmSettings.Show(polygon, ellipse);
            #endif

            // prints out the location of the point relative ot the polygon
            Console.WriteLine(Curve.PointRelativeToCurveLocation(point, polygon));

            //=====================================================================//
            // find out if one curve intersects another
            var polygon0 = new Polyline(new[] { new Point(7.041886, 4.683227), new Point(7.102811, 5.797279), new Point(8.303899, 6.467452), new Point(8.547598, 5.1097) }) { Closed = true };
            #if TEST
            LayoutAlgorithmSettings.Show(polygon, polygon0);
            #endif

            if (PolylinesIntersect(polygon0, polygon))
                Console.WriteLine("intersects");
            else
                Console.WriteLine("do not intersects");

            (polygon0 as ICurve).Translate(new Point(1, 0));
            #if TEST
            LayoutAlgorithmSettings.Show(polygon, polygon0);
            #endif

            if (PolylinesIntersect(polygon0, polygon))
                Console.WriteLine("intersect");
            else
                Console.WriteLine("do not intersect");
        }
Beispiel #3
0
        static ParallelogramNodeOverICurve CreateNodeWithSegmentSplit(double start, double end, Ellipse seg, double eps)
        {
            var pBNode = new ParallelogramInternalTreeNode(seg, eps);

            pBNode.AddChild(CreateParallelogramNodeForCurveSeg(start, 0.5 * (start + end), seg, eps));
            pBNode.AddChild(CreateParallelogramNodeForCurveSeg(0.5 * (start + end), end, seg, eps));
            var boxes = new List <Parallelogram>();

            boxes.Add(pBNode.Children[0].Parallelogram);
            boxes.Add(pBNode.Children[1].Parallelogram);
            pBNode.Parallelogram = Parallelogram.GetParallelogramOfAGroup(boxes);
            return(pBNode);
        }
 public static float EllipseSweepAngle(Ellipse el) {
     return (float)((el.ParEnd - el.ParStart) / Math.PI * 180);
 }
 private void WriteEllipse(Shape shape, Ellipse ellipse)
 {
     this.outputFileWriter.WriteLine(RectFileStrings.BeginEllipse);
     this.outputFileWriter.WriteLine(RectFileStrings.WriteId, shapeToIdMap[shape]);
     this.outputFileWriter.WriteLine(
         RectFileStrings.WriteEllipse,
         ellipse.AxisA.X,
         ellipse.AxisA.Y,
         ellipse.AxisB.X,
         ellipse.AxisB.Y,
         ellipse.Center.X,
         ellipse.Center.Y);
     this.outputFileWriter.WriteLine(RectFileStrings.EndEllipse);
 }
Beispiel #6
0
 static ParallelogramNodeOverICurve CreateParallelogramNodeForCurveSeg(Ellipse seg)
 {
     return(CreateParallelogramNodeForCurveSeg(seg.ParStart, seg.ParEnd, seg,
                                               ParallelogramNodeOverICurve.DefaultLeafBoxesOffset));
 }
        static void WriteEllepticalArc(Ellipse ellipse) {
// ReSharper restore UnusedParameter.Local
            throw new NotImplementedException();
        }
 string EllipseRadiuses(Ellipse ellipse) {
     return DoubleToString(ellipse.AxisA.Length) + "," + DoubleToString(ellipse.AxisB.Length);
 }
        internal static ParallelogramNodeOverICurve CreateParallelogramNodeForCurveSeg(double start, double end,
                                                                                       Ellipse seg, double eps){
            bool closedSeg = (start == seg.ParStart && end == seg.ParEnd && ApproximateComparer.Close(seg.Start, seg.End));
            if(closedSeg)
                return CreateNodeWithSegmentSplit(start, end, seg, eps);

            Point s = seg[start];
            Point e = seg[end];
            Point w = e - s;
            Point middle = seg[(start + end) / 2];
           
            if (ParallelogramNodeOverICurve.DistToSegm(middle, s, e) <= ApproximateComparer.IntersectionEpsilon &&
                w * w < Curve.LineSegmentThreshold * Curve.LineSegmentThreshold && end - start < Curve.LineSegmentThreshold) {
                var ls = new LineSegment(s, e);
                var leaf = ls.ParallelogramNodeOverICurve as ParallelogramLeaf;
                leaf.Low = start;
                leaf.High = end;
                leaf.Seg = seg;
                leaf.Chord = ls;
                return leaf;
            }

            bool we = WithinEpsilon(seg, start, end, eps);
            var box = new Parallelogram();

            if(we && CreateParallelogramOnSubSeg(start, end, seg, ref box)){
                return new ParallelogramLeaf(start, end, box, seg, eps);
            } else{
                return CreateNodeWithSegmentSplit(start, end, seg, eps);
            }
        }
Beispiel #10
0
 static float EllipseStandardAngle(Ellipse ellipse, double angle)
 {
     MsaglPoint p = Math.Cos(angle) * ellipse.AxisA + Math.Sin(angle) * ellipse.AxisB;
     return (float)Math.Atan2(p.Y, p.X) * toDegrees;
 }
Beispiel #11
0
        static float EllipseSweepAngle(Ellipse el)
        {
            float sweepAngle = (float)(el.ParEnd - el.ParStart) * toDegrees;

            if (!OrientedCounterClockwise(el))
                sweepAngle = -sweepAngle;
            return sweepAngle;
        }
        ICurve ReadEllepticalArc(CurveStream curveStream, ref Point currentPoint) {
            /*
            var rx = "A"+DoubleToString(ellipse.AxisA.Length);
            var ry = DoubleToString(ellipse.AxisB.Length);
            var xAxisRotation = DoubleToString(180*Point.Angle(new Point(1, 0), ellipse.AxisA)/Math.PI);
            var largeArcFlag = Math.Abs(ellipse.ParEnd - ellipse.ParStart) >= Math.PI ? "1" : "0";
            var sweepFlag = ellipse.ParEnd > ellipse.ParStart ? "1" : "0"; //it happens because of the y-axis orientation down in SVG
            var endPoint=PointToString(ellipse.End);
            return string.Join(" ", new[] {rx, ry, xAxisRotation, largeArcFlag, sweepFlag, endPoint});
            var endPoint = GetCurveDataPoint(curveStream);
             */
            var rx = GetNextDoubleFromCurveData(curveStream);
            var ry = GetNextDoubleFromCurveData(curveStream);
            var xAxisRotation = GetNextDoubleFromCurveData(curveStream)/180*Math.PI;
            var largeArcFlag = (int) GetNextDoubleFromCurveData(curveStream);
            var sweepFlag = (int) GetNextDoubleFromCurveData(curveStream);
            var endPoint = GetNextPointFromCurveData(curveStream);
            //figure out the transform to the circle
            //then solve this problem on the circle
            if (ApproximateComparer.Close(rx, 0) || ApproximateComparer.Close(ry, 0))
                Error("ellipseArc radius is too small");
            var yScale = rx/ry;
            var rotationMatrix = PlaneTransformation.Rotation(-xAxisRotation);
            var scaleMatrix = new PlaneTransformation(1, 0, 0, 0, yScale, 0);
            var transform = scaleMatrix*rotationMatrix;
            var start = transform*currentPoint;
            currentPoint = endPoint;
            var end = transform*endPoint;
            Point center;
            double startAngle;
            double endAngle;
            Point axisY;
            GetArcCenterAndAngles(rx, largeArcFlag, sweepFlag, start, end, out center, out startAngle, out endAngle,
                out axisY);
            var inverted = transform.Inverse;
            center = inverted*center;
            var rotation = PlaneTransformation.Rotation(xAxisRotation);
            var axisX = rotation*new Point(rx, 0);
            axisY = rotation*(axisY/yScale);
            var ret = new Ellipse(startAngle, endAngle, axisX, axisY, center);

            Debug.Assert(ApproximateComparer.Close(ret.End, endPoint));
            return ret;
        }
 static IList<IntersectionInfo> GetIntersectionsWithArrowheadCircle(ICurve curve, double arrowheadLength, Point circleCenter) {
     Debug.Assert(arrowheadLength > 0);
     var e = new Ellipse(arrowheadLength, arrowheadLength, circleCenter);
     return Curve.GetAllIntersections(e, curve, true);
 }
        static void TryToAddPointToLineCircleCrossing(LineSegment lineSeg,
            Ellipse ellipse, List<IntersectionInfo> ret, Point point, double segLength, Point lineDir) {
            Point ds = point - lineSeg.Start;
            Point de = point - lineSeg.End;
            double t = ds*lineDir;
            if (t < -ApproximateComparer.DistanceEpsilon)
                return;
            t = Math.Max(t, 0);
            if (t > segLength + ApproximateComparer.DistanceEpsilon)
                return;
            t = Math.Min(t, segLength);
            t /= segLength;

            double angle = Point.Angle(ellipse.AxisA, point - ellipse.Center);
            if (ellipse.ParStart - ApproximateComparer.Tolerance <= angle) {
                angle = Math.Max(angle, ellipse.ParStart);
                if (angle <= ellipse.ParEnd + ApproximateComparer.Tolerance) {
                    angle = Math.Min(ellipse.ParEnd, angle);
                    ret.Add(new IntersectionInfo(t, angle, point, lineSeg, ellipse));
                }
            }
        }
        static IList<IntersectionInfo> GetAllIntersectionsOfLineAndArc(LineSegment lineSeg, Ellipse ellipse) {
            Point lineDir = lineSeg.End - lineSeg.Start;
            var ret = new List<IntersectionInfo>();
            double segLength = lineDir.Length;
            if (segLength < ApproximateComparer.DistanceEpsilon) {
                if (ApproximateComparer.Close((lineSeg.Start - ellipse.Center).Length, ellipse.AxisA.Length)) {
                    double angle = Point.Angle(ellipse.AxisA, lineSeg.Start - ellipse.Center);
                    if (ellipse.ParStart - ApproximateComparer.Tolerance <= angle) {
                        angle = Math.Max(angle, ellipse.ParStart);
                        if (angle <= ellipse.ParEnd + ApproximateComparer.Tolerance) {
                            angle = Math.Min(ellipse.ParEnd, angle);
                            ret.Add(new IntersectionInfo(0, angle, lineSeg.Start, lineSeg, ellipse));
                        }
                    }
                }
                return ret;
            }

            Point perp = lineDir.Rotate90Ccw()/segLength;
            double segProjection = (lineSeg.Start - ellipse.Center)*perp;
            Point closestPointOnLine = ellipse.Center + perp*segProjection;

            double rad = ellipse.AxisA.Length;
            double absSegProj = Math.Abs(segProjection);
            if (rad < absSegProj - ApproximateComparer.DistanceEpsilon)
                return ret; //we don't have an intersection
            lineDir = perp.Rotate90Cw();
            if (ApproximateComparer.Close(rad, absSegProj))
                TryToAddPointToLineCircleCrossing(lineSeg, ellipse, ret, closestPointOnLine, segLength, lineDir);
            else {
                Debug.Assert(rad > absSegProj);
                double otherLeg = Math.Sqrt(rad*rad - segProjection*segProjection);
                TryToAddPointToLineCircleCrossing(lineSeg, ellipse, ret, closestPointOnLine + otherLeg*lineDir,
                                                  segLength, lineDir);
                TryToAddPointToLineCircleCrossing(lineSeg, ellipse, ret, closestPointOnLine - otherLeg*lineDir,
                                                  segLength, lineDir);
            }

            return ret;
        }
        /// <summary>
        /// this code only works for the standard ellipse
        /// </summary>
        /// <param name="ellipse"></param>
        /// <returns></returns>
        static Polyline RefineEllipse(Ellipse ellipse) {
            Polyline rect = StandardRectBoundary(ellipse);
            var dict = new SortedDictionary<double, Point>();
            double a = Math.PI/4;
            double w = ellipse.BoundingBox.Width;
            double h = ellipse.BoundingBox.Height;
            double l = Math.Sqrt(w*w + h*h);
            for (int i = 0; i < 4; i++) {
                double t = a + i*Math.PI/2; // parameter
                Point p = ellipse[t]; //point on the ellipse
                Point tan = l*(ellipse.Derivative(t).Normalize()); //make it long enough

                var ls = new LineSegment(p - tan, p + tan);
                //System.Diagnostics.Debug.Assert(ls.Start.X > -10000);
                foreach (IntersectionInfo ix in GetAllIntersections(rect, ls, true))
                    dict[ix.Par0] = ix.IntersectionPoint;
            }

            Debug.Assert(dict.Count > 0);
            return new Polyline(dict.Values) {Closed = true};
        }
 static bool IsFullEllipse(Ellipse ell) {
     return ell.ParEnd == Math.PI * 2 && ell.ParStart == 0;
 }
Beispiel #18
0
 static bool OrientedCounterClockwise(Ellipse ellipse)
 {
     return ellipse.AxisA.X * ellipse.AxisB.Y - ellipse.AxisB.X * ellipse.AxisA.Y > 0;
 }
        string EllipseToString(Ellipse ellipse) {
            string largeArc = Math.Abs(ellipse.ParEnd-ellipse.ParStart) >= Math.PI? "1":"0";
            string sweepFlag= ellipse.OrientedCounterclockwise()?"1":"0";

            return String.Join(" ", "A", EllipseRadiuses(ellipse), DoubleToString(Point.Angle(new Point(1, 0), ellipse.AxisA) / (Math.PI / 180.0)), largeArc, sweepFlag, PointsToString(ellipse.End));
        }
        static bool WithinEpsilon(Ellipse seg, double start, double end, double eps){
            int n = 3; //hack !!!! but maybe can be proven for Bezier curves and other regular curves
            double d = (end - start)/n;
            Point s = seg[start];
            Point e = seg[end];

            double d0 = ParallelogramNodeOverICurve.DistToSegm(seg[start + d], s, e);
            if(d0 > eps)
                return false;

            double d1 = ParallelogramNodeOverICurve.DistToSegm(seg[start + d*(n - 1)], s, e);
            //double d1d1 = seg.d1(start) * seg.d1(end);

            return d1 <= eps; // && d1d1 > 0;
        }
 static ParallelogramNodeOverICurve CreateNodeWithSegmentSplit(double start, double end, Ellipse seg, double eps){
     var pBNode = new ParallelogramInternalTreeNode(seg, eps);
     pBNode.AddChild(CreateParallelogramNodeForCurveSeg(start, 0.5*(start + end), seg, eps));
     pBNode.AddChild(CreateParallelogramNodeForCurveSeg(0.5*(start + end), end, seg, eps));
     var boxes = new List<Parallelogram>();
     boxes.Add(pBNode.Children[0].Parallelogram);
     boxes.Add(pBNode.Children[1].Parallelogram);
     pBNode.Parallelogram = Parallelogram.GetParallelogramOfAGroup(boxes);
     return pBNode;
 }
 void WriteEllipseInSvgStyle( Ellipse ellipse) {
     if( ApproximateComparer.Close(ellipse.ParStart,0) && ApproximateComparer.Close(ellipse.ParEnd, 2*Math.PI)) { WriteFullEllipse(ellipse); }
     else
     {
         WriteEllepticalArc(ellipse);
     }
 }
        internal static bool CreateParallelogramOnSubSeg(double start, double end, Ellipse seg, ref Parallelogram box){
            Point tan1 = seg.Derivative(start);

            Point tan2 = seg.Derivative(end);
            Point tan2Perp = Point.P(-tan2.Y, tan2.X);

            Point corner = seg[start];

            Point e = seg[end];

            Point p = e - corner;

            double numerator = p*tan2Perp;
            double denumerator = (tan1*tan2Perp);
            double x; // = (p * tan2Perp) / (tan1 * tan2Perp);
            if(Math.Abs(numerator) < ApproximateComparer.DistanceEpsilon)
                x = 0;
            else if(Math.Abs(denumerator) < ApproximateComparer.DistanceEpsilon){
                //it is degenerated; adjacent sides are parallel, but 
                //since p * tan2Perp is big it does not contain e
                return false;
            } else x = numerator/denumerator;

            tan1 *= x;

            box = new Parallelogram(corner, tan1, e - corner - tan1);
#if DEBUGCURVES
      if (!box.Contains(seg[end]))
      {
      
        throw new InvalidOperationException();//"the box does not contain the end of the segment");
      }
#endif

            return true;
        }
Beispiel #24
0
        internal static ParallelogramNodeOverICurve CreateParallelogramNodeForCurveSeg(double start, double end,
                                                                                       Ellipse seg, double eps)
        {
            bool closedSeg = (start == seg.ParStart && end == seg.ParEnd && ApproximateComparer.Close(seg.Start, seg.End));

            if (closedSeg)
            {
                return(CreateNodeWithSegmentSplit(start, end, seg, eps));
            }

            Point s      = seg[start];
            Point e      = seg[end];
            Point w      = e - s;
            Point middle = seg[(start + end) / 2];

            if (ParallelogramNodeOverICurve.DistToSegm(middle, s, e) <= ApproximateComparer.IntersectionEpsilon &&
                w * w < Curve.LineSegmentThreshold * Curve.LineSegmentThreshold && end - start < Curve.LineSegmentThreshold)
            {
                var ls   = new LineSegment(s, e);
                var leaf = ls.ParallelogramNodeOverICurve as ParallelogramLeaf;
                leaf.Low   = start;
                leaf.High  = end;
                leaf.Seg   = seg;
                leaf.Chord = ls;
                return(leaf);
            }

            bool we  = WithinEpsilon(seg, start, end, eps);
            var  box = new Parallelogram();

            if (we && CreateParallelogramOnSubSeg(start, end, seg, ref box))
            {
                return(new ParallelogramLeaf(start, end, box, seg, eps));
            }
            else
            {
                return(CreateNodeWithSegmentSplit(start, end, seg, eps));
            }
        }
 static ParallelogramNodeOverICurve CreateParallelogramNodeForCurveSeg(Ellipse seg) {
     return CreateParallelogramNodeForCurveSeg(seg.ParStart, seg.ParEnd, seg,
                                               ParallelogramNodeOverICurve.DefaultLeafBoxesOffset);
 }
Beispiel #26
0
        public static double EllipseSweepAngle(MEllipse ellipse)
        {
            double sweepAngle = ellipse.ParEnd - ellipse.ParStart;

            return(ellipse.OrientedCounterclockwise() ? sweepAngle : -sweepAngle);
        }
 void WriteFullEllipse(Ellipse ellipse) {
     WriteStartElement(GeometryToken.Ellipse);
     WriteAttribute(GeometryToken.Cx, ellipse.Center.X);
     WriteAttribute(GeometryToken.Cy, ellipse.Center.Y);
     WriteAttribute(GeometryToken.Rx, ellipse.AxisA.Length);
     WriteAttribute(GeometryToken.Ry, ellipse.AxisB.Length);
     WriteEndElement();
 }
 static Point CornerPoint(Ellipse ellipse) {
     return ellipse.Center + ellipse.AxisA + ellipse.AxisB;
 }
 string EllipticalArcToString(Ellipse ellipse) {
     /*
      * rx ry x-axis-rotation large-arc-flag sweep-flag x y
      * */
     //In general in an Msagl ellipse the axes don't have to be orthogonal: we have a possible bug here
     var rx = "A"+DoubleToString(ellipse.AxisA.Length);
     var ry = DoubleToString(ellipse.AxisB.Length);
     var xAxisRotation = DoubleToString(180*Point.Angle(new Point(1, 0), ellipse.AxisA)/Math.PI);
     var largeArcFlag = Math.Abs(ellipse.ParEnd - ellipse.ParStart) >= Math.PI ? "1" : "0";
     var sweepFlagInt = ellipse.ParEnd > ellipse.ParStart ? 1 : 0; //it happens because of the y-axis orientation down in SVG
     if (AxesSwapped(ellipse.AxisA, ellipse.AxisB)) {
         sweepFlagInt = sweepFlagInt == 1 ? 0 : 1;
     }
     var endPoint=PointToString(ellipse.End);
     return string.Join(" ", new[] {rx, ry, xAxisRotation, largeArcFlag, sweepFlagInt.ToString(), endPoint});
 }
 private static bool EllipseIsAlmostLineSegment(Ellipse ellipse) {
     return ellipse.AxisA.LengthSquared < 0.0001 || ellipse.AxisB.LengthSquared<0.0001;
 }
 public static float EllipseStartAngle(Ellipse el) {
     return (float)(el.ParStart / Math.PI * 180);
 }
        private static IEnumerable<Ellipse> GetFittedArcSegs(double radius, Point[] polyline) {
            Point leg = polyline[1] - polyline[0];
            Point dir = leg.Normalize();
            double rad0 = Math.Min(radius, leg.Length/2);

            for (int i = 1; i < polyline.Length - 1; i++) {
                Ellipse ret = null;
                leg = polyline[i + 1] - polyline[i];
                double legLength = leg.Length;

                if (legLength < ApproximateComparer.IntersectionEpsilon)
                    ret = new Ellipse(0, 0, polyline[i]);

                Point ndir = leg/legLength;
                if (Math.Abs(ndir*dir) > 0.9) //the polyline does't make a 90 degrees turn
                    ret = new Ellipse(0, 0, polyline[i]);

                double nrad0 = Math.Min(radius, leg.Length/2);
                Point axis0 = -nrad0*ndir;
                Point axis1 = rad0*dir;
                yield return ret ?? (new Ellipse(0, Math.PI/2, axis0, axis1, polyline[i] - axis1 - axis0));
                dir = ndir;
                rad0 = nrad0;
            }
        }
        /// <summary>
        /// returns the arc that a,b,c touches
        /// </summary>
        /// <param name="a">belongs to the arc, the tangent point of ba</param>
        /// <param name="b">ba, and bc are tangents to the arc</param>
        /// <param name="c">belongs to the arc, the tangent point of bc</param>
        /// <returns></returns>
        internal static ICurve ArcOn(Point a, Point b, Point c) {
            Point center;
            if (Math.Abs(Point.SignedDoubledTriangleArea(a, b, c)) < 0.0001 || !FindArcCenter(a, b, c, out center))
                return new LineSegment(a, c);

            var radius = (a - center).Length;
            var chordLength = (a - b).Length;
            if (chordLength / radius < 0.0001)//to avoid a floating point error
                return new LineSegment(a, c);
            var cenA = a - center;
            var aAngle = Math.Atan2(cenA.Y, cenA.X);
            var cenC = c - center;
            var cAngle = Math.Atan2(cenC.Y, cenC.X);
            var delac = cAngle - aAngle;
            if (delac < 0) {
                delac += 2 * Math.PI;
                cAngle += 2 * Math.PI;
            }
            if (delac <= Math.PI) {
                //going ccw
                var el = new Ellipse(aAngle, cAngle, new Point(radius, 0), new Point(0, radius), center);
                return el;
            }

            //going clockwise
            if (cAngle > 2 * Math.PI)
                cAngle -= 2 * Math.PI;

            aAngle = Math.PI - aAngle;
            cAngle = Math.PI - cAngle;
            if (aAngle < 0)
                aAngle += 2 * Math.PI;
            while (cAngle < aAngle)
                cAngle += 2 * Math.PI;

            delac = cAngle - aAngle;

            Debug.Assert(delac <= Math.PI);

            return new Ellipse(aAngle, cAngle, new Point(-radius, 0), new Point(0, radius), center);
        }
 public static double EllipseSweepAngle(Ellipse ellipse) {
     double sweepAngle = ellipse.ParEnd - ellipse.ParStart;
     return ellipse.OrientedCounterclockwise() ? sweepAngle : -sweepAngle;
 }