Example #1
0
        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);
            }
        }
Example #2
0
        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
            }
        }
Example #3
0
        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);
                }
            }
        }
Example #4
0
        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);
                }
            }
        }
Example #5
0
        /// <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);
        }
Example #6
0
            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));
                }
            }
Example #7
0
        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);
        }
Example #8
0
        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
                    }
                }
            }
        }
Example #9
0
        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);
                }
            }
        }
Example #10
0
    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);
          }
        }
      }
    }
Example #11
0
        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());
        }