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