/// <summary> /// Create a rounded rectangle geometry /// </summary> /// <param name="bounds">rounded rectangle will fit these bounds</param> /// <param name="radiusX">horizontal radius of the corner ellipse segments</param> /// <param name="radiusY">vertical radius of the corner ellipse segments</param> public RoundedRect(Rectangle bounds, double radiusX, double radiusY) { RadiusX = radiusX; RadiusY = radiusY; curve = new Curve(8); CurveFactory.CreateRectangleWithRoundedCorners(curve, bounds.Width, bounds.Height, radiusX, radiusY, bounds.Center); }
void CreateCurveLine(Metroline line, EdgeGeometry edge) { var c = new Curve(); Point start = FindCurveStart(metroGraphData, metroOrdering, line); Point currentEnd = start; var hubSegsOfLine = HubSegsOfLine(metroGraphData, metroOrdering, line); foreach (var seg in hubSegsOfLine) { if (seg == null) continue; c.AddSegment(new LineSegment(currentEnd, seg.Start)); c.AddSegment(seg); currentEnd = seg.End; } c.AddSegment(new LineSegment(currentEnd, FindCurveEnd(metroGraphData, metroOrdering, line))); edge.Curve = c; if (CreateUnderlyingPolylines) edge.SmoothedPolyline = BuildUnderlyingPolyline(start, currentEnd, hubSegsOfLine); }
/// <summary> /// Create in the specified curve, a rectangle with smoothed corners /// </summary> /// <param name="c"></param> /// <param name="width">the rectangle width</param> /// <param name="height">the rectangle height</param> /// <param name="radiusInXDirection">the length of the x axis of the corner smoothing ellipse</param> /// <param name="radiusInYDirection">the length of the y axis of the corner smoothing ellipse</param> /// <param name="center">the rectangle center</param> /// <returns></returns> static internal void CreateRectangleWithRoundedCorners(Curve c, double width, double height, double radiusInXDirection, double radiusInYDirection, Point center) { if (radiusInXDirection == 0 || radiusInYDirection == 0) { CreateRectangle(c, width, height, center); return; } double w = width / 2; if (radiusInXDirection > w/2) radiusInXDirection = w/2; double h = height / 2; if (radiusInYDirection > h/2) radiusInYDirection = h/2; double x = center.X; double y = center.Y; double ox = w - radiusInXDirection; double oy = h - radiusInYDirection; double top = y + h; double bottom = y - h; double left = x - w; double right = x + w; //ellipse's axises Point a = new Point(radiusInXDirection, 0); Point b = new Point(0, radiusInYDirection); c.IncreaseSegmentCapacity(8); if (ox > 0) c.AddSegment(new LineSegment(new Point(x - ox, bottom), new Point(x + ox, bottom))); c.AddSegment(new Ellipse(1.5 * Math.PI, 2 * Math.PI, a, b, x + ox, y - oy)); if (oy > 0) c.AddSegment(new LineSegment(new Point(right, y - oy), new Point(right, y + oy))); c.AddSegment(new Ellipse(0, 0.5 * Math.PI, a, b, x + ox, y + oy)); if (ox > 0) c.AddSegment(new LineSegment(new Point(x + ox, top), new Point(x - ox, top))); c.AddSegment(new Ellipse(0.5 * Math.PI, Math.PI, a, b, x - ox, y + oy)); if (oy > 0) c.AddSegment(new LineSegment(new Point(left, y + oy), new Point(left, y - oy))); c.AddSegment(new Ellipse(Math.PI, 1.5 * Math.PI, a, b, x - ox, y - oy)); }
ICurve TrimEntryCurve(Tuple<double, double> span) { var start = span.Item1; var end = span.Item2; if (start < end) { return this.EntryCurve.Trim(start, end); } // For the classes that implement it, wrap the Trim. if ((this.EntryCurve is Polyline) || (this.EntryCurve is Curve) || (this.EntryCurve is RoundedRect)) { return this.EntryCurve.TrimWithWrap(start, end); } // Ellipse does not (yet) support TrimWithWrap but for our purposes we can deal with it as a Curve. if (this.EntryCurve is Ellipse) { var c = new Curve(); c.AddSegment(this.EntryCurve.Trim(start, this.EntryCurve.ParEnd)); c.AddSegment(this.EntryCurve.Trim(this.EntryCurve.ParStart, end)); return c; } // For the remaining implementations of ICurve, this is what Trim does if start is greater than end, unless it throws. return this.EntryCurve.Trim(end, start); }
private void VerifyPolylines() { // Is this still needed? foreach (DEdge e in Edges.Concat(m_CrossEdges)) { var edge = e.GeometryEdge; if (edge.UnderlyingPolyline != null) continue; if (edge.Curve == null) continue; Curve c = edge.Curve as Curve; if (c == null) { c = new Curve(); c.Segments.Add(edge.Curve); } edge.UnderlyingPolyline = Microsoft.Msagl.Core.Geometry.SmoothedPolyline.FromPoints(new[] { edge.Source.Center }.Concat(PolylineFromCurve(c)).Concat(new[] { edge.Target.Center })); } }
private Curve ExtendCurveToEndpoints(Curve curve) { Point p = this.EdgePathPoint(0); if (!ApproximateComparer.Close(p, curve.Start)) { Curve nc = new Curve(); nc.AddSegs(new LineSegment(p, curve.Start), curve); curve = nc; } p = this.EdgePathPoint(edgePath.Count); if (!ApproximateComparer.Close(p, curve.End)) curve.AddSegment(new LineSegment(curve.End, p)); return curve; }
private static MsaglPolyline PolylineFromCurve(Curve curve) { var ret = new MsaglPolyline(); ret.AddPoint(curve.Start); foreach (var ls in curve.Segments) ret.AddPoint(ls.End); ret.Closed = curve.Start == curve.End; return ret; }
internal ICurve CreateBoundary() { double w = Width/2; double h = Height/2; Curve curve = new Curve(); Curve.AddLineSegment(curve, Center.X - w, Center.Y - h, Center.X - w, Center.Y + h); Curve.ContinueWithLineSegment(curve, Center.X + w, Center.Y + h); Curve.ContinueWithLineSegment(curve, Center.X + w, Center.Y - h); Curve.CloseCurve(curve); return curve; }
/// <summary> /// Following "Biarc approximation of NURBS curves", Les A. Piegl, and Wayne Tiller. The paper has a bug in V, where they write that v=p0+p4, it is p0-p4. /// Also I treat special cases differently. /// </summary> /// <param name="p0"></param> /// <param name="ts"></param> /// <param name="p4"></param> /// <param name="te"></param> /// <returns></returns> internal static ICurve BiArc(Point p0, Point ts, Point p4, Point te) { Debug.Assert(ApproximateComparer.Close(ts.LengthSquared, 1)); Debug.Assert(ApproximateComparer.Close(te.LengthSquared, 1)); var v = p0 - p4; if (v.Length < ApproximateComparer.DistanceEpsilon) return null; var vtse = v * (ts - te); var tste = -ts * te; //solving a quadratic equation var a = 2 * (tste - 1); var b = 2 * vtse; var c = v * v; double al; if (Math.Abs(a) < ApproximateComparer.DistanceEpsilon) { //we have b*al+c=0 if (Math.Abs(b) > ApproximateComparer.DistanceEpsilon) { al = -c / b; } else { return null; } } else { var d = b * b - 4 * a * c; Debug.Assert(d >= -ApproximateComparer.Tolerance); if (d < 0) d = 0; d = Math.Sqrt(d); al = (-b + d) / (2 * a); if (al < 0) al = (-b - d) / (2 * a); } var p1 = p0 + al * ts; var p3 = p4 + al * te; var p2 = 0.5 * (p1 + p3); var curve = new Curve(); curve.AddSegs(ArcOn(p0, p1, p2), ArcOn(p2, p3, p4)); //bad input for BiArc. we shouldn't allow such cases during bundle bases construction if (ts * (p4 - p0) <= 0 && ts * te <= 0) { //switch to Bezier var curve2 = StandardBezier(p0, ts, p4, te); #if DEBUG && TEST_MSAGL /*List<DebugCurve> dc = new List<DebugCurve>(); dc.Add(new DebugCurve(curve)); dc.Add(new DebugCurve(0.3, "black", curve2)); dc.Add(new DebugCurve(0.1, "red", new LineSegment(p0, p0 + 3 * ts))); dc.Add(new DebugCurve(0.1, "blue", new LineSegment(p4, p4 + 3 * te))); LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(dc);*/ #endif return curve2; } return curve; }
static void FillContexForCurve(StreamGeometryContext context,Curve c) { foreach(ICurve seg in c.Segments) { var bezSeg = seg as CubicBezierSegment; if(bezSeg != null) { context.BezierTo(Common.WpfPoint(bezSeg.B(1)), Common.WpfPoint(bezSeg.B(2)),Common.WpfPoint(bezSeg.B(3)),true,false); } else { var ls = seg as LineSegment; if(ls != null) context.LineTo(Common.WpfPoint(ls.End),true,false); else { var ellipse = seg as Ellipse; if(ellipse != null) { // context.LineTo(Common.WpfPoint(ellipse.End),true,false); double sweepAngle = EllipseSweepAngle(ellipse); bool largeArc = Math.Abs(sweepAngle) >= Math.PI; Rectangle box = ellipse.FullBox(); context.ArcTo(Common.WpfPoint(ellipse.End), new Size(box.Width / 2,box.Height / 2), sweepAngle, largeArc, sweepAngle < 0 ? SweepDirection.Counterclockwise : SweepDirection.Clockwise, true,true); } else throw new NotImplementedException(); } } } }
void WriteCurveGeometry(Curve curve) { WriteAttribute("d", CurveString(curve)); }
/// <summary> /// create a box of the given width and height at center. /// </summary> /// <param name="c"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="center"></param> /// <returns></returns> static internal void CreateRectangle(Curve c, double width, double height, Point center) { double w = width / 2; double h = height / 2; double x = center.X; double y = center.Y; Point[] p = new Point[] { new Point(x - w, y - h), new Point(x + w, y - h), new Point(x + w, y + h), new Point(x - w, y + h) }; c.AddSegs(new LineSegment(p[0], p[1]), new LineSegment(p[1], p[2]), new LineSegment(p[2], p[3]), new LineSegment(p[3], p[0])); }
/// <summary> /// Creates curve resembling a house within the rectangle formed by width and height at center /// (if the rectangle is a square, the house has the shape of home plate in baseball). /// </summary> /// <param name="width">the bounding rectangle width</param> /// <param name="height">the bounding rectangle height</param> /// <param name="center">the bounding rectangle center</param> /// <returns></returns> static public ICurve CreateInteriorHouse(double width, double height, Point center) { double w = width / 2; double h = height / 2; double x = center.X; double y = center.Y; Curve c = new Curve(4); Curve.AddLineSegment(c, x - w, y - h, x + w, y - h); Curve.ContinueWithLineSegment(c, x + w, y); Curve.ContinueWithLineSegment(c, x, y + h); Curve.ContinueWithLineSegment(c, x - w, y); Curve.CloseCurve(c); return c; }
static ICurve MakeShapeCurve(Point center, int width, int height) { var r = new Rectangle(center) {Width = width, Height = height}; var c = new Curve(); Curve.AddLineSegment(c, r.LeftBottom, r.LeftTop); Curve.ContinueWithLineSegment(c, r.RightTop); Curve.ContinueWithLineSegment(c, r.RightBottom); Curve.CloseCurve(c); return c; }
internal static void CreateGraphicsPathFromCurve(PathFigure pathFigure, Curve curve) { foreach (var seg in curve.Segments) { var bezSeg = seg as CubicBezierSegment; if (bezSeg != null) pathFigure.Segments.Add(new BezierSegment { Point1 = WinPoint(bezSeg.B(1)), Point2 = WinPoint(bezSeg.B(2)), Point3 = WinPoint(bezSeg.B(3)) }); else { var ls = seg as MsaglLineSegment; if (ls != null) pathFigure.Segments.Add(new WinLineSegment() { Point = WinPoint(ls.End) }); else { var ellipse = seg as Ellipse; if (ellipse != null) pathFigure.Segments.Add( new ArcSegment() { Size = new WinSize(ellipse.AxisA.Length, ellipse.AxisB.Length), SweepDirection = SweepDirection.Clockwise, Point = WinPoint(ellipse.End) }); else throw new InvalidOperationException(); } } } }
static void AddCurve(PathFigure pathFigure, Point c, Curve curve) { foreach (ICurve seg in curve.Segments) { var ls = seg as LineSegment; if (ls != null) pathFigure.Segments.Add(new System.Windows.Media.LineSegment(CommonX.WpfPoint(ls.End - c), true)); else { var ellipse = seg as Ellipse; pathFigure.Segments.Add(new ArcSegment(CommonX.WpfPoint(ellipse.End - c), new Size(ellipse.AxisA.Length, ellipse.AxisB.Length), Point.Angle(new Point(1, 0), ellipse.AxisA), ellipse.ParEnd - ellipse.ParEnd >= Math.PI, !ellipse.OrientedCounterclockwise() ? SweepDirection.Counterclockwise : SweepDirection.Clockwise, true)); } } }
private void AddSmoothedCorner(Site a, Site b, Site c, Curve curve) { double k = 0.5; CubicBezierSegment seg; do { seg = Curve.CreateBezierSeg(k, k, a, b, c); //if (Routing.db) // LayoutAlgorithmSettings .Show(seg, CreatePolyTest()); b.PreviousBezierSegmentFitCoefficient = k; k /= 2; } while (BezierSegIntersectsBoundary(seg)); k *= 2; //that was the last k if (k < 0.5) {//one time try a smoother seg k = 0.5 * (k + k * 2); CubicBezierSegment nseg = Curve.CreateBezierSeg(k, k, a, b, c); if (!BezierSegIntersectsBoundary(nseg)) { b.PreviousBezierSegmentFitCoefficient = b.NextBezierSegmentFitCoefficient = k; seg = nseg; } } if (curve.Segments.Count > 0 && !ApproximateComparer.Close(curve.End, seg.Start)) curve.AddSegment(new LineSegment(curve.End, seg.Start)); curve.AddSegment(seg); }
private void CreateFilletCurve(Curve curve, ref Site a, ref Site b, ref Site c) { do { AddSmoothedCorner(a, b, c, curve); a = b; b = c; if (b.Next != null) c = b.Next; else break; } while (true); }
private ICurve BoundingBoxCurve(ref Rectangle rectangle) { Curve c = new Curve(); c.AddSegment(new LineSegment(rectangle.LeftTop, rectangle.LeftBottom)); Curve.ContinueWithLineSegment(c, rectangle.RightBottom); Curve.ContinueWithLineSegment(c, rectangle.RightTop); Curve.CloseCurve(c); return c; }
/// <summary> /// Creates a curve resembling a diamond large enough to inscribe within it a rectangle of the /// given width and height at center. /// </summary> /// <param name="width">the width of the inscribed rectangle</param> /// <param name="height">the height of the inscribed rectangle</param> /// <param name="center">the diamond center</param> /// <returns></returns> static public ICurve CreateDiamond(double width, double height, Point center) { double w = width; double h = height; double x = center.X; double y = center.Y; Curve c = new Curve(); Point[] p = new Point[] { new Point(x, y - h), new Point(x + w, y), new Point(x, y + h), new Point(x - w, y) }; c.AddSegs(new LineSegment(p[0], p[1]), new LineSegment(p[1], p[2]), new LineSegment(p[2], p[3]), new LineSegment(p[3], p[0])); return c; }
internal static ICurve FitArcsIntoCorners(double radius, Point[] polyline) { IEnumerable<Ellipse> ellipses = GetFittedArcSegs(radius, polyline); var curve = new Curve(polyline.Length); Ellipse prevEllipse = null; foreach (Ellipse ellipse in ellipses) { bool ellipseIsAlmostCurve = EllipseIsAlmostLineSegment(ellipse); if (prevEllipse != null) { if (ellipseIsAlmostCurve) Curve.ContinueWithLineSegment(curve, CornerPoint(ellipse)); else { Curve.ContinueWithLineSegment(curve, ellipse.Start); curve.AddSegment(ellipse); } } else { if (ellipseIsAlmostCurve) Curve.AddLineSegment(curve, polyline[0], CornerPoint(ellipse)); else { Curve.AddLineSegment(curve, polyline[0], ellipse.Start); curve.AddSegment(ellipse); } } prevEllipse = ellipse; } if (curve.Segments.Count > 0) Curve.ContinueWithLineSegment(curve, polyline[polyline.Length - 1]); else Curve.AddLineSegment(curve, polyline[0], polyline[polyline.Length - 1]); return curve; }
/// <summary> /// testing, don't use /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <returns></returns> public static ICurve CreateTestShape(double width, double height ) { int mult = 1; double w = width *3; double h = height *3; Curve curve = new Curve(9); Curve.AddLineSegment(curve, - w, - h, 0, -h/2); Curve.ContinueWithLineSegment(curve, w / 2, -0.75 * h); Curve.ContinueWithLineSegment(curve, w, -h); Curve.ContinueWithLineSegment(curve, 0.75 * w, -h / 2); Curve.ContinueWithLineSegment(curve, w / 2, 0); Curve.ContinueWithLineSegment(curve, w, h); Curve.ContinueWithLineSegment(curve, 0, h / 2); Curve.ContinueWithLineSegment(curve, -w, mult * h); Curve.ContinueWithLineSegment(curve, -w / 3, 0); Curve.CloseCurve(curve); return curve; }
void WriteCurve(Curve curve, Node node) { WriteStartElement("path"); WriteFillAndStroke(node.Attr); WriteCurveGeometry(curve); WriteEndElement(); }
Curve CreatePolyTest() { Curve c = new Curve(); IEnumerator<Point> e = new PointNodesList(this.headSite); e.MoveNext(); Point p = e.Current; while (e.MoveNext()) { Curve.AddLineSegment(c, p, e.Current); p = e.Current; } return c; }
void WriteCurveInSvgStyle(Curve curve) { WriteStartElement(GeometryToken.Curve); WriteAttribute( GeometryToken.CurveData, CurveString(curve)); WriteEndElement(); }
// static int calls; // bool debug { get { return calls == 5;} } Curve Poly() { Curve c = new Curve(); for (Site s = this.headSite; s.Next != null; s = s.Next) c.AddSegment(new CubicBezierSegment(s.Point, 2 * s.Point / 3 + s.Next.Point / 3, s.Point / 3 + 2 * s.Next.Point / 3, s.Next.Point)); return c; }
private void WriteCurve(Shape shape, Curve curve) { this.outputFileWriter.WriteLine(RectFileStrings.BeginCurve); if (null != shape) { // If a path, this is null this.outputFileWriter.WriteLine(RectFileStrings.WriteId, shapeToIdMap[shape]); } foreach (var seg in curve.Segments) { this.outputFileWriter.WriteLine(RectFileStrings.WriteSegment, seg.Start.X, seg.Start.Y, seg.End.X, seg.End.Y); } this.outputFileWriter.WriteLine(RectFileStrings.EndCurve); }
internal static void CreateGraphicsPathFromCurve(PathFigure pathFigure, Curve curve) { foreach (ICurve seg in curve.Segments) { if (seg is CubicBezierSegment) { var bezSeg = seg as CubicBezierSegment; pathFigure.Segments.Add(new BezierSegment { Point1 = WinPoint(bezSeg.B(1)), Point2 = WinPoint(bezSeg.B(2)), Point3 = WinPoint(bezSeg.B(3)) }); } else if (seg is Ellipse) { var ellipse = seg as Ellipse; pathFigure.Segments.Add(new ArcSegment() { Size = new WinSize(ellipse.AxisA.Length, ellipse.AxisB.Length), SweepDirection = ellipse.OrientedCounterclockwise() ? SweepDirection.Clockwise : SweepDirection.Counterclockwise, Point = WinPoint(ellipse.End) }); } else pathFigure.Segments.Add(new WinLineSegment() { Point = WinPoint(seg.End) }); } }
/// <summary> /// create a triangle inside the box formed by width and height. /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="center"></param> /// <returns></returns> static public ICurve CreateInteriorTriangle(double width, double height, Point center) { double w = width / 2; double h = height / 2; double x = center.X; double y = center.Y; Curve c = new Curve(3); Point[] p = new Point[] { new Point(x - w, y - h), new Point(x + w, y - h), new Point(x, y + h) }; c.AddSegment(new LineSegment(p[0], p[1])); c.AddSegment(new LineSegment(p[1], p[2])); c.AddSegment(new LineSegment(p[2], p[0])); return c; }
Curve CreateSmoothedPolyline() { RemoveVerticesWithNoTurns(); Curve curve = new Curve(); Site a = headSite;//the corner start Site b; //the corner origin Site c;//the corner other end if (Curve.FindCorner(a, out b, out c)) { CreateFilletCurve(curve, ref a, ref b, ref c); curve = ExtendCurveToEndpoints(curve); } else curve.AddSegment(new LineSegment(EdgePathPoint(0), EdgePathPoint(edgePath.Count))); return curve; }