/// <summary> /// Creates a bounding parallelogram on a curve segment /// We suppose here that the segment is convex or concave from start to end, /// that is the region bounded by the straight segment seg[start], seg[end] and the curve seg is convex /// </summary> internal static bool CreateParallelogramOnSubSeg(double start, double end, ICurve seg, ref Parallelogram box, Point startPoint, Point endPoint) { if (seg is CubicBezierSegment) { return(CreateParallelogramOnSubSegOnBezierSeg(start, end, seg, ref box)); } Point tan1 = seg.Derivative(start); Point tan2 = seg.Derivative(end); Point tan2Perp = Point.P(-tan2.Y, tan2.X); Point p = endPoint - startPoint; 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(startPoint, tan1, endPoint - startPoint - tan1); #if DEBUGCURVES if (!box.Contains(seg[end])) { throw new InvalidOperationException();//"the box does not contain the end of the segment"); } #endif double delta = (end - start) / 64; for (int i = 1; i < 64; i++) { if (!box.Contains(seg[start + delta * i])) { return(false); } } return(true); }
void InitValues() { a = curveA[si]; b = curveB[ti]; a_b = a - b; ad = curveA.Derivative(si); add = curveA.SecondDerivative(si); bd = curveB.Derivative(ti); bdd = curveB.SecondDerivative(ti); }
/// <summary> /// in general works for convex curves /// </summary> /// <param name="iCurve"></param> /// <param name="pointInside"></param> /// <returns></returns> internal static bool CurveIsClockwise(ICurve iCurve, Point pointInside) { return (Point.GetTriangleOrientation(pointInside, iCurve.Start, iCurve.Start + iCurve.Derivative(iCurve.ParStart)) == TriangleOrientation.Clockwise); }
/// <summary> /// Places the label at the first position requested. Ignores all overlaps. /// </summary> void PlaceLabelAtFirstPosition(Label label) { var edge = (Edge)label.GeometryParent; ICurve curve = edge.Curve ?? new LineSegment(edge.Source.Center, edge.Target.Center); List <KeyValuePair <double, Point> > points = edgePoints[edge]; int index = StartIndex(label, points); Point point = points[index].Value; Point derivative = curve.Derivative(points[index].Key); // If the curve is a line of length (close to) 0, the derivative may be (close to) 0. // Pick a direction in that case. if (derivative.Length < ApproximateComparer.Tolerance) { derivative = new Point(1, 1); } var widthHeight = new Point(label.Width, label.Height); double side = GetPossibleSides(label.Side, derivative).First(); Rectangle bounds = GetLabelBounds(point, derivative, widthHeight, side); SetLabelBounds(label, bounds); }
static public bool edge_rendering_delegate(Edge edge, object edgeLine_path) { Path path = edgeLine_path as Path; ICurve cv = edge.EdgeCurve; var t_middle = cv.GetParameterAtLength(cv.Length / 2); var dva = cv.Derivative(t_middle); //求中点的导数 var midPoint = cv[t_middle]; // Common.WpfPoint( cv[t_middle]); float x = (float)midPoint.X, y = (float)midPoint.Y; var geo2 = DataDefine.get_svg2(); MatrixTransform mt = new MatrixTransform(); Func <double, double> rad2Deg = v => { return(v * 180 / Math.PI); }; //mt.Matrix. var deg = rad2Deg(Math.Atan2(dva.Y, dva.X)); var mat = Matrix.Identity; mat.TranslatePrepend(x, y); mat.RotatePrepend(deg); mat.ScalePrepend(-0.2f, 0.2f); mt.Matrix = mat; geo2.Transform = mt; var circle = new EllipseGeometry(new WpfPoint(x, y), 2, 2); PathGeometry pp = new PathGeometry(); pp.FillRule = FillRule.EvenOdd; pp.AddGeometry(Common.GetICurveWpfGeometry(cv)); pp.AddGeometry(circle); pp.AddGeometry(geo2); path.Data = pp; return(true); }
static ICurve GetSidesAndEdgeCurve(Label label, Edge e, List <KeyValuePair <double, Point> > curvePoints, int index, out double[] sides) { ICurve curve = e.Curve ?? new LineSegment(e.Source.Center, e.Target.Center); Point initialDer = curve.Derivative(curvePoints[index].Key); sides = GetPossibleSides(label.Side, initialDer); return(curve); }
///// <summary> ///// Gets the closest point on the curve to the point ///// </summary> ///// <param name="curve"></param> ///// <param name="coeff"></param> ///// <param name="hint">will return Double.MaxVal if Newton iterations fail</param> ///// <param name="closestPointParam"></param> internal static double ClosestPoint(ICurve curve, Point a, double hint, double low, double high) { /* * Let F=(c(t)-a)^2. We try to bring to zero the first derivative of F, Ft. Denote it by f(t). * Applying the Newton method we see that dt=-f(t)/der(f(t) * The first derivative of F, f, has the form (c-a)*ct. We discarded a multiplier here. * The second derivative has the form ct*ct+(c-a)*ctt * The new t becomes t-dt */ const int numberOfIterationsMax = 5; const int numberOfOverShootsMax = 5; double t = hint; int numberOfIteration = 0; int numberOfOvershoots = 0; double dt; bool abort = false; do { Point c = curve[t]; Point ct = curve.Derivative(t); Point ctt = curve.SecondDerivative(t); double secondDerivative = ct * ct + (c - a) * ctt; if (Math.Abs(secondDerivative) < ApproximateComparer.Tolerance) { return(t); } dt = (c - a) * ct / secondDerivative; t -= dt; if (t > high + ApproximateComparer.Tolerance) { t = high; numberOfOvershoots++; } else if (t < low - ApproximateComparer.Tolerance) { t = low; numberOfOvershoots++; } numberOfIteration++; } while (Math.Abs(dt) > ApproximateComparer.Tolerance && ! (abort = (numberOfIteration >= numberOfIterationsMax || numberOfOvershoots >= numberOfOverShootsMax))); //may be the initial value was just fine if (abort && (curve[hint] - a).Length < ApproximateComparer.DistanceEpsilon) { t = hint; } return(t); }
///// <summary> ///// Gets the closest point on the curve to the point ///// </summary> ///// <param name="curve"></param> ///// <param name="coeff"></param> ///// <param name="hint">will return Double.MaxVal if Newton iterations fail</param> ///// <param name="closestPointParam"></param> internal static double ClosestPoint(ICurve curve, Point a, double hint, double low, double high) { const int numberOfIterationsMax = 5; const int numberOfOverShootsMax = 5; double t = hint; int numberOfIteration = 0; int numberOfOvershoots = 0; double dt; bool abort = false; do { Point c = curve[t]; Point ct = curve.Derivative(t); Point ctt = curve.SecondDerivative(t); double secondDerivative = ct * ct + (c - a) * ctt; if (Math.Abs(secondDerivative) < ApproximateComparer.Tolerance) { return(t); } dt = (c - a) * ct / secondDerivative; t -= dt; if (t > high + ApproximateComparer.Tolerance) { t = high; numberOfOvershoots++; } else if (t < low - ApproximateComparer.Tolerance) { t = low; numberOfOvershoots++; } numberOfIteration++; } while (Math.Abs(dt) > ApproximateComparer.Tolerance && ! (abort = (numberOfIteration >= numberOfIterationsMax || numberOfOvershoots >= numberOfOverShootsMax))); //may be the initial value was just fine if (abort && (curve[hint] - a).Length < ApproximateComparer.DistanceEpsilon) { t = hint; } return(t); }
///// <summary> ///// Gets the closest point on the curve to the point ///// </summary> ///// <param name="curve"></param> ///// <param name="coeff"></param> ///// <param name="hint">will return Double.MaxVal if Newton iterations fail</param> ///// <param name="closestPointParam"></param> internal static double ClosestPoint(ICurve curve, Point a, double hint, double low, double high) { /* * Let F=(c(t)-a)^2. We try to bring to zero the first derivative of F, Ft. Denote it by f(t). * Applying the Newton method we see that dt=-f(t)/der(f(t) * The first derivative of F, f, has the form (c-a)*ct. We discarded a multiplier here. * The second derivative has the form ct*ct+(c-a)*ctt * The new t becomes t-dt */ const int numberOfIterationsMax = 5; const int numberOfOverShootsMax = 5; double t = hint; int numberOfIteration = 0; int numberOfOvershoots = 0; double dt; bool abort = false; do { Point c = curve[t]; Point ct = curve.Derivative(t); Point ctt = curve.SecondDerivative(t); double secondDerivative = ct * ct + (c - a) * ctt; if (Math.Abs(secondDerivative) < ApproximateComparer.Tolerance) return t; dt = (c - a) * ct / secondDerivative; t -= dt; if (t > high + ApproximateComparer.Tolerance) { t = high; numberOfOvershoots++; } else if (t < low - ApproximateComparer.Tolerance) { t = low; numberOfOvershoots++; } numberOfIteration++; } while (Math.Abs(dt) > ApproximateComparer.Tolerance &&! (abort = (numberOfIteration >= numberOfIterationsMax || numberOfOvershoots >= numberOfOverShootsMax))); //may be the initial value was just fine if (abort && (curve[hint] - a).Length < ApproximateComparer.DistanceEpsilon) t = hint; return t; }
void ProcessExpandingSearchOnSide(int index, List <KeyValuePair <double, Point> > curvePoints, ICurve curve, double side, double radius, double distanceFromCurve, Point wh, ref double coveredLength, PointSetList placedPoints, double labelLength) { foreach (int i in ExpandingSearch(index, 0, curvePoints.Count)) { KeyValuePair <double, Point> p = curvePoints[i]; Point der = curve.Derivative(p.Key); if (der.LengthSquared < ApproximateComparer.DistanceEpsilon) { continue; } Point o = der.Rotate(Math.PI / 2).Normalize() * side; Point labelPos = p.Value + (radius + distanceFromCurve) * o; if (!Conflict(labelPos, radius, wh)) { // found a valid candidate position var ps = new PointSet { Key = p.Key, Center = labelPos, Inner = p.Value + distanceFromCurve * o, Outer = p.Value + (2.0 * radius + distanceFromCurve) * o }; coveredLength = i <= index ? placedPoints.AddFirst(ps) : placedPoints.AddLast(ps); Debug.Assert(Math.Abs(PointSetLength(placedPoints.Points) - coveredLength) < 0.01); if (coveredLength >= labelLength) { break; } } else { // not going to work! break; } } }
/// <summary> /// </summary> /// <param name="label"></param> /// <returns></returns> public bool PlaceEdgeLabelHorizontally(Label label) { ValidateArg.IsNotNull(label, "label"); var e = (Edge)label.GeometryParent; // approximate label with a rectangle // process candidate points for label ordered by priority // check candidate point for conflicts - if none then stop and keep placement label.InnerPoints = null; List <KeyValuePair <double, Point> > curvePoints = edgePoints[e]; var wh = new Point(label.Width, label.Height); int bestConflictIndex = -1; var bestRectangle = new Rectangle(); foreach (int index in ExpandingSearch(StartIndex(label, curvePoints), 0, curvePoints.Count)) { KeyValuePair <double, Point> cp = curvePoints[index]; ICurve curve = e.Curve ?? new LineSegment(e.Source.Center, e.Target.Center); Point der = curve.Derivative(cp.Key); if (der.LengthSquared < ApproximateComparer.DistanceEpsilon) { continue; } foreach (double side in GetPossibleSides(label.Side, der)) { Rectangle queryRect = GetLabelBounds(cp.Value, der, wh, side); int conflictIndex = ConflictIndex(queryRect, label); if (conflictIndex > bestConflictIndex) { bestConflictIndex = conflictIndex; bestRectangle = queryRect; // If the best location was found, we're done if (bestConflictIndex == int.MaxValue) { break; } } } // If the best location was found, we're done if (bestConflictIndex == int.MaxValue) { break; } } if (bestConflictIndex >= 0) { SetLabelBounds(label, bestRectangle); var r = new RectangleObstacle(bestRectangle); AddLabelObstacle(r); #if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=371 if (bestConflictIndex == 0) { label.PlacementResult = LabelPlacementResult.OverlapsOtherLabels; } else if (bestConflictIndex == 1) { label.PlacementResult = LabelPlacementResult.OverlapsNodes; } else if (bestConflictIndex == 2) { label.PlacementResult = LabelPlacementResult.OverlapsEdges; } else { label.PlacementResult = LabelPlacementResult.OverlapsNothing; } #else label.PlacementResult = (LabelPlacementResult)bestConflictIndex; #endif return(true); } return(false); }
internal Point Derivative() { return(_curve.Derivative(_parameter)); }
static bool CurvesAreCloseAtParams(ICurve c0, ICurve c1, double c0S, double c1S) { return Close(c0[c0S], c1[c1S]) && Close(c0.Derivative(c0S), c1.Derivative(c1S)); }
/// <summary> /// Creates a bounding parallelogram on a curve segment /// We suppose here that the segment is convex or concave from start to end, /// that is the region bounded by the straight segment seg[start], seg[end] and the curve seg is convex /// </summary> internal static bool CreateParallelogramOnSubSeg(double start, double end, ICurve seg, ref Parallelogram box, Point startPoint, Point endPoint) { if (seg is CubicBezierSegment) return CreateParallelogramOnSubSegOnBezierSeg(start, end, seg, ref box); Point tan1 = seg.Derivative(start); Point tan2 = seg.Derivative(end); Point tan2Perp = Point.P(-tan2.Y, tan2.X); Point p = endPoint - startPoint; 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(startPoint, tan1, endPoint - startPoint - tan1); #if DEBUGCURVES if (!box.Contains(seg[end])) { throw new InvalidOperationException();//"the box does not contain the end of the segment"); } #endif double delta = (end - start) / 64; for (int i = 1; i < 64; i++) { if (!box.Contains(seg[start + delta * i])) return false; } return true; }
static CurveTangent TangentOnICurve(double p, ICurve iCurve) { return(new CurveTangent(iCurve[p], iCurve.Derivative(p))); }
static CurveTangent TangentOnICurve(double p, ICurve iCurve) { return new CurveTangent(iCurve[p], iCurve.Derivative(p)); }