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); } } }