Exemple #1
0
        internal TriangulationNode(List <Polygon> polygonsToProcess, List <SimpleEdge> edges)
        {
            for (int i = 0; i < edges.Count; i++)
            {
                List <Polygon> polygonsFront;
                List <Polygon> polygonsBack;
                if (PolygonFactory.SplitCoplanarPolygonsByPlane(polygonsToProcess, edges[i].Plane, out polygonsFront, out polygonsBack))
                {
                    // Split success
//					activePlane = planes[i];

                    List <SimpleEdge> frontEdges = new List <SimpleEdge>();
                    List <SimpleEdge> backEdges  = new List <SimpleEdge>();

                    for (int j = i + 1; j < edges.Count; j++)
                    {
//						Vector3 point = planes[j].normal * planes[j].distance;
                        Vector3 point = edges[j].MidPoint;
                        int     side  = MathHelper.GetSideThick(edges[i].Plane, point);
                        if (side == -1)
                        {
                            frontEdges.Add(edges[j]);
                        }
                        else if (side == 1)
                        {
                            backEdges.Add(edges[j]);
                        }
                        else
                        {
                            frontEdges.Add(edges[j]);
                            backEdges.Add(edges[j]);
                        }
                    }

                    front = new TriangulationNode(polygonsFront, frontEdges);
                    back  = new TriangulationNode(polygonsBack, backEdges);

//					Debug.Log(planes[i].ToStringLong() + " " + polygonsFront.Count + " " + polygonsBack.Count);

                    // Created some child nodes so early out
                    return;
                }
            }

            this.polygonsAtNode = polygonsToProcess;
        }
Exemple #2
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);
        }
        internal TriangulationNode(List <Polygon> polygonsToProcess, List <SimpleEdge> edges)
        {
            List <Polygon>    LastPolygonsFront = null;
            List <Polygon>    LastPolygonsBack  = null;
            List <SimpleEdge> LastFrontEdges    = null;
            List <SimpleEdge> LastBackEdges     = null;
            bool hasFound = false;

            for (int i = 0; i < edges.Count; i++)
            {
                List <Polygon> polygonsFront;
                List <Polygon> polygonsBack;

                if (PolygonFactory.SplitCoplanarPolygonsByPlane(polygonsToProcess, edges[i].Plane, out polygonsFront, out polygonsBack))
                {
                    // Split success
//					activePlane = planes[i];

                    List <SimpleEdge> frontEdges = new List <SimpleEdge>();
                    List <SimpleEdge> backEdges  = new List <SimpleEdge>();
                    bool cutedge = false;

                    for (int j = 0; j < edges.Count; j++)
                    {
                        if (i == j)
                        {
                            continue;
                        }
//						Vector3 point = planes[j].normal * planes[j].distance;
                        //when you cut through an edge, by checking midpoint you will put the edge in one side while it should be in both side
                        //So we should check both endpoint instead
                        Vector3 point1 = edges[j].Position1;
                        Vector3 point2 = edges[j].Position2;
                        int     side1  = MathHelper.GetSideThick(edges[i].Plane, point1);
                        int     side2  = MathHelper.GetSideThick(edges[i].Plane, point2);
                        if (side1 * side2 >= 0)
                        {
                            if (side1 + side2 < 0)
                            {
                                frontEdges.Add(edges[j]);
                            }
                            else
                            {
                                backEdges.Add(edges[j]);
                            }
                        }
                        else
                        {
                            cutedge = true;
                            frontEdges.Add(edges[j]);
                            backEdges.Add(edges[j]);
                        }
                    }
                    //don't early out when we cut through an edge, we will find a better cut
                    if (cutedge)
                    {
                        hasFound = true;
                        //Debug.DrawLine(edges[i].Position1, edges[i].Position2, Color.red, 300, false);
                        LastPolygonsFront = polygonsFront;
                        LastPolygonsBack  = polygonsBack;
                        LastFrontEdges    = frontEdges;
                        LastBackEdges     = backEdges;
                        continue;
                    }
                    //if(hasFound) Debug.DrawLine(edges[i].Position1, edges[i].Position2, Color.green, 300, false);
                    //else Debug.DrawLine(edges[i].Position1, edges[i].Position2, Color.blue, 300, false);
                    front = new TriangulationNode(polygonsFront, frontEdges);
                    back  = new TriangulationNode(polygonsBack, backEdges);

//					Debug.Log(planes[i].ToStringLong() + " " + polygonsFront.Count + " " + polygonsBack.Count);

                    // Created some child nodes so early out
                    return;
                }
            }
            //Fallback if we haven't found a better one
            if (hasFound)
            {
                front = new TriangulationNode(LastPolygonsFront, LastFrontEdges);
                back  = new TriangulationNode(LastPolygonsBack, LastBackEdges);
                return;
            }
            this.polygonsAtNode = polygonsToProcess;
        }