public void AppendLineSegment(Point p) { PathFigureEditor pathFigureEditor = this.CreatePathFigureEditor(this.path.Figures.Count - 1); if (!PathFigureUtilities.IsOpen(pathFigureEditor.PathFigure)) { throw new InvalidOperationException(ExceptionStringTable.LastFigureMustBeOpenToAppendALineSegment); } pathFigureEditor.LineTo(p); }
public PathGeometry OpenFit(List <Point> input, bool inputMayContainRepeats, double cornerThreshold, double distanceTolerance, bool onlyCubics, bool enforceStartTangent, Vector startTangent, bool enforceEndTangent, Vector endTangent) { if (cornerThreshold <= 0.0 || cornerThreshold >= Math.PI) { throw new ArgumentOutOfRangeException("cornerThreshold", (object)cornerThreshold, "Corner threshold must be strictly between zero and Pi."); } if (distanceTolerance <= 0.0) { throw new ArgumentOutOfRangeException("distanceTolerance", (object)distanceTolerance, "Distance tolerance must be strictly greater than zero."); } this.enforceStartTangent = enforceStartTangent; this.enforceEndTangent = enforceEndTangent; if (this.enforceStartTangent && startTangent.LengthSquared < FloatingPointArithmetic.SquaredDistanceTolerance && (this.enforceEndTangent && endTangent.LengthSquared < FloatingPointArithmetic.SquaredDistanceTolerance)) { throw new ArgumentException(ExceptionStringTable.CannotEnforceZeroLengthTangents); } if (this.enforceEndTangent) { endTangent.Normalize(); this.endTangent = endTangent; } if (this.enforceStartTangent) { startTangent.Normalize(); this.startTangent = startTangent; } this.sample = input; if (inputMayContainRepeats && input.Count > 1) { this.sample = new List <Point>(input.Count); this.sample.Add(input[0]); for (int index = 1; index < input.Count; ++index) { if (!VectorUtilities.ArePathPointsVeryClose(input[index], input[index - 1])) { this.sample.Add(input[index]); } } } PathGeometry path = new PathGeometry(); PathGeometryEditor pathGeometryEditor = new PathGeometryEditor(path); if (this.sample.Count > 0) { pathGeometryEditor.StartFigure(this.sample[0]); this.figure = path.Figures[0]; } PathFigureEditor pathFigureEditor = new PathFigureEditor(this.figure); if (this.sample.Count == 2) { if (VectorUtilities.Distance(this.sample[0], this.sample[1]) >= distanceTolerance) { if (onlyCubics) { pathFigureEditor.LinearCubicCurveTo(this.sample[1]); } else { pathFigureEditor.LineTo(this.sample[1]); } } } else if (this.sample.Count > 2) { int lastIndex = this.sample.Count - 1; this.chordLength = VectorUtilities.GetCumulatedChordLength(this.sample, 0, lastIndex); this.distanceTolerance = distanceTolerance; double cosThreshold = Math.Cos(cornerThreshold); int num = 0; int index = 1; while (true) { while (index >= lastIndex || this.IsSamplePointACorner(index, cosThreshold)) { if (index == num + 1) { if (onlyCubics) { pathFigureEditor.LinearCubicCurveTo(this.sample[index]); } else { pathFigureEditor.LineTo(this.sample[index]); } } else { this.OpenFit2DFromTo(num, this.GetUnitTangentVectorFirst(num), index, this.GetUnitTangentVectorLast(index), onlyCubics); } num = index; ++index; if (num >= lastIndex) { goto label_33; } } ++index; } } label_33: return(path); }
private void OpenFit2DFromTo(int first, Vector unitTangentFirst, int last, Vector unitTangentLast, bool onlyCubics) { int length = last - first + 1; int num1 = length - 1; PathFigureEditor pathFigureEditor = new PathFigureEditor(this.figure); if (length == 2) { if (onlyCubics) { double num2 = VectorUtilities.Distance(this.sample[first], this.sample[last]) / 3.0; Point p1 = this.sample[first] + unitTangentFirst * num2; Point p2 = this.sample[last] - unitTangentLast * num2; pathFigureEditor.CubicCurveTo(p1, p2, this.sample[last]); } else { pathFigureEditor.LineTo(this.sample[last]); } } else if (length == 3) { int index1 = first + 1; Vector vector1 = this.sample[first] - this.sample[index1]; Vector vector2 = this.sample[last] - this.sample[index1]; Vector vector3 = vector1; vector3.Normalize(); Vector vector4 = vector2; vector4.Normalize(); Vector vector5 = vector3 + vector4; Vector vector6; if (VectorUtilities.IsZero(vector5)) { vector6 = this.sample[last] - this.sample[first]; vector6.Normalize(); } else { vector6 = VectorUtilities.UnitNormal(vector5); } if (VectorUtilities.Dot(vector6, this.sample[last] - this.sample[first]) < 0.0) { vector6 *= -1.0; } this.OpenFit2DFromTo(first, unitTangentFirst, index1, vector6, onlyCubics); int index2 = PathFigureUtilities.PointCount(this.figure) - 1; this.OpenFit2DFromTo(index1, vector6, last, unitTangentLast, onlyCubics); this.SetupCollinearHandlesConstraint(index2, onlyCubics); } else { double[][] numArray1 = new double[length][]; for (int index = 0; index < length; ++index) { numArray1[index] = new double[4]; } double num2 = 1.0 / (this.chordLength[last] - this.chordLength[first]); double[] numArray2 = new double[length]; for (int index = 0; index <= num1; ++index) { numArray2[index] = (this.chordLength[first + index] - this.chordLength[first]) * num2; } double[] numArray3 = new double[4]; numArray3[0] = 1.0; for (int index1 = 0; index1 <= num1; ++index1) { numArray3[1] = 1.0 - numArray2[index1]; for (int index2 = 2; index2 <= 3; ++index2) { numArray3[index2] = numArray3[index2 - 1] * numArray3[1]; } numArray1[index1][0] = numArray3[3]; double num3 = numArray2[index1]; int index3 = 1; while (index3 <= 3) { numArray1[index1][index3] = (double)BezierCurveFitter.pascalTriangle[3][index3] * num3 * numArray3[3 - index3]; ++index3; num3 *= numArray2[index1]; } } double[][] numArray4 = new double[4][]; for (int index = 0; index < 4; ++index) { numArray4[index] = new double[4]; } for (int index1 = 0; index1 <= 3; ++index1) { for (int index2 = 0; index2 <= index1; ++index2) { for (int index3 = 0; index3 <= num1; ++index3) { numArray4[index1][index2] += numArray1[index3][index2] * numArray1[index3][index1]; } if (index1 != index2) { numArray4[index2][index1] = numArray4[index1][index2]; } } } double[][] m = new double[2][] { new double[2] { numArray4[1][1], numArray4[1][2] * VectorUtilities.Dot(unitTangentFirst, unitTangentLast) }, new double[2] { numArray4[1][2], numArray4[2][2] } }; double[] v = new double[2]; Vector[] vectorArray = new Vector[4]; for (int index1 = 0; index1 < 4; ++index1) { for (int index2 = 0; index2 <= num1; ++index2) { vectorArray[index1].X += numArray1[index2][index1] * this.sample[index2 + first].X; vectorArray[index1].Y += numArray1[index2][index1] * this.sample[index2 + first].Y; } } Vector vector1 = new Vector(this.sample[first].X, this.sample[first].Y); Vector vector2 = new Vector(this.sample[last].X, this.sample[last].Y); Vector b1 = (numArray4[1][0] + numArray4[1][1]) * vector1 + (numArray4[1][2] + numArray4[1][3]) * vector2 - vectorArray[1]; v[0] = -VectorUtilities.Dot(unitTangentFirst, b1); Vector b2 = (numArray4[2][0] + numArray4[2][1]) * vector1 + (numArray4[2][2] + numArray4[2][3]) * vector2 - vectorArray[2]; v[1] = -VectorUtilities.Dot(unitTangentLast, b2); bool flag = BezierCurveFitter.Solve2By2LinearSystem(m, v); int firstBadVertexInQ = 0; if (flag && v[0] > 0.0 && v[1] < 0.0) { Point[] controlPoints = new Point[4]; controlPoints[0] = this.sample[first]; controlPoints[1] = controlPoints[0] + v[0] * unitTangentFirst; controlPoints[3] = this.sample[last]; controlPoints[2] = controlPoints[3] + v[1] * unitTangentLast; List <Point> list = new List <Point>(128); BezierCurveFlattener.FlattenCubic(controlPoints, this.distanceTolerance, list, false); double[] cumulatedChordLength = VectorUtilities.GetCumulatedChordLength(list, 0, list.Count - 1); if (VectorUtilities.ArePolylinesClose(list, cumulatedChordLength, 0, list.Count - 1, this.sample, this.chordLength, first, last, this.distanceTolerance, ref firstBadVertexInQ)) { pathFigureEditor.CubicCurveTo(controlPoints[1], controlPoints[2], controlPoints[3]); return; } } int num4 = (first + last) / 2; Vector tangentVectorAtSplit = this.GetUnitTangentVectorAtSplit(num4); this.OpenFit2DFromTo(first, unitTangentFirst, num4, tangentVectorAtSplit, onlyCubics); int index4 = PathFigureUtilities.PointCount(this.figure) - 1; this.OpenFit2DFromTo(num4, tangentVectorAtSplit, last, unitTangentLast, onlyCubics); this.SetupCollinearHandlesConstraint(index4, onlyCubics); } }
private void SetPathUsingMapping(PathGeometry path) { SceneViewModel viewModel = this.targetElement.ViewModel; using (viewModel.AnimationProxyManager != null ? viewModel.AnimationProxyManager.ExpandAllProxiesInActiveContainer() : (IDisposable)null) { foreach (PathAction action in this.changeList.Changes) { System.Windows.Media.Geometry geometry = this.targetElement.GetLocalOrDefaultValueAsWpf((IPropertyId)this.pathProperty) as System.Windows.Media.Geometry; if (geometry == null && this.targetElement.IsValueExpression((IPropertyId)this.pathProperty)) { geometry = this.targetElement.ViewModel.DefaultView.ConvertToWpfValue(this.targetElement.ViewModel.CreateInstance(this.targetElement.GetLocalValueAsSceneNode((IPropertyId)this.pathProperty).DocumentNodePath)) as System.Windows.Media.Geometry; if (geometry == null) { geometry = this.targetElement.GetComputedValueAsWpf((IPropertyId)this.pathProperty) as System.Windows.Media.Geometry; if (geometry == null) { return; } } } PathGeometry oldGeometry = new PathGeometry(); oldGeometry.AddGeometry(geometry.Clone()); PathGeometry pathGeometry = new PathGeometry(); pathGeometry.AddGeometry(geometry); PathFigureEditor pathFigureEditor = new PathFigureEditor(pathGeometry.Figures[action.Figure]); PathGeometryEditor pathGeometryEditor = new PathGeometryEditor(pathGeometry); switch (action.Action) { case PathActionType.InsertPoint: pathFigureEditor.SubdivideSegment(action.PointIndex, action.Parameter); break; case PathActionType.DeletePoint: pathFigureEditor.RemovePoint(action.PointIndex); break; case PathActionType.DeleteSegment: if (action.Segment == 0 && pathFigureEditor.PathFigure.Segments.Count > 1) { pathFigureEditor.RemoveFirstSegment(); break; } pathFigureEditor.RemoveLastSegment(); break; case PathActionType.PromoteSegment: pathFigureEditor.PromoteSegment(action.PointIndex); break; case PathActionType.Rotate: pathFigureEditor.Rotate(); break; case PathActionType.Open: pathFigureEditor.Open(action.PointIndex); break; case PathActionType.Split: pathFigureEditor.Split(action.PointIndex); break; case PathActionType.SplitAndAdd: pathGeometryEditor.SplitFigure(action.Figure, action.PointIndex); break; case PathActionType.RemoveFigure: pathGeometryEditor.RemoveFigure(action.Figure); break; case PathActionType.AppendSegment: PathAppendLineAction appendLineAction; if ((appendLineAction = action as PathAppendLineAction) != null) { Point point = appendLineAction.Point; if (action.Figure < path.Figures.Count && action.Segment < path.Figures[action.Figure].Segments.Count) { LineSegment lineSegment = path.Figures[action.Figure].Segments[action.Segment] as LineSegment; if (lineSegment != null) { point = lineSegment.Point; } } pathFigureEditor.LineTo(point); break; } PathAppendQuadraticBezierAction quadraticBezierAction; if ((quadraticBezierAction = action as PathAppendQuadraticBezierAction) != null) { Point point1 = quadraticBezierAction.Point1; Point point2 = quadraticBezierAction.Point2; if (action.Figure < path.Figures.Count && action.Segment < path.Figures[action.Figure].Segments.Count) { QuadraticBezierSegment quadraticBezierSegment = path.Figures[action.Figure].Segments[action.Segment] as QuadraticBezierSegment; if (quadraticBezierSegment != null) { point1 = quadraticBezierSegment.Point1; point2 = quadraticBezierSegment.Point2; } } pathFigureEditor.QuadraticCurveTo(point1, point2); break; } PathAppendBezierAction appendBezierAction; if ((appendBezierAction = action as PathAppendBezierAction) != null) { Point point1 = appendBezierAction.Point1; Point point2 = appendBezierAction.Point2; Point point3 = appendBezierAction.Point3; if (action.Figure < path.Figures.Count && action.Segment < path.Figures[action.Figure].Segments.Count) { BezierSegment bezierSegment = path.Figures[action.Figure].Segments[action.Segment] as BezierSegment; if (bezierSegment != null) { point1 = bezierSegment.Point1; point2 = bezierSegment.Point2; point3 = bezierSegment.Point3; } } pathFigureEditor.CubicCurveTo(point1, point2, point3); break; } break; case PathActionType.Close: pathFigureEditor.CloseWithLineSegment(); break; case PathActionType.Join: pathGeometryEditor.JoinFigure(action.Figure, action.PointIndex); break; case PathActionType.Reverse: pathFigureEditor.Reverse(); break; } this.targetElement.SetLocalValueAsWpf((IPropertyId)this.pathProperty, (object)pathGeometry); this.ApplyAnimationChanges(oldGeometry, pathGeometry, action); if (action.Action == PathActionType.PromoteSegment && action.Segment < pathGeometry.Figures[action.Figure].Segments.Count) { this.targetElement.ViewModel.Document.OnUpdatedEditTransaction(); this.SetKeyframesForSegment(path, action.Figure, action.Segment); } } this.RemoveInvalidAnimations(PathGeometryUtilities.GetPathGeometryFromGeometry((System.Windows.Media.Geometry) this.targetElement.GetLocalOrDefaultValueAsWpf((IPropertyId)this.pathProperty))); } }