예제 #1
0
        /// <summary>
        /// Get intersection of ray with other ray.
        /// Returns 'null' (no intersection) or object of type 'Point3d', 'Segment3d' or 'Ray3d'.
        /// </summary>
        public object IntersectionWith(Ray3d r)
        {
            if (this == r)
            {
                return(this);
            }

            if (this.Point.BelongsTo(r) && this.IsParallelTo(r))
            {
                if (r.Point.BelongsTo(this))
                {
                    // Two rays are collinear and opposite
                    if (this.Point == r.Point)
                    {
                        return(this.Point);
                    }
                    else
                    {
                        return(new Segment3d(this.Point, r.Point));
                    }
                }
                else
                {
                    return(this);
                }
            }

            if (r.Point.BelongsTo(this) && r.IsParallelTo(this))
            {
                return(r);
            }

            object obj = this.ToLine.IntersectionWith(r.ToLine);

            if (obj == null)
            {
                return(null);
            }
            else
            {
                Point3d p = (Point3d)obj;
                if (p.BelongsTo(this) && p.BelongsTo(r))
                {
                    return(p);
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Shortest distance to a line
        /// </summary>
        public double DistanceTo(Line3d l)
        {
            Vector3d r1 = this.Point.ToVector;
            Vector3d r2 = l.Point.ToVector;
            Vector3d s1 = this.Direction;
            Vector3d s2 = l.Direction;

            if (s1.Cross(s2).Norm > GeometRi3D.Tolerance)
            {
                // Crossing lines
                Point3d p = l.PerpendicularTo(new Line3d(this.Point, this.Direction));
                if (p.BelongsTo(this))
                {
                    return(Abs((r2 - r1) * s1.Cross(s2)) / s1.Cross(s2).Norm);
                }
                else
                {
                    return(this.Point.DistanceTo(l));
                }
            }
            else
            {
                // Parallel lines
                return((r2 - r1).Cross(s1).Norm / s1.Norm);
            }
        }
예제 #3
0
        /// <summary>
        /// Point on the perpendicular to the line
        /// </summary>
        public Point3d PerpendicularTo(Line3d l)
        {
            Vector3d r1 = this.Point.ToVector;
            Vector3d r2 = l.Point.ToVector;
            Vector3d s1 = this.Direction;
            Vector3d s2 = l.Direction;

            if (s1.Cross(s2).Norm > GeometRi3D.Tolerance)
            {
                Point3d p = l.PerpendicularTo(new Line3d(this.Point, this.Direction));
                if (p.BelongsTo(this))
                {
                    r1 = r2 + (r2 - r1) * s1.Cross(s1.Cross(s2)) / (s1 * s2.Cross(s1.Cross(s2))) * s2;
                    return(r1.ToPoint);
                }
                else
                {
                    return(this.Point.ProjectionTo(l));
                }
            }
            else
            {
                throw new Exception("Lines are parallel");
            }
        }
예제 #4
0
        /// <summary>
        /// Get intersection of ray with line.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Ray3d'.
        /// </summary>
        public object IntersectionWith(Line3d l)
        {
            if (this.Point.BelongsTo(l) && this.IsParallelTo(l))
            {
                return(this);
            }

            object obj = this.ToLine.IntersectionWith(l);

            if (obj == null)
            {
                return(null);
            }
            else
            {
                Point3d p = (Point3d)obj;
                if (p.BelongsTo(this))
                {
                    return(p);
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #5
0
        internal override int _PointLocation(Point3d p)
        {
            if (GeometRi3D.UseAbsoluteTolerance)
            {
                Plane3d s    = new Plane3d(this.A, this.Normal);
                Point3d proj = p.ProjectionTo(s);
                if (GeometRi3D.AlmostEqual(p.DistanceTo(proj), 0))
                {
                    if (p.BelongsTo(new Segment3d(_a, _b)) || p.BelongsTo(new Segment3d(_a, _c)) || p.BelongsTo(new Segment3d(_c, _b)))
                    {
                        return(0); // Point is on boundary
                    }
                    else
                    {
                        double area = this.Area;

                        double alpha = new Vector3d(proj, _b).Cross(new Vector3d(proj, _c)).Norm / (2 * area);
                        double beta  = new Vector3d(proj, _c).Cross(new Vector3d(proj, _a)).Norm / (2 * area);
                        double gamma = new Vector3d(proj, _a).Cross(new Vector3d(proj, _b)).Norm / (2 * area);

                        if (GeometRi3D.AlmostEqual(((alpha + beta + gamma) - 1.0) * (AB + BC + AC) / 3, 0.0))
                        {
                            return(1); // Point is strictly inside
                        }
                        else
                        {
                            return(-1);
                        }
                    }
                }
                else
                {
                    return(-1); // Point is outside
                }
            }
            else
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * (AB + BC + AC) / 3;
                GeometRi3D.UseAbsoluteTolerance = true;
                int result = this._PointLocation(p);
                GeometRi3D.UseAbsoluteTolerance = false;
                GeometRi3D.Tolerance            = tol;
                return(result);
            }
        }
예제 #6
0
        /// <summary>
        /// Get intersection of segment with line.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Line3d l)
        {
            if (this.BelongsTo(l))
            {
                return(this.Copy());
            }

            Point3d p = l.PerpendicularTo(this.ToLine);

            if (p.BelongsTo(this) && p.BelongsTo(l))
            {
                return(p);
            }
            else
            {
                return(null);
            }
        }
예제 #7
0
        /// <summary>
        /// Point on circle (including interior points) closest to target point "p".
        /// </summary>
        public Point3d ClosestPoint(Point3d p)
        {
            Point3d projection = p.ProjectionTo(this.ToPlane);

            if (projection.BelongsTo(this))
            {
                return(projection);
            }
            else
            {
                return(this.Center.Translate(this.R * new Vector3d(this.Center, projection).Normalized));
            }
        }
예제 #8
0
        /// <summary>
        /// Shortest distance from point to circle (including interior points)
        /// </summary>
        public double DistanceTo(Point3d p)
        {
            Point3d projection = p.ProjectionTo(this.ToPlane);

            if (projection.BelongsTo(this))
            {
                return(projection.DistanceTo(p));
            }
            else
            {
                Point3d closest_point = this.Center.Translate(this.R * new Vector3d(this.Center, projection).Normalized);
                return(closest_point.DistanceTo(p));
            }
        }
예제 #9
0
 /// <summary>
 /// <para>Test if segment is located in the epsilon neighborhood of the line.</para>
 /// <para>Epsilon neighborhood is defined by a GeometRi3D.Tolerance property.</para>
 /// <para>For relative tolerance tests a fraction of the segment's length is used to define epsilon neighborhood.</para>
 /// </summary>
 public bool BelongsTo(Line3d l)
 {
     if (GeometRi3D.UseAbsoluteTolerance)
     {
         return(_p1.BelongsTo(l) && _p2.BelongsTo(l));
     }
     else
     {
         double tol = GeometRi3D.Tolerance;
         GeometRi3D.Tolerance            = tol * this.Length;
         GeometRi3D.UseAbsoluteTolerance = true;
         bool result = this.BelongsTo(l);
         GeometRi3D.UseAbsoluteTolerance = false;
         GeometRi3D.Tolerance            = tol;
         return(result);
     }
 }
예제 #10
0
        /// <summary>
        /// Get intersection of line with other line.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Line3d'.
        /// </summary>
        public object IntersectionWith(Line3d l)
        {
            if (l.IsParallelTo(this) && l.Point.BelongsTo(this))
            {
                return(this.Copy());
            }

            Point3d p = l.PerpendicularTo(this);

            if (p.BelongsTo(l))
            {
                return(p);
            }
            else
            {
                return(null);
            }
        }
예제 #11
0
        /// <summary>
        /// Returns shortest distance from segment to ray
        /// </summary>
        public double DistanceTo(Ray3d r)
        {
            Point3d p1 = this.ToLine.PerpendicularTo(r.ToLine);
            bool    b1 = p1.BelongsTo(r);
            Point3d p2 = r.ToLine.PerpendicularTo(this.ToLine);
            bool    b2 = p2.BelongsTo(this);

            if (this.ToLine.PerpendicularTo(r.ToLine).BelongsTo(r) && r.ToLine.PerpendicularTo(this.ToLine).BelongsTo(this))
            {
                return(this.ToLine.DistanceTo(r.ToLine));
            }

            double d1   = double.PositiveInfinity;
            double d2   = double.PositiveInfinity;
            double d3   = double.PositiveInfinity;
            bool   flag = false;

            if (r.Point.ProjectionTo(this.ToLine).BelongsTo(this))
            {
                d1   = r.Point.DistanceTo(this.ToLine);
                flag = true;
            }
            if (this.P1.ProjectionTo(r.ToLine).BelongsTo(r))
            {
                d2   = this.P1.DistanceTo(r.ToLine);
                flag = true;
            }
            if (this.P2.ProjectionTo(r.ToLine).BelongsTo(r))
            {
                d3   = this.P2.DistanceTo(r.ToLine);
                flag = true;
            }

            if (flag)
            {
                return(Min(d1, Min(d2, d3)));
            }

            return(Min(this.P1.DistanceTo(r.Point), this.P2.DistanceTo(r.Point)));
        }
예제 #12
0
        /// <summary>
        /// Get intersection of ray with triangle.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Ray3d r)
        {
            // Relative tolerance ================================
            if (!GeometRi3D.UseAbsoluteTolerance)
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * Max(AB, Max(BC, AC));
                GeometRi3D.UseAbsoluteTolerance = true;
                object result = this.IntersectionWith(r);
                GeometRi3D.UseAbsoluteTolerance = false;
                GeometRi3D.Tolerance            = tol;
                return(result);
            }
            //====================================================

            object obj = this.IntersectionWith(r.ToLine);

            if (obj == null)
            {
                return(null);
            }
            else if (obj.GetType() == typeof(Point3d))
            {
                Point3d p = (Point3d)obj;
                if (p.BelongsTo(r))
                {
                    return(p);
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                return(r.IntersectionWith((Segment3d)obj));
            }
        }
예제 #13
0
        /// <summary>
        /// Point on segment closest to target point "p".
        /// </summary>
        public Point3d ClosestPoint(Point3d p)
        {
            Point3d projection_point = p.ProjectionTo(this.ToLine);

            if (projection_point.BelongsTo(this))
            {
                return(projection_point);
            }
            else
            {
                double dist1 = p.DistanceTo(this.P1);
                double dist2 = p.DistanceTo(this.P2);

                if (dist1 <= dist2)
                {
                    return(this.P1);
                }
                else
                {
                    return(this.P2);
                }
            }
        }
예제 #14
0
        /// <summary>
        /// Get intersection of segment with other segment.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Segment3d s)
        {
            if (this == s)
            {
                return(this.Copy());
            }

            object obj = this.ToLine.IntersectionWith(s);

            if (obj == null)
            {
                return(null);
            }

            if (obj.GetType() == typeof(Point3d))
            {
                Point3d p = (Point3d)obj;
                if (p.BelongsTo(this) && p.BelongsTo(s))
                {
                    return(p);
                }
                else
                {
                    return(null);
                }
            }
            else if (obj.GetType() == typeof(Segment3d))
            {
                // Segments are collinear

                // Relative tolerance check ================================
                double tol = GeometRi3D.Tolerance;
                if (!GeometRi3D.UseAbsoluteTolerance)
                {
                    tol = GeometRi3D.Tolerance * Max(this.Length, s.Length);
                }
                //==========================================================

                // Create local CS with X-axis along segment 's'
                Vector3d v2 = s.ToVector.OrthogonalVector;
                Coord3d  cs = new Coord3d(s.P1, s.ToVector, v2);
                double   x1 = 0.0;
                double   x2 = s.Length;

                double x3 = this.P1.ConvertTo(cs).X;
                double x4 = this.P2.ConvertTo(cs).X;



                if (GeometRi3D.Smaller(Max(x3, x4), x1, tol) || GeometRi3D.Greater(Min(x3, x4), x2, tol))
                {
                    return(null);
                }

                if (GeometRi3D.AlmostEqual(Max(x3, x4), x1, tol))
                {
                    return(new Point3d(x1, 0, 0, cs));
                }
                if (GeometRi3D.AlmostEqual(Min(x3, x4), x2, tol))
                {
                    return(new Point3d(x2, 0, 0, cs));
                }

                if (GeometRi3D.Smaller(Min(x3, x4), x1, tol) && GeometRi3D.Greater(Max(x3, x4), x2, tol))
                {
                    return(s.Copy());
                }

                if (GeometRi3D.Greater(Min(x3, x4), x1, tol) && GeometRi3D.Smaller(Max(x3, x4), x2, tol))
                {
                    return(this.Copy());
                }

                if (GeometRi3D.Smaller(Min(x3, x4), x1, tol))
                {
                    return(new Segment3d(new Point3d(x1, 0, 0, cs), new Point3d(Max(x3, x4), 0, 0, cs)));
                }

                if (GeometRi3D.Greater(Max(x3, x4), x2, tol))
                {
                    return(new Segment3d(new Point3d(x2, 0, 0, cs), new Point3d(Min(x3, x4), 0, 0, cs)));
                }

                return(null);
            }
            else
            {
                return(null);
            }
        }
예제 #15
0
        /// <summary>
        /// Shortest distance between two circles (including interior points) (approximate solution)
        /// <para> The output points may be not unique in case of parallel or intersecting circles.</para>
        /// </summary>
        /// <param name="c">Target circle</param>
        /// <param name="p1">Closest point on source circle</param>
        /// <param name="p2">Closest point on target circle</param>
        public double DistanceTo(Circle3d c, out Point3d p1, out Point3d p2)
        {
            if (this.Normal.IsParallelTo(c.Normal))
            {
                Point3d projection = c.Center.ProjectionTo(this.ToPlane);
                double  dist       = projection.DistanceTo(this.Center);
                double  vdist      = projection.DistanceTo(c.Center);
                if (dist < this.R + c.R)
                {
                    if (projection.BelongsTo(this))
                    {
                        p1 = projection;
                        p2 = c.Center;
                    }
                    else
                    {
                        p1 = this.Center.Translate(this.R * new Vector3d(this.Center, projection).Normalized);
                        p2 = p1.ProjectionTo(c.ToPlane);
                    }
                    return(vdist);
                }
                else
                {
                    Vector3d v = new Vector3d(this.Center, projection).Normalized;
                    p1 = this.Center.Translate(this.R * v);
                    p2 = c.Center.Translate(-c.R * v);
                    return(Sqrt((dist - this.R - c.R) * (dist - this.R - c.R) + vdist * vdist));
                }
            }

            double tol  = GeometRi3D.Tolerance;
            bool   mode = GeometRi3D.UseAbsoluteTolerance;

            GeometRi3D.Tolerance            = GeometRi3D.DefaultTolerance;
            GeometRi3D.UseAbsoluteTolerance = true;

            object obj = this.IntersectionWith(c);

            if (obj != null)
            {
                // Restore initial state
                GeometRi3D.UseAbsoluteTolerance = mode;
                GeometRi3D.Tolerance            = tol;

                if (obj.GetType() == typeof(Point3d))
                {
                    p1 = (Point3d)obj;
                    p2 = (Point3d)obj;
                }
                else if (obj.GetType() == typeof(Segment3d))
                {
                    p1 = ((Segment3d)obj).P1;
                    p2 = ((Segment3d)obj).P1;
                }
                else
                {
                    p1 = ((Circle3d)obj).Center;
                    p2 = ((Circle3d)obj).Center;
                }

                return(0);
            }

            Point3d p1_1, p1_2, p2_1, p2_2;
            double  dist1 = _distance_cicle_to_circle(this, c, out p1_1, out p1_2);
            double  dist2 = _distance_cicle_to_circle(c, this, out p2_1, out p2_2);

            // Restore initial state
            GeometRi3D.UseAbsoluteTolerance = mode;
            GeometRi3D.Tolerance            = tol;

            if (dist1 < dist2)
            {
                p1 = p1_1;
                p2 = p1_2;
            }
            else
            {
                p1 = p2_2;
                p2 = p2_1;
            }
            return(Min(dist1, dist2));
        }
예제 #16
0
        /// <summary>
        /// Intersection of ellipse with line.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Line3d l)
        {
            // Relative tolerance ================================
            if (!GeometRi3D.UseAbsoluteTolerance)
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * this.A;
                GeometRi3D.UseAbsoluteTolerance = true;
                object result = this.IntersectionWith(l);
                GeometRi3D.UseAbsoluteTolerance = false;
                GeometRi3D.Tolerance            = tol;
                return(result);
            }
            //====================================================


            if (l.Direction.IsOrthogonalTo(this.Normal))
            {
                if (l.Point.BelongsTo(new Plane3d(this.Center, this.Normal)))
                {
                    // coplanar objects
                    // Find intersection of line and ellipse (2D)
                    // Solution from: http://www.ambrsoft.com/TrigoCalc/Circles2/Ellipse/EllipseLine.htm

                    Coord3d  local_coord = new Coord3d(this.Center, this._v1, this._v2);
                    Point3d  p           = l.Point.ConvertTo(local_coord);
                    Vector3d v           = l.Direction.ConvertTo(local_coord);
                    double   a           = this.A;
                    double   b           = this.B;

                    if (Abs(v.Y / v.X) > 100)
                    {
                        // line is almost vertical, rotate local coord
                        local_coord = new Coord3d(this.Center, this._v2, this._v1);
                        p           = l.Point.ConvertTo(local_coord);
                        v           = l.Direction.ConvertTo(local_coord);
                        a           = this.B;
                        b           = this.A;
                    }

                    // Line equation in form: y = mx + c
                    double m = v.Y / v.X;
                    double c = p.Y - m * p.X;

                    double amb = Math.Pow(a, 2) * Math.Pow(m, 2) + Math.Pow(b, 2);
                    double det = amb - Math.Pow(c, 2);
                    if (det < -GeometRi3D.Tolerance)
                    {
                        return(null);
                    }
                    else if (det > 1e-12)
                    {
                        double x1 = (-Math.Pow(a, 2) * m * c + a * b * Sqrt(det)) / amb;
                        double x2 = (-Math.Pow(a, 2) * m * c - a * b * Sqrt(det)) / amb;
                        double y1 = (Math.Pow(b, 2) * c + a * b * m * Sqrt(det)) / amb;
                        double y2 = (Math.Pow(b, 2) * c - a * b * m * Sqrt(det)) / amb;
                        return(new Segment3d(new Point3d(x1, y1, 0, local_coord), new Point3d(x2, y2, 0, local_coord)));
                    }
                    else
                    {
                        double x = -Math.Pow(a, 2) * m * c / amb;
                        double y = Math.Pow(b, 2) * c / amb;
                        return(new Point3d(x, y, 0, local_coord));
                    }
                }
                else
                {
                    // parallel objects
                    return(null);
                }
            }
            else
            {
                // Line intersects ellipse' plane
                Point3d p = (Point3d)l.IntersectionWith(new Plane3d(this.Center, this.Normal));
                if (p.BelongsTo(this))
                {
                    return(p);
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #17
0
        /// <summary>
        /// Get intersection of segment with other segment.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Segment3d s)
        {
            if (this == s)
            {
                return(this.Copy());
            }

            Line3d l1 = this.ToLine;
            Line3d l2 = s.ToLine;

            if (this.BelongsTo(l2) || s.BelongsTo(l1))
            {
                // Segments are collinear

                // Relative tolerance check ================================
                double tol = GeometRi3D.Tolerance;
                if (!GeometRi3D.UseAbsoluteTolerance)
                {
                    tol = GeometRi3D.Tolerance * Max(this.Length, s.Length);
                }
                //==========================================================

                // Create local CS with X-axis along segment 's'
                Vector3d v2 = s.ToVector.OrthogonalVector;
                Coord3d  cs = new Coord3d(s.P1, s.ToVector, v2);
                double   x1 = 0.0;
                double   x2 = s.Length;

                double t3 = this.P1.ConvertTo(cs).X;
                double t4 = this.P2.ConvertTo(cs).X;
                double x3 = Min(t3, t4);
                double x4 = Max(t3, t4);

                // Segments do not overlap
                if (GeometRi3D.Smaller(x4, x1, tol) || GeometRi3D.Greater(x3, x2, tol))
                {
                    return(null);
                }

                // One common point
                if (GeometRi3D.AlmostEqual(Max(x3, x4), x1, tol))
                {
                    return(new Point3d(x1, 0, 0, cs));
                }
                if (GeometRi3D.AlmostEqual(Min(x3, x4), x2, tol))
                {
                    return(new Point3d(x2, 0, 0, cs));
                }

                // Overlaping segments
                x1 = Max(x1, x3);
                x2 = Min(x2, x4);
                return(new Segment3d(new Point3d(x1, 0, 0, cs), new Point3d(x2, 0, 0, cs)));
            }
            else
            {
                Point3d p = l1.PerpendicularTo(l2);
                if (p.BelongsTo(this) && p.BelongsTo(s))
                {
                    return(p);
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #18
0
        /// <summary>
        /// Get intersection of line with triangle.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Line3d l)
        {
            // Relative tolerance ================================
            if (!GeometRi3D.UseAbsoluteTolerance)
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * Max(AB, Max(BC, AC));
                GeometRi3D.UseAbsoluteTolerance = true;
                object result = this.IntersectionWith(l);
                GeometRi3D.UseAbsoluteTolerance = false;
                GeometRi3D.Tolerance            = tol;
                return(result);
            }
            //====================================================

            Plane3d s = new Plane3d(this.A, this.Normal);

            object obj = l.IntersectionWith(s);

            if (obj == null)
            {
                return(null);
            }
            else
            {
                if (obj.GetType() == typeof(Line3d))
                {
                    Segment3d sAB = new Segment3d(A, B);
                    Segment3d sBC = new Segment3d(B, C);
                    Segment3d sAC = new Segment3d(A, C);

                    // Line coincides with one side, return segment
                    if (sAB.BelongsTo(l))
                    {
                        return(sAB);
                    }
                    if (sBC.BelongsTo(l))
                    {
                        return(sBC);
                    }
                    if (sAC.BelongsTo(l))
                    {
                        return(sAC);
                    }

                    Point3d pAB = (Point3d)sAB.IntersectionWith(l);
                    Point3d pBC = (Point3d)sBC.IntersectionWith(l);
                    Point3d pAC = (Point3d)sAC.IntersectionWith(l);

                    bool bAB = (object.ReferenceEquals(null, pAB)) ? false : pAB.BelongsTo(sAB);
                    bool bAC = (object.ReferenceEquals(null, pAC)) ? false : pAC.BelongsTo(sAC);
                    bool bBC = (object.ReferenceEquals(null, pBC)) ? false : pBC.BelongsTo(sBC);

                    // Line crosses one corner, return point
                    if (bAB && bBC && pAB == pBC && !bAC)
                    {
                        return(pAB);
                    }
                    if (bAB && bAC && pAB == pAC && !bBC)
                    {
                        return(pAB);
                    }
                    if (bAC && bBC && pAC == pBC && !bAB)
                    {
                        return(pAC);
                    }

                    // Line crosses two sides, return segment
                    if (bAB && bBC && !bAC)
                    {
                        return(new Segment3d(pAB, pBC));
                    }
                    if (bAB && bAC && !bBC)
                    {
                        return(new Segment3d(pAB, pAC));
                    }
                    if (bAC && bBC && !bAB)
                    {
                        return(new Segment3d(pAC, pBC));
                    }

                    // Line crosses one corner and one side, return segment
                    if (pAB == pBC && bAC)
                    {
                        return(new Segment3d(pAB, pAC));
                    }
                    if (pAB == pAC && bBC)
                    {
                        return(new Segment3d(pAB, pBC));
                    }
                    if (pAC == pBC && bAB)
                    {
                        return(new Segment3d(pAB, pAC));
                    }

                    //else
                    return(null);
                }
                else
                {
                    // result of intersection is point
                    Point3d p = (Point3d)obj;
                    if (p.BelongsTo(this))
                    {
                        return(p);
                    }
                    else
                    {
                        return(null);
                    }
                }
            }
        }
예제 #19
0
        /// <summary>
        /// Intersection of ellipsoid with plane.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Ellipse'.
        /// </summary>
        public object IntersectionWith(Plane3d plane)
        {
            // Solution 1:
            // Peter Paul Klein
            // On the Ellipsoid and Plane Intersection Equation
            // Applied Mathematics, 2012, 3, 1634-1640 (DOI:10.4236/am.2012.311226)

            // Solution 2:
            // Sebahattin Bektas
            // Intersection of an Ellipsoid and a Plane
            // International Journal of Research in Engineering and Applied Sciences, VOLUME 6, ISSUE 6 (June, 2016)

            Coord3d lc = new Coord3d(_point, _v1, _v2, "LC1");

            plane.SetCoord(lc);
            double Ax, Ay, Az, Ad;
            double a, b, c;

            if (Abs(plane.C) >= Abs(plane.A) && Abs(plane.C) >= Abs(plane.B))
            {
                a = this.A; b = this.B; c = this.C;
            }
            else
            {
                lc = new Coord3d(_point, _v2, _v3, "LC2");
                plane.SetCoord(lc);
                if (Abs(plane.C) >= Abs(plane.A) && Abs(plane.C) >= Abs(plane.B))
                {
                    a = this.B; b = this.C; c = this.A;
                }
                else
                {
                    lc = new Coord3d(_point, _v3, _v1, "LC3");
                    plane.SetCoord(lc);
                    a = this.C; b = this.A; c = this.B;
                }
            }

            Ax = plane.A; Ay = plane.B; Az = plane.C; Ad = plane.D;
            double tmp = (Az * Az * c * c);
            double AA  = 1.0 / (a * a) + Ax * Ax / tmp;
            double BB  = 2.0 * Ax * Ay / tmp;
            double CC  = 1.0 / (b * b) + Ay * Ay / tmp;
            double DD  = 2.0 * Ax * Ad / tmp;
            double EE  = 2.0 * Ay * Ad / tmp;
            double FF  = Ad * Ad / tmp - 1.0;

            double det = 4.0 * AA * CC - BB * BB;

            if (GeometRi3D.AlmostEqual(det, 0))
            {
                return(null);
            }
            double X0 = (BB * EE - 2 * CC * DD) / det;
            double Y0 = (BB * DD - 2 * AA * EE) / det;
            double Z0 = -(Ax * X0 + Ay * Y0 + Ad) / Az;

            Point3d P0 = new Point3d(X0, Y0, Z0, lc);

            if (P0.BelongsTo(this))
            {
                // the plane is tangent to ellipsoid
                return(P0);
            }
            else if (P0.IsInside(this))
            {
                Vector3d q  = P0.ToVector.ConvertTo(lc);
                Matrix3d D1 = Matrix3d.DiagonalMatrix(1 / a, 1 / b, 1 / c);
                Vector3d r  = plane.Normal.ConvertTo(lc).OrthogonalVector.Normalized;
                Vector3d s  = plane.Normal.ConvertTo(lc).Cross(r).Normalized;

                double omega = 0;
                double qq, qr, qs, rr, ss, rs;
                if (!GeometRi3D.AlmostEqual((D1 * r) * (D1 * s), 0))
                {
                    rr = (D1 * r) * (D1 * r);
                    rs = (D1 * r) * (D1 * s);
                    ss = (D1 * s) * (D1 * s);
                    if (GeometRi3D.AlmostEqual(rr - ss, 0))
                    {
                        omega = PI / 4;
                    }
                    else
                    {
                        omega = 0.5 * Atan(2.0 * rs / (rr - ss));
                    }
                    Vector3d rprim = Cos(omega) * r + Sin(omega) * s;
                    Vector3d sprim = -Sin(omega) * r + Cos(omega) * s;
                    r = rprim;
                    s = sprim;
                }

                qq = (D1 * q) * (D1 * q);
                qr = (D1 * q) * (D1 * r);
                qs = (D1 * q) * (D1 * s);
                rr = (D1 * r) * (D1 * r);
                ss = (D1 * s) * (D1 * s);

                double d = qq - qr * qr / rr - qs * qs / ss;
                AA = Sqrt((1 - d) / rr);
                BB = Sqrt((1 - d) / ss);

                return(new Ellipse(P0, AA * r, BB * s));
            }
            else
            {
                return(null);
            }
        }
예제 #20
0
        /// <summary>
        /// Get intersection of ray with segment.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Segment3d s)
        {
            // Relative tolerance ================================
            if (!GeometRi3D.UseAbsoluteTolerance)
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * s.Length;
                GeometRi3D.UseAbsoluteTolerance = true;
                object result = this.IntersectionWith(s);
                GeometRi3D.UseAbsoluteTolerance = false;
                GeometRi3D.Tolerance            = tol;
                return(result);
            }
            //====================================================

            object obj = this.ToLine.IntersectionWith(s);

            if (obj == null)
            {
                return(null);
            }
            else if (obj.GetType() == typeof(Point3d))
            {
                Point3d p = (Point3d)obj;
                if (p.BelongsTo(this))
                {
                    return(p);
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                Segment3d intersection = (Segment3d)obj;
                if (intersection.P1.BelongsTo(this) && intersection.P2.BelongsTo(this))
                {
                    return(intersection);
                }
                else if (intersection.P1.BelongsTo(this))
                {
                    if (intersection.P1 == this.Point)
                    {
                        return(this.Point);
                    }
                    else
                    {
                        return(new Segment3d(this.Point, intersection.P1));
                    }
                }
                else if (intersection.P2.BelongsTo(this))
                {
                    if (intersection.P2 == this.Point)
                    {
                        return(this.Point);
                    }
                    else
                    {
                        return(new Segment3d(this.Point, intersection.P2));
                    }
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #21
0
        /// <summary>
        /// Intersection of two circles.
        /// Returns 'null' (no intersection) or object of type 'Circle3d', 'Point3d' or 'Segment3d'.
        /// In 2D (coplanar circles) the segment will define two intersection points.
        /// </summary>
        public object IntersectionWith(Circle3d c)
        {
            // Relative tolerance ================================
            if (!GeometRi3D.UseAbsoluteTolerance)
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * Max(this.R, c.R);
                GeometRi3D.UseAbsoluteTolerance = true;
                object result = this.IntersectionWith(c);
                GeometRi3D.UseAbsoluteTolerance = false;
                GeometRi3D.Tolerance            = tol;
                return(result);
            }
            //====================================================

            if (this.Normal.IsParallelTo(c.Normal))
            {
                if (this.Center.BelongsTo(new Plane3d(c.Center, c.Normal)))
                {
                    // Coplanar objects
                    // Search 2D intersection of two circles

                    // Equal circles
                    if (this.Center == c.Center && GeometRi3D.AlmostEqual(this.R, c.R))
                    {
                        return(this.Copy());
                    }

                    double d = this.Center.DistanceTo(c.Center);

                    // Separated circles
                    if (GeometRi3D.Greater(d, this.R + c.R))
                    {
                        return(null);
                    }

                    // One circle inside the other
                    if (d < Abs(this.R - c.R) - GeometRi3D.Tolerance)
                    {
                        return(null);
                    }

                    // Outer tangency
                    if (GeometRi3D.AlmostEqual(d, this.R + c.R))
                    {
                        Vector3d vec = new Vector3d(this.Center, c.Center);
                        return(this.Center.Translate(this.R * vec.Normalized));
                    }

                    // Inner tangency
                    if (Abs(Abs(this.R - c.R) - d) < GeometRi3D.Tolerance)
                    {
                        Vector3d vec = new Vector3d(this.Center, c.Center);
                        if (this.R > c.R)
                        {
                            return(this.Center.Translate(this.R * vec.Normalized));
                        }
                        else
                        {
                            return(this.Center.Translate(-this.R * vec.Normalized));
                        }
                    }

                    // intersecting circles
                    // Create local CS with origin in circle's center
                    Vector3d vec1     = new Vector3d(this.Center, c.Center);
                    Vector3d vec2     = vec1.Cross(this.Normal);
                    Coord3d  local_cs = new Coord3d(this.Center, vec1, vec2);

                    double  x  = 0.5 * (d * d - c.R * c.R + this.R * this.R) / d;
                    double  y  = 0.5 * Sqrt((-d + c.R - this.R) * (-d - c.R + this.R) * (-d + c.R + this.R) * (d + c.R + this.R)) / d;
                    Point3d p1 = new Point3d(x, y, 0, local_cs);
                    Point3d p2 = new Point3d(x, -y, 0, local_cs);
                    return(new Segment3d(p1, p2));
                }
                else
                {
                    // parallel objects
                    return(null);
                }
            }
            else
            {
                // Check 3D intersection
                Plane3d plane = new Plane3d(this.Center, this.Normal);
                object  obj   = plane.IntersectionWith(c);

                if (obj == null)
                {
                    return(null);
                }
                else if (obj.GetType() == typeof(Point3d))
                {
                    Point3d p = (Point3d)obj;
                    if (p.BelongsTo(c))
                    {
                        return(p);
                    }
                    else
                    {
                        return(null);
                    }
                }
                else
                {
                    Segment3d s = (Segment3d)obj;
                    return(s.IntersectionWith(this));
                }
            }
        }
예제 #22
0
        /// <summary>
        /// Get intersection of line with triangle.
        /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Line3d l)
        {
            // Relative tolerance ================================
            if (!GeometRi3D.UseAbsoluteTolerance)
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * Max(AB, Max(BC, AC));
                GeometRi3D.UseAbsoluteTolerance = true;
                object result = this.IntersectionWith(l);
                GeometRi3D.UseAbsoluteTolerance = false;
                GeometRi3D.Tolerance            = tol;
                return(result);
            }
            //====================================================

            Plane3d s = new Plane3d(this.A, this.Normal);

            object obj = l.IntersectionWith(s);

            if (obj == null)
            {
                return(null);
            }
            else
            {
                if (obj.GetType() == typeof(Line3d))
                {
                    // Coplanar line and triangle

                    // Check intersection in one corner
                    // or in corner and opposite side
                    if (_a.BelongsTo(l))
                    {
                        object obj2 = new Segment3d(_b, _c).IntersectionWith(l);
                        if (obj2 != null && obj2.GetType() == typeof(Point3d))
                        {
                            return(new Segment3d(_a, (Point3d)obj2));
                        }
                        else
                        {
                            return(A);
                        }
                    }

                    if (_b.BelongsTo(l))
                    {
                        object obj2 = new Segment3d(_a, _c).IntersectionWith(l);
                        if (obj2 != null && obj2.GetType() == typeof(Point3d))
                        {
                            return(new Segment3d(_b, (Point3d)obj2));
                        }
                        else
                        {
                            return(B);
                        }
                    }

                    if (_c.BelongsTo(l))
                    {
                        object obj2 = new Segment3d(_a, _b).IntersectionWith(l);
                        if (obj2 != null && obj2.GetType() == typeof(Point3d))
                        {
                            return(new Segment3d(_c, (Point3d)obj2));
                        }
                        else
                        {
                            return(C);
                        }
                    }

                    // Check intersection with two sides
                    object objAB = new Segment3d(_a, _b).IntersectionWith(l);
                    object objBC = new Segment3d(_b, _c).IntersectionWith(l);
                    if (objAB != null && objAB.GetType() == typeof(Point3d))
                    {
                        if (objBC != null && objBC.GetType() == typeof(Point3d))
                        {
                            return(new Segment3d((Point3d)objAB, (Point3d)objBC));
                        }
                        else
                        {
                            object objAC = new Segment3d(_a, _c).IntersectionWith(l);
                            if (objAC != null && objAC.GetType() == typeof(Point3d))
                            {
                                return(new Segment3d((Point3d)objAB, (Point3d)objAC));
                            }
                            else
                            {
                                return((Point3d)objAB);
                            }
                        }
                    }

                    if (objBC != null && objBC.GetType() == typeof(Point3d))
                    {
                        object objAC = new Segment3d(_a, _c).IntersectionWith(l);
                        if (objAC != null && objAC.GetType() == typeof(Point3d))
                        {
                            return(new Segment3d((Point3d)objBC, (Point3d)objAC));
                        }
                        else
                        {
                            return((Point3d)objBC);
                        }
                    }

                    object objAC2 = new Segment3d(_a, _c).IntersectionWith(l);
                    if (objAC2 != null && objAC2.GetType() == typeof(Point3d))
                    {
                        return((Point3d)objAC2);
                    }
                    else
                    {
                        return(null);
                    }
                }
                else
                {
                    // result of intersection is point
                    Point3d p = (Point3d)obj;
                    if (p.BelongsTo(this))
                    {
                        return(p);
                    }
                    else
                    {
                        return(null);
                    }
                }
            }
        }