//throw away the segments [0,u] and [v,1] of the segment /// <summary> /// Returns the trimmed curve /// </summary> /// <param name="u"></param> /// <param name="v"></param> /// <returns></returns> public ICurve Trim(double u, double v) { AdjustParamTo01(ref u); AdjustParamTo01(ref v); if (u > v) { return(Trim(v, u)); } if (u > 1.0 - ApproximateComparer.Tolerance) { return(new CubicBezierSegment(b[3], b[3], b[3], b[3])); } Point[] b1 = new Point[3]; Point[] b2 = new Point[2]; Point pv = Casteljau(u, b1, b2); //this will be the trim to [v,1] CubicBezierSegment trimByU = new CubicBezierSegment(pv, b2[1], b1[2], b[3]); //1-v is not zero here because we have handled already the case v=1 Point pu = trimByU.Casteljau((v - u) / (1.0 - u), b1, b2); return(new CubicBezierSegment(trimByU.b[0], b1[0], b2[0], pu)); }
static IEnumerable <CurveTangent> TangentsOfBezier(CubicBezierSegment bez) { const int numOfTangents = 8; double span = (bez.ParEnd - bez.ParStart) / numOfTangents; for (int i = 0; i < numOfTangents; i++) { yield return(TangentOnICurve(span / 2 + bez.ParStart + span * i, bez)); } }
static IEnumerable <CurveTangent> TangentsAroundCurve(ICurve iCurve) { Curve c = iCurve as Curve; if (c != null) { foreach (ICurve seg in c.Segments) { foreach (CurveTangent ct in TangentsAroundCurve(seg)) { yield return(ct); } } } else { LineSegment ls = iCurve as LineSegment; if (ls != null) { yield return(new CurveTangent(ls.Start, ls.Derivative(0))); } else { Ellipse ellipse = iCurve as Ellipse; if (ellipse != null) { foreach (CurveTangent ct in TangentsOfEllipse(ellipse)) { yield return(ct); } } else { CubicBezierSegment bez = iCurve as CubicBezierSegment; if (bez != null) { foreach (CurveTangent ct in TangentsOfBezier(bez)) { yield return(ct); } } } } } }
internal static bool CreateParallelogramOnSubSegOnBezierSeg(double start, double end, ICurve seg, ref Parallelogram box) { CubicBezierSegment trimSeg = seg.Trim(start, end) as CubicBezierSegment; B b = trimSeg.B; Point a = b(1) - b(0); box = new Parallelogram(b(0), a, b(3) - b(0)); if (box.Contains(b(2))) { return(true); } box = new Parallelogram(b(3), b(2) - b(3), b(0) - b(3)); if (box.Contains(b(1))) { return(true); } return(false); }
static bool BezierSegIntersectsBoundary(CubicBezierSegment seg, ICurve curve) { foreach (IntersectionInfo x in Curve.GetAllIntersections(seg, curve, false)) { Curve c = curve as Curve; if (c != null) { if (Curve.RealCutWithClosedCurve(x, c, false)) return true; } else { //curve is a line from a thin hierarchy that's forbidden to touch return true; } } return false; }
private bool BezierSegIntersectsTree(CubicBezierSegment seg, ParallelogramNode tree) { if (tree == null) return false; if (Parallelogram.Intersect(seg.ParallelogramNodeOverICurve.Parallelogram, tree.Parallelogram)) { ParallelogramBinaryTreeNode n = tree as ParallelogramBinaryTreeNode; if (n != null) { return BezierSegIntersectsTree(seg, n.LeftSon) || BezierSegIntersectsTree(seg, n.RightSon); } else return BezierSegIntersectsBoundary(seg, ((ParallelogramNodeOverICurve)tree).Seg); } else return false; }
private bool BezierSegIntersectsBoundary(CubicBezierSegment seg) { double side = Point.SignedDoubledTriangleArea(seg.B(0), seg.B(1), seg.B(2)); if (side > 0) return BezierSegIntersectsTree(seg, thinLeftHierarchy) || BezierSegIntersectsTree(seg, leftHierarchy); else return BezierSegIntersectsTree(seg, thinRightHierarchy) || BezierSegIntersectsTree(seg, rightHierarchy); }
internal static void DrawControlPoints(Graphics g, CubicBezierSegment bs){ using (var pen = new Pen(Color.Green, (float) (1.0/1000.0))){ pen.DashPattern = new[]{1, (float) 1}; pen.DashStyle = DashStyle.Dot; g.DrawLine(pen, PointF(bs.B(0)), PointF(bs.B(1))); g.DrawLine(pen, PointF(bs.B(1)), PointF(bs.B(2))); g.DrawLine(pen, PointF(bs.B(2)), PointF(bs.B(3))); } }
bool FitLonger(OrientedHubSegment longerOrientedSeg, Point del0, Point del1, Point midPointOfShorter, double minDelLength, double maxDel, Point center, double radius) { CubicBezierSegment seg = (CubicBezierSegment)longerOrientedSeg.Segment; Point start = seg.Start; Point end = seg.End; // LayoutAlgorithmSettings.ShowDebugCurves(new DebugCurve("green", shorterDebugOnly), new DebugCurve("red", seg)); int steps = 0; const int maxSteps = 10; Point lowP1 = (1 - SqueezeBound) * seg.Start + SqueezeBound * seg.B(1); Point lowP2 = (1 - SqueezeBound) * seg.End + SqueezeBound * seg.B(2); Point highP1 = 2 * seg.B(1) - seg.Start; //originally the tangents were 0.25 of the length of seg[1]-seg[0] - so were are safe to lengthen two times Point highP2 = 2 * seg.B(2) - seg.End; PullControlPointToTheCircle(seg.Start, ref highP1, center, radius); int r = NicelyAligned(seg, del0, del1, midPointOfShorter, minDelLength, maxDel); do { if (r == -1) { //pull the control points lower Point p1 = (seg.B(1) + lowP1) / 2; Point p2 = (seg.B(2) + lowP2) / 2; highP1 = seg.B(1); highP2 = seg.B(2); seg = new CubicBezierSegment(start, p1, p2, end); } else { Debug.Assert(r == 1); //pull the control points higher Point p1 = (seg.B(1) + highP1) / 2; Point p2 = (seg.B(2) + highP2) / 2; lowP1 = seg.B(1); lowP2 = seg.B(2); seg = new CubicBezierSegment(start, p1, p2, end); } if ((r = NicelyAligned(seg, del0, del1, midPointOfShorter, minDelLength, maxDel)) == 0) { longerOrientedSeg.Other.Segment = longerOrientedSeg.Segment = seg; return true; } if (steps++ > maxSteps) return false; //cannot fix it } while (true); }
void WriteBezierSegment(CubicBezierSegment bs) { WriteStartElement(GeometryToken.CubicBezierSegment); WriteAttribute(GeometryToken.Points, PointsToString(bs.B(0), bs.B(1), bs.B(2), bs.B(3))); WriteEndElement(); }
static IEnumerable<CurveTangent> TangentsOfBezier(CubicBezierSegment bez) { const int numOfTangents = 8; double span = (bez.ParEnd - bez.ParStart) / numOfTangents; for (int i = 0; i < numOfTangents; i++) yield return TangentOnICurve(span / 2 + bez.ParStart + span * i, bez); }
List<ICurve> Getsegs() { var l = new List<ICurve>(); var bs0 = new CubicBezierSegment(new Point(), new Point(0, 1), new Point(1, 2), new Point(1, 0)); l.Add(bs0); var bs1 = new CubicBezierSegment(new Point(2,2), new Point(3, 1), new Point(4, 2), new Point(1, -5)); bs1.Translate(new Point(10,10)); l.Add(new LineSegment(bs0.End, bs1.Start)); l.Add(bs1); var xAxis = new Point(2, 0); l.Add(new Ellipse(0, Math.PI/2, xAxis, new Point(0, 1), bs1.End - xAxis)); return l; }
public void LengthTestingForCubucBezier() { var bs = new CubicBezierSegment(new Point(), new Point(0, 1), new Point(1, 1), new Point(1, 0)); var len = bs.Length; Assert.IsTrue(Math.Abs(len - 2) < 0.001); bs = new CubicBezierSegment(new Point(), new Point(0, 1), new Point(1, 2), new Point(1, 0)); var par = bs.GetParameterAtLength(2); var trimmed = bs.Trim(0, par); var trimmedLen =trimmed.Length; Assert.IsTrue(Math.Abs(trimmedLen - 2) < 0.000001); }
static GraphicsPath CreatePathOnCurvaturePoint(Tuple<double, double> t, CubicBezierSegment cubic){ var gp = new GraphicsPath(); P2 center = cubic[t.Item1]; int radius = 10; gp.AddEllipse((float) (center.X - radius), (float) (center.Y - radius), (2*radius), (2*radius)); return gp; }
static GraphicsPath CreateControlPointPolygon(Tuple<double, double> t, CubicBezierSegment cubic){ var gp = new GraphicsPath(); gp.AddLines(new[]{PP(cubic.B(0)), PP(cubic.B(1)), PP(cubic.B(2)), PP(cubic.B(3))}); return gp; }
static PathGeometry CreateControlPointPolygon(Tuple<double, double> t, CubicBezierSegment cubic) { throw new NotImplementedException(); /* var gp = new GraphicsPath(); gp.AddLines(new[] { PP(cubic.B(0)), PP(cubic.B(1)), PP(cubic.B(2)), PP(cubic.B(3)) }); return gp; */ }
static PathGeometry CreatePathOnCurvaturePoint(Tuple<double, double> t, CubicBezierSegment cubic) { throw new NotImplementedException(); /* var gp = new GraphicsPath(); Point center = cubic[t.First]; int radius = 10; gp.AddEllipse((float)(center.X - radius), (float)(center.Y - radius), (2 * radius), (2 * radius)); return gp; //*/ }
//throw away the segments [0,u] and [v,1] of the segment /// <summary> /// Returns the trimmed curve /// </summary> /// <param name="u"></param> /// <param name="v"></param> /// <returns></returns> public ICurve Trim(double u, double v) { AdjustParamTo01(ref u); AdjustParamTo01(ref v); if (u > v) return Trim(v, u); if (u > 1.0 - ApproximateComparer.Tolerance) return new CubicBezierSegment(b[3], b[3], b[3], b[3]); Point[] b1 = new Point[3]; Point[] b2 = new Point[2]; Point pv = Casteljau(u, b1, b2); //this will be the trim to [v,1] CubicBezierSegment trimByU = new CubicBezierSegment(pv, b2[1], b1[2], b[3]); //1-v is not zero here because we have handled already the case v=1 Point pu = trimByU.Casteljau((v - u) / (1.0 - u), b1, b2); return new CubicBezierSegment(trimByU.b[0], b1[0], b2[0], pu); }
string CubicBezierSegmentToString(CubicBezierSegment cubic) { return "C" + PointsToString(cubic.B(1), cubic.B(2), cubic.B(3)); }
Rail ContinueReadingRail(LgEdgeInfo topRankedEdgoInfo, int zoomLevel, LgLevel level) { XmlRead(); string pointString; if (TokenIs(GeometryToken.Arrowhead)) { Point arrowheadPosition = TryGetPointAttribute(GeometryToken.ArrowheadPosition); Point attachmentPoint = TryGetPointAttribute(GeometryToken.CurveAttachmentPoint); Arrowhead ah = new Arrowhead { TipPosition = arrowheadPosition, Length = (attachmentPoint - arrowheadPosition).Length }; XmlRead(); ReadEndElement(); var rail = new Rail(ah, attachmentPoint, topRankedEdgoInfo, zoomLevel); var tuple = new SymmetricSegment(arrowheadPosition, attachmentPoint); level._railDictionary[tuple] = rail; return rail; } if (TokenIs(GeometryToken.LineSegment)) { pointString = GetAttribute(GeometryToken.Points); var linePoints = ParsePoints(pointString); Debug.Assert(linePoints.Length == 2); LineSegment ls = new LineSegment(linePoints[0], linePoints[1]); XmlRead(); ReadEndElement(); var rail = new Rail(ls, topRankedEdgoInfo, zoomLevel); var tuple = new SymmetricSegment(ls.Start, ls.End); level._railDictionary[tuple] = rail; level._railTree.Add(ls.BoundingBox, rail); return rail; } if (TokenIs(GeometryToken.CubicBezierSegment)) { pointString = GetAttribute(GeometryToken.Points); var controlPoints = ParsePoints(pointString); Debug.Assert(controlPoints.Length == 4); var bs = new CubicBezierSegment(controlPoints[0], controlPoints[1], controlPoints[2], controlPoints[3]); XmlRead(); ReadEndElement(); var rail = new Rail(bs, topRankedEdgoInfo, zoomLevel); var tuple = new SymmetricSegment(bs.Start, bs.End); level._railDictionary[tuple] = rail; return rail; } throw new Exception(); }
string CubicBezierSegmentToString(CubicBezierSegment cubic, char previousInstruction) { var str = PointsToString(cubic.B(1), cubic.B(2), cubic.B(3)); return previousInstruction=='C'?str:"C"+str; }
static ICurve CreateBaseSegOnSourceTargetAndOrth(ref Point a, ref Point b, ref Point abOrtog) { ICurve seg = new CubicBezierSegment(a, a*3.0/4 + b/4 + abOrtog, b*3.0/4.0 + a/4.0 + abOrtog, b); return seg; }
/// <summary> /// /// </summary> /// <param name="longerSeg"></param> /// <param name="del0"></param> /// <param name="del1"></param> /// <param name="midPointOfShorter"></param> /// <param name="minDelLength"></param> /// <param name="maxDelLen"></param> /// <returns> 1 - need to stretch, -1 - need to squeze, 0 - OK </returns> int NicelyAligned(CubicBezierSegment longerSeg, Point del0, Point del1, Point midPointOfShorter, double minDelLength, double maxDelLen) { const double eps = 0.001; Point midDel = longerSeg[0.5] - midPointOfShorter; double midDelLen = midDel.Length; if (del0 * midDel < 0 || del1 * midDel < 0) return 1; if (midDelLen < minDelLength - eps) return 1; if (midDelLen > maxDelLen + eps) return -1; return 0; }
static void DrawBezier(DGraph graphToDraw, Pen myPen, Graphics g, CubicBezierSegment bs){ g.DrawBezier(myPen, (float) bs.B(0).X, (float) bs.B(0).Y, (float) bs.B(1).X, (float) bs.B(1).Y, (float) bs.B(2).X, (float) bs.B(2).Y, (float) bs.B(3).X, (float) bs.B(3).Y); if(graphToDraw.DrawingGraph.ShowControlPoints) DrawControlPoints(g, bs); }