public static void Test_GetWestNorthVectors_02() { const double maxDev = 1E-6; for (int i = -1; i <= 1; i += 2) { var v = new VectorD3D(0, 0, i); var westNorth = PolylineMath3D.GetWestNorthVectors(new LineD3D(PointD3D.Empty, (PointD3D)v)); var west = westNorth.Item1; var north = westNorth.Item2; Assert.AreEqual(west.Length, 1, maxDev); // is west normalized Assert.AreEqual(north.Length, 1, maxDev); // is north normalized Assert.AreEqual(VectorD3D.DotProduct(west, v), 0, maxDev); // is west perpendicular to forward Assert.AreEqual(VectorD3D.DotProduct(north, v), 0, maxDev); // is north perpendicular to forward Assert.AreEqual(VectorD3D.DotProduct(west, north), 0, maxDev); // is west perpendicular to north var matrix = Altaxo.Geometry.Matrix4x3.NewFromBasisVectorsAndLocation(west, north, v, PointD3D.Empty); Assert.AreEqual(matrix.Determinant, 1, maxDev); var westExpected = new VectorD3D(-1, 0, 0); var northExpected = new VectorD3D(0, -i, 0); Assert.AreEqual(westExpected.X, west.X, maxDev); Assert.AreEqual(westExpected.Y, west.Y, maxDev); Assert.AreEqual(westExpected.Z, west.Z, maxDev); Assert.AreEqual(northExpected.X, north.X, maxDev); Assert.AreEqual(northExpected.Y, north.Y, maxDev); Assert.AreEqual(northExpected.Z, north.Z, maxDev); } }
public static void Test_GetPolylinePointsWithWestAndNorth_02() { const double maxDev = 1E-6; var rnd = new System.Random(); var testPoints = new PointD3D[1024]; testPoints[0] = PointD3D.Empty; testPoints[1] = new PointD3D(0, 0.1, 0); // first line segment always in y direction, so that north is in z direction and west in -x direction for (int i = 2; i < testPoints.Length; ++i) { testPoints[i] = new PointD3D(rnd.NextDouble(), rnd.NextDouble(), rnd.NextDouble()); } var result = PolylineMath3D.GetPolylinePointsWithWestAndNorth(testPoints).ToArray(); for (int i = 1; i < result.Length; ++i) { var forwardRaw = result[i].Position - result[i - 1].Position; var west = result[i].WestVector; var north = result[i].NorthVector; Assert.AreNotEqual(forwardRaw.Length, 0); // GetPolylinePointsWithWestAndNorth should only deliver non-empty segments var forward = forwardRaw.Normalized; Assert.AreEqual(west.Length, 1, maxDev); // is west normalized Assert.AreEqual(north.Length, 1, maxDev); // is north normalized Assert.AreEqual(VectorD3D.DotProduct(west, forward), 0, maxDev); // is west perpendicular to forward Assert.AreEqual(VectorD3D.DotProduct(north, forward), 0, maxDev); // is north perpendicular to forward Assert.AreEqual(VectorD3D.DotProduct(west, north), 0, maxDev); // is west perpendicular to north var matrix = Altaxo.Geometry.Matrix4x3.NewFromBasisVectorsAndLocation(west, north, forward, PointD3D.Empty); Assert.AreEqual(matrix.Determinant, 1, maxDev); // west-north-forward are a right handed coordinate system } }
public static void Test_GetPolylinePointsWithWestAndNorth_01() { const double maxDev = 1E-6; for (int caseNo = 0; caseNo < _testCases.Length; ++caseNo) { var points = _testCases[caseNo].Item1; var expectedOutput = _testCases[caseNo].Item2; var result = PolylineMath3D.GetPolylinePointsWithWestAndNorth(points).ToArray(); // Verify results Assert.AreEqual(expectedOutput.Length, result.Length); for (int i = 0; i < expectedOutput.Length; ++i) { string comment = string.Format("In case no. {0}, i={1}", caseNo, i); Assert.AreEqual(expectedOutput[i].Item1, result[i].Position, comment); Assert.AreEqual(expectedOutput[i].Item2.X, result[i].WestVector.X, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item2.Y, result[i].WestVector.Y, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item2.Z, result[i].WestVector.Z, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item3.X, result[i].NorthVector.X, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item3.Y, result[i].NorthVector.Y, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item3.Z, result[i].NorthVector.Z, maxDev, comment); } } }
public static void Test_GetWestNorthVectors_01() { const double maxDev = 1E-6; for (int iTheta = -89; iTheta < 90; ++iTheta) { double theta = Math.PI * iTheta / 180.0; for (int iPhi = 0; iPhi < 360; ++iPhi) { double phi = Math.PI * iPhi / 180.0; var v = new VectorD3D(Math.Cos(phi) * Math.Cos(theta), Math.Sin(phi) * Math.Cos(theta), Math.Sin(theta)); Assert.AreEqual(v.Length, 1, maxDev); // is forward normalized var rawNorth = PolylineMath3D.GetRawNorthVectorAtStart(v); Assert.AreEqual(rawNorth.X, 0); Assert.AreEqual(rawNorth.Y, 0); Assert.AreEqual(rawNorth.Z, 1); var westNorth = PolylineMath3D.GetWestNorthVectors(new LineD3D(PointD3D.Empty, (PointD3D)v)); var west = westNorth.Item1; var north = westNorth.Item2; Assert.AreEqual(west.Length, 1, maxDev); // is west normalized Assert.AreEqual(north.Length, 1, maxDev); // is north normalized Assert.AreEqual(VectorD3D.DotProduct(west, v), 0, maxDev); // is west perpendicular to forward Assert.AreEqual(VectorD3D.DotProduct(north, v), 0, maxDev); // is north perpendicular to forward Assert.AreEqual(VectorD3D.DotProduct(west, north), 0, maxDev); // is west perpendicular to north var matrix = Altaxo.Geometry.Matrix4x3.NewFromBasisVectorsAndLocation(west, north, v, PointD3D.Empty); Assert.AreEqual(matrix.Determinant, 1, maxDev); var westExpected = new VectorD3D(-Math.Sin(phi), Math.Cos(phi), 0); var northExpected = new VectorD3D(-Math.Cos(phi) * Math.Sin(theta), -Math.Sin(phi) * Math.Sin(theta), Math.Cos(theta)); Assert.AreEqual(westExpected.X, west.X, maxDev); Assert.AreEqual(westExpected.Y, west.Y, maxDev); Assert.AreEqual(westExpected.Z, west.Z, maxDev); Assert.AreEqual(northExpected.X, north.X, maxDev); Assert.AreEqual(northExpected.Y, north.Y, maxDev); Assert.AreEqual(northExpected.Z, north.Z, maxDev); } } }
/// <summary> /// Determines whether a polyline is hit. /// </summary> /// <param name="points">The points that make out the polyline.</param> /// <param name="thickness1">The thickness of the pen in east direction.</param> /// <param name="thickness2">The thickness of the pen in north direction.</param> /// <returns>True if the polyline is hit; otherwise false.</returns> public bool IsHit(IEnumerable <PointD3D> points, double thickness1, double thickness2) { var polyline = PolylineMath3D.GetPolylinePointsWithWestAndNorth(points); var coll = polyline.GetEnumerator(); if (!coll.MoveNext()) { return(false); // no points } double thickness1By2 = thickness1 / 2; double thickness2By2 = thickness2 / 2; var pts = new PointD3D[8]; PointD3D P0 = coll.Current.Position; while (coll.MoveNext()) { var P1 = coll.Current.Position; // end point of current line var e = coll.Current.WestVector; // east vector var n = coll.Current.NorthVector; // north vector pts[0] = _hitTransformation.Transform(P0 - thickness1By2 * e - thickness2By2 * n); pts[1] = _hitTransformation.Transform(P1 - thickness1By2 * e - thickness2By2 * n); pts[2] = _hitTransformation.Transform(P0 + thickness1By2 * e - thickness2By2 * n); pts[3] = _hitTransformation.Transform(P1 + thickness1By2 * e - thickness2By2 * n); pts[4] = _hitTransformation.Transform(P0 - thickness1By2 * e + thickness2By2 * n); pts[5] = _hitTransformation.Transform(P1 - thickness1By2 * e + thickness2By2 * n); pts[6] = _hitTransformation.Transform(P0 + thickness1By2 * e + thickness2By2 * n); pts[7] = _hitTransformation.Transform(P1 + thickness1By2 * e + thickness2By2 * n); foreach (var ti in RectangleD3D.GetTriangleIndices()) { if (HitTestWithAlreadyTransformedPoints(pts[ti.Item1], pts[ti.Item2], pts[ti.Item3], out var z) && z >= 0) { return(true); } } P0 = P1; // take previous point from current point } return(false); }
public override IGripManipulationHandle[] GetGrips(int gripLevel) { if (gripLevel <= 1) { var ls = (LineShape)_hitobject; var pts = new PointD3D[] { PointD3D.Empty, (PointD3D)ls.Size }; for (int i = 0; i < pts.Length; i++) { var pt = ls._transformation.Transform(pts[i]); pt = Transformation.Transform(pt); pts[i] = pt; } var grips = new IGripManipulationHandle[gripLevel == 0 ? 1 : 3]; // Translation grips var bounds = ls.Bounds; var wn = PolylineMath3D.GetWestNorthVectors(bounds.Size); var transformation = Matrix4x3.NewFromBasisVectorsAndLocation(wn.Item1, wn.Item2, bounds.Size.Normalized, PointD3D.Empty); transformation.AppendTransform(ls._transformation); transformation.AppendTransform(Transformation); double t1 = 0.55 * ls._linePen.Thickness1; double t2 = 0.55 * ls._linePen.Thickness2; var rect = new RectangleD3D(-t1, -t2, 0, 2 * t1, 2 * t2, bounds.Size.Length); var objectOutline = new RectangularObjectOutline(rect, transformation); grips[0] = new MovementGripHandle(this, objectOutline, null); // PathNode grips if (gripLevel == 1) { grips[2] = grips[0]; // put the movement grip to the background, the two NodeGrips need more priority var gripRadius = Math.Max(t1, t2); grips[0] = new PathNodeGripHandle(this, new VectorD3D(0, 0, 0), pts[0], gripRadius); grips[1] = new PathNodeGripHandle(this, new VectorD3D(1, 1, 1), pts[1], gripRadius); } return(grips); } else { return(base.GetGrips(gripLevel)); } }
public bool IsHit(LineD3D line, double thickness1, double thickness2) { if (!(line.Length > 0)) { return(false); } var eastnorth = PolylineMath3D.GetWestNorthVectors(line); var e = eastnorth.Item1; // east vector var n = eastnorth.Item2; // north vector double thickness1By2 = thickness1 / 2; double thickness2By2 = thickness2 / 2; var pts = new PointD3D[8]; pts[0] = _hitTransformation.Transform(line.P0 - thickness1By2 * e - thickness2By2 * n); pts[1] = _hitTransformation.Transform(line.P1 - thickness1By2 * e - thickness2By2 * n); pts[2] = _hitTransformation.Transform(line.P0 + thickness1By2 * e - thickness2By2 * n); pts[3] = _hitTransformation.Transform(line.P1 + thickness1By2 * e - thickness2By2 * n); pts[4] = _hitTransformation.Transform(line.P0 - thickness1By2 * e + thickness2By2 * n); pts[5] = _hitTransformation.Transform(line.P1 - thickness1By2 * e + thickness2By2 * n); pts[6] = _hitTransformation.Transform(line.P0 + thickness1By2 * e + thickness2By2 * n); pts[7] = _hitTransformation.Transform(line.P1 + thickness1By2 * e + thickness2By2 * n); double z; foreach (var ti in RectangleD3D.GetTriangleIndices()) { if (HitTestWithAlreadyTransformedPoints(pts[ti.Item1], pts[ti.Item2], pts[ti.Item3], out z) && z >= 0) { return(true); } } z = double.NaN; return(false); }
public static void Test_GetFractionalPolyline_01() { const double maxDev = 1E-6; string comment = string.Empty; for (int caseNo = 0; caseNo < _testCases.Length; ++caseNo) { if (caseNo == 1 || caseNo == 2) // not with coincidenting points { continue; } var points = _testCases[caseNo].Item1; var expectedOutput = _testCases[caseNo].Item2; var maxEndIndex = points.Length - 1; for (double endIndex = 0.25; endIndex <= maxEndIndex; endIndex += 0.25) { for (double startIndex = 0; startIndex < endIndex; startIndex += 0.25) { var result = PolylineMath3D.GetPolylineWithFractionalStartAndEndIndex( points, expectedOutput[0].Item2, expectedOutput[0].Item3, (points[1] - points[0]).Normalized, startIndex, endIndex, false, false, new PolylinePointD3DAsClass(), false, false, new PolylinePointD3DAsClass()).ToArray(); int iShift = (int)Math.Floor(startIndex); for (int i = (int)Math.Ceiling(startIndex); i < (int)Math.Floor(endIndex); ++i) { comment = string.Format("In case no. {0}, startIndex={1}, endIndex={2}, i={3}", caseNo, startIndex, endIndex, i); Assert.AreEqual(expectedOutput[i].Item1, result[i - iShift].Position, comment); Assert.AreEqual(expectedOutput[i].Item2.X, result[i - iShift].WestVector.X, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item2.Y, result[i - iShift].WestVector.Y, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item2.Z, result[i - iShift].WestVector.Z, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item3.X, result[i - iShift].NorthVector.X, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item3.Y, result[i - iShift].NorthVector.Y, maxDev, comment); Assert.AreEqual(expectedOutput[i].Item3.Z, result[i - iShift].NorthVector.Z, maxDev, comment); } // start int startIndexInt = (int)Math.Floor(startIndex); double startIndexFrac = startIndex - startIndexInt; var expectedStartPoint = startIndexFrac == 0 ? points[startIndexInt] : PointD3D.Interpolate(points[startIndexInt], points[startIndexInt + 1], startIndexFrac); int vecIndex = startIndexFrac == 0 ? startIndexInt : startIndexInt + 1; comment = string.Format("In case no. {0}, startIndex={1}, endIndex={2}", caseNo, startIndex, endIndex); Assert.AreEqual(expectedStartPoint, result[0].Position, comment); Assert.AreEqual(expectedOutput[vecIndex].Item2.X, result[0].WestVector.X, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item2.Y, result[0].WestVector.Y, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item2.Z, result[0].WestVector.Z, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item3.X, result[0].NorthVector.X, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item3.Y, result[0].NorthVector.Y, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item3.Z, result[0].NorthVector.Z, maxDev, comment); // end int endIndexInt = (int)Math.Floor(endIndex); double endIndexFrac = endIndex - endIndexInt; var expectedEndPoint = endIndexFrac == 0 ? points[endIndexInt] : PointD3D.Interpolate(points[endIndexInt], points[endIndexInt + 1], endIndexFrac); vecIndex = endIndexFrac == 0 ? endIndexInt : endIndexInt + 1; var resultLast = result[result.Length - 1]; Assert.AreEqual(expectedEndPoint, resultLast.Position, comment); Assert.AreEqual(expectedOutput[vecIndex].Item2.X, resultLast.WestVector.X, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item2.Y, resultLast.WestVector.Y, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item2.Z, resultLast.WestVector.Z, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item3.X, resultLast.NorthVector.X, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item3.Y, resultLast.NorthVector.Y, maxDev, comment); Assert.AreEqual(expectedOutput[vecIndex].Item3.Z, resultLast.NorthVector.Z, maxDev, comment); // test first returned } } } }
public void AddGeometry( Action <PointD3D, VectorD3D> AddPositionAndNormal, Action <int, int, int, bool> AddIndices, ref int vertexIndexOffset, PenX3D pen, LineD3D line ) { var westnorth = PolylineMath3D.GetWestNorthVectors(line); var westVector = westnorth.Item1; var northVector = westnorth.Item2; if (pen.DashPattern is DashPatterns.Solid) { // draw without a dash pattern - we consider the whole line as one dash segment, but instead of dash caps, with line caps _dashSegment.Initialize(pen.CrossSection, pen.Thickness1, pen.Thickness2, pen.LineStartCap, pen.LineEndCap, westVector, northVector, line); _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, line, null, null); } else { // draw with a dash pattern _dashSegment.Initialize(pen, westVector, northVector, line); double dashOffset = 0; PointD3D lineStart = line.P0; PointD3D lineEnd = line.P1; var lineVector = line.LineVector; double lineLength = lineVector.Length; var lineVectorNormalized = lineVector / lineLength; // calculate the real start and end of the line, taking the line start and end cap length into account if (null != pen.LineStartCap) { var v = pen.LineStartCap.GetAbsoluteBaseInset(pen.Thickness1, pen.Thickness2); if (v < 0) { dashOffset = -v; lineStart += -v * lineVectorNormalized; lineLength += v; } } if (null != pen.LineEndCap) { var v = pen.LineEndCap.GetAbsoluteBaseInset(pen.Thickness1, pen.Thickness2); if (v < 0) { lineEnd += v * lineVectorNormalized; lineLength += v; } } // now draw the individual dash segments bool wasLineStartCapDrawn = false; bool wasLineEndCapDrawn = false; if (lineLength > 0) { foreach (var seg in Math3D.DissectStraightLineWithDashPattern(new LineD3D(lineStart, lineEnd), pen.DashPattern, pen.DashPattern.DashOffset, Math.Max(pen.Thickness1, pen.Thickness2), dashOffset)) { if (seg.P0 == lineStart) // this is the start of the line, thus we must use the lineStartCap instead of the dashStartCap { _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, seg, pen.LineStartCap, null); wasLineStartCapDrawn = true; } else if (seg.P1 == lineEnd) // this is the end of the line, thus we must use the lineEndCap instead of the dashEndCap { _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, seg, null, pen.LineEndCap); wasLineEndCapDrawn = true; } else // this is a normal dashSegment, thus we can use dashStartCap and dashEndCap { _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, seg, null, null); } } } object temporaryStorageSpace = null; // if the start cap was not drawn before, it must be drawn now if (!wasLineStartCapDrawn && null != pen.LineStartCap) { pen.LineStartCap.AddGeometry( AddPositionAndNormal, AddIndices, ref vertexIndexOffset, true, lineStart, westVector, northVector, lineVectorNormalized, pen.CrossSection, null, null, ref temporaryStorageSpace); } // if the end cap was not drawn before, it must be drawn now if (!wasLineEndCapDrawn && null != pen.LineEndCap) { pen.LineEndCap.AddGeometry( AddPositionAndNormal, AddIndices, ref vertexIndexOffset, false, lineEnd, westVector, northVector, lineVectorNormalized, pen.CrossSection, null, null, ref temporaryStorageSpace); } } }
public void AddWithNormals( Action<PointD3D, VectorD3D> AddPositionAndNormal, Action<int, int, int, bool> AddIndices, ref int vertexIndexOffset, PenX3D pen, IList<PointD3D> polylinePoints ) { if (pen.DashPattern is DashPatterns.Solid) { // draw without a dash pattern - we consider the whole line as one dash segment, but instead of dash caps, with line caps _dashSegment.Initialize(pen.CrossSection, pen.Thickness1, pen.Thickness2, pen.LineJoin, pen.MiterLimit, pen.LineStartCap, pen.LineEndCap); var westNorth = PolylineMath3D.GetWestNorthVectorAtStart(polylinePoints); _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, polylinePoints, westNorth.WestVector, westNorth.NorthVector, westNorth.ForwardVector, null, null); } else { // draw with a dash pattern _dashSegment.Initialize(pen); double dashOffset = 0; bool startCapForwardAndPositionProvided = false; bool startCapNeedsJoinSegment = false; var startCapCOS = new PolylinePointD3DAsClass(); bool endCapForwardAndPositionProvided = false; bool endCapNeedsJoinSegment = false; var endCapCOS = new PolylinePointD3DAsClass(); double startIndex = 0; double endIndex = polylinePoints.Count - 1; // calculate the real start and end of the line, taking the line start and end cap length into account if (null != pen.LineStartCap) { var v = pen.LineStartCap.GetAbsoluteBaseInset(pen.Thickness1, pen.Thickness2); if (v < 0) { dashOffset = -v; startIndex = PolylineMath3D.GetFractionalStartIndexOfPolylineWithCapInsetAbsolute( polylinePoints, -v, out startCapForwardAndPositionProvided, out startCapNeedsJoinSegment, startCapCOS); } } if (null != pen.LineEndCap) { var v = pen.LineEndCap.GetAbsoluteBaseInset(pen.Thickness1, pen.Thickness2); if (v < 0) { endIndex = PolylineMath3D.GetFractionalEndIndexOfPolylineWithCapInsetAbsolute( polylinePoints, -v, out endCapForwardAndPositionProvided, out endCapNeedsJoinSegment, endCapCOS); } } // now draw the individual dash segments bool wasLineStartCapDrawn = false; bool wasLineEndCapDrawn = false; var en = PolylineMath3D.DissectPolylineWithDashPattern( polylinePoints, startIndex, endIndex, pen.DashPattern, pen.DashPattern.DashOffset, Math.Max(pen.Thickness1, pen.Thickness2), dashOffset, startCapForwardAndPositionProvided, startCapNeedsJoinSegment, startCapCOS, endCapForwardAndPositionProvided, endCapNeedsJoinSegment, endCapCOS ).GetEnumerator(); if (!en.MoveNext()) { // there is no segment at all in the list, but maybe we can draw the start and end line caps } else { var previousPointList = en.Current; var currentPointList = en.Current; if (en.MoveNext()) currentPointList = en.Current; else currentPointList = null; // if current point list is null, then there is only one segment, namely previousPointList, we have to draw it with start line cap and end line cap. if (currentPointList == null) { // note start line cap and end line cap will be overridden for this segment, but only then if the seamless merge with the dash segment bool overrideLineStartCap = startCapForwardAndPositionProvided && previousPointList[0].Position == startCapCOS.Position; bool overrideLineEndCap = endCapForwardAndPositionProvided && previousPointList[previousPointList.Count - 1].Position == endCapCOS.Position; _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, previousPointList, overrideLineStartCap ? pen.LineStartCap : null, overrideLineEndCap ? pen.LineEndCap : null); wasLineStartCapDrawn = overrideLineStartCap; wasLineEndCapDrawn = overrideLineEndCap; } else // there are at least two segments { // this is the start of the line, thus we must use the lineStartCap instead of the dashStartCap // note start line cap will be overridden for this first segment, but only then if it seamlessly merge with the start of the dash segment bool overrideLineStartCap = startCapForwardAndPositionProvided && previousPointList[0].Position == startCapCOS.Position; _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, previousPointList, overrideLineStartCap ? pen.LineStartCap : null, null); wasLineStartCapDrawn = overrideLineStartCap; previousPointList = currentPointList; while (en.MoveNext()) { var currentList = en.Current; // draw the previous list as a normal dashSegment, thus we can use dashStartCap and dashEndCap _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, previousPointList, null, null); previousPointList = currentList; } // now currentList is the last list, we can draw an endcap to this bool overrideLineEndCap = endCapForwardAndPositionProvided && previousPointList[previousPointList.Count - 1].Position == endCapCOS.Position; _dashSegment.AddGeometry(AddPositionAndNormal, AddIndices, ref vertexIndexOffset, previousPointList, null, overrideLineEndCap ? pen.LineEndCap : null); wasLineEndCapDrawn = overrideLineEndCap; } object temporaryStorageSpace = null; // if the start cap was not drawn before, it must be drawn now if (!wasLineStartCapDrawn && null != pen.LineStartCap) { pen.LineStartCap.AddGeometry( AddPositionAndNormal, AddIndices, ref vertexIndexOffset, true, startCapCOS.Position, startCapCOS.WestVector, startCapCOS.NorthVector, startCapCOS.ForwardVector, pen.CrossSection, null, null, ref temporaryStorageSpace); } // if the end cap was not drawn before, it must be drawn now if (!wasLineEndCapDrawn && null != pen.LineEndCap) { pen.LineEndCap.AddGeometry( AddPositionAndNormal, AddIndices, ref vertexIndexOffset, false, endCapCOS.Position, endCapCOS.WestVector, endCapCOS.NorthVector, endCapCOS.ForwardVector, pen.CrossSection, null, null, ref temporaryStorageSpace); } } } }
protected override IGripManipulationHandle[] GetGrips(IHitTestObject hitTest, GripKind gripKind) { var list = new List <IGripManipulationHandle>(); /* * * const double gripNominalSize = 10; // 10 Points nominal size on the screen * if ((GripKind.Resize & gripKind) != 0) * { * double gripSize = gripNominalSize / pageScale; // 10 Points, but we have to consider the current pageScale * for (int i = 1; i < _gripRelPositions.Length; i++) * { * PointD2D outVec, pos; * if (1 == i % 2) * GetCornerOutVector(_gripRelPositions[i], hitTest, out outVec, out pos); * else * GetMiddleRayOutVector(_gripRelPositions[i], hitTest, out outVec, out pos); * * outVec *= (gripSize / outVec.VectorLength); * PointD2D altVec = outVec.Get90DegreeRotated(); * PointD2D ptStart = pos; * list.Add(new ResizeGripHandle(hitTest, _gripRelPositions[i], new MatrixD2D(outVec.X, outVec.Y, altVec.X, altVec.Y, ptStart.X, ptStart.Y))); * } * } */ /* * if ((GripKind.Rotate & gripKind) != 0) * { * double gripSize = 10 / pageScale; * // Rotation grips * for (int i = 1; i < _gripRelPositions.Length; i += 2) * { * PointD2D outVec, pos; * GetCornerOutVector(_gripRelPositions[i], hitTest, out outVec, out pos); * * outVec *= (gripSize / outVec.VectorLength); * PointD2D altVec = outVec.Get90DegreeRotated(); * PointD2D ptStart = pos; * list.Add(new RotationGripHandle(hitTest, _gripRelPositions[i], new MatrixD2D(outVec.X, outVec.Y, altVec.X, altVec.Y, ptStart.X, ptStart.Y))); * } * } */ /* * if ((GripKind.Rescale & gripKind) != 0) * { * double gripSize = 10 / pageScale; // 10 Points, but we have to consider the current pageScale * for (int i = 1; i < _gripRelPositions.Length; i++) * { * PointD2D outVec, pos; * if (1 == i % 2) * GetCornerOutVector(_gripRelPositions[i], hitTest, out outVec, out pos); * else * GetMiddleRayOutVector(_gripRelPositions[i], hitTest, out outVec, out pos); * * outVec *= (gripSize / outVec.VectorLength); * PointD2D altVec = outVec.Get90DegreeRotated(); * PointD2D ptStart = pos; * list.Add(new RescaleGripHandle(hitTest, _gripRelPositions[i], new MatrixD2D(outVec.X, outVec.Y, altVec.X, altVec.Y, ptStart.X, ptStart.Y))); * } * } */ /* * if ((GripKind.Shear & gripKind) != 0) * { * double gripSize = 10 / pageScale; // 10 Points, but we have to consider the current pageScale * for (int i = 2; i < _gripRelPositions.Length; i += 2) * { * PointD2D outVec, pos; * GetEdgeOutVector(_gripRelPositions[i], hitTest, out outVec, out pos); * * outVec *= (gripSize / outVec.VectorLength); * PointD2D altVec = outVec.Get90DegreeRotated(); * PointD2D ptStart = pos; * list.Add(new ShearGripHandle(hitTest, _gripRelPositions[i], new MatrixD2D(outVec.X, outVec.Y, altVec.X, altVec.Y, ptStart.X, ptStart.Y))); * } * } */ if ((GripKind.Move & gripKind) != 0) { var bounds = Bounds; var wn = PolylineMath3D.GetWestNorthVectors(bounds.Size); var transformation = Matrix4x3.NewFromBasisVectorsAndLocation(wn.Item1, wn.Item2, bounds.Size.Normalized, PointD3D.Empty); transformation.AppendTransform(_transformation); transformation.AppendTransform(hitTest.Transformation); double t1 = 0.55 * _linePen.Thickness1; double t2 = 0.55 * _linePen.Thickness2; var rect = new RectangleD3D(-t1, -t2, 0, 2 * t1, 2 * t2, bounds.Size.Length); var objectOutline = new RectangularObjectOutline(rect, transformation); list.Add(new MovementGripHandle(hitTest, objectOutline, null)); } return(list.ToArray()); }