/// <summary> /// Join two polygones by an edge. /// </summary> /// <param name="other">the other polygone</param> /// <param name="edgeStart">the start of the edge that joines</param> /// <param name="edgeStart">the end of the edge that joines</param> /// <returns>-1: the polygone is closed. Otherwise the start/end key that was changed</returns> public int Join(PolygonLine other, int edgeStart, int edgeEnd) { return(this.JoinAndClose(other) ?? this.JoinSameDirection(other, edgeStart, edgeEnd) ?? this.JoinWithEdgeInInverseDirection(other, edgeStart, edgeEnd) ?? this.JoinReversingOtherPolygon(other, edgeStart, edgeEnd) ?? throw new InvalidOperationException($"Can't join s:{edgeStart} e:{edgeEnd}, ts: {this.StartKey} te: {this.EndKey}, os: {other.StartKey} oe: {other.EndKey}")); }
/// <summary> /// Join and close the polygon if this and other is the same instance /// </summary> /// <param name="other">the other polygon line</param> /// <returns>-1 if the polygon was joined, null else</returns> private int?JoinAndClose(PolygonLine other) { if (ReferenceEquals(this, other)) { this.Closed = true; return(-1); } return(null); }
/// <summary> /// The connecting edge fits one start and one end. Join with consistent direction. /// </summary> /// <param name="other">the other polygon line</param> /// <param name="edgeStart">the start of the joining edge</param> /// <param name="edgeEnd">the end of the joining edge</param> /// <returns>The start/end key that was changed or null if it doesn't fit</returns> private int?JoinSameDirection(PolygonLine other, int edgeStart, int edgeEnd) { if (CompareEdgeToKeys(edgeStart, edgeEnd, this.EndKey, other.StartKey)) { return(this.AppendRange(other.vertexIds, other.EndKey)); } if (CompareEdgeToKeys(edgeStart, edgeEnd, other.EndKey, this.StartKey)) { return(this.InsertRange(other.vertexIds, other.StartKey)); } return(null); }
/// <summary> /// Add a new edge to the polygon line. Either join two polygon lines, creates a new or adds the edge to the neighboring line /// </summary> /// <param name="start"></param> /// <param name="end"></param> private void AddEdge(int start, int end) { var startFits = this.openPolygones.TryGetValue(start, out var firstSegment); if (startFits) { this.openPolygones.Remove(start); } var endFits = this.openPolygones.TryGetValue(end, out var lastSegment); if (endFits) { this.openPolygones.Remove(end); } if (!startFits && !endFits) { var segment = new PolygonLine(start, end); this.openPolygones.Add(start, segment); this.openPolygones.Add(end, segment); } else if (startFits && endFits) { var remainingKeyOfOther = firstSegment.Join(lastSegment, start, end); if (remainingKeyOfOther < 0) { this.closedPolygones.Add(firstSegment); } else { this.openPolygones[remainingKeyOfOther] = firstSegment; } } else if (startFits) { firstSegment.AddMatchingStart(start, end); this.openPolygones[end] = firstSegment; } else { lastSegment.AddMatchingEnd(start, end); this.openPolygones[start] = lastSegment; } }
/// <summary> /// new edge connects at both start or both end points, reverse the other segment and join /// </summary> /// <param name="other">the other polygon line</param> /// <param name="edgeStart">the start of the joining edge</param> /// <param name="edgeEnd">the end of the joining edge</param> /// <returns>The start/end key that was changed or null if it doesn't fit</returns> private int?JoinReversingOtherPolygon(PolygonLine other, int edgeStart, int edgeEnd) { var reversedOther = new List <int>(other.vertexIds); reversedOther.Reverse(); if (CompareEdgeToKeysOrSwappedKeys(edgeStart, edgeEnd, this.StartKey, other.StartKey)) { this.Dirty = true; return(this.InsertRange(reversedOther, other.EndKey)); } if (CompareEdgeToKeysOrSwappedKeys(edgeStart, edgeEnd, this.EndKey, other.EndKey)) { this.Dirty = true; return(this.AppendRange(reversedOther, other.StartKey)); } return(null); }