public void PointInsideTriangleInside() { Assert.IsTrue(ContainmentTests.PointInsideTriangle( new Vector2D(0.25, 0.25), Vector2D.Zero, new Vector2D(1, 0), new Vector2D(0, 1))); }
public void PointInsideTriangleOnEdge() { Assert.IsFalse(ContainmentTests.PointInsideTriangle( new Vector2D(0.5, 0), Vector2D.Zero, new Vector2D(1, 0), new Vector2D(0, 1))); }
public void PointInsideThreeSidedInfinitePyramidOutside() { Assert.IsFalse(ContainmentTests.PointInsideThreeSidedInfinitePyramid( new Vector3D(2, 0, 0.5), Vector3D.Zero, new Vector3D(1, -1, 1), new Vector3D(1, 1, 1), new Vector3D(-1, 0, 1))); }
public static IndicesUnsignedInt Triangulate(IEnumerable <Vector3D> positions) { if (positions == null) { throw new ArgumentNullException("positions"); } // // Doubly linked list. This would be a tad cleaner if it were also circular. // LinkedList <IndexedVector <Vector3D> > remainingPositions = new LinkedList <IndexedVector <Vector3D> >();; int index = 0; foreach (Vector3D position in positions) { remainingPositions.AddLast(new IndexedVector <Vector3D>(position, index++)); } if (remainingPositions.Count < 3) { throw new ArgumentOutOfRangeException("positions", "At least three positions are required."); } IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * (remainingPositions.Count - 2)); /////////////////////////////////////////////////////////////////// LinkedListNode <IndexedVector <Vector3D> > previousNode = remainingPositions.First; LinkedListNode <IndexedVector <Vector3D> > node = previousNode.Next; LinkedListNode <IndexedVector <Vector3D> > nextNode = node.Next; int bailCount = remainingPositions.Count * remainingPositions.Count; while (remainingPositions.Count > 3) { Vector3D p0 = previousNode.Value.Vector; Vector3D p1 = node.Value.Vector; Vector3D p2 = nextNode.Value.Vector; if (IsTipConvex(p0, p1, p2)) { bool isEar = true; for (LinkedListNode <IndexedVector <Vector3D> > n = ((nextNode.Next != null) ? nextNode.Next : remainingPositions.First); n != previousNode; n = ((n.Next != null) ? n.Next : remainingPositions.First)) { if (ContainmentTests.PointInsideThreeSidedInfinitePyramid(n.Value.Vector, Vector3D.Zero, p0, p1, p2)) { isEar = false; break; } } if (isEar) { indices.AddTriangle(new TriangleIndicesUnsignedInt(previousNode.Value.Index, node.Value.Index, nextNode.Value.Index)); remainingPositions.Remove(node); node = nextNode; nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First; continue; } } previousNode = (previousNode.Next != null) ? previousNode.Next : remainingPositions.First; node = (node.Next != null) ? node.Next : remainingPositions.First; nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First; if (--bailCount == 0) { break; } } LinkedListNode <IndexedVector <Vector3D> > n0 = remainingPositions.First; LinkedListNode <IndexedVector <Vector3D> > n1 = n0.Next; LinkedListNode <IndexedVector <Vector3D> > n2 = n1.Next; indices.AddTriangle(new TriangleIndicesUnsignedInt(n0.Value.Index, n1.Value.Index, n2.Value.Index)); return(indices); }
public static IndicesUnsignedInt Triangulate(IEnumerable <Vector2D> positions) { // // O(n^3) // // There are several optimization opportunities: // * http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf // * http://cgm.cs.mcgill.ca/~godfried/publications/triangulation.held.ps.gz // * http://blogs.agi.com/insight3d/index.php/2008/03/20/triangulation-rhymes-with-strangulation/ // if (positions == null) { throw new ArgumentNullException("positions"); } // // Doubly linked list. This would be a tad cleaner if it were also circular. // LinkedList <IndexedVector <Vector2D> > remainingPositions = new LinkedList <IndexedVector <Vector2D> >();; int index = 0; foreach (Vector2D position in positions) { remainingPositions.AddLast(new IndexedVector <Vector2D>(position, index++)); } if (remainingPositions.Count < 3) { throw new ArgumentOutOfRangeException("positions", "At least three positions are required."); } IndicesUnsignedInt indices = new IndicesUnsignedInt(3 * (remainingPositions.Count - 2)); /////////////////////////////////////////////////////////////////// LinkedListNode <IndexedVector <Vector2D> > previousNode = remainingPositions.First; LinkedListNode <IndexedVector <Vector2D> > node = previousNode.Next; LinkedListNode <IndexedVector <Vector2D> > nextNode = node.Next; int bailCount = remainingPositions.Count * remainingPositions.Count; while (remainingPositions.Count > 3) { Vector2D p0 = previousNode.Value.Vector; Vector2D p1 = node.Value.Vector; Vector2D p2 = nextNode.Value.Vector; if (IsTipConvex(p0, p1, p2)) { bool isEar = true; for (LinkedListNode <IndexedVector <Vector2D> > n = ((nextNode.Next != null) ? nextNode.Next : remainingPositions.First); n != previousNode; n = ((n.Next != null) ? n.Next : remainingPositions.First)) { if (ContainmentTests.PointInsideTriangle(n.Value.Vector, p0, p1, p2)) { isEar = false; break; } } if (isEar) { indices.AddTriangle(new TriangleIndicesUnsignedInt(previousNode.Value.Index, node.Value.Index, nextNode.Value.Index)); remainingPositions.Remove(node); node = nextNode; nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First; continue; } } previousNode = (previousNode.Next != null) ? previousNode.Next : remainingPositions.First; node = (node.Next != null) ? node.Next : remainingPositions.First; nextNode = (nextNode.Next != null) ? nextNode.Next : remainingPositions.First; if (--bailCount == 0) { break; } } LinkedListNode <IndexedVector <Vector2D> > n0 = remainingPositions.First; LinkedListNode <IndexedVector <Vector2D> > n1 = n0.Next; LinkedListNode <IndexedVector <Vector2D> > n2 = n1.Next; indices.AddTriangle(new TriangleIndicesUnsignedInt(n0.Value.Index, n1.Value.Index, n2.Value.Index)); return(indices); }