/// <summary>
		/// Initialization that is needed only once per straigth line (not once per dash).
		/// </summary>
		/// <param name="pen">The pen that is used to draw the line.</param>
		/// <param name="west">The west vector.</param>
		/// <param name="north">The north vector.</param>
		/// <param name="line">The global line to draw. This argument is needed to extract the line vector, which for a straight line is also the line vector for each individual dash segment.</param>
		public void Initialize(
			PenX3D pen,
			VectorD3D west,
			VectorD3D north,
			LineD3D line)
		{
			Initialize(
				pen.CrossSection,
				pen.Thickness1,
				pen.Thickness2,
				pen.DashStartCap,
				pen.DashEndCap,
				west,
				north,
				line
				);
		}
Example #2
0
        /// <summary>
        /// Dissects a straight line into individual line segments, using a dash pattern.
        /// </summary>
        /// <param name="line">The line to dissect.</param>
        /// <param name="dashPattern">The dash pattern.</param>
        /// <param name="dashPatternOffset">The dash pattern offset (relative units, i.e. same units as dashPattern itself).</param>
        /// <param name="dashPatternScale">The dash pattern scale.</param>
        /// <param name="dashPatternStartAbsolute">An absolute length. This parameter is similar to <paramref name="dashPatternOffset"/>, but in absolute units.</param>
        /// <returns></returns>
        public static IEnumerable <LineD3D> DissectStraightLineWithDashPattern(LineD3D line, IReadOnlyList <double> dashPattern, double dashPatternOffset, double dashPatternScale, double dashPatternStartAbsolute)
        {
            int dashIndex = 0;
            int dashCount = dashPattern.Count;

            // Fast forward in dash
            double remainingOffset = dashPatternOffset;
            double currDash        = dashPattern[dashIndex];

            while (remainingOffset > 0)
            {
                if ((remainingOffset - currDash) >= 0)
                {
                    dashIndex       = (dashIndex + 1) % dashCount;
                    remainingOffset = remainingOffset - currDash;
                    currDash        = dashPattern[dashIndex];
                }
                else
                {
                    currDash       -= remainingOffset;
                    remainingOffset = 0;
                }
            }

            // now move forward to dashPatternStartAbsolute
            double remainingOffsetAbsolute = dashPatternStartAbsolute;

            while (remainingOffsetAbsolute > 0)
            {
                var diff = remainingOffsetAbsolute - currDash * dashPatternScale;
                if (diff >= 0)
                {
                    dashIndex = (dashIndex + 1) % dashCount;
                    remainingOffsetAbsolute = diff;
                    currDash = dashPattern[dashIndex];
                }
                else
                {
                    currDash -= remainingOffsetAbsolute / dashPatternScale;
                    remainingOffsetAbsolute = 0;
                }
            }

            // now we are ready to start
            double lineLength = line.Length;

            double sumPrev    = 0;
            double lengthPrev = 0;

            for (; lengthPrev < lineLength;)
            {
                double sumCurr    = sumPrev + currDash;
                double lengthCurr = sumCurr * dashPatternScale;
                if (lengthCurr >= lineLength)
                {
                    lengthCurr = lineLength;
                }

                if ((0 == dashIndex % 2) && (lengthCurr > lengthPrev))
                {
                    yield return(new LineD3D(
                                     line.GetPointAtLineFromRelativeValue(lengthPrev / lineLength),
                                     line.GetPointAtLineFromRelativeValue(lengthCurr / lineLength)
                                     ));
                }

                sumPrev    = sumCurr;
                lengthPrev = lengthCurr;
                dashIndex  = (dashIndex + 1) % dashCount;
                currDash   = dashPattern[dashIndex];
            }
        }
Example #3
0
		/// <summary>
		/// Gets the west and north vector for a single straight line.
		/// </summary>
		/// <param name="line">The line.</param>
		/// <returns>The west and the north vector (Item1=west vector, Item2 = north vector).</returns>
		public static Tuple<VectorD3D, VectorD3D> GetWestNorthVectors(LineD3D line)
		{
			return GetWestNorthVectors(line.Vector);
		}
Example #4
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 #5
0
		/// <summary>
		/// Dissects a straight line into individual line segments, using a dash pattern.
		/// </summary>
		/// <param name="line">The line to dissect.</param>
		/// <param name="dashPattern">The dash pattern.</param>
		/// <param name="dashPatternOffset">The dash pattern offset (relative units, i.e. same units as dashPattern itself).</param>
		/// <param name="dashPatternScale">The dash pattern scale.</param>
		/// <param name="dashPatternStartAbsolute">An absolute length. This parameter is similar to <paramref name="dashPatternOffset"/>, but in absolute units.</param>
		/// <returns></returns>
		public static IEnumerable<LineD3D> DissectStraightLineWithDashPattern(LineD3D line, IList<double> dashPattern, double dashPatternOffset, double dashPatternScale, double dashPatternStartAbsolute)
		{
			int dashIndex = 0;
			int dashCount = dashPattern.Count;

			// Fast forward in dash
			double remainingOffset = dashPatternOffset;
			double currDash = dashPattern[dashIndex];

			while (remainingOffset > 0)
			{
				if ((remainingOffset - currDash) >= 0)
				{
					dashIndex = (dashIndex + 1) % dashCount;
					remainingOffset = remainingOffset - currDash;
					currDash = dashPattern[dashIndex];
				}
				else
				{
					currDash -= remainingOffset;
					remainingOffset = 0;
				}
			}

			// now move forward to dashPatternStartAbsolute
			double remainingOffsetAbsolute = dashPatternStartAbsolute;
			while (remainingOffsetAbsolute > 0)
			{
				var diff = remainingOffsetAbsolute - currDash * dashPatternScale;
				if (diff >= 0)
				{
					dashIndex = (dashIndex + 1) % dashCount;
					remainingOffsetAbsolute = diff;
					currDash = dashPattern[dashIndex];
				}
				else
				{
					currDash -= remainingOffsetAbsolute / dashPatternScale;
					remainingOffsetAbsolute = 0;
				}
			}

			// now we are ready to start
			double lineLength = line.Length;

			double sumPrev = 0;
			double lengthPrev = 0;
			for (; lengthPrev < lineLength;)
			{
				double sumCurr = sumPrev + currDash;
				double lengthCurr = sumCurr * dashPatternScale;
				if (lengthCurr >= lineLength)
				{
					lengthCurr = lineLength;
				}

				if ((0 == dashIndex % 2) && (lengthCurr > lengthPrev))
				{
					yield return new LineD3D(
						line.GetPointAtLineFromRelativeValue(lengthPrev / lineLength),
						line.GetPointAtLineFromRelativeValue(lengthCurr / lineLength)
						);
				}

				sumPrev = sumCurr;
				lengthPrev = lengthCurr;
				dashIndex = (dashIndex + 1) % dashCount;
				currDash = dashPattern[dashIndex];
			}
		}
Example #6
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;
			PointD3D[] 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 void Initialize(
		ICrossSectionOfLine crossSection,
		double thickness1,
		double thickness2,
		ILineCap startCap,
		ILineCap endCap,
		VectorD3D westVector,
		VectorD3D northVector,
		LineD3D line)
		{
			this._crossSection = crossSection;
			this._crossSectionVertexCount = crossSection.NumberOfVertices;
			this._crossSectionNormalCount = crossSection.NumberOfNormals;
			this._dashStartCap = startCap;
			this._dashStartCapBaseInsetAbsolute = null == _dashStartCap ? 0 : _dashStartCap.GetAbsoluteBaseInset(thickness1, thickness2);
			this._dashEndCap = endCap;
			this._dashEndCapBaseInsetAbsolute = null == _dashEndCap ? 0 : _dashEndCap.GetAbsoluteBaseInset(thickness1, thickness2);
			this._westVector = westVector;
			this._northVector = northVector;
			this._forwardVector = line.LineVectorNormalized;
			this._lastNormalsTransformed = new VectorD3D[_crossSectionNormalCount];
			this._lastPositionsTransformedStart = new PointD3D[_crossSectionVertexCount];
			this._lastPositionsTransformedEnd = new PointD3D[_crossSectionVertexCount];

			// Get the matrix for the start plane
			var matrix = Math3D.Get2DProjectionToPlane(westVector, northVector, PointD3D.Empty);

			// note: for a single line segment, the normals need to be calculated only once

			for (int i = 0; i < _lastNormalsTransformed.Length; ++i)
			{
				_lastNormalsTransformed[i] = matrix.Transform(crossSection.Normals(i));
			}
		}
		public void AddGeometry(
		Action<PointD3D, VectorD3D> AddPositionAndNormal,
		Action<int, int, int, bool> AddIndices,
		ref int vertexIndexOffset,
		LineD3D dashSegment,
			ILineCap overrideStartCap,
			ILineCap overrideEndCap)
		{
			if (null == _lastNormalsTransformed)
				throw new InvalidProgramException("The structure is not initialized yet. Call Initialize before using it!");

			PointD3D lineStart = dashSegment.P0;
			PointD3D lineEnd = dashSegment.P1;

			var lineVector = dashSegment.LineVector;
			double lineLength = lineVector.Length;

			if (null != _dashStartCap && null == overrideStartCap)
			{
				if (_dashStartCapBaseInsetAbsolute < 0)
				{
					lineStart += -_dashStartCapBaseInsetAbsolute * _forwardVector;
					lineLength += _dashStartCapBaseInsetAbsolute;
				}
			}

			if (null != _dashEndCap && null == overrideEndCap)
			{
				if (_dashEndCapBaseInsetAbsolute < 0)
				{
					lineEnd += _dashEndCapBaseInsetAbsolute * _forwardVector;
					lineLength += _dashEndCapBaseInsetAbsolute;
				}
			}

			AddGeometry(AddPositionAndNormal,
				AddIndices,
				ref vertexIndexOffset,
				lineStart,
				lineEnd,
				lineLength > 0,
				overrideStartCap,
				overrideEndCap);
		}