internal static IEnumerable <GeoLine> GetLines(IEnumerable <Point> points, double distance, bool isClosed) { var firstLine = default(GeoLine?); var lastPoint = default(Point); var isFirst = true; foreach (var point in points) { if (isFirst) { isFirst = false; } else { var start = lastPoint; var end = point; var vec = GetVector(end - start) * distance; start += vec; end += vec; var line = new GeoLine(start, end); if (isClosed && firstLine == null) { firstLine = line; } yield return(line); } lastPoint = point; } if (firstLine.HasValue) { yield return(firstLine.Value); } }
public Point?Cross(GeoLine line) { var crossPoint = default(Point?); var d = A * line.B - B * line.A; if (!Utilities.IsZero(d)) { var p = new Point(); p.X = (line.C * B - C * line.B) / d; p.Y = -(line.C * A - C * line.A) / d; crossPoint = p; } return(crossPoint); }
public double AngleTo(GeoLine line) { return(Vector.AngleBetween(_direction, line._direction)); }
internal static IGraphic Extend(IList <Point> points, double distance, JointType jointType, IEnumerable <Segment> segments, bool isClosed) { var tuples = new List <Tuple <IGraphic, GeoLine?> >(); var lastLine = default(GeoLine?); var lastOrigin = default(GeoLine?); var index = 0; foreach (var line in GetLines(points, distance, isClosed)) { if (lastLine.HasValue) { var beforeOrigin = lastOrigin.Value; var before = lastLine.Value; var after = line; var angle = before.AngleTo(after); if (Utilities.IsZero(Math.Abs(angle))) { tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicLine(before.P1, before.P2), beforeOrigin)); } else { var flag = Utilities.IsClose(Math.Abs(angle), 180); if (angle < 0 ^ distance > 0) { switch (jointType) { case JointType.Flat: { tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicLine(before.P1, before.P2), beforeOrigin)); tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicLine(before.P2, after.P1), null)); } break; case JointType.Sharp: { if (flag) { return(null); } var cp = before.Cross(after); if (!cp.HasValue) { return(null); } tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicLine(before.P1, cp.Value), beforeOrigin)); after = new GeoLine(cp.Value, after.P2); } break; case JointType.Rounded: { tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicLine(before.P1, before.P2), beforeOrigin)); var center = points[index]; var radius = Math.Abs(distance); var startV = before.P2 - center; var endV = after.P1 - center; var startAngle = Vector.AngleBetween(new Vector(1, 0), startV); var endAngle = startAngle + Vector.AngleBetween(startV, endV); if (endAngle > startAngle) { tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicArc(center, radius, startAngle, endAngle), null)); } else { tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicArc(center, radius, endAngle, startAngle, true), null)); } } break; } } else { if (flag) { return(null); } var cp = before.Cross(after); if (cp.HasValue && before.IsOnLine(cp.Value) && after.IsOnLine(cp.Value)) { before = new GeoLine(before.P1, cp.Value); after = new GeoLine(cp.Value, after.P2); tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicLine(before.P1, before.P2), beforeOrigin)); } else { return(null); } } } lastLine = after; } else { lastLine = line; } lastOrigin = line; index++; } if (lastLine.HasValue) { if (!isClosed) { tuples.Add(new Tuple <IGraphic, GeoLine?>(new GraphicLine(lastLine.Value.P1, lastLine.Value.P2), lastOrigin)); } else { var tuple = tuples[0]; var firstLine = (GraphicLine)tuple.Item1; var p1 = lastLine.Value.P1; var p2 = firstLine.P2; var vec1 = p2 - firstLine.P1; var vec2 = p2 - p1; if (Utilities.IsSameDirection(vec1, vec2)) { firstLine = new GraphicLine(p1, p2); tuples[0] = new Tuple <IGraphic, GeoLine?>(firstLine, tuple.Item2); } else { return(null); } } } if (tuples.Count > 0) { if (segments != null) { var graphics = new List <IGraphic>(); foreach (var segment in segments) { var started = false; var subGraphics = new List <IGraphic>(); var currentOffset = 0d; var startOffset = segment.StartOffset; var endOffset = segment.EndOffset; foreach (var tuple in tuples) { var item = tuple.Item2; if (item.HasValue) { var line = item.Value; var offset = currentOffset + line.Length; if (currentOffset < endOffset && offset > startOffset) { if (currentOffset >= startOffset && offset <= endOffset) { subGraphics.Add(tuple.Item1); started = true; } else { var brk = false; var newLine = (GraphicLine)tuple.Item1; var sp = newLine.Start; var ep = newLine.End; if (startOffset > currentOffset) { var p = line.GetPoint(startOffset - currentOffset); if (newLine.IsOnLine(p)) { sp = p; started = true; } else { var vec1 = newLine.End - p; var vec2 = newLine.End - newLine.Start; started = Utilities.IsSameDirection(vec1, vec2); } } else { started = true; } if (endOffset < offset) { var p = line.GetPoint(endOffset - currentOffset); if (newLine.IsOnLine(p)) { ep = p; } else { var vec1 = p - newLine.Start; var vec2 = newLine.End - newLine.Start; started = Utilities.IsSameDirection(vec1, vec2); } brk = true; } if (started) { subGraphics.Add(new GraphicLine(sp, ep)); } if (brk) { break; } } } else if (currentOffset >= endOffset) { if (subGraphics.Count > 0) { graphics.Add(new GraphicCompositeCurve(subGraphics, true)); } break; } currentOffset = offset; } else if (started) { subGraphics.Add(tuple.Item1); } } if (subGraphics.Count > 0) { graphics.Add(new GraphicCompositeCurve(subGraphics, true)); } } if (graphics.Count > 0) { return(new GraphicCompositeCurve(graphics, false)); } } else { return(new GraphicCompositeCurve(tuples.Select(graphic => graphic.Item1), true)); } } return(null); }