/// <summary> /// Divide a triangle at the given vertex located on a side /// without performing any edge swaps. /// </summary> /// <param name="t">The triangle to divide</param> /// <param name="loc">The location of the vertex on the triangle</param> /// <param name="v">The vertex on the side</param> private Triangle[] DivideTriangleOnEdgeNoSwap(Triangle t, PointOnTriangle loc, Vertex v) { Triangle t1 = null; Triangle t2 = null; if (loc == PointOnTriangle.OnS12) { // divide edge 12 t1 = new Triangle(t.V1, v, t.V3); t2 = new Triangle(v, t.V2, t.V3); t1.SetMeshParams(t.S12.Opposite, t2.S31, t.S31.Opposite); t2.SetMeshParams(t.S12.Opposite, t.S23.Opposite, t1.S23); } else if (loc == PointOnTriangle.OnS23) { // divide edge 23 t1 = new Triangle(t.V2, v, t.V1); t2 = new Triangle(v, t.V3, t.V1); t1.SetMeshParams(t.S23.Opposite, t2.S31, t.S12.Opposite); t2.SetMeshParams(t.S23.Opposite, t.S31.Opposite, t1.S23); } else if (loc == PointOnTriangle.OnS31) { // divide edge 31 t1 = new Triangle(t.V3, v, t.V2); t2 = new Triangle(v, t.V1, t.V2); t1.SetMeshParams(t.S31.Opposite, t2.S31, t.S23.Opposite); t2.SetMeshParams(t.S31.Opposite, t.S12.Opposite, t1.S23); } return(new Triangle[] { t1, t2 }); }
/// <summary> /// Divide two triangles at the given vertex located on /// their shared edge into four new triangles performing local /// edge swaps as necessary to keep the mesh delaunay. /// </summary> /// <param name="tt1">First triangle to divide</param> /// <param name="loc1">The location of the vertex on the first triangle</param> /// <param name="tt2">Second triangle to divide</param> /// <param name="loc2">The location of the vertex on the second triangle</param> /// <param name="v">The vertex on the shared side</param> private void DivideTrianglesOnSharedEdge(Triangle tt1, PointOnTriangle loc1, Triangle tt2, PointOnTriangle loc2, Vertex v) { OnDividingTriangle(new DividingTriangleEventArgs(v, new Triangle[] { tt1, tt2 })); Halfedge e1 = (loc1 == PointOnTriangle.OnS12 ? tt1.S12 : (loc1 == PointOnTriangle.OnS23 ? tt1.S23 : tt1.S31)); Halfedge e2 = (loc2 == PointOnTriangle.OnS12 ? tt2.S12 : (loc2 == PointOnTriangle.OnS23 ? tt2.S23 : tt2.S31)); // Divide into four triangles Triangle[] tn1 = DivideTriangleOnEdgeNoSwap(tt1, loc1, v); Triangle[] tn2 = DivideTriangleOnEdgeNoSwap(tt2, loc2, v); Triangle t1 = tn1[0]; Triangle t2 = tn1[1]; Triangle t3 = tn2[0]; Triangle t4 = tn2[1]; t1.SetMeshParams(t4.S12, t2.S31, null); t2.SetMeshParams(t3.S12, null, t1.S23); t3.SetMeshParams(t2.S12, t4.S31, null); t4.SetMeshParams(t1.S12, null, t3.S23); tt1.IsRemoved = true; tt2.IsRemoved = true; Triangles.SetRootTriangle(t1); OnDividedTriangle(new DividedTriangleEventArgs(v, new Triangle[] { tt1, tt2 }, new Triangle[] { t1, t2, t3, t4 })); // edge flip SwapTest(t1.S31, v); SwapTest(t2.S23, v); SwapTest(t3.S31, v); SwapTest(t4.S23, v); }
/// <summary> /// Divides a triangles at the given vertex located on /// its edge into two new triangles performing local /// edge swaps as necessary to keep the mesh delaunay. /// </summary> /// <param name="tt">First triangle to divide</param> /// <param name="loc">The location of the vertex on the first triangle</param> /// <param name="tt2">Second triangle to divide</param> /// <param name="loc2">The location of the vertex on the second triangle</param> /// <param name="v">The vertex on the shared side</param> private void DivideTriangleOnEdge(Triangle tt, PointOnTriangle loc, Vertex v) { OnDividingTriangle(new DividingTriangleEventArgs(v, new Triangle[] { tt })); // Divide into two triangles Triangle[] tn1 = DivideTriangleOnEdgeNoSwap(tt, loc, v); Triangle t1 = tn1[0]; Triangle t2 = tn1[1]; t1.SetMeshParams(null, t2.S31, null); t2.SetMeshParams(null, null, t1.S23); tt.IsRemoved = true; Triangles.SetRootTriangle(t1); OnDividedTriangle(new DividedTriangleEventArgs(v, new Triangle[] { tt }, new Triangle[] { t1, t2 })); }
/// <summary> /// Find the triangle(s) containing the given point. The search starts from an arbitrary /// triangle and homes in on the vertex by visiting triangles closest to the vertex. /// If the vertex is on and edge seperating two triangles, both are returned. /// </summary> /// <param name="v">The vertex to search for</param> /// <returns>The triangles(s) containing the vertex</returns> internal FindTriangle[] FindContaining(Vertex v) { Triangle current = root; while (true) { PointOnTriangle loc = PointOnTriangle.None; Halfedge closestEdge = null; PointShapeRelation rel = current.Contains(v, out loc, out closestEdge); if (rel == PointShapeRelation.Inside) { // Inside triangle, return. return(new FindTriangle[] { new FindTriangle(current, rel, loc) }); } else if (rel == PointShapeRelation.Outside) { // Outside triangle, continue searching from the neighbour closest to the point Halfedge opp = closestEdge.Opposite; if (opp == null) { throw new InvalidOperationException("No triangle contains this vertex."); } current = opp.Parent; } else { // On an edge, return the triangle and its neighbour (if there is one) Halfedge opp = closestEdge.Opposite; if (opp == null) { return(new FindTriangle[] { new FindTriangle(current, rel, loc) }); } else { Triangle other = opp.Parent; PointOnTriangle otherLoc = PointOnTriangle.None; PointShapeRelation otherRel = other.Contains(v, out otherLoc); return(new FindTriangle[] { new FindTriangle(current, rel, loc), new FindTriangle(other, otherRel, otherLoc) }); } } } }
/// <summary> /// Determines whether the triangle contains the given vertex. /// </summary> /// <param name="v">The vertex to check</param> /// <param name="location">On return, contains where on the triangle the vertex lies</param> /// <param name="closestEdge">On return, contains the edge closest to the input vertex</param> /// <returns>The relative location of the vertex</returns> public PointShapeRelation Contains(Vertex v, out PointOnTriangle location, out Halfedge closestEdge) { double a12 = new Matrix3( V1.X, V1.Y, 1, V2.X, V2.Y, 1, v.X, v.Y, 1).Determinant; double a23 = new Matrix3( V2.X, V2.Y, 1, V3.X, V3.Y, 1, v.X, v.Y, 1).Determinant; double a31 = new Matrix3( V3.X, V3.Y, 1, V1.X, V1.Y, 1, v.X, v.Y, 1).Determinant; if (Utility.AlmostZero(a12)) { if (Utility.AlmostZero(a23)) { location = PointOnTriangle.OnV2; } else if (Utility.AlmostZero(a31)) { location = PointOnTriangle.OnV1; } else { location = PointOnTriangle.OnS12; } closestEdge = S12; return(PointShapeRelation.On); } else if (Utility.AlmostZero(a23)) { if (Utility.AlmostZero(a31)) { location = PointOnTriangle.OnV3; } else if (Utility.AlmostZero(a12)) { location = PointOnTriangle.OnV2; } else { location = PointOnTriangle.OnS23; } closestEdge = S23; return(PointShapeRelation.On); } else if (Utility.AlmostZero(a31)) { if (Utility.AlmostZero(a12)) { location = PointOnTriangle.OnV1; } else if (Utility.AlmostZero(a23)) { location = PointOnTriangle.OnV3; } else { location = PointOnTriangle.OnS31; } closestEdge = S31; return(PointShapeRelation.On); } else if (a12 < 0 || a23 < 0 || a31 < 0) { if (a12 < 0) { closestEdge = S12; } else if (a23 < 0) { closestEdge = S23; } else { closestEdge = S31; } location = PointOnTriangle.None; return(PointShapeRelation.Outside); } else { double d12 = a12 / S12.Length; double d23 = a23 / S23.Length; double d31 = a31 / S31.Length; if (d12 < d23 && d12 < d31) { closestEdge = S12; } else if (d23 < d12 && d23 < d31) { closestEdge = S23; } else { closestEdge = S31; } location = PointOnTriangle.None; return(PointShapeRelation.Inside); } }
/// <summary> /// Determines whether the triangle contains the given vertex. /// </summary> /// <param name="v">The vertex to check</param> /// <param name="location">On return, contains where on the triangle the vertex lies</param> /// <returns>The relative location of the vertex</returns> public PointShapeRelation Contains(Vertex v, out PointOnTriangle location) { double a12 = new Matrix3( V1.X, V1.Y, 1, V2.X, V2.Y, 1, v.X, v.Y, 1).Determinant; double a23 = new Matrix3( V2.X, V2.Y, 1, V3.X, V3.Y, 1, v.X, v.Y, 1).Determinant; double a31 = new Matrix3( V3.X, V3.Y, 1, V1.X, V1.Y, 1, v.X, v.Y, 1).Determinant; if (Utility.AlmostZero(a12)) { if (Utility.AlmostZero(a23)) { location = PointOnTriangle.OnV2; } else if (Utility.AlmostZero(a31)) { location = PointOnTriangle.OnV1; } else { location = PointOnTriangle.OnS12; } return(PointShapeRelation.On); } else if (Utility.AlmostZero(a23)) { if (Utility.AlmostZero(a31)) { location = PointOnTriangle.OnV3; } else if (Utility.AlmostZero(a12)) { location = PointOnTriangle.OnV2; } else { location = PointOnTriangle.OnS23; } return(PointShapeRelation.On); } else if (Utility.AlmostZero(a31)) { if (Utility.AlmostZero(a12)) { location = PointOnTriangle.OnV1; } else if (Utility.AlmostZero(a23)) { location = PointOnTriangle.OnV3; } else { location = PointOnTriangle.OnS31; } return(PointShapeRelation.On); } else if (a12 < 0 || a23 < 0 || a31 < 0) { location = PointOnTriangle.None; return(PointShapeRelation.Outside); } else { location = PointOnTriangle.None; return(PointShapeRelation.Inside); } }
public FindTriangle(Triangle tri, PointShapeRelation rel, PointOnTriangle loc) { Triangle = tri; Relation = rel; Location = loc; }