/// <summary> /// Get all notches in a list of ordered points that represent the vertices of /// a polygon. A notch is a point that the reflex angle in internal. /// </summary> /// <param name="points"> /// The poitns in the LinkedList must be ordered in clockwise order. /// </param> /// <returns> /// Returns a List with the notches. /// </returns> private List <UV> GetNotches(CircularLinkedList <UV> points) { List <UV> notches = new List <UV>(); if (points.Count < 5) { return(notches); } CircularLinkedListNode <UV> node = points.Head; do { UV p0 = node.Value; UV p1 = node.Next.Value; UV p2 = node.Next.Next.Value; double angle = VectorManipulator.CalculatesAngle(p0, p1, p2); if (angle > Math.PI) { notches.Add(p1); } node = node.Next; } while (node != points.Head); return(notches); }
/// <summary> /// Add a new vertice in order in the list of vertices of the polygon given the IntersectionResultArray. /// </summary> /// <param name="points"></param> /// <param name="resultArray"></param> /// <param name="curve"></param> private static CircularLinkedListNode <UV> AddPointsInList(CircularLinkedList <UV> points, IntersectionResultArray resultArray, Curve curve) { UV p0 = VectorManipulator.ProjectInPlaneXY(curve.GetEndPoint(0)); CircularLinkedListNode <UV> newNode = null; CircularLinkedListNode <UV> node = FindPoint(points, p0); IntersectionResultArrayIterator iterator = resultArray.ForwardIterator(); iterator.Reset(); while (iterator.MoveNext()) { IntersectionResult result = iterator.Current as IntersectionResult; UV intersectionPoint = VectorManipulator.ProjectInPlaneXY(result.XYZPoint); newNode = points.AddAfter(node, intersectionPoint); } if (newNode.Next.Value.IsAlmostEqualTo(newNode.Value)) { points.Remove(newNode.Next.Value); } else if (newNode.Previous.Value.IsAlmostEqualTo(newNode.Value)) { points.Remove(newNode.Previous.Value); } return(newNode); }
/// <summary> /// Adds the specified item before the specified existing node in the list. /// </summary> /// <param name="node">Existing node before which new item will be inserted</param> /// <param name="item">New item to be inserted</param> /// <exception cref="ArgumentNullException"><paramref name="node"/> is NULL</exception> /// <exception cref="InvalidOperationException"><paramref name="node"/> doesn't belongs to list</exception> public CircularLinkedListNode <T> AddBefore(CircularLinkedListNode <T> node, T item) { if (node == null) { throw new ArgumentNullException("node"); } // ensuring the supplied node belongs to this list CircularLinkedListNode <T> temp = FindNode(head, node.Value); if (temp != node) { throw new InvalidOperationException("Node doesn't belongs to this list"); } CircularLinkedListNode <T> newNode = new CircularLinkedListNode <T>(item); node.Previous.Next = newNode; newNode.Previous = node.Previous; newNode.Next = node; node.Previous = newNode; // if the node adding is head node, then repointing head node if (node == head) { head = newNode; } ++count; return(newNode); }
private void AddFirstItem(T item) { head = new CircularLinkedListNode <T>(item); tail = head; head.Next = tail; head.Previous = tail; }
public bool Normalize() { bool normalized = true; CircularLinkedList <UV> points = GetPoints(); CircularLinkedListNode <UV> node = points.Head; do { UV p0 = node.Previous.Value; UV p1 = node.Value; UV p2 = node.Next.Value; double angle = VectorManipulator.CalculatesAngle(p0, p1, p2); if (AlmostEqual(angle, Math.PI, 0.01) || AlmostEqual(angle, 0, 0.01)) { points.Remove(p1); normalized = false; } node = node.Next; } while (node != points.Head); curveArray = CreateCurveArrayFromPoints(points); if (!normalized) { Normalize(); } return(normalized); }
/// <summary> /// Removes the first occurance of the supplied item /// </summary> /// <param name="item">Item to be removed</param> /// <returns>TRUE if removed, else FALSE</returns> public bool Remove(T item) { // finding the first occurance of this item CircularLinkedListNode <T> nodeToRemove = Find(item); if (nodeToRemove != null) { return(RemoveNode(nodeToRemove)); } return(false); }
/// <summary> /// Adds the new item before the specified existing item in the list. /// </summary> /// <param name="existingItem">Existing item before which new item will be added</param> /// <param name="newItem">New item to be added to the list</param> /// <exception cref="ArgumentException"><paramref name="existingItem"/> doesn't exist in the list</exception> public void AddBefore(T existingItem, T newItem) { // finding a node for the existing item CircularLinkedListNode <T> node = Find(existingItem); if (node == null) { throw new ArgumentException("existingItem doesn't exist in the list"); } AddBefore(node, newItem); }
/// <summary> /// Create a sub group of the linkedList that starts with node 'first' and ends with node 'last'. /// </summary> /// <param name="first"></param> /// <param name="last"></param> /// <returns> /// Returns the vertives of the new polygon. /// </returns> private CircularLinkedList <UV> CreatePolygonBetweenVertices(CircularLinkedListNode <UV> first, CircularLinkedListNode <UV> last) { CircularLinkedList <UV> polygon = new CircularLinkedList <UV>(); CircularLinkedListNode <UV> node = first; do { polygon.AddLast(node.Value); node = node.Next; } while (node != last); polygon.AddLast(node.Value); return(polygon); }
/// <summary> /// Gets a reverse enumerator /// </summary> /// <returns></returns> public IEnumerator <T> GetReverseEnumerator() { CircularLinkedListNode <T> current = tail; if (current != null) { do { yield return(current.Value); current = current.Previous; } while (current != tail); } }
/// <summary> /// Gets a forward enumerator /// </summary> /// <returns></returns> public IEnumerator <T> GetEnumerator() { CircularLinkedListNode <T> current = head; if (current != null) { do { yield return(current.Value); current = current.Next; } while (current != head); } }
private UV CalculatePolygonCentroid(CircularLinkedList <UV> vertices) { CircularLinkedListNode <UV> node = vertices.Head; UV sum = UV.Zero; do { UV vertex = node.Value; sum += vertex; node = node.Next; } while (node != vertices.Head); sum /= vertices.Count; return(sum); }
/// <summary> /// Eliminates a notch by creating a new line between the notch and an edge of the polygon. /// </summary> /// <param name="notch">Coordinates of the notch.</param> /// <param name="curveArray">The polygon.</param> /// <param name="points">The vertices of the polygon.</param> /// <param name="preferredOrientation">The method will try to make a cut that is parallel to this vector.</param> /// <param name="cutLine">The line that cut the polygon.</param> /// <returns> /// Returns the list of the CurveArrays. /// </returns> private List <CurveArray> EliminateNotch(UV notch, CurveArray curveArray, CircularLinkedList <UV> points, XYZ preferredOrientation, out Line cutLine) { XYZ notche3D = VectorManipulator.TransformUVinXYZ(notch); Line line1 = Line.CreateUnbound(notche3D, preferredOrientation); XYZ otherOrientation = new XYZ(preferredOrientation.Y, preferredOrientation.X, 0); Line line2 = Line.CreateUnbound(notche3D, otherOrientation); CircularLinkedListNode <UV> notchNode = FindPoint(points, notch); // get the posible curves for the new point CurveArray posibleCurves = new CurveArray(); foreach (Curve curve in curveArray) { if (PosibleCurve(curve, notchNode)) { posibleCurves.Append(curve); } } // iterate for each possible curve, and if // a intersection is found, the point will // added in the linked list CircularLinkedListNode <UV> newNode; newNode = FindNewNode(ref points, line1, posibleCurves, notch); if (newNode == null) { newNode = FindNewNode(ref points, line2, posibleCurves, notch); } // generates the 2 new polygons CircularLinkedList <UV> polygonA = CreatePolygonBetweenVertices(newNode, notchNode); CircularLinkedList <UV> polygonB = CreatePolygonBetweenVertices(notchNode, newNode); // creates the curves List <CurveArray> list = new List <CurveArray> { CreateCurveArrayFromPoints(polygonA), CreateCurveArrayFromPoints(polygonB) }; // returns the cutLine cutLine = Line.CreateBound(notche3D, VectorManipulator.TransformUVinXYZ(newNode.Value)); return(list); }
private CircularLinkedListNode <T> FindNode(CircularLinkedListNode <T> node, T valueToCompare) { CircularLinkedListNode <T> result = null; if (comparer.Equals(node.Value, valueToCompare)) { result = node; } else if (result == null && node.Next != head) { result = FindNode(node.Next, valueToCompare); } return(result); }
/// <summary> /// Finds a point that /// </summary> /// <param name="points"></param> /// <param name="line1"></param> /// <param name="posibleCurves"></param> /// <returns></returns> private static CircularLinkedListNode <UV> FindNewNode(ref CircularLinkedList <UV> points, Line line, CurveArray posibleCurves, UV notch) { // iterate for each possible curve, and if // a intersection is found, the point will // be added in the linked list CircularLinkedListNode <UV> newNode = null; // get the closest point UV newPoint = null, previousPoint = null; double minDistance = double.MaxValue; foreach (Curve curve in posibleCurves) { SetComparisonResult intersection = curve.Intersect(line, out IntersectionResultArray resultArray); if (intersection == SetComparisonResult.Overlap) { IntersectionResultArrayIterator iterator = resultArray.ForwardIterator(); iterator.Reset(); while (iterator.MoveNext()) { IntersectionResult result = iterator.Current as IntersectionResult; UV point = VectorManipulator.ProjectInPlaneXY(result.XYZPoint); double distance = point.DistanceTo(notch); if (distance < minDistance) { minDistance = distance; newPoint = point; previousPoint = VectorManipulator.ProjectInPlaneXY(curve.GetEndPoint(0)); } } } } // insert the new point in the list CircularLinkedListNode <UV> node = FindPoint(points, previousPoint); newNode = points.AddAfter(node, newPoint); if (newNode.Next.Value.IsAlmostEqualTo(newNode.Value)) { points.Remove(newNode.Next.Value); } else if (newNode.Previous.Value.IsAlmostEqualTo(newNode.Value)) { points.Remove(newNode.Previous.Value); } return(newNode); }
/// <summary> /// Searches for a point in the LinkedList /// </summary> /// <returns> /// Returns the node. /// </returns> private static CircularLinkedListNode <UV> FindPoint(CircularLinkedList <UV> points, UV key) { CircularLinkedListNode <UV> node = points.Head; do { UV point = node.Value; if (point.IsAlmostEqualTo(key, 0.01)) { return(node); } node = node.Next; } while (node != points.Head); return(null); }
/// <summary> /// Adds item to the last /// </summary> /// <param name="item">Item to be added</param> public void AddFirst(T item) { if (head == null) { AddFirstItem(item); } else { CircularLinkedListNode <T> newNode = new CircularLinkedListNode <T>(item); head.Previous = newNode; newNode.Previous = tail; newNode.Next = head; tail.Next = newNode; head = newNode; } ++count; }
private bool PosibleCurve(Curve curve, CircularLinkedListNode <UV> pointNode) { // the curve cannot contain the 2 points after or before or the pointNode itself List <UV> forbiddenPoints = new List <UV> { pointNode.Value, pointNode.Previous.Value, pointNode.Previous.Previous.Value, pointNode.Next.Value, pointNode.Next.Next.Value }; UV p0 = VectorManipulator.ProjectInPlaneXY(curve.GetEndPoint(0)); UV p1 = VectorManipulator.ProjectInPlaneXY(curve.GetEndPoint(1)); return(!(SearchForUVInList(forbiddenPoints, p0) && SearchForUVInList(forbiddenPoints, p1))); }
private static CircularLinkedListNode <UV> AddPointBetween(CircularLinkedList <UV> points, UV p0, UV p1, UV newPoint) { CircularLinkedListNode <UV> p0Node = FindPoint(points, p0); CircularLinkedListNode <UV> p1Node = FindPoint(points, p1); if (p0Node.Next.Equals(p1Node)) { return(points.AddAfter(p0Node, newPoint)); } if (p1Node.Next.Equals(p0Node)) { return(points.AddAfter(p1Node, newPoint)); } throw new ArgumentException("The points are not sequential."); }
/// <summary> /// Create a CurveArray given its vertices. /// </summary> public CurveArray CreateCurveArrayFromPoints(CircularLinkedList <UV> points) { CurveArray curveArray = new CurveArray(); CircularLinkedListNode <UV> node = points.Head; Line line; do { // for the cases that the 2 lines are colinear if (!node.Value.IsAlmostEqualTo(node.Next.Value)) { line = Line.CreateBound(VectorManipulator.TransformUVinXYZ(node.Value), VectorManipulator.TransformUVinXYZ(node.Next.Value)); curveArray.Append(line); } node = node.Next; } while (node != points.Head); return(curveArray); }
/// <summary> /// Add a new item to the end of the list /// </summary> /// <param name="item">Item to be added</param> public void AddLast(T item) { // if head is null, then this will be the first item if (head == null) { AddFirstItem(item); } else { CircularLinkedListNode <T> newNode = new CircularLinkedListNode <T>(item); tail.Next = newNode; newNode.Next = head; newNode.Previous = tail; tail = newNode; head.Previous = tail; } ++count; }
/// <summary> /// Gets the item at the current index /// </summary> /// <param name="index">Zero-based index</param> /// <exception cref="ArgumentOutOfRangeException">index is out of range</exception> public CircularLinkedListNode <T> this[int index] { get { if (index >= count || index < 0) { throw new ArgumentOutOfRangeException("index"); } else { CircularLinkedListNode <T> node = head; for (int i = 0; i < index; i++) { node = node.Next; } return(node); } } }
private bool RemoveNode(CircularLinkedListNode <T> nodeToRemove) { CircularLinkedListNode <T> previous = nodeToRemove.Previous; previous.Next = nodeToRemove.Next; nodeToRemove.Next.Previous = nodeToRemove.Previous; // if this is head, we need to update the head reference if (head == nodeToRemove) { head = nodeToRemove.Next; } else if (tail == nodeToRemove) { tail = tail.Previous; } --count; return(true); }
public void CopyTo(T[] array, int arrayIndex) { if (array == null) { throw new ArgumentNullException("array"); } if (arrayIndex < 0 || arrayIndex > array.Length) { throw new ArgumentOutOfRangeException("arrayIndex"); } CircularLinkedListNode <T> node = head; do { array[arrayIndex++] = node.Value; node = node.Next; } while (node != head); }
/// <summary> /// Finds the supplied item and returns a node which contains item. Returns NULL if item not found /// </summary> /// <param name="item">Item to search</param> /// <returns><see cref="CircularLinkedListNode<T>"/> instance or NULL</returns> public CircularLinkedListNode <T> Find(T item) { CircularLinkedListNode <T> node = FindNode(head, item); return(node); }
/// <summary> /// Clears the list /// </summary> public void Clear() { head = null; tail = null; count = 0; }
/// <summary> /// Offset a polygon in all directions, except the edge of this polygon that is equal to the unchangedLine parameter. /// </summary> /// <param name="vertices">A list of 2D coordinates that represents the vertices of the polygon. The list must be ordered counter-clockwise</param> /// <param name="offset">The offset value.</param> /// <param name="unchangedLine">If an edge of the polygon is collinear to this line, that edge will remain unchanged.</param> /// <returns>Returns a List of 2D coordinates that represents the offseted polygon.</returns> private static CircularLinkedList <UV> OffsetPolygon(CircularLinkedList <UV> vertices, double offset, List <Line> unchangedLines) { if (offset == 0) { return(vertices); } CircularLinkedList <UV> adjusted_points = new CircularLinkedList <UV>(); CircularLinkedListNode <UV> node = vertices.Head; do { //find the points before and after our target point. UV vertexI = node.Previous.Value; UV vertexJ = node.Value; UV vertexK = node.Next.Value; //the next step is to push out each point based on the position of its surrounding points and then //figure out the intersections of the pushed out points UV v1 = vertexJ - vertexI; UV v2 = vertexK - vertexJ; // verifies if one of the segments ij, ji, jk or kj is the unchangedLine if (unchangedLines != null) { foreach (Line l in unchangedLines) { UV p0 = VectorManipulator.ProjectInPlaneXY(l.GetEndPoint(0)); UV p1 = VectorManipulator.ProjectInPlaneXY(l.GetEndPoint(1)); if ((vertexI.IsAlmostEqualTo(p0) && vertexJ.IsAlmostEqualTo(p1)) || (vertexJ.IsAlmostEqualTo(p0) && vertexI.IsAlmostEqualTo(p1))) { v1 = UV.Zero; break; } if ((vertexJ.IsAlmostEqualTo(p0) && vertexK.IsAlmostEqualTo(p1)) || (vertexK.IsAlmostEqualTo(p0) && vertexJ.IsAlmostEqualTo(p1))) { v2 = UV.Zero; break; } } } v1 = v1.Normalize() * offset; v2 = v2.Normalize() * offset; // creates a shifted line that is parallel to the vector v1 UV n1 = new UV(-v1.V, v1.U); UV pij1 = vertexI + n1; UV pij2 = vertexJ + n1; Line line1 = Line.CreateBound(VectorManipulator.TransformUVinXYZ(pij1), VectorManipulator.TransformUVinXYZ(pij2)); line1.MakeUnbound(); // creates a shifted line that is parallel to the vector v2 UV n2 = new UV(-v2.V, v2.U); UV pjk1 = vertexJ + n2; UV pjk2 = vertexK + n2; Line line2 = Line.CreateBound(VectorManipulator.TransformUVinXYZ(pjk1), VectorManipulator.TransformUVinXYZ(pjk2)); line2.MakeUnbound(); //see where the shifted lines 1 and 2 intersect SetComparisonResult comparisonResult = line1.Intersect(line2, out IntersectionResultArray intersection); if (comparisonResult == SetComparisonResult.Overlap) { IntersectionResult result = intersection.get_Item(0); UV intersection_point = VectorManipulator.ProjectInPlaneXY(result.XYZPoint); //add the intersection as our adjusted vert point adjusted_points.AddLast(new UV(intersection_point.U, intersection_point.V)); } node = node.Next; } while (node != vertices.Head); return(adjusted_points); }