Ejemplo n.º 1
0
        /// <summary>
        /// Touch check between 2 faces. Currently only returns true/false. Should be improved with a new face that overlap between the 2 input faces
        /// </summary>
        /// <param name="F1">Face 1</param>
        /// <param name="F2">Face 2</param>
        /// <returns></returns>
        public static bool touch(Face3D F1, Face3D F2)
        {
            if (Vector3D.Parallels(F1._basePlane.normalVector, F2._basePlane.normalVector))
            {
                // test for any point inside another face
                for (int i = 0; i < F2._vertices.Count; i++)
                {
                    if (Face3D.inside(F1, F2._vertices[i]))
                    {
                        return(true);
                    }
                }
                for (int i = 0; i < F1._vertices.Count; i++)
                {
                    if (Face3D.inside(F2, F1._vertices[i]))
                    {
                        return(true);
                    }
                }
                // if still not returning true, test whether the edges intersect
                List <Point3D> intPoints = new List <Point3D>();
                for (int i = 0; i < F2.boundaries.Count; ++i)
                {
                    if (Face3D.intersect(F1, F2.boundaries[i], out intPoints))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Test a linesegment is completely inside a bounded face. For it to be true, it must fulfill:
        /// 1. Both endpoints are inside the face
        /// 2. the segment does not intersect the face
        /// </summary>
        /// <param name="F1">The Face</param>
        /// <param name="LS">The Line Segment</param>
        /// <returns>true=inside; otherwise false</returns>
        public static bool inside(Face3D F1, LineSegment3D LS)
        {
            // Line segment must completely lie on the face
            LineSegment3D lineS1 = new LineSegment3D(F1.basePlane.point, LS.startPoint);
            LineSegment3D lineS2 = new LineSegment3D(F1.basePlane.point, LS.endPoint);

            double d1 = Vector3D.DotProduct(F1.basePlane.normalVector, lineS1.baseLine.direction);
            double d2 = Vector3D.DotProduct(F1.basePlane.normalVector, lineS2.baseLine.direction);

            if (!MathUtils.equalTol(d1, 0.0, MathUtils.defaultTol) || !MathUtils.equalTol(d2, 0.0, MathUtils.defaultTol))
            {
                return(false);                                                                                                              // The segment does not lie on the face/plane
            }
            // To optimize the algorithm a little bit, we will change the way we test:
            // First we do intersection test between the face and the linesegment
            // Second we test at least one point must be inside the face
            List <Point3D> iPoints = new List <Point3D>();
            bool           ret     = intersect(F1, LS, out iPoints);

            if (ret)
            {
                return(false);                      // The segment intersect the face
            }
            // Test whether at least one point is inside the face
            ret = inside(F1, LS.startPoint);
            if (ret)
            {
                return(true);
            }
            return(false);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Testing intersection between a line segment and a polyhedron and return ALL intersection points
        /// </summary>
        /// <param name="polyH">Polyhedron</param>
        /// <param name="lineS">Line segment</param>
        /// <param name="intPoints">List of intersection points</param>
        /// <returns></returns>
        public static bool intersect(Polyhedron polyH, LineSegment3D lineS, out List <Point3D> intPoints)
        {
            List <Point3D> iPoints = new List <Point3D>();

            intPoints = iPoints;

            List <Point3D> corners = new List <Point3D>();

            corners.Add(lineS.startPoint);
            corners.Add(lineS.endPoint);
            BoundingBox3D bound       = new BoundingBox3D(corners);
            List <Face3D> reducedList = Face3D.exclFacesOutsideOfBound(polyH.Faces, bound, 0x111);

            if (reducedList.Count == 0)
            {
                return(false);                       // no faces left, either they are all on the left or they are all on the right
            }
            // Now test whether there is any intersection. It needs to complete the test with entire faces to collect the intersection points
            for (int i = 0; i < reducedList.Count; i++)
            {
                List <Point3D> iPts = new List <Point3D>();
                if (Face3D.intersect(reducedList[i], lineS, out iPts))
                {
                    for (int j = 0; j < iPts.Count; j++)
                    {
                        iPoints.Add(iPts[j]);
                    }
                }
            }
            if (iPoints.Count > 0)
            {
                return(true);
            }
            return(false);
        }
Ejemplo n.º 4
0
        public static bool isNullFace(Face3D theFace)
        {
            Point3D firstP   = null;
            bool    first    = true;
            bool    nullFace = false;

            foreach (Point3D p in theFace.vertices)
            {
                if (first)
                {
                    firstP = p;
                    first  = false;
                }
                else
                {
                    if (p == firstP)
                    {
                        nullFace = true;
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            return(nullFace);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// A static function to offset a face. It basically shifts the entire face according to the supplies vector value
        /// </summary>
        /// <param name="theFace">the Face to be shifted</param>
        /// <param name="offsetVector">the vector value to shift the Face</param>
        /// <returns>the new Face</returns>
        public static Face3D offsetFace(Face3D theFace, Vector3D offsetVector)
        {
            List <List <Point3D> > newFaceVerts  = new List <List <Point3D> >();
            List <Point3D>         newOuterVerts = new List <Point3D>();

            foreach (Point3D p in theFace.verticesWithHoles[0])
            {
                Point3D newP = new Point3D();
                newP = p + offsetVector;
                newOuterVerts.Add(newP);
            }
            newFaceVerts.Add(newOuterVerts);
            for (int i = 1; i < theFace.verticesWithHoles.Count; ++i)
            {
                List <Point3D> newInnerVerts = new List <Point3D>();
                foreach (Point3D p in theFace.verticesWithHoles[i])
                {
                    Point3D newP = new Point3D();
                    newP = p + offsetVector;
                    newInnerVerts.Add(newP);
                }
                newFaceVerts.Add(newInnerVerts);
            }
            Face3D newFace = new Face3D(newFaceVerts);

            return(newFace);
        }
Ejemplo n.º 6
0
        public static bool Overlaps(Plane3D P1, Face3D F1)
        {
            bool parallel = Vector3D.Parallels(P1.normalVector, F1.basePlane.normalVector);
            bool pOnPlane = pointOnPlane(P1, F1.vertices[0]);

            // if the normals are the same and point in P2 is also point in P1, the two planes are overlapped
            return(parallel && pOnPlane);
        }
Ejemplo n.º 7
0
 public Face3DLW(Face3D f3d)
 {
     vertices = new List <Point3DLW>();
     foreach (Point3D p in f3d.vertices)
     {
         vertices.Add(new Point3DLW(p));
     }
 }
Ejemplo n.º 8
0
        public static bool validateFace(Face3D face)
        {
            if (double.IsNaN(face.basePlane.normalVector.X) || double.IsNaN(face.basePlane.normalVector.Y) || double.IsNaN(face.basePlane.normalVector.Z) ||
                (face.basePlane.normalVector.X == 0.0 && face.basePlane.normalVector.Y == 0.0 && face.basePlane.normalVector.Z == 0.0))
            {
                return(false);
            }

            return(true);
        }
Ejemplo n.º 9
0
 /// <summary>
 /// To determin a face is inside a polyhedron, all the segments must be completely inside the polyhedron (fulfills the inside test for linesegment)
 /// </summary>
 /// <param name="polyH"></param>
 /// <param name="face"></param>
 /// <returns></returns>
 public static bool inside(Polyhedron polyH, Face3D face)
 {
     for (int i = 0; i < face.boundaries.Count; i++)
     {
         if (!inside(polyH, face.boundaries[i]))
         {
             return(false);
         }
     }
     return(true);
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Testing a point inside a polyhedron is similar with the 2D version of a point inside a polygon by testing intersection between a ray starting from the point.
        /// If the number of intersection is odd the point is inside. In 3D the intersection is against the Faces
        /// </summary>
        /// <param name="polyH"></param>
        /// <param name="aPoint"></param>
        /// <returns></returns>
        public static bool inside(Polyhedron polyH, Point3D aPoint)
        {
            double extent = 0;

            if (Octree.WorldBB == null)
            {
                extent = Point3D.distance(polyH.boundingBox.LLB, polyH.boundingBox.URT);
            }
            else
            {
                extent = Octree.WorldBB.extent;
            }

            // define a ray using linesegment from the point toward and along +X-axis with 2*the extent of the World BB to ensure ray is always long enough
            LineSegment3D  ray         = new LineSegment3D(aPoint, new Point3D(aPoint.X + 2 * extent, aPoint.Y, aPoint.Z));
            List <Face3D>  reducedList = Face3D.inclFacesBeyondAxis(polyH.Faces, new Plane3D(aPoint, new Vector3D(1.0, 0.0, 0.0))); // beyond YZ plane
            List <Point3D> corners     = new List <Point3D>();

            corners.Add(aPoint);
            corners.Add(aPoint);
            BoundingBox3D bound = new BoundingBox3D(corners);

            if (reducedList.Count > 0)
            {
                reducedList = Face3D.exclFacesOutsideOfBound(reducedList, bound, 0x011); // reduce list on Y and Z both direction
            }
            if (reducedList.Count == 0)
            {
                return(false);                       // no faces left, either they are all on the left or they are all on the right
            }
            int iCount = 0;

            for (int i = 0; i < reducedList.Count; i++)
            {
                List <Point3D> intPts = new List <Point3D>();
                if (Face3D.intersect(reducedList[i], ray, out intPts))
                {
                    iCount++;
                }
            }
            if ((iCount % 2) == 1)
            {
                return(true);
            }
            return(false);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Calculating an intersection between a Face and a LineSegment
        /// </summary>
        /// <param name="F1">the Face3D</param>
        /// <param name="LS">the Line Segment</param>
        /// <param name="intPoint">the intersection point</param>
        /// <returns></returns>
        public static bool intersect(Face3D F1, LineSegment3D LS, out List <Point3D> intPoints)
        {
            intPoints = new List <Point3D>();
            Point3D intPt = new Point3D();

            // There are 2 possible cases: 1. Line punching the face, 2. Line lies on the same plane as the face
            // Test whether the line is on the same plane
            if (MathUtils.equalTol(Vector3D.DotProduct(F1.basePlane.normalVector, LS.baseLine.direction), 0.0, MathUtils.defaultTol))
            {
                // test whether at least one point of the segment is on the plane
                if (!Plane3D.pointOnPlane(F1.basePlane, LS.startPoint))
                {
                    return(false);       // line is parallel with the plane, no intersection
                }
                LineSegmentIntersectEnum mode = LineSegmentIntersectEnum.Undefined;
                for (int i = 0; i < F1.boundaries.Count; i++)
                {
                    bool st = LineSegment3D.intersect(F1.boundaries[i], LS, out intPt, out mode);
                    if (st)
                    {
                        intPoints.Add(intPt);
                    }
                }
                if (intPoints.Count > 0)
                {
                    return(true);
                }
                return(false);
            }
            else
            {
                bool res = Plane3D.PLintersect(F1.basePlane, LS, out intPt);
                if (res == false)
                {
                    return(false);                          // intersection occurs beyond the line segment
                }
                // There is intersection point, test whether the point in within (inside the boundary of the face boundaries
                res = inside(F1, intPt);
                if (res)
                {
                    intPoints.Add(intPt);
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// To determine that a line segment is inside (completely inside) of a polyhedron, it must satisfy the following:
        /// 1. both end points are inside the polyhedron
        /// 2. There no intersection between the segment and the polyhedron
        /// </summary>
        /// <param name="polyH"></param>
        /// <param name="lineS"></param>
        /// <returns></returns>
        public static bool inside(Polyhedron polyH, LineSegment3D lineS)
        {
            // reducing the face candidate list is less expensive than inside test, do it first
            Point3D leftX  = new Point3D();
            Point3D rightX = new Point3D();

            leftX.X  = lineS.startPoint.X < lineS.endPoint.X ? lineS.startPoint.X : lineS.endPoint.X;
            rightX.X = lineS.startPoint.X < lineS.endPoint.X ? lineS.endPoint.X : lineS.startPoint.X;
            List <Face3D> reducedList = Face3D.inclFacesBeyondAxis(polyH.Faces, new Plane3D(leftX, new Vector3D(1.0, 0.0, 0.0)));
            // reducedList = Face3D.exclFacesBeyondAxis(reducedList, rightX);   // cannot remove this otherwise inside test for StartPoint may not be correct!!!
            List <Point3D> corners = new List <Point3D>();

            corners.Add(lineS.startPoint);
            corners.Add(lineS.endPoint);
            BoundingBox3D bound = new BoundingBox3D(corners);

            if (reducedList.Count > 0)
            {
                reducedList = Face3D.exclFacesOutsideOfBound(reducedList, bound, 0x011); // reduce list on Y and Z both direction
            }
            if (reducedList.Count == 0)
            {
                return(false);                       // no faces left, either they are all on the left or they are all on the right
            }
            // inside test for both segment ends. Test one by one so that we can exit when any one of them are not inside
            if (!inside(polyH, lineS.startPoint))
            {
                return(false);
            }
            if (!inside(polyH, lineS.endPoint))
            {
                return(false);
            }

            // Now test whether there is any intersection. If there is, the segment is not completely inside
            for (int i = 0; i < reducedList.Count; i++)
            {
                List <Point3D> iPoints = new List <Point3D>();
                if (Face3D.intersect(reducedList[i], lineS, out iPoints))
                {
                    return(false);
                }
            }
            return(true);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Test whether a Face (bounded plane) intersects with a plane
        /// </summary>
        /// <param name="P1">Plane</param>
        /// <param name="F1">Face</param>
        /// <param name="intersectingLine">Resulting intercting linesegment (bounded)</param>
        /// <returns></returns>
        public static bool PPintersect(Plane3D P1, Face3D F1, out LineSegment3D intersectingLine)
        {
            Line3D        intLine = new Line3D();
            LineSegment3D ls      = new LineSegment3D(new Point3D(0.0, 0.0, 0.0), new Point3D(1.0, 1.0, 1.0));

            intersectingLine = ls;

            // Intersect operation: get the intersection (unbounded) line
            if (!PPintersect(P1, F1.basePlane, out intLine))
            {
                return(false);
            }

            // Now needs to check get the segment by getting intersecting points between the line and the Face boundaries
            List <Point3D> intPts = new List <Point3D>();
            // Use line segment that is large enough to ensure it covers the extent of the face
            //double extent = Point3D.distance(F1.boundingBox.LLB, F1.boundingBox.URT) * 10;        // Bug: NOT big enough for some cases!, use worldBB extent
            double extent;

            if (Octree.WorldBB == null)
            {
                extent = 1000000000;
            }
            else
            {
                extent = Octree.WorldBB.extent * 10;
            }
            LineSegment3D intLS = new LineSegment3D(new Point3D(intLine.point - (intLine.direction * extent)), new Point3D(intLine.point + (intLine.direction * extent)));

            bool res = Face3D.intersect(F1, intLS, out intPts);

            if (res)
            {
                intersectingLine.startPoint = intPts[0];
                intersectingLine.endPoint   = intPts[intPts.Count - 1];
                return(true);
            }
            return(false);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Test intersection between a polyhedron and a face. There is optmization applied for axis-aligned face (useful for Octree cells as they are all axis aligned)
        /// </summary>
        /// <param name="polyH">The Polyhedron</param>
        /// <param name="face">The face to test the intersection</param>
        /// <returns>true=intersected; false otherwise</returns>
        public static bool intersect(Polyhedron polyH, Face3D face)
        {
            List <Face3D> faceList = new List <Face3D>();
            BoundingBox3D bound    = new BoundingBox3D(face.vertices);

            faceList = Face3D.exclFacesOutsideOfBound(polyH.Faces, bound, 0x111);

            if (faceList.Count == 0)
            {
                return(false);                   // There is no face remaining to test, return false
            }
            for (int i = 0; i < faceList.Count; i++)
            {
                FaceIntersectEnum mode;
                LineSegment3D     intL = new LineSegment3D(new Point3D(), new Point3D());
                bool status            = Face3D.intersect(face, faceList[i], out intL, out mode);
                if (status == true)
                {
                    return(true);                   // return true as soon as an intersection is detected
                }
            }
            return(false);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Test a face is completely inside another face. For it to be true, it must fulfill:
        /// 1. All the vertices are inside the other face
        /// 2. There is no intersection between the edges with the other face
        /// </summary>
        /// <param name="F1">The Face</param>
        /// <param name="F2">The other face to test whether it is inside the first face</param>
        /// <returns>true=inside, otherwise false</returns>
        public static bool inside(Face3D F1, Face3D F2)
        {
            // Do intersection first
            for (int i = 0; i < F1.boundaries.Count; i++)
            {
                for (int j = 0; j < F2.boundaries.Count; j++)
                {
                    Point3D iPoint = new Point3D();
                    LineSegmentIntersectEnum mode;
                    if (LineSegment3D.intersect(F1.boundaries[i], F2.boundaries[j], out iPoint, out mode))
                    {
                        return(false);                                                                                      // there is intersection
                    }
                }
            }

            // If there is no intersection, at least one vertex of F2 must be inside F1
            if (inside(F1, F2.vertices[0]))
            {
                return(true);                               // one vertex of F2 is inside F1 and there is no intersection
            }
            return(false);
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Compute Octree for a face
        /// </summary>
        /// <param name="elementID"></param>
        /// <param name="face"></param>
        /// <param name="forUserDict"></param>
        public void ComputeOctree(string elementID, Face3D face, bool forUserDict)
        {
            // Make sure ElementID string is 22 character long for correct encoding/decoding
            if (elementID.Length < 22)
            {
                elementID = elementID.PadLeft(22, '0');
            }

            ElementID eidNo = new ElementID(elementID);
            Tuple <UInt64, UInt64> elementIDNo = eidNo.ElementIDNo;

            OctreeNode theTree = new OctreeNode();

            // Add a step:
            // 1. Find the smallest containing cell based on the Face BB, it it to quickly eliminate the irrelevant cells very quickly
            theTree.nodeCellID = OctreeNodeProcess.getSmallestContainingCell(face);
            theTree._depth     = theTree.nodeCellID.Level;

            OctreeNodeProcess.Process(theTree, face);
            List <CellID64> collCellID;
            List <int>      collBorderFlag;

            OctreeNodeProcess.collectCellIDs(theTree, out collCellID, out collBorderFlag);
            for (int i = 0; i < collCellID.Count; ++i)
            {
                if (forUserDict)
                {
                    insertDataToUserDict(elementIDNo, collCellID[i], collBorderFlag[i], false);
                }
                else
                {
                    //insertDataToDictDB(elementID, collCellID[i]);
                    insertDataToDict(elementIDNo, collCellID[i]);
                }
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Testing intersection between a line segment and a polyhedron only. It stops at the first intersection
        /// </summary>
        /// <param name="polyH">polyhedron</param>
        /// <param name="lineS">Line segment</param>
        /// <returns></returns>
        public static bool intersect(Polyhedron polyH, LineSegment3D lineS)
        {
            List <Point3D> corners = new List <Point3D>();

            corners.Add(lineS.startPoint);
            corners.Add(lineS.endPoint);
            BoundingBox3D bound       = new BoundingBox3D(corners);
            List <Face3D> reducedList = Face3D.exclFacesOutsideOfBound(polyH.Faces, bound, 0x111);

            if (reducedList.Count == 0)
            {
                return(false);                       // no faces left, either they are all on the left or they are all on the right
            }
            // Now test whether there is any intersection.
            for (int i = 0; i < reducedList.Count; i++)
            {
                List <Point3D> iPoints = new List <Point3D>();
                if (Face3D.intersect(reducedList[i], lineS, out iPoints))
                {
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 18
0
 public static CellID64 getSmallestContainingCell(Face3D face)
 {
     return(getSmallestContainingCell(face.boundingBox));
 }
Ejemplo n.º 19
0
 public bool intersectWith(Face3D F)
 {
     return(Polyhedron.intersect(this._polyHRep, F));
 }
Ejemplo n.º 20
0
        /// <summary>
        /// Test a point is inside a face
        /// </summary>
        /// <param name="F1"></param>
        /// <param name="P1"></param>
        /// <returns></returns>
        public static bool inside(Face3D F1, Point3D P1)
        {
            if (!Plane3D.pointOnPlane(F1.basePlane, P1))
            {
                return(false);                                          // Point is not on a plane
            }
            // test Point inside a Face
            // Need to project the plane to 2D (XY-, YZ-, or XZ- plane). It should work well with convex face (esp. triangles and rectangles we will deal with mostly)
            double maxDim     = Double.MinValue;
            int    DimttoZero = 0;

            // First test whether the plane is already axis-aligned (in this case we can just remove the appropriate axis)
            if (MathUtils.equalTol(F1.basePlane.normalVector.Y, 0.0, MathUtils.defaultTol) && MathUtils.equalTol(F1.basePlane.normalVector.Z, 0.0, MathUtils.defaultTol))
            {
                DimttoZero = 0;     // Ignore X, project to Y-Z plane
            }
            else if (MathUtils.equalTol(F1.basePlane.normalVector.X, 0.0, MathUtils.defaultTol) && MathUtils.equalTol(F1.basePlane.normalVector.Z, 0.0, MathUtils.defaultTol))
            {
                DimttoZero = 1;     // Ignore Y, project to X-Z plane
            }
            else if (MathUtils.equalTol(F1.basePlane.normalVector.X, 0.0, MathUtils.defaultTol) && MathUtils.equalTol(F1.basePlane.normalVector.Y, 0.0, MathUtils.defaultTol))
            {
                DimttoZero = 2;     // Ignore Z, project to X-Y plane
            }
            else
            {
                if (maxDim < Math.Abs(F1.basePlane.normalVector.X))
                {
                    maxDim     = Math.Abs(F1.basePlane.normalVector.X);
                    DimttoZero = 0;
                }
                if (maxDim < Math.Abs(F1.basePlane.normalVector.Y))
                {
                    maxDim     = Math.Abs(F1.basePlane.normalVector.Y);
                    DimttoZero = 1;
                }
                if (maxDim < Math.Abs(F1.basePlane.normalVector.Z))
                {
                    maxDim     = Math.Abs(F1.basePlane.normalVector.Z);
                    DimttoZero = 2;
                }
            }

            // We ignore the largest component, which means the least impact to the projection plane
            List <Point3D> projVert = new List <Point3D>();
            Point3D        projIntP = new Point3D(P1.X, P1.Y, P1.Z);
            Point3D        rayEndP  = new Point3D(P1.X, P1.Y, P1.Z);

            if (DimttoZero == 0)
            {
                for (int i = 0; i < F1.vertices.Count; i++)
                {
                    projVert.Add(new Point3D(0.0, F1.vertices[i].Y, F1.vertices[i].Z));
                }
                projIntP.X = 0.0;
                rayEndP.X  = 0.0;
                if (Octree.WorldBB == null)
                {
                    rayEndP.Y += Point3D.distance(F1.containingBB.URT, F1.containingBB.LLB) * 1000;
                }
                else
                {
                    rayEndP.Y += Octree.WorldBB.extent * 2;
                }
            }
            else if (DimttoZero == 1)
            {
                for (int i = 0; i < F1.vertices.Count; i++)
                {
                    projVert.Add(new Point3D(F1.vertices[i].X, 0.0, F1.vertices[i].Z));
                }
                projIntP.Y = 0.0;
                rayEndP.Y  = 0.0;
                //rayEndP.Z += Point3D.distance(F1.containingBB.URT, F1.containingBB.LLB) * 2;
                if (Octree.WorldBB == null)
                {
                    rayEndP.X += Point3D.distance(F1.containingBB.URT, F1.containingBB.LLB) * 2;    // Use X axis for the ray
                }
                else
                {
                    rayEndP.X += Octree.WorldBB.extent * 2;
                }
            }
            else if (DimttoZero == 2)
            {
                for (int i = 0; i < F1.vertices.Count; i++)
                {
                    projVert.Add(new Point3D(F1.vertices[i].X, F1.vertices[i].Y, 0.0));
                }
                projIntP.Z = 0.0;
                rayEndP.Z  = 0.0;
                if (Octree.WorldBB == null)
                {
                    rayEndP.X += Point3D.distance(F1.containingBB.URT, F1.containingBB.LLB) * 2;
                }
                else
                {
                    rayEndP.X += Octree.WorldBB.extent * 2;
                }
            }
            Face3D projFace = new Face3D(projVert);

            // define a ray from the intersection point along the X-axis of the projected plane by using long enough line segment beginning from the point, using
            //    max extent of the face containingBB *2
            LineSegment3D ray = new LineSegment3D(projIntP, rayEndP);

            // Now do intersection between the ray and all the segments of the face. Odd number indicates the point is inside
            // 4 rules to follow:
            //    1. If the segment is upward, exclude the endpoint for intersection (only consider the startpoint)
            //    2. If the segment is downward, exclude the startpoint for intersection (only considers the end point)
            //    3. Ignore the segment that is horizontal (parallel to the ray)
            //    4. ray is always strictly to the right of the Point
            int     intCount             = 0;
            Point3D iP                   = new Point3D();
            LineSegmentIntersectEnum mod = LineSegmentIntersectEnum.Undefined;

            for (int i = 0; i < projFace.boundaries.Count; i++)
            {
                if (ray.baseLine.direction == projFace.boundaries[i].baseLine.direction)
                {
                    continue;   //ignore segment that is parallel to the ray (rule #3)
                }
                Point3D pointToExclude = new Point3D();
                if (DimttoZero == 0 || DimttoZero == 1)
                {
                    // for both X-Z and Y-Z plane (Z as vertical axis)
                    if (projFace.boundaries[i].startPoint.Z <= ray.startPoint.Z && projFace.boundaries[i].endPoint.Z > ray.startPoint.Z)
                    {
                        pointToExclude = projFace.boundaries[i].endPoint;       // Rule #1
                    }
                    else if (projFace.boundaries[i].startPoint.Z > ray.startPoint.Z && projFace.boundaries[i].endPoint.Z <= ray.startPoint.Z)
                    {
                        pointToExclude = projFace.boundaries[i].startPoint;     // Rule #2
                    }
                }
                else
                {
                    // for X-Y plane (Y as vertical axis)
                    if (projFace.boundaries[i].startPoint.Y <= ray.startPoint.Y && projFace.boundaries[i].endPoint.Y > ray.startPoint.Y)
                    {
                        pointToExclude = projFace.boundaries[i].endPoint;       // Rule #1
                    }
                    else if (projFace.boundaries[i].startPoint.Y > ray.startPoint.Y && projFace.boundaries[i].endPoint.Y <= ray.startPoint.Y)
                    {
                        pointToExclude = projFace.boundaries[i].startPoint;     // Rule #2
                    }
                }

                // In the evaluation of the number of intersection between a ray and a face, we will ignore the intersection point that is equal to the rule #2 or #3
                if (LineSegment3D.intersect(ray, projFace.boundaries[i], out iP, out mod) && (iP != pointToExclude))
                {
                    intCount++;
                }
            }
            if (intCount % 2 == 1)
            {
                return(true);
            }
            return(false);
        }
Ejemplo n.º 21
0
 public bool isInside(Face3D F)
 {
     return(Polyhedron.inside(this._polyHRep, F));
 }
Ejemplo n.º 22
0
        /// <summary>
        /// Calculating intersection beween 2 Faces. The outcome of the intersection should be a LineSegment
        /// </summary>
        /// <param name="F1">First Face</param>
        /// <param name="F2">Second Face</param>
        /// <param name="intersectionLine">The resulting intersection line. Zero if no intersection</param>
        /// <param name="mode">The mode of the intersection: No intersection/parallel, partially intersect, no actual intersection/undefined</param>
        /// <returns></returns>
        public static bool intersect(Face3D F1, Face3D F2, out LineSegment3D intersectionLine, out FaceIntersectEnum mode)
        {
            intersectionLine = new LineSegment3D(new Point3D(0, 0, 0), new Point3D(0, 0, 0));
            mode             = FaceIntersectEnum.Undefined;

            if (F1._basePlane.normalVector == F2._basePlane.normalVector)
            {
                // test points inside another face
                for (int i = 0; i < F2._vertices.Count; i++)
                {
                    if (!Face3D.inside(F1, F2._vertices[i]))
                    {
                        continue;
                    }
                    mode = FaceIntersectEnum.Overlap;
                    return(true);
                }
                mode = FaceIntersectEnum.NoIntersectionParallel;
                return(false);
            }

            LineSegment3D ls1;
            LineSegment3D ls2;
            bool          res1 = Plane3D.PPintersect(F1._basePlane, F2, out ls1);
            bool          res2 = Plane3D.PPintersect(F2._basePlane, F1, out ls2);

            if (!res1 || !res2)
            {
                return(false);       // the faces do not intersect
            }
            // Special case if the intersection occurs only at a single point
            if (ls1.startPoint == ls1.endPoint && ls2.startPoint == ls2.endPoint)
            {
                if (ls1.startPoint.Equals(ls2.startPoint))
                {
                    mode = FaceIntersectEnum.IntersectPartial;
                    return(true);
                }
                return(false);
            }
            else if (ls1.startPoint.Equals(ls1.endPoint))
            {
                // a single point intersection: ls1 is 0 length linesegnment = point
                if (LineSegment3D.isInSegment(ls2, ls1.startPoint))
                {
                    mode = FaceIntersectEnum.IntersectPartial;
                    return(true);
                }
                return(false);
            }
            else if (ls2.startPoint.Equals(ls2.endPoint))
            {
                // a single point intersection: ls1 is 0 length linesegnment = point
                if (LineSegment3D.isInSegment(ls1, ls2.startPoint))
                {
                    mode = FaceIntersectEnum.IntersectPartial;
                    return(true);
                }
                return(false);
            }

            LineSegment3D          ovSegment;
            LineSegmentOverlapEnum ovstat = LineSegmentOverlapEnum.Undefined;
            bool lint = LineSegment3D.overlap(ls1, ls2, out ovSegment, out ovstat);

            if (lint)
            {
                intersectionLine = ovSegment;
                mode             = FaceIntersectEnum.IntersectPartial;
                return(true);
            }
            return(false);
        }
Ejemplo n.º 23
0
        public static void Process(OctreeNode node, Polyhedron _polyH, List <Face3D> polyHF)
        {
            // 3rd step. Subdivide the cells collected by the step 2 and operate on them with the actual polyhedron to get the detail

            if (node._depth < Octree.MaxDepth)
            {
                int disjointCount = 0;
                int insideCount   = 0;

                Split(node);
                List <int> childToRemove   = new List <int>();
                List <int> childToTraverse = new List <int>();

                List <Face3D> faceList;
                faceList = Face3D.exclFacesOutsideOfBound(polyHF, node.nodeCellCuboid.cuboidPolyhedron.boundingBox, 0x111);

                if (faceList.Count == 0)
                {
                    // No face inside this cuboid left, no intersection nor completely enclosing the polyH.
                    node._flag = PolyhedronIntersectEnum.Disjoint;
                    node._children.Clear();
                    return;
                }

                for (int i = 0; i < node._children.Count; i++)
                {
                    OctreeNode childNode = node._children[i];
                    //PolyhedronIntersectEnum intS = childNode.Process(polyH);
                    if (Polyhedron.intersect(childNode.nodeCellCuboid.cuboidPolyhedron, faceList))
                    {
                        childToTraverse.Add(i);
                        childNode._flag = PolyhedronIntersectEnum.Intersect;
                        childNode.nodeCellID.setBorderCell();
#if (DBG_OCTREE)
                        if (childNode._depth >= _dbgDepth)
                        {
                            BIMRLCommon         refCommon = new BIMRLCommon();
                            string              dbgFile   = "c:\\temp\\octree\\" + childNode.nodeCellID.ToString() + " - intersect polyH.x3d";
                            BIMRLExportSDOToX3D x3d       = new BIMRLExportSDOToX3D(refCommon, dbgFile);
                            x3d.drawCellInX3d(childNode.nodeCellID.ToString());     // draw the cell
                            x3d.exportFacesToX3D(faceList);
                            x3d.endExportToX3D();
                        }
#endif
                        continue;
                    }

                    // If doesn't intersect (passes the check above), either it is fully contained, full contains or disjoint
                    // To optimize the operation, we will use a single sampling point instead of checking the entire polyhedron since a single point can tell if a polyhedron is inside the other one
                    //if (Polyhedron.inside(childNode.nodeCellCuboid.cuboidPolyhedron, polyH))

                    //// No need to check this since the previous step (no 1) would have removed the fullycontaining cells

                    // Fully contains check only valid if the parent is fully contains, if intersect, it should never be full contains
                    //if (node._flag == PolyhedronIntersectEnum.FullyContains)
                    //{
                    //    if (Polyhedron.insideCuboid(childNode.nodeCellCuboid.cuboidPolyhedron, faceList[0].vertices[0]))
                    //    {
                    //        // if polyH is entirely inside the cuboid, we will set this for further split (the same as intersection
                    //        childToTraverse.Add(i);       // We will remove the node if it is disjoint, otherwise it will continue splitting until the condition met
                    //        childNode._flag = PolyhedronIntersectEnum.FullyContains;
                    //        childNode.nodeCellID.setBorderCell();
                    //        continue;
                    //    }
                    //}

                    //if (Polyhedron.inside(polyH, childNode.nodeCellCuboid.cuboidPolyhedron))
                    if (Polyhedron.inside(_polyH, childNode.nodeCellCuboid.cuboidPolyhedron.Vertices[3]))
                    {
                        childNode._flag = PolyhedronIntersectEnum.Inside;
                        insideCount++;
#if (DBG_OCTREE)
                        if (childNode._depth >= _dbgDepth)
                        {
                            BIMRLCommon         refCommon = new BIMRLCommon();
                            string              dbgFile   = "c:\\temp\\octree\\" + childNode.nodeCellID.ToString() + " - inside polyH.x3d";
                            BIMRLExportSDOToX3D x3d       = new BIMRLExportSDOToX3D(refCommon, dbgFile);
                            x3d.drawCellInX3d(childNode.nodeCellID.ToString());     // draw the cell
                            x3d.exportFacesToX3D(_polyH.Faces);
                            x3d.endExportToX3D();
                        }
#endif
                        continue;
                    }

                    // If the 2 polyH do not intersect, the cuboid does not fully contain the polyH, nor the cuboid is fully inside the polyH, it must be disjoint
                    childNode._flag = PolyhedronIntersectEnum.Disjoint;
                    disjointCount++;
#if (DBG_OCTREE)
                    if (childNode._depth >= _dbgDepth)
                    {
                        BIMRLCommon         refCommon = new BIMRLCommon();
                        string              dbgFile   = "c:\\temp\\octree\\" + childNode.nodeCellID.ToString() + " - disjoint polyH.x3d";
                        BIMRLExportSDOToX3D x3d       = new BIMRLExportSDOToX3D(refCommon, dbgFile);
                        x3d.drawCellInX3d(childNode.nodeCellID.ToString());     // draw the cell
                        x3d.exportFacesToX3D(_polyH.Faces);
                        x3d.endExportToX3D();
                    }
#endif
                    continue;

                    // else: the cuboid is completely inside the polyH, keep
                }

                if (disjointCount == 8)
                {
                    // All children are disjoint. Remove all children and set the node to Disjoint
                    node._children.Clear();
                    node._flag = PolyhedronIntersectEnum.Disjoint;
                    return;
                }

                if (insideCount == 8)
                {
                    // All children are inside. Remove all children and set the node to Inside
                    node._children.Clear();
                    node._flag = PolyhedronIntersectEnum.Inside;
                    return;
                }


                if (childToTraverse.Count == 1)
                {
                    OctreeNodeProcess.Process(node._children[childToTraverse[0]], _polyH, faceList);
                }
                else if (childToTraverse.Count > 1)
                {
#if (DEBUG_NOPARALLEL)
                    // Non - parallel option for easier debugging
                    foreach (int i in childToTraverse)
                    {
                        OctreeNodeProcess.Process(node._children[i], _polyH, faceList);
                    }
#else
                    ParallelOptions po = new ParallelOptions();
                    po.MaxDegreeOfParallelism = 8;

                    Parallel.ForEach(childToTraverse, po, i => OctreeNodeProcess.Process(node._children[i], _polyH, faceList));
#endif
                }
                // If there is any disjoint, we need to keep this node as it is. This should be done after we processed all the children to be traversed!!
                if (disjointCount > 0 && disjointCount < 8)
                {
                    return;
                }

                int countGrandChildren = 0;
                // If there is no disjoint, we need to check whether all children are terminal (i.e. child._children.Count == 0)
                foreach (OctreeNode child in node._children)
                {
                    countGrandChildren += child._children.Count;
                }

                // All children are terminal and no disjoint (by implication of previous steps). Remove children
                if (countGrandChildren == 0)
                {
                    node._children.Clear();
                    node._flag = PolyhedronIntersectEnum.IntersectOrInside;
                    return;
                }
            }
            else
            {
                // at _depth == Octree.MaxDepth there is nothing else to do since the test has been done at the parent level and when entering this stage, the test has determined
                // that the cell is intersected with the polyH
            }

            return;
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Process Octree for a face
        /// </summary>
        /// <param name="_polyH"></param>
        /// <param name="polyHF"></param>
        public static void Process(OctreeNode node, Face3D face)
        {
            if (node._depth < Octree.MaxDepth)
            {
                int disjointCount = 0;

                OctreeNodeProcess.Split(node);
                List <int> childToRemove   = new List <int>();
                List <int> childToTraverse = new List <int>();

                for (int i = 0; i < node._children.Count; i++)
                {
                    OctreeNode childNode = node._children[i];
                    if (Polyhedron.intersect(childNode.nodeCellCuboid.cuboidPolyhedron, face))
                    {
                        childToTraverse.Add(i);
                        childNode._flag = PolyhedronIntersectEnum.Intersect;
                        childNode.nodeCellID.setBorderCell();
                        continue;
                    }

                    // If doesn't intersect (passes the check above), either it is fully contained, full contains or disjoint
                    // To optimize the operation, we will use a single sampling point instead of checking the entire polyhedron since a single point can tell if a polyhedron is inside the other one

                    // Fully contains check only valid if the parent is fully contains, if intersect, it should never be full contains
                    if (node._flag == PolyhedronIntersectEnum.FullyContains)
                    {
                        if (Polyhedron.insideCuboid(childNode.nodeCellCuboid.cuboidPolyhedron, face.vertices[2]))
                        {
                            // if polyH is entirely inside the cuboid, we will set this for further split (the same as intersection
                            childToTraverse.Add(i);       // We will remove the node if it is disjoint, otherwise it will continue splitting until the condition met
                            childNode._flag = PolyhedronIntersectEnum.FullyContains;
                            childNode.nodeCellID.setBorderCell();
                            continue;
                        }
                    }

                    // If the face does not intersect the cuboid, or the cuboid does not fully contain the polyH, it must be disjoint
                    childNode._flag = PolyhedronIntersectEnum.Disjoint;
                    disjointCount++;
                    continue;
                }

                if (disjointCount == 8)
                {
                    // All children are disjoint. Remove all children and set the node to Disjoint
                    node._children.Clear();
                    node._flag = PolyhedronIntersectEnum.Disjoint;
                    return;
                }

                if (childToTraverse.Count == 1)
                {
                    OctreeNodeProcess.Process(node._children[childToTraverse[0]], face);
                }
                else if (childToTraverse.Count > 1)
                {
                    Parallel.ForEach(childToTraverse, i => OctreeNodeProcess.Process(node._children[i], face));
                }

                // If there is any disjoint, we need to keep this node as it is. This should be done after we processed all the children to be traversed!!
                if (disjointCount > 0 && disjointCount < 8)
                {
                    return;
                }

                int countGrandChildren = 0;
                // If there is no disjoint, we need to check whether all children are terminal (i.e. child._children.Count == 0)
                foreach (OctreeNode child in node._children)
                {
                    countGrandChildren += child._children.Count;
                }

                // All children are terminal and no disjoint (by implication of previous steps). Remove children
                if (countGrandChildren == 0)
                {
                    node._children.Clear();
                    node._flag = PolyhedronIntersectEnum.IntersectOrInside;
                    return;
                }
            }
            else
            {
                // at _depth == Octree.MaxDepth there is nothing else to do since the test has been done at the parent level and when entering this stage, the test has determined
                // that the cell is intersected with the polyH
            }

            return;
        }
Ejemplo n.º 25
0
 public static bool Parallels(Plane3D P1, Face3D F1)
 {
     return(Vector3D.Parallels(P1.normalVector, F1.basePlane.normalVector));
 }