public static bool SplitPolygonsByPlane(List <Polygon> polygons, // Source polygons that will be split Plane splitPlane, bool excludeNewPolygons, // Whether new polygons should be marked as excludeFromBuild out List <Polygon> polygonsFront, out List <Polygon> polygonsBack) { polygonsFront = new List <Polygon>(); polygonsBack = new List <Polygon>(); // First of all make sure splitting actually needs to occur (we'll get bad issues if // we try splitting geometry when we don't need to) if (!PolygonsIntersectPlane(polygons, splitPlane)) { return(false); } Material newMaterial = polygons[0].Material; // These are the vertices that will be used in the new caps List <Vertex> newVertices = new List <Vertex>(); for (int polygonIndex = 0; polygonIndex < polygons.Count; polygonIndex++) { Polygon.PolygonPlaneRelation planeRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane); // Polygon has been found to span both sides of the plane, attempt to split into two pieces if (planeRelation == Polygon.PolygonPlaneRelation.Spanning) { Polygon frontPolygon; Polygon backPolygon; Vertex newVertex1; Vertex newVertex2; // Attempt to split the polygon if (Polygon.SplitPolygon(polygons[polygonIndex], out frontPolygon, out backPolygon, out newVertex1, out newVertex2, splitPlane)) { // If the split algorithm was successful (produced two valid polygons) then add each polygon to // their respective points and track the intersection points polygonsFront.Add(frontPolygon); polygonsBack.Add(backPolygon); newVertices.Add(newVertex1); newVertices.Add(newVertex2); newMaterial = polygons[polygonIndex].Material; } else { // Two valid polygons weren't generated, so use the valid one if (frontPolygon != null) { planeRelation = Polygon.PolygonPlaneRelation.InFront; } else if (backPolygon != null) { planeRelation = Polygon.PolygonPlaneRelation.Behind; } else { Debug.LogError("Polygon splitting has resulted in two zero area polygons. This is unhandled."); // Polygon.PolygonPlaneRelation secondplaneRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane); } } } // If the polygon is on one side of the plane or the other if (planeRelation != Polygon.PolygonPlaneRelation.Spanning) { // Make sure any points that are coplanar on non-straddling polygons are still used in polygon // construction for (int vertexIndex = 0; vertexIndex < polygons[polygonIndex].Vertices.Length; vertexIndex++) { if (Polygon.ComparePointToPlane(polygons[polygonIndex].Vertices[vertexIndex].Position, splitPlane) == Polygon.PointPlaneRelation.On) { newVertices.Add(polygons[polygonIndex].Vertices[vertexIndex]); } } if (planeRelation == Polygon.PolygonPlaneRelation.Behind) { polygonsBack.Add(polygons[polygonIndex]); } else { polygonsFront.Add(polygons[polygonIndex]); } } } // If any splits occured or coplanar vertices are found. (For example if you're splitting a sphere at the // equator then no polygons will be split but there will be a bunch of coplanar vertices!) if (newVertices.Count > 0) { // HACK: This code is awful, because we end up with lots of duplicate vertices List <Vector3> positions = newVertices.Select(item => item.Position).ToList(); Polygon newPolygon = PolygonFactory.ConstructPolygon(positions, true); // Assuming it was possible to create a polygon if (newPolygon != null) { if (!MathHelper.PlaneEqualsLooser(newPolygon.Plane, splitPlane)) { // Polygons are sometimes constructed facing the wrong way, possibly due to a winding order // mismatch. If the two normals are opposite, flip the new polygon if (Vector3.Dot(newPolygon.Plane.normal, splitPlane.normal) < -0.9f) { newPolygon.Flip(); } } newPolygon.ExcludeFromFinal = excludeNewPolygons; newPolygon.Material = newMaterial; polygonsFront.Add(newPolygon); newPolygon = newPolygon.DeepCopy(); newPolygon.Flip(); newPolygon.ExcludeFromFinal = excludeNewPolygons; newPolygon.Material = newMaterial; if (newPolygon.Plane.normal == Vector3.zero) { Debug.LogError("Invalid Normal! Shouldn't be zero. This is unexpected since extraneous positions should have been removed!"); // Polygon fooNewPolygon = PolygonFactory.ConstructPolygon(positions, true); } polygonsBack.Add(newPolygon); } return(true); } else { // It wasn't possible to create the polygon, for example the constructed polygon was too small // This could happen if you attempt to clip the tip off a long but thin brush, the plane-polyhedron test // would say they intersect but in reality the resulting polygon would be near zero area return(false); } }
public static Polygon[] ConnectVertices(Polygon[] polygons, List <Vertex> sourceVertices, out List <Edge> newEdges) { List <Polygon> newPolygons = new List <Polygon>(polygons); newEdges = new List <Edge>(); for (int i = 0; i < newPolygons.Count; i++) { // Source vertices on the polygon int matchedIndex1 = -1; int matchedIndex2 = -1; for (int j = 0; j < sourceVertices.Count; j++) { int index = System.Array.IndexOf(newPolygons[i].Vertices, sourceVertices[j]); if (index != -1) { if (matchedIndex1 == -1) { matchedIndex1 = index; } else if (matchedIndex2 == -1) { matchedIndex2 = index; } } } // Check that found two valid points and that they're not neighbours // (neighbouring vertices can't be connected as they already are by an edge) if (matchedIndex1 != -1 && matchedIndex2 != -1 && !AreNeighbours(matchedIndex1, matchedIndex2, newPolygons[i].Vertices.Length)) { // Vertex neighbourVertex = newPolygons[i].Vertices[(matchedIndex1 + 1) % newPolygons[i].Vertices.Length]; // // Vector3 vector1 = newPolygons[i].Vertices[matchedIndex1].Position - neighbourVertex.Position; // Vector3 vector2 = newPolygons[i].Vertices[matchedIndex2].Position - newPolygons[i].Vertices[matchedIndex1].Position; // Vector3 normal = Vector3.Cross(vector1, vector2).normalized; // // Vector3 thirdPoint = newPolygons[i].Vertices[matchedIndex1].Position + normal; Vector3 thirdPoint = newPolygons[i].Vertices[matchedIndex1].Position + newPolygons[i].Plane.normal; // First split the shared polygon Plane splitPlane = new Plane(newPolygons[i].Vertices[matchedIndex1].Position, newPolygons[i].Vertices[matchedIndex2].Position, thirdPoint); Polygon splitPolygon1; Polygon splitPolygon2; Vertex newVertex1; Vertex newVertex2; if (Polygon.SplitPolygon(newPolygons[i], out splitPolygon1, out splitPolygon2, out newVertex1, out newVertex2, splitPlane)) { newPolygons[i] = splitPolygon1; newPolygons.Insert(i + 1, splitPolygon2); // Skip over new polygon i++; newEdges.Add(new Edge(newVertex1, newVertex2)); } else { Debug.LogWarning("Split polygon failed"); } } } return(newPolygons.ToArray()); }
internal static bool SplitCoplanarPolygonsByPlane(List <Polygon> polygons, // Source polygons that will be split Plane splitPlane, out List <Polygon> polygonsFront, out List <Polygon> polygonsBack) { polygonsFront = new List <Polygon>(); polygonsBack = new List <Polygon>(); for (int polygonIndex = 0; polygonIndex < polygons.Count; polygonIndex++) { Polygon.PolygonPlaneRelation planeRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane); // Polygon has been found to span both sides of the plane, attempt to split into two pieces if (planeRelation == Polygon.PolygonPlaneRelation.Spanning) { Polygon frontPolygon; Polygon backPolygon; Vertex newVertex1; Vertex newVertex2; // Attempt to split the polygon if (Polygon.SplitPolygon(polygons[polygonIndex], out frontPolygon, out backPolygon, out newVertex1, out newVertex2, splitPlane)) { // If the split algorithm was successful (produced two valid polygons) then add each polygon to // their respective points and track the intersection points polygonsFront.Add(frontPolygon); polygonsBack.Add(backPolygon); } else { // Two valid polygons weren't generated, so use the valid one if (frontPolygon != null) { planeRelation = Polygon.PolygonPlaneRelation.InFront; } else if (backPolygon != null) { planeRelation = Polygon.PolygonPlaneRelation.Behind; } else { planeRelation = Polygon.PolygonPlaneRelation.InFront; Debug.LogError("Polygon splitting has resulted in two zero area polygons. This is unhandled."); // Polygon.PolygonPlaneRelation secondplaneRelation = Polygon.TestPolygonAgainstPlane(polygons[polygonIndex], splitPlane); } } } // If the polygon is on one side of the plane or the other if (planeRelation != Polygon.PolygonPlaneRelation.Spanning) { if (planeRelation == Polygon.PolygonPlaneRelation.Behind) { polygonsBack.Add(polygons[polygonIndex]); } else { polygonsFront.Add(polygons[polygonIndex]); } } } if (polygonsBack.Count >= 1 && polygonsFront.Count >= 1) { return(true); } else { return(false); } }
public static bool SplitPolygonsByEdges(Polygon[] polygons, List <Edge> sourceEdges, out Polygon[] finalPolygons, out List <Edge> newEdges) { // First of all refine the list of edges to those that are on the polygons and share a polygon with another specified edge // Verification step, no more than two edges should be selected per face // Once the list of edges is refined, walk through each set of polygons // Where a polygon has two specified edges, it needs to be split in two // Where a polygon has one specified edge, it needs a vertex to be added List <Polygon> newPolygons = new List <Polygon>(polygons); // Complete set of new polygons newEdges = new List <Edge>(); // These are the new edges we create List <Edge> edges = new List <Edge>(); // Pull out a list of edges that occur on any of the polygons at least twice. // This way we ignore edges on other brushes or edges which aren't possible to connect via a polygon for (int edge1Index = 0; edge1Index < sourceEdges.Count; edge1Index++) { bool found = false; for (int i = 0; i < polygons.Length && !found; i++) { Edge edge1 = sourceEdges[edge1Index]; for (int edge2Index = 0; edge2Index < sourceEdges.Count && !found; edge2Index++) { if (edge2Index != edge1Index) // Skip the same edge { Edge edge2 = sourceEdges[edge2Index]; bool edge1Contained = Polygon.ContainsEdge(polygons[i], edge1); bool edge2Contained = Polygon.ContainsEdge(polygons[i], edge2); if (edge1Contained && edge2Contained) { if (!edges.Contains(edge1)) { edges.Add(edge1); } if (!edges.Contains(edge2)) { edges.Add(edge2); } found = true; } } } } } // Now process each polygon for (int i = 0; i < polygons.Length; i++) { Polygon polygon = polygons[i]; List <Edge> edgesOnPolygon = new List <Edge>(); for (int edgeIndex = 0; edgeIndex < edges.Count; edgeIndex++) { Edge edge = edges[edgeIndex]; if (Polygon.ContainsEdge(polygon, edge)) { edgesOnPolygon.Add(edge); } } if (edgesOnPolygon.Count == 1) { Vertex newVertex; // Add vertex if (!SplitPolygonAtEdge(polygon, edgesOnPolygon[0], out newVertex)) { Debug.LogError("Could not add vertex to adjacent polygon"); } } else if (edgesOnPolygon.Count == 2) { // Split into two Edge edge1 = edgesOnPolygon[0]; Edge edge2 = edgesOnPolygon[1]; // First split the shared polygon Vector3 edge1Center = edge1.GetCenterPoint(); Vector3 edge2Center = edge2.GetCenterPoint(); Vector3 thirdPoint = edge1Center + polygon.Plane.normal; Plane splitPlane = new Plane(edge1Center, edge2Center, thirdPoint); Polygon splitPolygon1; Polygon splitPolygon2; Vertex edge1Vertex; Vertex edge2Vertex; Polygon.SplitPolygon(polygon, out splitPolygon1, out splitPolygon2, out edge1Vertex, out edge2Vertex, splitPlane); newEdges.Add(new Edge(edge1Vertex, edge2Vertex)); newPolygons.Remove(polygon); newPolygons.Add(splitPolygon1); newPolygons.Add(splitPolygon2); } } finalPolygons = newPolygons.ToArray(); return(true); }