Exemple #1
0
        /// <summary>
        /// Given a set of coplanar polygons, this method uses the perimeter and calculates the convex hulls. Concavities and holes are supported and in general this method has been observed to produce mathematically optimal or close to. Applying a heuristic to the BSP tree phase could reduce excessive splitting, but from observation the current method is probably good enough.
        /// </summary>
        /// <returns>A set of polygons that describe the convex hulls.</returns>
        /// <param name="polygons">Coplanar set of polygons.</param>
        internal static List <Polygon> CalculateConvexHulls(List <Polygon> polygons)
        {
            // Convex hull of 1 polygon is guaranteed to be itself, so early out. Note that care must be taken as the reference is the same as the input
            //if(polygons.Count == 1)
            //{
            //    return polygons;
            //}

            //Coplanar test. If failed, abort optimization;
            for (int i = 0; i < polygons.Count; i++)
            {
                for (int j = i + 1; j < polygons.Count; j++)
                {
                    if (!MathHelper.PlaneEqualsLooser(polygons[i].Plane, polygons[j].Plane))
                    {
                        return(polygons);
                    }
                }
            }
            // Cache the polygon's normal so that we don't have to calculate it for the new polygons
            Vector3 normal = polygons[0].Plane.normal;

            // TODO: Generate islands

            // Create a list of edges from the source polygons and track how many times each edge occurs
            List <SimpleEdge> edges = new List <SimpleEdge>();

            for (int i = 0; i < polygons.Count; i++)
            {
                Polygon polygon = polygons[i];
                //if (!polygons[0].UserExcludeFromFinal)
                //    VisualDebug.AddPolygon(polygon, Color.blue);
                Edge[] polygonEdges = polygon.GetEdges();

                for (int j = 0; j < polygonEdges.Length; j++)
                {
                    Vector3 position1 = polygonEdges[j].Vertex1.Position;
                    Vector3 position2 = polygonEdges[j].Vertex2.Position;
                    //int foundIndex = edges.FindIndex(item => item.Matches(position1, position2));
                    List <SimpleEdge> found = edges.FindAll(item => item.CollinearIntersects(position1, position2));

                    if (found.Count > 0)
                    {
                        for (int k = 0; k < found.Count; k++)
                        {
                            found[k].Count++;
                        }
                        edges.Add(new SimpleEdge(position1, position2, polygons[0].Plane.normal, 2));
                    }
                    else
                    {
                        edges.Add(new SimpleEdge(position1, position2, polygons[0].Plane.normal));
                    }
                }
            }

            // Construct a list of perimeter edges by extracting the edges that only occur once
            List <SimpleEdge> splitEdges = new List <SimpleEdge>();

            for (int i = 0; i < edges.Count; i++)
            {
                if (edges[i].Count == 1)// && (edges[i].Position2 - edges[i].Position1).sqrMagnitude > Mathf.Pow(0.01f, 2))
                {
                    splitEdges.Add(edges[i]);
                    //VisualDebug.AddLine(edges[i].Position1, edges[i].Position2, Color.green, 8);
                }
                //else
                //{
                //    if (!polygons[0].UserExcludeFromFinal && i == 838)
                //        VisualDebug.AddLine(edges[i].Position1, edges[i].Position2, Color.red, 8);
                //}
            }

            // Using a BSP Tree subdivide the source polygons until they are classified into convex hulls. At this stage each convex hull may contain multiple polygons
            List <Polygon>    unsortedPolygons = new List <Polygon>(polygons);
            TriangulationNode rootNode         = new TriangulationNode(unsortedPolygons, splitEdges);

            // Pull out all the convex hull polygon sets from the BSP Tree
            List <List <Polygon> > convexHulls = rootNode.GetAggregated();

            //string message = "Convex hulls found: " + convexHulls.Count + " { ";

            List <Polygon> outputPolygons = new List <Polygon>(convexHulls.Count);

            // Walk through each set of polygons that maps to a convex hull
            for (int i = 0; i < convexHulls.Count; i++)
            {
                //float hue = i / 6f;
                //float sat = 1 - 0.6f * Mathf.Floor(i / 6f);
                //Color color = Color.HSVToRGB(hue, sat, 1);


                // Aggregate all the vertices from all the polygons classified in this convex hull
                List <Vertex> allVertices = new List <Vertex>();
                for (int j = 0; j < convexHulls[i].Count; j++)
                {
                    //if (!polygons[0].UserExcludeFromFinal)
                    //{
                    //    VisualDebug.AddLinePolygon(convexHulls[i][j].Vertices, Color.red);
                    //}

                    // TODO: Should this be a deep copy?
                    //                    allPositions.AddRange(convexHulls[i][j].Vertices);
                    allVertices.AddRange(convexHulls[i][j].Vertices.DeepCopy());
                }

                //if(!polygons[0].UserExcludeFromFinal && i == 15)
                //{
                //    VisualDebug.AddLinePolygon(allVertices, color);
                //}

                if (allVertices.Count < 3)
                {
                    continue;
                }


                // Refine the source vertices into the minimum needed to form a convex hull, stripping out cospatial, collinear and interior vertices
                List <Vertex> newVertices = PolygonFactory.RefineVertices(normal, allVertices, true, true, true);
                // Now that the vertices of the convex hull have been refined, create a new polygon from them using the source polygon as a template
                Polygon polygon = new Polygon(newVertices.ToArray(), polygons[0].Material, polygons[0].ExcludeFromFinal, polygons[0].UserExcludeFromFinal, polygons[0].UniqueIndex);

                // TODO: Shouldn't need to do this
                //polygon.Flip();
                outputPolygons.Add(polygon);

                //Vertex[] vertices2 = polygon.Vertices;
                //message += vertices2.Length + ", ";
                //for (int k = 0; k < vertices2.Length; k++)
                //{
                //	VisualDebug.AddPoint(vertices2[k].Position, color, 0.1f);
                //}
                //VisualDebug.AddPolygon(polygon, color);
            }

            //message += " }";
            //Debug.Log(message);

            return(outputPolygons);
        }