public Side GetSide(UniversalLine otherLine) { if (VisuallyClosed || otherLine.VisuallyClosed) { return(GetSideClosedCase(otherLine)); } else { return(GetSideOpenedCase(otherLine)); } }
private Side GetSideClosedCase(UniversalLine other) { Point3d getPointMaxY(UniversalLine line) => line.Segments .Select(segment => segment.EndPoint) .Aggregate(line.StartPoint, (p1, p2) => p1.Y > p2.Y ? p1 : p2); Side GetTurnDirectionAt(UniversalLine line, Point3d point) { Point3d previous = default(Point3d), next = default(Point3d); bool hasNext = false, hasPrevious = false; foreach (var segment in Segments) { if (point == segment.StartPoint) { next = segment.EndPoint; hasNext = true; if (hasPrevious) { break; } } if (point == segment.EndPoint) { previous = segment.StartPoint; hasPrevious = true; if (hasNext) { break; } } } if (!hasNext || !hasPrevious) { throw new InvalidOperationException("Bottom line is strange"); } return(previous.GetVectorTo(point).GetSide(point.GetVectorTo(next))); } var pointMaxY = getPointMaxY(this); var isOutside = pointMaxY.Y > getPointMaxY(other).Y; var turnDirection = GetTurnDirectionAt(this, pointMaxY); return(isOutside ? turnDirection : (Side)(-(int)turnDirection)); }
private Side GetSideOpenedCase(UniversalLine otherLine) { bool codirectional(UniversalLine line, UniversalLine other) { using (var connectedFronts = new Line(line.StartPoint, other.StartPoint)) using (var connectedEnds = new Line(line.EndPoint, other.EndPoint)) { return(!connectedFronts.Intersects(connectedEnds, 0) && !line.Intersects(connectedFronts, 1) && !other.Intersects(connectedFronts, 1) && !line.Intersects(connectedEnds, 1) && !other.Intersects(connectedEnds, 1)); } } var thisSegment = Segments.First(); var otherSegment = codirectional(this, otherLine) ? otherLine.Segments.First() : otherLine.Segments.Last(); if (thisSegment.StartPoint == otherSegment.StartPoint) { return(thisSegment.GetFirstDerivative(0).GetSide(otherSegment.GetFirstDerivative(0))); } else if (thisSegment.StartPoint == otherSegment.EndPoint) { return(thisSegment.GetFirstDerivative(0).GetSide(otherSegment.GetFirstDerivative(1))); } var tangent = thisSegment.GetFirstDerivative(thisSegment.EvaluatePoint(0)); var normal = new Vector3d(tangent.Y, -tangent.X, 0); using (var normalLine = new Line(thisSegment.StartPoint, thisSegment.StartPoint + normal)) using (var otherLineSegment = new Line(otherSegment.StartPoint, otherSegment.EndPoint)) using (var intersection = new Point3dCollection()) { normalLine.IntersectWith(otherLineSegment, Intersect.ExtendBoth, intersection, IntPtr.Zero, IntPtr.Zero); if (intersection.Count == 0) { throw new InvalidOperationException("Top line does not intersect bottom's normal"); } return(tangent.GetSide(thisSegment.StartPoint.GetVectorTo(intersection[0]))); } }
public bool TryAddSegment(UniversalLine line) { var allowance = Segments.LastOrDefault()?.Length * 0.1 ?? 0.0; if (!Lines.Any()) { Lines.Add(line); } else if (VisuallyClosed || line.VisuallyClosed && Lines.Any()) { return(false); } else if (AlmostEqual(line.EndPoint, StartPoint, allowance)) { Lines.Insert(0, line); } else if (AlmostEqual(line.StartPoint, EndPoint, allowance)) { Lines.Add(line); } else if (AlmostEqual(line.StartPoint, StartPoint, allowance)) { line.Reverse(); Lines.Insert(0, line); } else if (AlmostEqual(line.EndPoint, EndPoint, allowance)) { line.Reverse(); Lines.Add(line); } else { return(false); } return(true); }