private static DecorationSpot GetPosition(PointF[] points, double pathLength, int start, int end) { double lenSqr = 0; double pathLenSqr = pathLength * pathLength; DecorationSpot result = new DecorationSpot(); for (int i = start; i < end; i++) { double dx = points[i + 1].X - points[i].X; double dy = points[i + 1].Y - points[i].Y; lenSqr += dx * dx + dy * dy; if (pathLenSqr >= lenSqr) { continue; } double segLen = Math.Sqrt(dx * dx + dy * dy); double backLen = Math.Sqrt(lenSqr) - Math.Sqrt(pathLenSqr); double rat = backLen / segLen; float x = (float)(points[i + 1].X - rat * dx); float y = (float)(points[i + 1].Y - rat * dy); result.Position = new PointF(x, y); result.Before = points[i]; result.After = points[i + 1]; return(result); } return(result); }
private static DecorationSpot GetPosition(PointF[] points, double pathLength, int start, int end) { double lenSqr = 0; double pathLenSqr = pathLength * pathLength; DecorationSpot result = new DecorationSpot(); for (int i = start; i < end; i++) { double dx = points[i + 1].X - points[i].X; double dy = points[i + 1].Y - points[i].Y; lenSqr += dx * dx + dy * dy; if (pathLenSqr >= lenSqr) continue; double segLen = Math.Sqrt(dx * dx + dy * dy); double backLen = Math.Sqrt(lenSqr) - Math.Sqrt(pathLenSqr); double rat = backLen / segLen; float x = (float)(points[i + 1].X - rat * dx); float y = (float)(points[i + 1].Y - rat * dy); result.Position = new PointF(x, y); result.Before = points[i]; result.After = points[i + 1]; return result; } return result; }
/// <summary> /// Get the decoration spots that result from the given line and segLength. The decoration spot needed for the endpoint is not included. /// </summary> /// <param name="points">Point-Array that contains the points of the line.</param> /// <param name="segLength">Distance between two decoration spots.</param> /// <param name="start">Index of the first point that belongs to the line.</param> /// <param name="end">Index of the last point that belongs to the line.</param> /// <returns>List of decoration spots that result from the given points and segLength.</returns> private static List <DecorationSpot> GetPosition(PointF[] points, double segLength, int start, int end) { double coveredDistance = 0; // distance between the last decoration spot and the line end; needed to get the correct position of the next decoration spot on the next line List <DecorationSpot> liste = new List <DecorationSpot>(); for (int i = start; i < end; i++) { if (coveredDistance == 0) { // startpoint of the first line or last segment ended on startpoint of next line DecorationSpot result = new DecorationSpot(points[i], points[i + 1], points[i]); liste.Add(result); coveredDistance = 0; if (double.IsInfinity(segLength)) { return(liste); // when segLength is infinit we're looking only for the first decoration spot } } double dx = points[i + 1].X - points[i].X; double dy = points[i + 1].Y - points[i].Y; double lineLength = Math.Sqrt(dx * dx + dy * dy); if (coveredDistance + lineLength <= segLength) { coveredDistance += lineLength; continue; // line was shorter than segment -> does not contain any decorations } double offset = segLength - coveredDistance; // offset of the first decoration spot if (dx == 0) { // line is parallel to y-axis while (Math.Round(offset, 3) < Math.Round(lineLength, 3)) { float x = points[i].X; float y; if (points[i].Y > points[i + 1].Y) { // line goes bottom up y = (float)(points[i].Y - offset); } else { // line goes top down y = (float)(points[i].Y + offset); } liste.Add(new DecorationSpot(points[i], points[i + 1], new PointF(x, y))); offset += segLength; } if (Math.Round(offset, 3) > Math.Round(lineLength, 3)) { var lastpnt = liste[liste.Count - 1]; coveredDistance = GetLength(lastpnt.Position, lastpnt.After); } else { coveredDistance = 0; // segment ends on endpoint of the current line -> reset coveredDistance to add a decoration spot at the beginning of the next line } } else { // line is not parallel to y-axis double slope = dy / dx; double alpha = Math.Atan(slope); while (Math.Round(offset, 3) < Math.Round(lineLength, 3)) { float x, y; if (points[i].X < points[i + 1].X) { // line goes right to left x = (float)(points[i].X + Math.Cos(alpha) * offset); y = (float)(points[i].Y + Math.Sin(alpha) * offset); } else { // line goes left to right x = (float)(points[i].X - Math.Cos(alpha) * offset); y = (float)(points[i].Y - Math.Sin(alpha) * offset); } var newPoint = new PointF(x, y); liste.Add(new DecorationSpot(points[i], points[i + 1], newPoint)); offset += segLength; } if (Math.Round(offset, 3) > Math.Round(lineLength, 3)) { var lastpnt = liste[liste.Count - 1]; coveredDistance = GetLength(lastpnt.Position, lastpnt.After); } else { coveredDistance = 0; // segment ends on endpoint of the current line -> reset coveredDistance to add a decoration spot at the beginning of the next line } } } return(liste); }
/// <summary> /// Given the points on this line decoration, this will cycle through and handle /// the drawing as dictated by this decoration. /// </summary> /// <param name="g"></param> /// <param name="path"></param> /// <param name="scaleWidth">The double scale width for controling markers</param> public void Draw(Graphics g, GraphicsPath path, double scaleWidth) { if (NumSymbols == 0) { return; } GraphicsPathIterator myIterator = new GraphicsPathIterator(path); myIterator.Rewind(); int start, end; bool isClosed; Size2D symbolSize = _symbol.GetSize(); Bitmap symbol = new Bitmap((int)symbolSize.Width, (int)symbolSize.Height); Graphics sg = Graphics.FromImage(symbol); _symbol.Draw(sg, new Rectangle(0, 0, (int)symbolSize.Width, (int)symbolSize.Height)); sg.Dispose(); Matrix oldMat = g.Transform; PointF[] points; if (path.PointCount == 0) { return; } try { points = path.PathPoints; } catch { return; } PointF offset; int count = 0; while (myIterator.NextSubpath(out start, out end, out isClosed) > 0) { count = count + 1; // First marker PointF startPoint = points[start]; PointF stopPoint = points[start + 1]; float angle = 0F; if (_rotateWithLine) { angle = GetAngle(startPoint, stopPoint); } if (FlipFirst && !FlipAll) { FlipAngle(ref angle); } offset = GetOffset(startPoint, stopPoint); startPoint = new PointF(startPoint.X + offset.X, startPoint.Y + offset.Y); Matrix rotated = g.Transform; rotated.RotateAt(angle, startPoint); g.Transform = rotated; DrawImage(g, startPoint, symbol); g.Transform = oldMat; // Second marker if (NumSymbols > 1) { angle = 0F; if (_rotateWithLine) { angle = GetAngle(points[end - 1], points[end]); } if (FlipAll) { FlipAngle(ref angle); } offset = GetOffset(points[end - 1], points[end]); PointF endPoint = new PointF(points[end].X + offset.X, points[end].Y + offset.Y); rotated = g.Transform; rotated.RotateAt(angle, endPoint); g.Transform = rotated; DrawImage(g, endPoint, symbol); g.Transform = oldMat; } if (NumSymbols > 2) { double totalLength = GetLength(points, start, end); double span = totalLength / (NumSymbols - 1); for (int i = 1; i < NumSymbols - 1; i++) { DecorationSpot spot = GetPosition(points, span * i, start, end); angle = 0F; if (_rotateWithLine) { angle = GetAngle(spot.Before, spot.After); } offset = GetOffset(spot.Before, spot.After); PointF location = new PointF(spot.Position.X + offset.X, spot.Position.Y + offset.Y); if (FlipAll) { FlipAngle(ref angle); } rotated = g.Transform; rotated.RotateAt(angle, location); g.Transform = rotated; DrawImage(g, location, symbol); g.Transform = oldMat; } } } }
/// <summary> /// Get the decoration spots that result from the given line and segLength. The decoration spot needed for the endpoint is not included. /// </summary> /// <param name="points">Point-Array that contains the points of the line.</param> /// <param name="segLength">Distance between two decoration spots.</param> /// <param name="start">Index of the first point that belongs to the line.</param> /// <param name="end">Index of the last point that belongs to the line.</param> /// <returns>List of decoration spots that result from the given points and segLength.</returns> private List<DecorationSpot> GetPosition(PointF[] points, double segLength, int start, int end) { double coveredDistance = 0; //distance between the last decoration spot and the line end; needed to get the correct position of the next decoration spot on the next line List<DecorationSpot> liste = new List<DecorationSpot>(); for (int i = start; i < end; i++) { if (coveredDistance == 0) //startpoint of the first line or last segment ended on startpoint of next line { DecorationSpot result = new DecorationSpot(); result.Position = points[i]; result.Before = points[i]; result.After = points[i + 1]; liste.Add(result); coveredDistance = 0; if (double.IsInfinity(segLength)) return liste; // when segLength is infinit we're looking only for the first decoration spot } double dx = points[i + 1].X - points[i].X; double dy = points[i + 1].Y - points[i].Y; double lineLength = Math.Sqrt(dx * dx + dy * dy); if (coveredDistance + lineLength <= segLength) { coveredDistance += lineLength; continue; // line was shorter than segment -> does not contain any decorations } double offset = segLength - coveredDistance; // offset of the first decoration spot if (dx == 0) // line is parallel to y-axis { while (Math.Round(offset, 3) < Math.Round(lineLength, 3)) { float x = points[i].X; float y; if (points[i].Y > points[i + 1].Y) // line goes bottom up { y = (float)(points[i].Y - offset); } else // line goes top down { y = (float)(points[i].Y + offset); } liste.Add(new DecorationSpot(points[i], points[i + 1], new PointF(x, y))); offset += segLength; } if (Math.Round(offset, 3) > Math.Round(lineLength, 3)) { var lastpnt = liste[liste.Count - 1]; coveredDistance = GetLength(lastpnt.Position, lastpnt.After); } else { coveredDistance = 0; // segment ends on endpoint of the current line -> reset coveredDistance to add a decoration spot at the beginning of the next line } } else // line is not parallel to y-axis { double slope = dy / dx; double alpha = Math.Atan(slope); while (Math.Round(offset, 3) < Math.Round(lineLength, 3)) { float x, y; if (points[i].X < points[i + 1].X) // line goes right to left { x = (float)(points[i].X + Math.Cos(alpha) * offset); y = (float)(points[i].Y + Math.Sin(alpha) * offset); } else // line goes left to right { x = (float)(points[i].X - Math.Cos(alpha) * offset); y = (float)(points[i].Y - Math.Sin(alpha) * offset); } var newPoint = new PointF(x, y); liste.Add(new DecorationSpot(points[i], points[i + 1], newPoint)); offset += segLength; } if (Math.Round(offset, 3) > Math.Round(lineLength, 3)) { var lastpnt = liste[liste.Count - 1]; coveredDistance = GetLength(lastpnt.Position, lastpnt.After); } else { coveredDistance = 0; // segment ends on endpoint of the current line -> reset coveredDistance to add a decoration spot at the beginning of the next line } } } return liste; }