示例#1
0
        /// <summary>
        /// Fills solid arrays with data about faces of an object generated whose status is as required
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="vertices"></param>
        /// <param name="indices"></param>
        /// <param name="faceStatus1"></param>
        /// <param name="faceStatus2"></param>
        private void GroupObjectComponents(CsgObject3D obj, List <Vertex> vertices, List <int> indices, FaceStatus faceStatus1, FaceStatus faceStatus2)
        {
            var vertexIndexByHashCode = new Dictionary <Vector3, int>();

            //for each face..
            foreach (CsgFace face in obj.Faces.All())
            {
                //if the face status fits with the desired status...
                if (face.Status == faceStatus1 || face.Status == 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 (vertexIndexByHashCode.ContainsKey(faceVerts[j].Position))
                        {
                            indices.Add(vertexIndexByHashCode[faceVerts[j].Position]);
                        }
                        else
                        {
                            vertexIndexByHashCode.Add(faceVerts[j].Position, vertices.Count);
                            indices.Add(vertices.Count);
                            vertices.Add(faceVerts[j]);
                        }
                    }
                }
            }
        }
示例#2
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(CsgObject3D otherObject, CancellationToken cancellationToken, Action <CsgFace> classifyFaces = null)
        {
            var otherBounds = otherObject.Bounds;

            foreach (var vertex in vertices)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (!otherBounds.Contains(vertex.Position) &&
                    vertex.Status != FaceStatus.Outside)
                {
                    vertex.Status = FaceStatus.Outside;
                }
            }

            //calculate adjacency information
            Faces.All();
            foreach (var face in Faces.QueryResults)
            {
                cancellationToken.ThrowIfCancellationRequested();

                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
            foreach (var face in Faces.QueryResults)
            {
                cancellationToken.ThrowIfCancellationRequested();

                // If the face vertices can't be classified with the simple classify
                if (face.SimpleClassify() == false)
                {
                    //makes the ray trace classification
                    face.RayTraceClassify(otherObject);

                    //mark the vertices
                    if (face.v1.Status == FaceStatus.Unknown)
                    {
                        face.v1.Mark(face.Status);
                    }
                    if (face.v2.Status == FaceStatus.Unknown)
                    {
                        face.v2.Mark(face.Status);
                    }
                    if (face.v3.Status == FaceStatus.Unknown)
                    {
                        face.v3.Mark(face.Status);
                    }
                }

                classifyFaces?.Invoke(face);
            }
        }
示例#3
0
        public BooleanModeller(Solid solid1, Solid solid2, Action <string, double> reporter, CancellationToken cancellationToken)
        {
            this.reporter          = reporter;
            this.cancellationToken = cancellationToken;

            //representation to apply boolean operations
            reporter?.Invoke("Create Csg Object 1", 0.1);
            object1 = new CsgObject3D(solid1);

            reporter?.Invoke("Create Csg Object 2", 0.2);
            object2 = new CsgObject3D(solid2);

            object1Copy = new CsgObject3D(solid1);
        }
示例#4
0
        private void PrepareData()
        {
            if (object1Copy != null)
            {
                //split the faces so that none of them intercepts each other
                reporter?.Invoke("Split Faces 1", 0.4);
                object1.SplitFaces(object2, cancellationToken, Object1SplitFace, Object1SplitResults);

                reporter?.Invoke("Split Faces 2", 0.6);
                object2.SplitFaces(object1Copy, cancellationToken, Object2SplitFace, Object2SplitResults);
                // free the memory
                object1Copy = null;

                //classify faces as being inside or outside the other solid
                reporter?.Invoke("Classify Faces 1", 0.8);
                object1.ClassifyFaces(object2, Object1ClassifyFace);

                reporter?.Invoke("Classify Faces 2", 0.9);
                object2.ClassifyFaces(object1, Object2ClassifyFace);
            }
        }
示例#5
0
        /// <summary>
        /// Split faces so that no 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(CsgObject3D compareObject, CancellationToken cancellationToken,
                               Action <CsgFace, CsgFace> splitFaces = null,
                               Action <List <CsgFace> > results     = null)
        {
            Stack <CsgFace> newFacesFromSplitting = new Stack <CsgFace>();

            int numFacesStart = this.Faces.Count;

            //if the objects bounds overlap...
            //for each object1 face...
            var bounds = compareObject.GetBound();

            Faces.SearchBounds(bounds);
            foreach (var thisFaceIn in Faces.QueryResults)             // put it in an array as we will be adding new faces to it
            {
                newFacesFromSplitting.Push(thisFaceIn);
                // make sure we process every face that we have added during splitting before moving on to the next face
                while (newFacesFromSplitting.Count > 0)
                {
                    var faceToSplit = newFacesFromSplitting.Pop();

                    // stop processing if operation has been canceled
                    cancellationToken.ThrowIfCancellationRequested();

                    //if object1 face bound and object2 bound overlap ...
                    //for each object2 face...
                    compareObject.Faces.SearchBounds(faceToSplit.GetBound());
                    foreach (var cuttingFace in compareObject.Faces.QueryResults)
                    {
                        //if object1 face bound and object2 face bound overlap...
                        //PART I - DO TWO POLIGONS INTERSECT?
                        //POSSIBLE RESULTS: INTERSECT, NOT_INTERSECT, COPLANAR

                        //distance from the face1 vertices to the face2 plane
                        double v1DistToCuttingFace = cuttingFace.DistanceFromPlane(faceToSplit.v1);
                        double v2DistToCuttingFace = cuttingFace.DistanceFromPlane(faceToSplit.v2);
                        double v3DistToCuttingFace = cuttingFace.DistanceFromPlane(faceToSplit.v3);

                        //distances signs from the face1 vertices to the face2 plane
                        PlaneSide sideFace1Vert1 = (v1DistToCuttingFace > EqualityTolerance ? PlaneSide.Front : (v1DistToCuttingFace < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));
                        PlaneSide sideFace1Vert2 = (v2DistToCuttingFace > EqualityTolerance ? PlaneSide.Front : (v2DistToCuttingFace < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));
                        PlaneSide sideFace1Vert3 = (v3DistToCuttingFace > EqualityTolerance ? PlaneSide.Front : (v3DistToCuttingFace < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));

                        //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 (!(sideFace1Vert1 == sideFace1Vert2 && sideFace1Vert2 == sideFace1Vert3))
                        {
                            //distance from the face2 vertices to the face1 plane
                            double faceToSplitTo1 = faceToSplit.DistanceFromPlane(cuttingFace.v1);
                            double faceToSplitTo2 = faceToSplit.DistanceFromPlane(cuttingFace.v2);
                            double faceToSplitTo3 = faceToSplit.DistanceFromPlane(cuttingFace.v3);

                            //distances signs from the face2 vertices to the face1 plane
                            PlaneSide signFace2Vert1 = (faceToSplitTo1 > EqualityTolerance ? PlaneSide.Front : (faceToSplitTo1 < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));
                            PlaneSide signFace2Vert2 = (faceToSplitTo2 > EqualityTolerance ? PlaneSide.Front : (faceToSplitTo2 < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));
                            PlaneSide signFace2Vert3 = (faceToSplitTo3 > EqualityTolerance ? PlaneSide.Front : (faceToSplitTo3 < -EqualityTolerance ? PlaneSide.Back : PlaneSide.On));

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

                                //intersection of the face1 and the plane of face2
                                var segment1 = new Segment(line, faceToSplit, sideFace1Vert1, sideFace1Vert2, sideFace1Vert3);

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

                                //if the two segments intersect...
                                if (segment1.Intersect(segment2))
                                {
                                    //PART II - SUBDIVIDING NON-COPLANAR POLYGONS
                                    Stack <CsgFace> facesFromSplit = new Stack <CsgFace>();

                                    if (this.SplitFace(faceToSplit, segment1, segment2, facesFromSplit) &&
                                        facesFromSplit.Count > 0 &&
                                        !(facesFromSplit.Count == 1 && facesFromSplit.Peek().Equals(faceToSplit)))
                                    {
                                        foreach (var face in facesFromSplit)
                                        {
                                            newFacesFromSplitting.Push(face);
                                        }

                                        // send debugging information if registered
                                        splitFaces?.Invoke(faceToSplit, cuttingFace);
                                        results?.Invoke(facesFromSplit.ToList());

                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
示例#6
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(CsgObject3D obj)
        {
            var random = new Random();

            //creating a ray starting at the face baricenter going to the normal direction
            Ray ray = new Ray(center, Normal);

            //Line ray = new Line(GetNormal(), center);
            ray.PerturbDirection(random);

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

            do
            {
                success         = true;
                closestDistance = Double.MaxValue;
                //for each face from the other solid...
                //foreach (Face face in obj.Faces.AllObjects())
                obj.Faces.AlongRay(ray);
                foreach (var face in obj.Faces.QueryResults)
                {
                    double hitDistance;
                    bool   front;

                    //if ray intersects the plane...
                    if (face.Plane.RayHitPlane(ray, out hitDistance, out front))
                    {
                        double dotProduct = Vector3.Dot(face.Normal, ray.directionNormal);
                        distance                  = hitDistance;
                        intersectionPoint         = ray.origin + ray.directionNormal * hitDistance;
                        ray.maxDistanceToConsider = hitDistance;

                        //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(random);
                            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 = FaceStatus.Outside;
            }
            else             //face found: test dot product
            {
                double dotProduct = Vector3.Dot(closestFace.Normal, ray.directionNormal);

                //distance = 0: coplanar faces
                if (Math.Abs(closestDistance) < EqualityTolerance)
                {
                    if (dotProduct > EqualityTolerance)
                    {
                        Status = FaceStatus.Same;
                    }
                    else if (dotProduct < -EqualityTolerance)
                    {
                        Status = FaceStatus.Opposite;
                    }
                }
                else if (dotProduct > EqualityTolerance)
                {
                    //dot product > 0 (same direction): inside face
                    Status = FaceStatus.Inside;
                }
                else if (dotProduct < -EqualityTolerance)
                {
                    //dot product < 0 (opposite direction): outside face
                    Status = FaceStatus.Outside;
                }
            }
        }