Пример #1
0
        //--------------------------------CONSTRUCTORS----------------------------------//
        /**
         * Constructs a BooleanModeller object to apply boolean operation in two solids.
         * Makes preliminary calculations
         *
         * @param solid1 first solid where boolean operations will be applied
         * @param solid2 second solid where boolean operations will be applied
         */
        public BooleanModeller(Solid solid1, Solid solid2)
        {
            //representation to apply boolean operations
            object1 = new Object3D(solid1);
            object2 = new Object3D(solid2);

            //split the faces so that none of them intercepts each other
            object1.splitFaces(object2);
            object2.splitFaces(object1);

            //classify faces as being inside or outside the other solid
            object1.classifyFaces(object2);
            object2.classifyFaces(object1);
        }
Пример #2
0
        /// <summary>
        /// Clones the Object3D object
        /// </summary>
        /// <returns>cloned object</returns>
        public Object3D Clone()
        {
            Object3D clone = new Object3D();
            clone.vertices = new List<Vertex>();
            for (int i = 0; i < vertices.Count; i++)
            {
                clone.vertices.Add(vertices[i].Clone());
            }
            clone.faces = new List<Face>();
            for (int i = 0; i < vertices.Count; i++)
            {
                clone.faces.Add(faces[i].Clone());
            }
            clone.bound = bound;

            return clone;
        }
Пример #3
0
        /// <summary>
        /// Clones the Object3D object
        /// </summary>
        /// <returns>cloned object</returns>
        public Object3D Clone()
        {
            Object3D clone = new Object3D();

            clone.Vertices = new List <Vertex>();
            for (int i = 0; i < Vertices.Count; i++)
            {
                clone.Vertices.Add(Vertices[i].Clone());
            }
            clone.Faces = new List <Face>();
            for (int i = 0; i < Vertices.Count; i++)
            {
                clone.Faces.Add(Faces[i].Clone());
            }
            clone._Bound = _Bound;

            return(clone);
        }
Пример #4
0
        /// <summary>
        /// Classify faces as being inside, outside or on boundary of other object
        /// </summary>
        /// <param name="otherObject">object 3d used for the comparison</param>
        public void ClassifyFaces(Object3D otherObject)
        {
            //calculate adjacency information
            Face face;

            for (int i = 0; i < this.GetNumFaces(); i++)
            {
                face = this.GetFace(i);
                face.v1.AddAdjacentVertex(face.v2);
                face.v1.AddAdjacentVertex(face.v3);
                face.v2.AddAdjacentVertex(face.v1);
                face.v2.AddAdjacentVertex(face.v3);
                face.v3.AddAdjacentVertex(face.v1);
                face.v3.AddAdjacentVertex(face.v2);
            }

            //for each face
            for (int i = 0; i < GetNumFaces(); i++)
            {
                face = GetFace(i);

                //if the face vertices aren't classified to make the simple classify
                if (face.SimpleClassify() == false)
                {
                    //makes the ray trace classification
                    face.RayTraceClassify(otherObject);

                    //mark the vertices
                    if (face.v1.GetStatus() == Status.UNKNOWN)
                    {
                        face.v1.Mark(face.GetStatus());
                    }
                    if (face.v2.GetStatus() == Status.UNKNOWN)
                    {
                        face.v2.Mark(face.GetStatus());
                    }
                    if (face.v3.GetStatus() == Status.UNKNOWN)
                    {
                        face.v3.Mark(face.GetStatus());
                    }
                }
            }
        }
Пример #5
0
        //-----------------------------------OTHERS-------------------------------------//

        /**
         * Classify faces as being inside, outside or on boundary of other object
         *
         * @param object object 3d used for the comparison
         */
        public void classifyFaces(Object3D obj)
        {
            //calculate adjacency information
            Face face;

            for (int i = 0; i < this.getNumFaces(); i++)
            {
                face = this.getFace(i);
                face.v1.addAdjacentVertex(face.v2);
                face.v1.addAdjacentVertex(face.v3);
                face.v2.addAdjacentVertex(face.v1);
                face.v2.addAdjacentVertex(face.v3);
                face.v3.addAdjacentVertex(face.v1);
                face.v3.addAdjacentVertex(face.v2);
            }

            //for each face
            for (int i = 0; i < getNumFaces(); i++)
            {
                face = getFace(i);

                //if the face vertices aren't classified to make the simple classify
                if (face.simpleClassify() == false)
                {
                    //makes the ray trace classification
                    face.rayTraceClassify(obj);

                    //mark the vertices
                    if (face.v1.getStatus() == Vertex.UNKNOWN)
                    {
                        face.v1.mark(face.getStatus());
                    }
                    if (face.v2.getStatus() == Vertex.UNKNOWN)
                    {
                        face.v2.mark(face.getStatus());
                    }
                    if (face.v3.getStatus() == Vertex.UNKNOWN)
                    {
                        face.v3.mark(face.getStatus());
                    }
                }
            }
        }
Пример #6
0
        /// <summary>
        /// 划分自身平面为在其他对象的内部、外部或边界上
        /// </summary>
        /// <param name="otherObject">用来比较的 3D 物件</param>
        public void ClassifyFaces(Object3D otherObject)
        {
            Face face;

            for (int i = 0; i < GetNumFaces(); i++)  // 指定邻接点
            {
                face = GetFace(i);
                face.v1.AddAdjacentVertex(face.v2);
                face.v1.AddAdjacentVertex(face.v3);
                face.v2.AddAdjacentVertex(face.v1);
                face.v2.AddAdjacentVertex(face.v3);
                face.v3.AddAdjacentVertex(face.v1);
                face.v3.AddAdjacentVertex(face.v2);
            }
            for (int i = 0; i < GetNumFaces(); i++)  // 采样每个面
            {
                face = GetFace(i);
                if (!face.SimpleClassify())             // 简单分类没有分类的顶点
                {
                    face.RayTraceClassify(otherObject); // 用射线采样分类
                    // 标记顶点
                    if (face.v1.Status == Status.UNKNOWN)
                    {
                        face.v1.Mark(face.Status);
                    }
                    if (face.v2.Status == Status.UNKNOWN)
                    {
                        face.v2.Mark(face.Status);
                    }
                    if (face.v3.Status == Status.UNKNOWN)
                    {
                        face.v3.Mark(face.Status);
                    }
                }
            }
        }
Пример #7
0
        //-------------------------FACES_SPLITTING_METHODS------------------------------//

        /**
         * Split faces so that none face is intercepted by a face of other object
         *
         * @param object the other object 3d used to make the split
         */
        public void splitFaces(Object3D obj)
        {
            Line line;
            Face face1, face2;

            Segment[] segments;
            Segment   segment1;
            Segment   segment2;
            double    distFace1Vert1, distFace1Vert2, distFace1Vert3, distFace2Vert1, distFace2Vert2, distFace2Vert3;
            int       signFace1Vert1, signFace1Vert2, signFace1Vert3, signFace2Vert1, signFace2Vert2, signFace2Vert3;
            int       numFacesBefore = getNumFaces();
            int       numFacesStart  = getNumFaces();
            int       facesIgnored   = 0;

            //if the objects bounds overlap...
            if (getBound().overlap(obj.getBound()))
            {
                //for each object1 face...
                for (int i = 0; i < getNumFaces(); i++)
                {
                    //if object1 face bound and object2 bound overlap ...
                    face1 = getFace(i);

                    if (face1.getBound().overlap(obj.getBound()))
                    {
                        //for each object2 face...
                        for (int j = 0; j < obj.getNumFaces(); j++)
                        {
                            //if object1 face bound and object2 face bound overlap...
                            face2 = obj.getFace(j);
                            if (face1.getBound().overlap(face2.getBound()))
                            {
                                //PART I - DO TWO POLIGONS INTERSECT?
                                //POSSIBLE RESULTS: INTERSECT, NOT_INTERSECT, COPLANAR

                                //distance from the face1 vertices to the face2 plane
                                distFace1Vert1 = computeDistance(face1.v1, face2);
                                distFace1Vert2 = computeDistance(face1.v2, face2);
                                distFace1Vert3 = computeDistance(face1.v3, face2);

                                //distances signs from the face1 vertices to the face2 plane
                                signFace1Vert1 = (distFace1Vert1 > TOL ? 1 : (distFace1Vert1 < -TOL ? -1 : 0));
                                signFace1Vert2 = (distFace1Vert2 > TOL ? 1 : (distFace1Vert2 < -TOL ? -1 : 0));
                                signFace1Vert3 = (distFace1Vert3 > TOL ? 1 : (distFace1Vert3 < -TOL ? -1 : 0));

                                //if all the signs are zero, the planes are coplanar
                                //if all the signs are positive or negative, the planes do not intersect
                                //if the signs are not equal...
                                if (!(signFace1Vert1 == signFace1Vert2 && signFace1Vert2 == signFace1Vert3))
                                {
                                    //distance from the face2 vertices to the face1 plane
                                    distFace2Vert1 = computeDistance(face2.v1, face1);
                                    distFace2Vert2 = computeDistance(face2.v2, face1);
                                    distFace2Vert3 = computeDistance(face2.v3, face1);

                                    //distances signs from the face2 vertices to the face1 plane
                                    signFace2Vert1 = (distFace2Vert1 > TOL ? 1 : (distFace2Vert1 < -TOL ? -1 : 0));
                                    signFace2Vert2 = (distFace2Vert2 > TOL ? 1 : (distFace2Vert2 < -TOL ? -1 : 0));
                                    signFace2Vert3 = (distFace2Vert3 > TOL ? 1 : (distFace2Vert3 < -TOL ? -1 : 0));

                                    //if the signs are not equal...
                                    if (!(signFace2Vert1 == signFace2Vert2 && signFace2Vert2 == signFace2Vert3))
                                    {
                                        line = new Line(face1, face2);

                                        //intersection of the face1 and the plane of face2
                                        segment1 = new Segment(line, face1, signFace1Vert1, signFace1Vert2, signFace1Vert3);

                                        //intersection of the face2 and the plane of face1
                                        segment2 = new Segment(line, face2, signFace2Vert1, signFace2Vert2, signFace2Vert3);

                                        //if the two segments intersect...
                                        if (segment1.intersect(segment2))
                                        {
                                            //PART II - SUBDIVIDING NON-COPLANAR POLYGONS
                                            int lastNumFaces = getNumFaces();
                                            this.splitFace(i, segment1, segment2);

                                            //prevent from infinite loop (with a loss of faces...)
                                            //if(numFacesStart*20<getNumFaces())
                                            //{
                                            //  System.out.println("possible infinite loop situation: terminating faces split");
                                            //  return;
                                            //}

                                            //if the face in the position isn't the same, there was a break
                                            if (face1 != getFace(i))
                                            {
                                                //if the generated solid is equal the origin...
                                                if (face1.equals(getFace(getNumFaces() - 1)))
                                                {
                                                    //return it to its position and jump it
                                                    if (i != (getNumFaces() - 1))
                                                    {
                                                        faces.RemoveAt(getNumFaces() - 1);
                                                        faces.Insert(i, face1);
                                                    }
                                                    else
                                                    {
                                                        continue;
                                                    }
                                                }
                                                //else: test next face
                                                else
                                                {
                                                    i--;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #8
0
        /**
         * Classifies the face based on the ray trace technique
         *
         * @param object object3d used to compute the face status
         */
        public void rayTraceClassify(Object3D obj)
        {
            //creating a ray starting starting at the face baricenter going to the normal direction
            Point3d p0 = new Point3d();

            p0.X = (v1.X + v2.X + v3.X) / 3.0f;
            p0.Y = (v1.Y + v2.Y + v3.Y) / 3.0f;
            p0.Z = (v1.Z + v2.Z + v3.Z) / 3.0f;
            Line ray = new Line(getNormal(), p0);

            bool    success;
            double  dotProduct, distance;
            Point3d?intersectionPoint;
            Face    closestFace = null;
            double  closestDistance;

            do
            {
                success         = true;
                closestDistance = Double.MaxValue;
                //for each face from the other solid...
                for (int i = 0; i < obj.getNumFaces(); i++)
                {
                    Face face = obj.getFace(i);
                    //dotProduct = face.getNormal().dot(ray.getDirection());

                    dotProduct = Vector3d.Dot(face.getNormal(), ray.getDirection());

                    intersectionPoint = ray.computePlaneIntersection(face.getNormal(), face.v1.getPosition());


                    //if ray intersects the plane...
                    if (intersectionPoint != null)
                    {
                        distance = ray.computePointToPointDistance(intersectionPoint.Value);

                        //if ray lies in plane...
                        if (Math.Abs(distance) < TOL && Math.Abs(dotProduct) < TOL)
                        {
                            //disturb the ray in order to not lie into another plane
                            ray.perturbDirection();
                            success = false;
                            break;
                        }

                        //if ray starts in plane...
                        if (Math.Abs(distance) < TOL && Math.Abs(dotProduct) > TOL)
                        {
                            //if ray intersects the face...
                            if (face.hasPoint(intersectionPoint.Value))
                            {
                                //faces coincide
                                closestFace     = face;
                                closestDistance = 0;
                                break;
                            }
                        }

                        //if ray intersects plane...
                        else if (Math.Abs(dotProduct) > TOL && distance > TOL)
                        {
                            if (distance < closestDistance)
                            {
                                //if ray intersects the face;
                                if (face.hasPoint(intersectionPoint.Value))
                                {
                                    //this face is the closest face untill now
                                    closestDistance = distance;
                                    closestFace     = face;
                                }
                            }
                        }
                    }
                }
            } while (success == false);

            //none face found: outside face
            if (closestFace == null)
            {
                status = OUTSIDE;
            }
            //face found: test dot product
            else
            {
                //dotProduct = closestFace.getNormal().dot(ray.getDirection());
                dotProduct = Vector3d.Dot(closestFace.getNormal(), ray.getDirection());

                //distance = 0: coplanar faces
                if (Math.Abs(closestDistance) < TOL)
                {
                    if (dotProduct > TOL)
                    {
                        status = SAME;
                    }
                    else if (dotProduct < -TOL)
                    {
                        status = OPPOSITE;
                    }
                }

                //dot product > 0 (same direction): inside face
                else if (dotProduct > TOL)
                {
                    status = INSIDE;
                }

                //dot product < 0 (opposite direction): outside face
                else if (dotProduct < -TOL)
                {
                    status = OUTSIDE;
                }
            }
        }
Пример #9
0
        /// <summary>
        /// Split faces so that none face is intercepted by a face of other object
        /// </summary>
        /// <param name="compareObject">the other object 3d used to make the split</param>
        public void SplitFaces(Object3D compareObject)
        {
            Line    line;
            Face    thisFace, compareFace;
            Segment segment1;
            Segment segment2;
            double  v1DistToCompareFace, distFace1Vert2, distFace1Vert3, distFace2Vert1, distFace2Vert2, distFace2Vert3;
            int     signFace1Vert1, signFace1Vert2, signFace1Vert3, signFace2Vert1, signFace2Vert2, signFace2Vert3;
            int     numFacesBefore = this.GetNumFaces();
            int     numFacesStart  = this.GetNumFaces();

            //if the objects bounds overlap...
            if (this.GetBound().Overlap(compareObject.GetBound()))
            {
                //for each object1 face...
                for (int thisFaceIndex = 0; thisFaceIndex < this.GetNumFaces(); thisFaceIndex++)
                {
                    //if object1 face bound and object2 bound overlap ...
                    thisFace = GetFace(thisFaceIndex);

                    if (thisFace.GetBound().Overlap(compareObject.GetBound()))
                    {
                        //for each object2 face...
                        for (int compareFaceIndex = 0; compareFaceIndex < compareObject.GetNumFaces(); compareFaceIndex++)
                        {
                            //if object1 face bound and object2 face bound overlap...
                            compareFace = compareObject.GetFace(compareFaceIndex);
                            if (thisFace.GetBound().Overlap(compareFace.GetBound()))
                            {
                                //PART I - DO TWO POLIGONS INTERSECT?
                                //POSSIBLE RESULTS: INTERSECT, NOT_INTERSECT, COPLANAR

                                //distance from the face1 vertices to the face2 plane
                                v1DistToCompareFace = ComputeDistance(thisFace.v1, compareFace);
                                distFace1Vert2      = ComputeDistance(thisFace.v2, compareFace);
                                distFace1Vert3      = ComputeDistance(thisFace.v3, compareFace);

                                //distances signs from the face1 vertices to the face2 plane
                                signFace1Vert1 = (v1DistToCompareFace > EqualityTolerance ? 1 : (v1DistToCompareFace < -EqualityTolerance ? -1 : 0));
                                signFace1Vert2 = (distFace1Vert2 > EqualityTolerance ? 1 : (distFace1Vert2 < -EqualityTolerance ? -1 : 0));
                                signFace1Vert3 = (distFace1Vert3 > EqualityTolerance ? 1 : (distFace1Vert3 < -EqualityTolerance ? -1 : 0));

                                //if all the signs are zero, the planes are coplanar
                                //if all the signs are positive or negative, the planes do not intersect
                                //if the signs are not equal...
                                if (!(signFace1Vert1 == signFace1Vert2 && signFace1Vert2 == signFace1Vert3))
                                {
                                    //distance from the face2 vertices to the face1 plane
                                    distFace2Vert1 = ComputeDistance(compareFace.v1, thisFace);
                                    distFace2Vert2 = ComputeDistance(compareFace.v2, thisFace);
                                    distFace2Vert3 = ComputeDistance(compareFace.v3, thisFace);

                                    //distances signs from the face2 vertices to the face1 plane
                                    signFace2Vert1 = (distFace2Vert1 > EqualityTolerance ? 1 : (distFace2Vert1 < -EqualityTolerance ? -1 : 0));
                                    signFace2Vert2 = (distFace2Vert2 > EqualityTolerance ? 1 : (distFace2Vert2 < -EqualityTolerance ? -1 : 0));
                                    signFace2Vert3 = (distFace2Vert3 > EqualityTolerance ? 1 : (distFace2Vert3 < -EqualityTolerance ? -1 : 0));

                                    //if the signs are not equal...
                                    if (!(signFace2Vert1 == signFace2Vert2 && signFace2Vert2 == signFace2Vert3))
                                    {
                                        line = new Line(thisFace, compareFace);

                                        //intersection of the face1 and the plane of face2
                                        segment1 = new Segment(line, thisFace, signFace1Vert1, signFace1Vert2, signFace1Vert3);

                                        //intersection of the face2 and the plane of face1
                                        segment2 = new Segment(line, compareFace, signFace2Vert1, signFace2Vert2, signFace2Vert3);

                                        //if the two segments intersect...
                                        if (segment1.Intersect(segment2))
                                        {
                                            //PART II - SUBDIVIDING NON-COPLANAR POLYGONS
                                            int  lastNumFaces = GetNumFaces();
                                            bool splitOccured = this.SplitFace(thisFaceIndex, segment1, segment2);

                                            //prevent from infinite loop (with a loss of faces...)
                                            if (GetNumFaces() > numFacesStart * 100)
                                            {
                                                //System.out.println("possible infinite loop situation: terminating faces split");
                                                //return;
                                                int a = 0;
                                            }

                                            //if the face in the position isn't the same, there was a break
                                            if (splitOccured &&
                                                thisFace != GetFace(thisFaceIndex))
                                            {
                                                //if the generated solid is equal the origin...
                                                if (thisFace.Equals(GetFace(GetNumFaces() - 1)))
                                                {
                                                    //return it to its position and jump it
                                                    if (thisFaceIndex != (GetNumFaces() - 1))
                                                    {
                                                        faces.RemoveAt(GetNumFaces() - 1);
                                                        faces.Insert(thisFaceIndex, thisFace);
                                                    }
                                                    else
                                                    {
                                                        continue;
                                                    }
                                                }
                                                //else: test next face
                                                else
                                                {
                                                    thisFaceIndex--;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #10
0
        /// <summary>
        /// 为表面分类,基于光线追踪技术
        /// </summary>
        /// <param name="obj">计算面状态的 3D 物件</param>
        public void RayTraceClassify(Object3D obj)
        {
            Line   ray         = new Line(PlaneNormal, Center); // 射线从面的几何中心发出,方向为法线方向
            Face   closet      = default;
            bool   foundCloset = false;
            double closestDistance;
            bool   success;

            do
            {
                success         = true;
                closestDistance = double.MaxValue;
                for (int faceIndex = 0; faceIndex < obj.GetNumFaces(); faceIndex++)
                {
                    Face face = obj.GetFace(faceIndex);
                    var  intersectionPoint = ray.ComputePlaneIntersection(face.Plane); // 对三角面所在的平面采样
                    if (intersectionPoint.x < float.PositiveInfinity)                  // 射线被平面拦截
                    {
                        var  distance = ray.ComputePointToPointDistance(intersectionPoint);
                        var  dot      = Vector3Double.Dot(face.PlaneNormal, ray.Direction);
                        bool parallel = Math.Abs(dot) < epsilon; // 射线与平面平行
                        //if ray lies in plane...
                        if (Math.Abs(distance) < epsilon)        // 交点是射线起点
                        {
                            if (parallel)
                            {
                                // 略微抖动光线方向以免采样到另一平面
                                ray.PerturbDirection();
                                success = false;
                                break;
                            }
                            else if (face.ContainsPoint(intersectionPoint))
                            {
                                // 面重合
                                closet          = face;
                                foundCloset     = true;
                                closestDistance = 0;
                                break;
                            }
                        }
                        else if (!parallel && distance > epsilon)  // 射线产生交点
                        {
                            if (distance < closestDistance && face.ContainsPoint(intersectionPoint))
                            {
                                closestDistance = distance;
                                closet          = face; // 当前的面时最近的平面
                                foundCloset     = true;
                            }
                        }
                    }
                }
            } while (!success);

            if (!foundCloset)
            {
                Status = Status.OUTSIDE;
            }                                               // 没有找到面,自己是外部面
            else // 由离自己最近的面,检查方向
            {
                var dot = Vector3Double.Dot(closet.PlaneNormal, ray.Direction);
                if (Math.Abs(closestDistance) < epsilon)  // 距离为零,这个面和自己重合
                {
                    if (dot > epsilon)
                    {
                        Status = Status.SAME;
                    }
                    else if (dot < -epsilon)
                    {
                        Status = Status.OPPOSITE;
                    }
                }
                else if (dot > epsilon)
                {
                    Status = Status.INSIDE;
                }                                                    // 不重合,同向,在参数物件内部
                else if (dot < -epsilon)
                {
                    Status = Status.OUTSIDE;
                }                                                      // 不重合,反向,在参数物件外部
            }
        }
Пример #11
0
        //-----------------------------------OVERRIDES----------------------------------//
        /**
         * Clones the Object3D object
         *
         * @return cloned Object3D object
         */
        public Object3D Clone()
        {
            Object3D clone = new Object3D();
            clone.vertices = new List<Vertex>();
            for (int i = 0; i < vertices.Count; i++)
            {
                clone.vertices.Add(vertices[i].Clone());
            }
            clone.faces = new List<Face>();
            for (int i = 0; i < vertices.Count; i++)
            {
                clone.faces.Add(faces[i].Clone());
            }
            clone.bound = bound;

            return clone;
        }
Пример #12
0
        /// <summary>
        /// Split faces so that none face is intercepted by a face of other object
        /// </summary>
        /// <param name="obj">the other object 3d used to make the split</param>
        public void SplitFaces(Object3D obj)
        {
            Line    line;
            Face    face1, face2;
            Segment segment1;
            Segment segment2;
            double  distFace1Vert1, distFace1Vert2, distFace1Vert3, distFace2Vert1, distFace2Vert2, distFace2Vert3;
            int     signFace1Vert1, signFace1Vert2, signFace1Vert3, signFace2Vert1, signFace2Vert2, signFace2Vert3;
            int     numFacesBefore = NumFaces;
            int     numFacesStart  = NumFaces;

            //if the objects bounds overlap...
            if (_Bound.Overlap(obj._Bound))
            {
                //for each object1 face...
                for (int i = 0; i < NumFaces; i++)
                {
                    //if object1 face bound and object2 bound overlap ...
                    face1 = GetFace(i);

                    if (face1.GetBound().Overlap(obj._Bound))
                    {
                        //for each object2 face...
                        for (int j = 0; j < obj.NumFaces; j++)
                        {
                            //if object1 face bound and object2 face bound overlap...
                            face2 = obj.GetFace(j);
                            if (face1.GetBound().Overlap(face2.GetBound()))
                            {
                                //PART I - DO TWO POLIGONS INTERSECT?
                                //POSSIBLE RESULTS: INTERSECT, NOT_INTERSECT, COPLANAR

                                //distance from the face1 vertices to the face2 plane
                                distFace1Vert1 = ComputeDistance(face1.V1, face2);
                                distFace1Vert2 = ComputeDistance(face1.V2, face2);
                                distFace1Vert3 = ComputeDistance(face1.V3, face2);

                                //distances signs from the face1 vertices to the face2 plane
                                signFace1Vert1 = distFace1Vert1 > EqualityTolerance ? 1 : (distFace1Vert1 < -EqualityTolerance ? -1 : 0);
                                signFace1Vert2 = distFace1Vert2 > EqualityTolerance ? 1 : (distFace1Vert2 < -EqualityTolerance ? -1 : 0);
                                signFace1Vert3 = distFace1Vert3 > EqualityTolerance ? 1 : (distFace1Vert3 < -EqualityTolerance ? -1 : 0);

                                //if all the signs are zero, the planes are coplanar
                                //if all the signs are positive or negative, the planes do not intersect
                                //if the signs are not equal...
                                if (!(signFace1Vert1 == signFace1Vert2 && signFace1Vert2 == signFace1Vert3))
                                {
                                    //distance from the face2 vertices to the face1 plane
                                    distFace2Vert1 = ComputeDistance(face2.V1, face1);
                                    distFace2Vert2 = ComputeDistance(face2.V2, face1);
                                    distFace2Vert3 = ComputeDistance(face2.V3, face1);

                                    //distances signs from the face2 vertices to the face1 plane
                                    signFace2Vert1 = distFace2Vert1 > EqualityTolerance ? 1 : (distFace2Vert1 < -EqualityTolerance ? -1 : 0);
                                    signFace2Vert2 = distFace2Vert2 > EqualityTolerance ? 1 : (distFace2Vert2 < -EqualityTolerance ? -1 : 0);
                                    signFace2Vert3 = distFace2Vert3 > EqualityTolerance ? 1 : (distFace2Vert3 < -EqualityTolerance ? -1 : 0);

                                    //if the signs are not equal...
                                    if (!(signFace2Vert1 == signFace2Vert2 && signFace2Vert2 == signFace2Vert3))
                                    {
                                        line = new Line(face1, face2);

                                        //intersection of the face1 and the plane of face2
                                        segment1 = new Segment(line, face1, signFace1Vert1, signFace1Vert2, signFace1Vert3);

                                        //intersection of the face2 and the plane of face1
                                        segment2 = new Segment(line, face2, signFace2Vert1, signFace2Vert2, signFace2Vert3);

                                        //if the two segments intersect...
                                        if (segment1.Intersect(segment2))
                                        {
                                            //PART II - SUBDIVIDING NON-COPLANAR POLYGONS
                                            int lastNumFaces = NumFaces;
                                            SplitFace(i, segment1, segment2);

                                            //prevent from infinite loop (with a loss of faces...)
                                            // TODO: Determine a ideal face number.
                                            // 20 is too less!
                                            // 87 is required for the Sample Application
                                            // 1000 to be sure
                                            // Is there a better way?
                                            if (numFacesStart * 1000 < NumFaces)
                                            {
                                                Console.WriteLine("possible infinite loop situation: terminating faces split");
                                                return;
                                            }

                                            //if the face in the position isn't the same, there was a break
                                            if (face1 != GetFace(i))
                                            {
                                                //if the generated solid is equal the origin...
                                                if (face1.Equals(GetFace(NumFaces - 1)))
                                                {
                                                    //return it to its position and jump it
                                                    if (i != (NumFaces - 1))
                                                    {
                                                        Faces.RemoveAt(NumFaces - 1);
                                                        Faces.Insert(i, face1);
                                                    }
                                                    else
                                                    {
                                                        continue;
                                                    }
                                                }
                                                //else: test next face
                                                else
                                                {
                                                    i--;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #13
0
 /**
  * Fills solid arrays with data about faces of an object generated whose status
  * is as required
  *
  * @param object3d solid object used to fill the arrays
  * @param vertices vertices array to be filled
  * @param indices indices array to be filled
  * @param colors colors array to be filled
  * @param faceStatus1 a status expected for the faces used to to fill the data arrays
  * @param faceStatus2 a status expected for the faces used to to fill the data arrays
  */
 private void groupObjectComponents(Object3D obj, List<Vertex> vertices, List<int> indices, List<Color3f> colors, int faceStatus1, int faceStatus2)
 {
     Face face;
     //for each face..
     for (int i = 0; i < obj.getNumFaces(); i++)
     {
         face = obj.getFace(i);
         //if the face status fits with the desired status...
         if (face.getStatus() == faceStatus1 || face.getStatus() == faceStatus2)
         {
             //adds the face elements into the arrays
             Vertex[] faceVerts = { face.v1, face.v2, face.v3 };
             for (int j = 0; j < faceVerts.Length; j++)
             {
                 if (vertices.Contains(faceVerts[j]))
                 {
                     indices.Add(vertices.IndexOf(faceVerts[j]));
                 }
                 else
                 {
                     indices.Add(vertices.Count);
                     vertices.Add(faceVerts[j]);
                     colors.Add(faceVerts[j].getColor());
                 }
             }
         }
     }
 }
Пример #14
0
        //-------------------------FACES_SPLITTING_METHODS------------------------------//
        /**
         * Split faces so that none face is intercepted by a face of other object
         *
         * @param object the other object 3d used to make the split
         */
        public void splitFaces(Object3D obj)
        {
            Line line;
            Face face1, face2;
            Segment[] segments;
            Segment segment1;
            Segment segment2;
            double distFace1Vert1, distFace1Vert2, distFace1Vert3, distFace2Vert1, distFace2Vert2, distFace2Vert3;
            int signFace1Vert1, signFace1Vert2, signFace1Vert3, signFace2Vert1, signFace2Vert2, signFace2Vert3;
            int numFacesBefore = getNumFaces();
            int numFacesStart = getNumFaces();
            int facesIgnored = 0;

            //if the objects bounds overlap...
            if (getBound().overlap(obj.getBound()))
            {
                //for each object1 face...
                for (int i = 0; i < getNumFaces(); i++)
                {
                    //if object1 face bound and object2 bound overlap ...
                    face1 = getFace(i);

                    if (face1.getBound().overlap(obj.getBound()))
                    {
                        //for each object2 face...
                        for (int j = 0; j < obj.getNumFaces(); j++)
                        {
                            //if object1 face bound and object2 face bound overlap...
                            face2 = obj.getFace(j);
                            if (face1.getBound().overlap(face2.getBound()))
                            {
                                //PART I - DO TWO POLIGONS INTERSECT?
                                //POSSIBLE RESULTS: INTERSECT, NOT_INTERSECT, COPLANAR

                                //distance from the face1 vertices to the face2 plane
                                distFace1Vert1 = computeDistance(face1.v1, face2);
                                distFace1Vert2 = computeDistance(face1.v2, face2);
                                distFace1Vert3 = computeDistance(face1.v3, face2);

                                //distances signs from the face1 vertices to the face2 plane
                                signFace1Vert1 = (distFace1Vert1 > TOL ? 1 : (distFace1Vert1 < -TOL ? -1 : 0));
                                signFace1Vert2 = (distFace1Vert2 > TOL ? 1 : (distFace1Vert2 < -TOL ? -1 : 0));
                                signFace1Vert3 = (distFace1Vert3 > TOL ? 1 : (distFace1Vert3 < -TOL ? -1 : 0));

                                //if all the signs are zero, the planes are coplanar
                                //if all the signs are positive or negative, the planes do not intersect
                                //if the signs are not equal...
                                if (!(signFace1Vert1 == signFace1Vert2 && signFace1Vert2 == signFace1Vert3))
                                {
                                    //distance from the face2 vertices to the face1 plane
                                    distFace2Vert1 = computeDistance(face2.v1, face1);
                                    distFace2Vert2 = computeDistance(face2.v2, face1);
                                    distFace2Vert3 = computeDistance(face2.v3, face1);

                                    //distances signs from the face2 vertices to the face1 plane
                                    signFace2Vert1 = (distFace2Vert1 > TOL ? 1 : (distFace2Vert1 < -TOL ? -1 : 0));
                                    signFace2Vert2 = (distFace2Vert2 > TOL ? 1 : (distFace2Vert2 < -TOL ? -1 : 0));
                                    signFace2Vert3 = (distFace2Vert3 > TOL ? 1 : (distFace2Vert3 < -TOL ? -1 : 0));

                                    //if the signs are not equal...
                                    if (!(signFace2Vert1 == signFace2Vert2 && signFace2Vert2 == signFace2Vert3))
                                    {
                                        line = new Line(face1, face2);

                                        //intersection of the face1 and the plane of face2
                                        segment1 = new Segment(line, face1, signFace1Vert1, signFace1Vert2, signFace1Vert3);

                                        //intersection of the face2 and the plane of face1
                                        segment2 = new Segment(line, face2, signFace2Vert1, signFace2Vert2, signFace2Vert3);

                                        //if the two segments intersect...
                                        if (segment1.intersect(segment2))
                                        {
                                            //PART II - SUBDIVIDING NON-COPLANAR POLYGONS
                                            int lastNumFaces = getNumFaces();
                                            this.splitFace(i, segment1, segment2);

                                            //prevent from infinite loop (with a loss of faces...)
                                            //if(numFacesStart*20<getNumFaces())
                                            //{
                                            //  System.out.println("possible infinite loop situation: terminating faces split");
                                            //  return;
                                            //}

                                            //if the face in the position isn't the same, there was a break
                                            if (face1 != getFace(i))
                                            {
                                                //if the generated solid is equal the origin...
                                                if (face1.equals(getFace(getNumFaces() - 1)))
                                                {
                                                    //return it to its position and jump it
                                                    if (i != (getNumFaces() - 1))
                                                    {
                                                        faces.RemoveAt(getNumFaces() - 1);
                                                        faces.Insert(i, face1);
                                                    }
                                                    else
                                                    {
                                                        continue;
                                                    }
                                                }
                                                                                    //else: test next face
                                                                                    else
                                                {
                                                    i--;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #15
0
        /**
         * Classifies the face based on the ray trace technique
         *
         * @param object object3d used to compute the face status
         */
        public void rayTraceClassify(Object3D obj)
        {
            //creating a ray starting starting at the face baricenter going to the normal direction
            Point3d p0 = new Point3d();
            p0.x = (v1.x + v2.x + v3.x) / 3d;
            p0.y = (v1.y + v2.y + v3.y) / 3d;
            p0.z = (v1.z + v2.z + v3.z) / 3d;
            Line ray = new Line(getNormal(), p0);

            bool success;
            double dotProduct, distance;
            Point3d intersectionPoint;
            Face closestFace = null;
            double closestDistance;

            do
            {
                success = true;
                closestDistance = Double.MaxValue;
                //for each face from the other solid...
                for (int i = 0; i < obj.getNumFaces(); i++)
                {
                    Face face = obj.getFace(i);
                    dotProduct = face.getNormal().dot(ray.getDirection());
                    intersectionPoint = ray.computePlaneIntersection(face.getNormal(), face.v1.getPosition());

                    //if ray intersects the plane...
                    if (intersectionPoint != null)
                    {
                        distance = ray.computePointToPointDistance(intersectionPoint);

                        //if ray lies in plane...
                        if (Math.Abs(distance) < TOL && Math.Abs(dotProduct) < TOL)
                        {
                            //disturb the ray in order to not lie into another plane
                            ray.perturbDirection();
                            success = false;
                            break;
                        }

                        //if ray starts in plane...
                        if (Math.Abs(distance) < TOL && Math.Abs(dotProduct) > TOL)
                        {
                            //if ray intersects the face...
                            if (face.hasPoint(intersectionPoint))
                            {
                                //faces coincide
                                closestFace = face;
                                closestDistance = 0;
                                break;
                            }
                        }

                                    //if ray intersects plane...
                                    else if (Math.Abs(dotProduct) > TOL && distance > TOL)
                        {
                            if (distance < closestDistance)
                            {
                                //if ray intersects the face;
                                if (face.hasPoint(intersectionPoint))
                                {
                                    //this face is the closest face untill now
                                    closestDistance = distance;
                                    closestFace = face;
                                }
                            }
                        }
                    }
                }
            } while(success == false);

            //none face found: outside face
            if (closestFace == null)
            {
                status = OUTSIDE;
            }
            //face found: test dot product
            else
            {
                dotProduct = closestFace.getNormal().dot(ray.getDirection());

                //distance = 0: coplanar faces
                if (Math.Abs(closestDistance) < TOL)
                {
                    if (dotProduct > TOL)
                    {
                        status = SAME;
                    }
                    else if (dotProduct < -TOL)
                    {
                        status = OPPOSITE;
                    }
                }

                    //dot product > 0 (same direction): inside face
                    else if (dotProduct > TOL)
                {
                    status = INSIDE;
                }

                    //dot product < 0 (opposite direction): outside face
                    else if (dotProduct < -TOL)
                {
                    status = OUTSIDE;
                }
            }
        }
Пример #16
0
        /// <summary>
        /// Classifies the face based on the ray trace technique
        /// </summary>
        /// <param name="obj">object3d used to compute the face status</param>
        public void RayTraceClassify(Object3D obj)
        {
            //creating a ray starting at the face baricenter going to the normal direction
            Line ray = new Line(GetNormal(), center);

            bool    success;
            double  distance;
            Vector3 intersectionPoint;
            Face    closestFace = null;
            double  closestDistance;

            do
            {
                success         = true;
                closestDistance = Double.MaxValue;
                //for each face from the other solid...
                for (int faceIndex = 0; faceIndex < obj.GetNumFaces(); faceIndex++)
                {
                    Face face = obj.GetFace(faceIndex);
                    intersectionPoint = ray.ComputePlaneIntersection(face.GetPlane());

                    //if ray intersects the plane...
                    if (intersectionPoint.x != double.PositiveInfinity)
                    {
                        double dotProduct = Vector3.Dot(face.GetNormal(), ray.Direction);
                        distance = ray.ComputePointToPointDistance(intersectionPoint);

                        //if ray lies in plane...
                        if (Math.Abs(distance) < EqualityTolerance && Math.Abs(dotProduct) < EqualityTolerance)
                        {
                            //disturb the ray in order to not lie into another plane
                            ray.PerturbDirection();
                            success = false;
                            break;
                        }

                        //if ray starts in plane...
                        if (Math.Abs(distance) < EqualityTolerance && Math.Abs(dotProduct) > EqualityTolerance)
                        {
                            //if ray intersects the face...
                            if (face.ContainsPoint(intersectionPoint))
                            {
                                //faces coincide
                                closestFace     = face;
                                closestDistance = 0;
                                break;
                            }
                        }

                        //if ray intersects plane...
                        else if (Math.Abs(dotProduct) > EqualityTolerance && distance > EqualityTolerance)
                        {
                            if (distance < closestDistance)
                            {
                                //if ray intersects the face;
                                if (face.ContainsPoint(intersectionPoint))
                                {
                                    //this face is the closest face until now
                                    closestDistance = distance;
                                    closestFace     = face;
                                }
                            }
                        }
                    }
                }
            } while (success == false);


            if (closestFace == null)
            {
                //none face found: outside face
                status = Status.OUTSIDE;
            }
            else             //face found: test dot product
            {
                double dotProduct = Vector3.Dot(closestFace.GetNormal(), ray.Direction);

                //distance = 0: coplanar faces
                if (Math.Abs(closestDistance) < EqualityTolerance)
                {
                    if (dotProduct > EqualityTolerance)
                    {
                        status = Status.SAME;
                    }
                    else if (dotProduct < -EqualityTolerance)
                    {
                        status = Status.OPPOSITE;
                    }
                }
                else if (dotProduct > EqualityTolerance)
                {
                    //dot product > 0 (same direction): inside face
                    status = Status.INSIDE;
                }
                else if (dotProduct < -EqualityTolerance)
                {
                    //dot product < 0 (opposite direction): outside face
                    status = Status.OUTSIDE;
                }
            }
        }
Пример #17
0
        //-----------------------------------OTHERS-------------------------------------//
        /**
         * Classify faces as being inside, outside or on boundary of other object
         *
         * @param object object 3d used for the comparison
         */
        public void classifyFaces(Object3D obj)
        {
            //calculate adjacency information
            Face face;
            for (int i = 0; i < this.getNumFaces(); i++)
            {
                face = this.getFace(i);
                face.v1.addAdjacentVertex(face.v2);
                face.v1.addAdjacentVertex(face.v3);
                face.v2.addAdjacentVertex(face.v1);
                face.v2.addAdjacentVertex(face.v3);
                face.v3.addAdjacentVertex(face.v1);
                face.v3.addAdjacentVertex(face.v2);
            }

            //for each face
            for (int i = 0; i < getNumFaces(); i++)
            {
                face = getFace(i);

                //if the face vertices aren't classified to make the simple classify
                if (face.simpleClassify() == false)
                {
                    //makes the ray trace classification
                    face.rayTraceClassify(obj);

                    //mark the vertices
                    if (face.v1.getStatus() == Vertex.UNKNOWN)
                    {
                        face.v1.mark(face.getStatus());
                    }
                    if (face.v2.getStatus() == Vertex.UNKNOWN)
                    {
                        face.v2.mark(face.getStatus());
                    }
                    if (face.v3.getStatus() == Vertex.UNKNOWN)
                    {
                        face.v3.mark(face.getStatus());
                    }
                }
            }
        }