Ejemplo n.º 1
0
		public Triangle(Triangle triangle)
		{
			OrientationPlane = triangle.OrientationPlane;
			A = triangle.A;
			B = triangle.B;
			C = triangle.C;
		}
Ejemplo n.º 2
0
        /**
         * Categorize or slice @triangle using @plane. Triangles existing completely on the front side of @plane
         * are placed in @greaterThan, triangles exisitng completely on the back side of @plane are placed in
         * @lessThan. Co-planar triangles go in @greaterThanPlanar if their normals are the same direction as
         * @plane's normal, otherwise they go in @lessThanPlanar.
         *
         * If a triangle spans @plane and has vertices on both sides, it is split into multiple triangles
         * along @plane. The resulting triangles are then categorized as specified above (in this case they are either
         * in front or back, they could not be co-planar).
         *
         * Determining the orientation of a given vertex involves taking the dot product of the vertex's position with
         * @plane's normal and comparing that to @plane's offset from the origin (plane.D). If the dot-product is greater
         * than that offset (plus some small epsilon), it is in front; if it is less than that offset (minus a small epsilon)
         * it is in back. Otherwise it is co-planar.
         *
         */
        public static Orientation SliceTriangle(Triangle triangle, Plane plane, 
		                                        IList<Triangle> lessThan, IList<Triangle> greaterThan, 
		                                        IList<Triangle> lessThanPlanar, IList<Triangle> greaterThanPlanar)
        {
            Orientation[] vertOrientations = new Orientation[3];
            Orientation triOrientation = Orientation.CoPlanar;
            int orientationsFound = 0;

            // loop through each vertex and categorize each based
            // on its position relative to @plane.
            for(int i =0; i < 3; i++)
            {
                Orientation currentOrientation =  ClassifyVertexOrientation(triangle.GetVertexByIndex(i), plane);
                vertOrientations[i] = currentOrientation;
                orientationsFound |= (int)currentOrientation;
            }

            // classify @triangle's orientation relative to @plane based
            // on the orientations of all vertices.
            if (orientationsFound > (int)Orientation.GreaterThan)
                triOrientation = Orientation.Split;
            else
                triOrientation = (Orientation)orientationsFound;

            // place @triangle in the appropriate list based on its orientation, or
            // split it if necessary
            switch(triOrientation)
            {
            case Orientation.CoPlanar:
                // if @triangle's normal matches @plane's normal, i.e. dot product will be 1,
                // then we consider @triangle to be front-facing
                float planeTriOrientation = triangle.OrientationPlane.Normal.Dot(plane.Normal);
                if(planeTriOrientation > 0)
                    greaterThanPlanar.Add(triangle);
                else
                    lessThanPlanar.Add(triangle);
                break;
            case Orientation.LessThan:
                lessThan.Add(triangle);
                break;
            case Orientation.GreaterThan:
                greaterThan.Add(triangle);
                break;
            case Orientation.Split:
                List<Vertex> ltSplit = new List<Vertex>();
                List<Vertex> gtSplit = new List<Vertex>();

                // loop through each edge in @triangle.
                // @currentVertex = edge's first vertex.
                // @nextVertex = edge's second vertex.
                // @currentOrientation = orientation of the edge's first vertex.
                // @nextOrientation = orientation of the edge's second vertex.
                for(int i=0; i < 3; i++)
                {
                    int currentIndex = i;
                    int nextIndex = currentIndex < 2 ? currentIndex + 1 : 0;

                    Orientation currentOrientation = vertOrientations[currentIndex];
                    Orientation nextOrientation = vertOrientations[nextIndex];

                    Vertex currentVertex = triangle.GetVertexByIndex(currentIndex);
                    Vertex nextVertex = triangle.GetVertexByIndex(nextIndex);

                    Vector3D currentEdge = nextVertex.Position.SubtractedBy(currentVertex.Position);

                    // vertices are traversed in clock-wise order, which means @triangle's edges
                    // are also traversed in clock-wise order. this means that as vertices are added to
                    // @gtSplit and @ltSplit, their respective vertices will also be in clock-wise order.
                    switch(currentOrientation)
                    {
                    case Orientation.CoPlanar:
                        gtSplit.Add(currentVertex);
                        ltSplit.Add(currentVertex);
                        break;
                    case Orientation.LessThan:
                        ltSplit.Add(currentVertex);
                        break;
                    case Orientation.GreaterThan:
                        gtSplit.Add(currentVertex);
                        break;
                    }

                    // if we move from a "GreaterThan" orientation to a "LessThan" orientation or vice-versa,
                    // then we have crossed @plane. this means we need to interpolate between the edge's vertices
                    // to create a new vertex that is co-planar with @plane.
                    if(currentOrientation == Orientation.GreaterThan && nextOrientation == Orientation.LessThan ||
                       currentOrientation == Orientation.LessThan && nextOrientation == Orientation.GreaterThan )
                    {
                        float splitPortion = plane.D - plane.Normal.Dot(currentVertex.Position);
                        float fullPortion = plane.Normal.Dot(currentEdge);
                        float splitFraction = splitPortion / fullPortion;
                        Vertex splitVertex = currentVertex.Lerped(nextVertex, splitFraction);

                        gtSplit.Add(splitVertex);
                        ltSplit.Add(splitVertex);
                    }
                }

                // create 1 new triangle if @ltSplit contains 3 vertices. create 2 triangles if it
                // contains 4
                if (ltSplit.Count >= 3)
                {
                    lessThan.Add(new Triangle(ltSplit[0], ltSplit[1], ltSplit[2]));
                    if(ltSplit.Count == 4)
                        lessThan.Add(new Triangle(ltSplit[0], ltSplit[2], ltSplit[3]));
                }

                // create 1 new triangle if @gtSplit contains 3 vertices. create 2 triangles if it
                // contains 4
                if (gtSplit.Count >= 3)
                {
                    greaterThan.Add(new Triangle(gtSplit[0], gtSplit[1], gtSplit[2]));
                    if(gtSplit.Count == 4)
                        greaterThan.Add(new Triangle(gtSplit[0], gtSplit[2], gtSplit[3]));
                }
                break;
            }

            return triOrientation;
        }