Exemplo n.º 1
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);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Testing whether 2 line segments intersect
        /// </summary>
        /// <param name="L1">Line 1</param>
        /// <param name="L2">Line 2</param>
        /// <param name="intersectionPoint">Intersection point</param>
        /// <param name="mode">enumeration that identifies how the two lines intersect</param>
        /// <returns></returns>
        public static bool intersect(LineSegment3D L1, LineSegment3D L2, out Point3D intersectionPoint, out LineSegmentIntersectEnum mode)
        {
            mode = LineSegmentIntersectEnum.Undefined;
            Point3D ip = new Point3D();

            intersectionPoint = ip;

            if (Line3D.parallel(L1.baseLine, L2.baseLine))
            {
                return(false);                                             // Lines are parallel, no intersection
            }
            // With segments AB and CD, we get Pab = (1-s)A + sB, and Qab = (1-t)C + D
            // For intersection Pab = Qcd and therefore (1-s)A + sB = (1-t)C + tD. We get s(B-A) - t(D-C) = C-A for some s,t
            // using matrix operation we can get s and t using X and Y, and also using X and Z. If they intersect s and t have to be equal for both
            double a = L1.endPoint.X - L1.startPoint.X;
            double b = L2.startPoint.X - L2.endPoint.X;
            double c = L1.endPoint.Y - L1.startPoint.Y;
            double d = L2.startPoint.Y - L2.endPoint.Y;
            double e = L1.endPoint.Z - L1.startPoint.Z;
            double f = L2.startPoint.Z - L2.endPoint.Z;
            double g = L2.startPoint.X - L1.startPoint.X;
            double h = L2.startPoint.Y - L1.startPoint.Y;
            double i = L2.startPoint.Z - L1.startPoint.Z;

            // Work on special case when the lines are 2D
            if ((MathUtils.equalTol(a, 0.0) && MathUtils.equalTol(b, 0.0) && MathUtils.equalTol(g, 0.0)) ||
                (MathUtils.equalTol(e, 0.0) && MathUtils.equalTol(f, 0.0) && MathUtils.equalTol(i, 0.0)) ||
                (MathUtils.equalTol(c, 0.0) && MathUtils.equalTol(d, 0.0) && MathUtils.equalTol(h, 0.0)))
            {
                double s = -1.0;
                double t = -1.0;
                // 2D line segments on Y-Z plane (X = 0)
                if (MathUtils.equalTol(a, 0.0) && MathUtils.equalTol(b, 0.0) && MathUtils.equalTol(g, 0.0))
                {
                    s = (d * i - h * f) / (d * e - c * f);
                    t = (e * h - i * c) / (d * e - c * f);
                }
                // 2D line segments on X-Y plane (Z = 0)
                else if (MathUtils.equalTol(e, 0.0) && MathUtils.equalTol(f, 0.0) && MathUtils.equalTol(i, 0.0))
                {
                    s = (b * h - g * d) / (b * c - a * d);
                    t = (g * c - h * a) / (b * c - a * d);
                }
                // 2D line segment on X-Z plane (Y = 0)
                else if (MathUtils.equalTol(c, 0.0) && MathUtils.equalTol(d, 0.0) && MathUtils.equalTol(h, 0.0))
                {
                    s = (b * i - g * f) / (b * e - a * f);
                    t = (g * e - i * a) / (b * e - a * f);
                }

                // calculate intersection point
                ip.X = (1 - s) * L1.startPoint.X + s * L1.endPoint.X;
                ip.Y = (1 - s) * L1.startPoint.Y + s * L1.endPoint.Y;
                ip.Z = (1 - s) * L1.startPoint.Z + s * L1.endPoint.Z;
                intersectionPoint = ip;

                if ((0 <= s && s <= 1) && (0 <= t && t <= 1))
                {
                    // If the segments intersect s and t have to be between 0 and 1
                    mode = LineSegmentIntersectEnum.IntersectedWithinSegments;
                    return(true);
                }
                else
                {
                    // Lines intersect but intersection occurs outside of the segments
                    mode = LineSegmentIntersectEnum.IntersectedOutsideSegments;
                    return(false);
                }
            }

            // Line segments are real 3D lines
            {
                // on X-Y
                double s1 = (b * h - g * d) / (b * c - a * d);
                double t1 = (g * c - h * a) / (b * c - a * d);

                // on X-Z
                double s2 = (b * i - g * f) / (b * e - a * f);
                double t2 = (g * e - i * a) / (b * e - a * f);

                // on Y-Z
                double s3 = (d * i - h * f) / (d * e - c * f);
                double t3 = (e * h - i * c) / (d * e - c * f);

                // When the result of calculation gives infinity or NaN, the line is somewhat aligned, so it can hav any value. Set it here to be the same with one other
                if (double.IsInfinity(s1) || double.IsNaN(s1))
                {
                    if (double.IsInfinity(s2) || double.IsNaN(s2))
                    {
                        if (double.IsInfinity(s3) || double.IsNaN(s3))
                        {
                            s1 = 0.0;
                        }
                        else
                        {
                            s1 = s3;
                        }
                    }
                    else
                    {
                        s1 = s2;
                    }
                }

                if (double.IsInfinity(s2) || double.IsNaN(s2))
                {
                    if (double.IsInfinity(s1) || double.IsNaN(s1))
                    {
                        if (double.IsInfinity(s3) || double.IsNaN(s3))
                        {
                            s2 = 0.0;
                        }
                        else
                        {
                            s2 = s3;
                        }
                    }
                    else
                    {
                        s2 = s1;
                    }
                }

                if (double.IsInfinity(s3) || double.IsNaN(s3))
                {
                    if (double.IsInfinity(s1) || double.IsNaN(s1))
                    {
                        if (double.IsInfinity(s2) || double.IsNaN(s2))
                        {
                            s3 = 0.0;
                        }
                        else
                        {
                            s3 = s2;
                        }
                    }
                    else
                    {
                        s3 = s1;
                    }
                }

                // When the result of calculation gives infinity or NaN, the line is somewhat aligned, so it can hav any value. Set it here to be the same with one other
                if (double.IsInfinity(t1) || double.IsNaN(t1))
                {
                    if (double.IsInfinity(t2) || double.IsNaN(t2))
                    {
                        if (double.IsInfinity(t3) || double.IsNaN(t3))
                        {
                            t1 = 0.0;
                        }
                        else
                        {
                            t1 = t3;
                        }
                    }
                    else
                    {
                        t1 = t2;
                    }
                }

                if (double.IsInfinity(t2) || double.IsNaN(t2))
                {
                    if (double.IsInfinity(t1) || double.IsNaN(t1))
                    {
                        if (double.IsInfinity(t3) || double.IsNaN(t3))
                        {
                            t2 = 0.0;
                        }
                        else
                        {
                            t2 = t3;
                        }
                    }
                    else
                    {
                        t2 = t1;
                    }
                }

                if (double.IsInfinity(t3) || double.IsNaN(t3))
                {
                    if (double.IsInfinity(t1) || double.IsNaN(t1))
                    {
                        if (double.IsInfinity(t2) || double.IsNaN(t2))
                        {
                            t3 = 0.0;
                        }
                        else
                        {
                            t3 = t2;
                        }
                    }
                    else
                    {
                        t3 = t1;
                    }
                }

                // Lines intersect when s1=s2 and t1=t2 and als s1=s3 and t1=t3
                if (MathUtils.equalTol(s1, s2, MathUtils.defaultTol) && MathUtils.equalTol(t1, t2, MathUtils.defaultTol) && MathUtils.equalTol(s1, s3, MathUtils.defaultTol) && MathUtils.equalTol(t1, t3, MathUtils.defaultTol))
                {
                    // calculate intersection point
                    ip.X = (1 - s1) * L1.startPoint.X + s1 * L1.endPoint.X;
                    ip.Y = (1 - s1) * L1.startPoint.Y + s1 * L1.endPoint.Y;
                    ip.Z = (1 - s1) * L1.startPoint.Z + s1 * L1.endPoint.Z;
                    intersectionPoint = ip;

                    if ((0 <= s1 && s1 <= 1) && (0 <= t1 && t1 <= 1))
                    {
                        // If the segments intersect s and t have to be between 0 and 1
                        mode = LineSegmentIntersectEnum.IntersectedWithinSegments;
                        return(true);
                    }
                    else
                    {
                        // Lines intersect but intersection occurs outside of the segments
                        mode = LineSegmentIntersectEnum.IntersectedOutsideSegments;
                        return(false);
                    }
                }
            }
            return(false);
        }
Exemplo n.º 3
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);
        }