Пример #1
0
        // Split `polygon` by this plane if needed, then put the polygon or polygon
        // fragments in the appropriate lists. Coplanar polygons go into either
        // `coplanarFront` or `coplanarBack` depending on their orientation with
        // respect to this plane. Polygons in front or in back of this plane go into
        // either `front` or `back`.
        public void SplitPolygon(CsgPolygon polygon, List <CsgPolygon> coplanarFront, List <CsgPolygon> coplanarBack, List <CsgPolygon> front, List <CsgPolygon> back)
        {
            double splitTolerance = 0.00001;
            // Classify each point as well as the entire polygon into one of the above
            // four classes.
            PolyType        polygonType = PolyType.COPLANAR;
            List <PolyType> types       = new List <PolyType>();

            for (int i = 0; i < polygon.vertices.Count; i++)
            {
                double   t    = Vector3.Dot(this.normal, polygon.vertices[i].Position) - this.w;
                PolyType type = (t < -splitTolerance) ? PolyType.BACK : ((t > splitTolerance) ? PolyType.FRONT : PolyType.COPLANAR);
                polygonType |= type;
                types.Add(type);
            }

            // Put the polygon in the correct list, splitting it when necessary.
            switch (polygonType)
            {
            case PolyType.COPLANAR:
            {
                if (Vector3.Dot(this.normal, polygon.plane.normal) > 0)
                {
                    coplanarFront.Add(polygon);
                }
                else
                {
                    coplanarBack.Add(polygon);
                }
                break;
            }

            case PolyType.FRONT:
            {
                front.Add(polygon);
                break;
            }

            case PolyType.BACK:
            {
                back.Add(polygon);
                break;
            }

            case PolyType.SPANNING:
            {
                List <IVertex> frontVertices = new List <IVertex>();
                List <IVertex> backVertices  = new List <IVertex>();
                for (int firstVertexIndex = 0; firstVertexIndex < polygon.vertices.Count; firstVertexIndex++)
                {
                    int      nextVertexIndex = (firstVertexIndex + 1) % polygon.vertices.Count;
                    PolyType firstPolyType   = types[firstVertexIndex];
                    PolyType nextPolyType    = types[nextVertexIndex];
                    IVertex  firstVertex     = polygon.vertices[firstVertexIndex];
                    IVertex  nextVertex      = polygon.vertices[nextVertexIndex];
                    if (firstPolyType != PolyType.BACK)
                    {
                        frontVertices.Add(firstVertex);
                    }

                    if (firstPolyType != PolyType.FRONT)
                    {
                        backVertices.Add(firstVertex);
                    }

                    if ((firstPolyType | nextPolyType) == PolyType.SPANNING)
                    {
                        double  planDotFirstVertex   = Vector3.Dot(this.normal, firstVertex.Position);
                        double  firstDistToPlane     = this.w - planDotFirstVertex;
                        Vector3 deltaFromFirstToNext = nextVertex.Position - firstVertex.Position;
                        double  t         = firstDistToPlane / Vector3.Dot(this.normal, deltaFromFirstToNext);
                        IVertex newVertex = firstVertex.CreateInterpolated(nextVertex, t);
                        frontVertices.Add(newVertex);
                        backVertices.Add(newVertex);
                    }
                }

                if (frontVertices.Count >= 3)
                {
                    front.Add(new CsgPolygon(frontVertices));
                }

                if (backVertices.Count >= 3)
                {
                    back.Add(new CsgPolygon(backVertices));
                }
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }