private UniversalFaceSpatialPartitioning Initialize(Surface surface, Topology topology, IVertexAttribute <Vector3> vertexPositions) { _surface = surface; _topology = topology; var edges = _topology.faceEdges; _partitionBinaryTree = new Partition[edges.Count]; int edgesProcessed = 0; int increment = 1; if (edges.Count % 23 != 0) { increment = 23; } else if (edges.Count % 19 != 0) { increment = 19; } else if (edges.Count % 17 != 0) { increment = 17; } else if (edges.Count % 13 != 0) { increment = 13; } else if (edges.Count % 11 != 0) { increment = 11; } else if (edges.Count % 7 != 0) { increment = 7; } else if (edges.Count % 5 != 0) { increment = 5; } else if (edges.Count % 3 != 0) { increment = 3; } else if (edges.Count % 2 != 0) { increment = 2; } int edgeIndex = (edges.Count * 7) / 16; // Find the first edge that will work as the root. It must be the earlier twin, and should not // have any face-to-face wrapping or be on the boundary between an internal face and external faces. while (edgesProcessed < edges.Count) { ++edgesProcessed; var edge = edges[edgeIndex]; if (edgeIndex < edge.twinIndex && (edge.wrap & EdgeWrap.FaceToFace) == EdgeWrap.None && edge.isNonBoundary) { _partitionBinaryTree[0] = Partition.Create(edge, vertexPositions, surface); edgeIndex = (edgeIndex + increment) % edges.Count; break; } edgeIndex = (edgeIndex + increment) % edges.Count; } int nextPartitionIndex = 1; // Process all remaining non-wrapping non-boundary edges. As above, only concentrate on the earlier twins. while (edgesProcessed < edges.Count) { ++edgesProcessed; var edge = edges[edgeIndex]; if (edgeIndex < edge.twinIndex && (edge.wrap & EdgeWrap.FaceToFace) == EdgeWrap.None && edge.isNonBoundary) { PartitionEdge(edge, vertexPositions, ref nextPartitionIndex); } edgeIndex = (edgeIndex + increment) % edges.Count; } edgesProcessed = 0; // Process all wrapping edges, which should be at or near the leaves of the tree. while (edgesProcessed < edges.Count) { ++edgesProcessed; var edge = edges[edgeIndex]; // If the edge has face-to-face wrapping, then don't restrict to only the earlier twin. // Both twins should be processed. if ((edge.wrap & EdgeWrap.FaceToFace) != EdgeWrap.None && edge.isNonBoundary) { PartitionEdge(edge, vertexPositions, ref nextPartitionIndex); } edgeIndex = (edgeIndex + increment) % edges.Count; } edgesProcessed = 0; // Process all external edges, which should be at or near the leaves of the tree. // Note that it is critical that boundary edges occur after all wrapping edges. // Otherwise, false negatives (hitting an external face when a wrap should have // led to an internal face instead) or even infinite loops are possible. while (edgesProcessed < edges.Count) { ++edgesProcessed; var edge = edges[edgeIndex]; // If the edge is a boundary edge, then only process it if it's the external // edge. The internal half doesn't need to be processed at all. if (edge.isBoundary && edge.isExternal) { PartitionEdge(edge, vertexPositions, ref nextPartitionIndex); } edgeIndex = (edgeIndex + increment) % edges.Count; } if (nextPartitionIndex < _partitionBinaryTree.Length) { TruncateBinaryTree(nextPartitionIndex); } return(this); }
public static Partition Create(Topology.FaceEdge edge, IVertexAttribute <Vector3> vertexPositions, Surface surface) { var prevEdge = edge.prev; var vPos0 = vertexPositions[prevEdge]; var vPos1 = vertexPositions[edge]; var edgeVector = vPos1 - vPos0; var edgeNormal = surface.GetNormal(vPos0); var planeNormal = Vector3.Cross(edgeVector, edgeNormal).normalized; return(new Partition(planeNormal, vPos0, edge.twinIndex, edge.index)); }
/// <summary> /// Creates a spatial partitioning for the given manifold. /// </summary> /// <param name="surface">The surface describing the overall shape of the manifold.</param> /// <param name="topology">The topological relations of vertices, edges, and faces of the manifold.</param> /// <param name="vertexPositions">The positions of the manifold's vertices.</param> /// <returns>A spatial partitioning for the given manifold.</returns> public static UniversalFaceSpatialPartitioning Create(Surface surface, Topology topology, IVertexAttribute <Vector3> vertexPositions) { return(CreateInstance <UniversalFaceSpatialPartitioning>().Initialize(surface, topology, vertexPositions)); }