Example #1
0
        /// <summary>
        /// Determines whether two objects are equal.
        /// </summary>
        public override bool Equals(object obj)
        {
            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))
            {
                return(false);
            }
            Ellipse e = (Ellipse)obj;

            if (GeometRi3D.UseAbsoluteTolerance)
            {
                if (GeometRi3D.AlmostEqual(this.A, this.B))
                {
                    // Ellipse is circle
                    if (GeometRi3D.AlmostEqual(e.A, e.B))
                    {
                        // Second ellipse also circle
                        return(this.Center == e.Center && GeometRi3D.AlmostEqual(this.A, e.A) && e.Normal.IsParallelTo(this.Normal));
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    return(this.Center == e.Center && GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B) &&
                           e.MajorSemiaxis.IsParallelTo(this.MajorSemiaxis) && e.MinorSemiaxis.IsParallelTo(this.MinorSemiaxis));
                }
            }
            else
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * e.MajorSemiaxis.Norm;
                GeometRi3D.UseAbsoluteTolerance = true;

                if (GeometRi3D.AlmostEqual(this.A, this.B))
                {
                    // Ellipse is circle
                    if (GeometRi3D.AlmostEqual(e.A, e.B))
                    {
                        // Second ellipse also circle
                        bool res1 = this.Center == e.Center && GeometRi3D.AlmostEqual(this.A, e.A);
                        GeometRi3D.UseAbsoluteTolerance = false;
                        GeometRi3D.Tolerance            = tol;
                        bool res2 = e.Normal.IsParallelTo(this.Normal);
                        return(res1 && res2);
                    }
                    else
                    {
                        GeometRi3D.UseAbsoluteTolerance = false;
                        GeometRi3D.Tolerance            = tol;
                        return(false);
                    }
                }
                else
                {
                    bool res1 = this.Center == e.Center && GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B);
                    GeometRi3D.UseAbsoluteTolerance = false;
                    GeometRi3D.Tolerance            = tol;
                    bool res2 = e.MajorSemiaxis.IsParallelTo(this.MajorSemiaxis) && e.MinorSemiaxis.IsParallelTo(this.MinorSemiaxis);
                    return(res1 && res2);
                }
            }
        }
Example #2
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.IsOnBoundary(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);
            }
        }
Example #3
0
        private object _line_intersection(Line3d l, double t0, double t1)
        {
            // Smith's algorithm:
            // "An Efficient and Robust Ray–Box Intersection Algorithm"
            // Amy Williams, Steve Barrus, R. Keith Morley, Peter Shirley
            // http://www.cs.utah.edu/~awilliam/box/box.pdf

            // Modified to allow tolerance based checks

            // Relative tolerance ================================
            if (!GeometRi3D.UseAbsoluteTolerance)
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * this.Diagonal;
                GeometRi3D.UseAbsoluteTolerance = true;
                object result = _line_intersection(l, t0, t1);
                GeometRi3D.UseAbsoluteTolerance = false;
                GeometRi3D.Tolerance            = tol;
                return(result);
            }
            //====================================================

            // Define local CS aligned with box
            Coord3d local_CS = new Coord3d(this.Center, this.Orientation.ConvertToGlobal().ToRotationMatrix, "local_CS");

            Point3d Pmin = this.P1.ConvertTo(local_CS);
            Point3d Pmax = this.P7.ConvertTo(local_CS);

            l = new Line3d(l.Point.ConvertTo(local_CS), l.Direction.ConvertTo(local_CS).Normalized);

            double tmin, tmax, tymin, tymax, tzmin, tzmax;
            double divx = 1 / l.Direction.X;

            if (divx >= 0)
            {
                tmin = (Pmin.X - l.Point.X) * divx;
                tmax = (Pmax.X - l.Point.X) * divx;
            }
            else
            {
                tmin = (Pmax.X - l.Point.X) * divx;
                tmax = (Pmin.X - l.Point.X) * divx;
            }

            double divy = 1 / l.Direction.Y;

            if (divy >= 0)
            {
                tymin = (Pmin.Y - l.Point.Y) * divy;
                tymax = (Pmax.Y - l.Point.Y) * divy;
            }
            else
            {
                tymin = (Pmax.Y - l.Point.Y) * divy;
                tymax = (Pmin.Y - l.Point.Y) * divy;
            }

            if (GeometRi3D.Greater(tmin, tymax) || GeometRi3D.Greater(tymin, tmax))
            {
                return(null);
            }
            if (GeometRi3D.Greater(tymin, tmin))
            {
                tmin = tymin;
            }
            if (GeometRi3D.Smaller(tymax, tmax))
            {
                tmax = tymax;
            }

            double divz = 1 / l.Direction.Z;

            if (divz >= 0)
            {
                tzmin = (Pmin.Z - l.Point.Z) * divz;
                tzmax = (Pmax.Z - l.Point.Z) * divz;
            }
            else
            {
                tzmin = (Pmax.Z - l.Point.Z) * divz;
                tzmax = (Pmin.Z - l.Point.Z) * divz;
            }

            if (GeometRi3D.Greater(tmin, tzmax) || GeometRi3D.Greater(tzmin, tmax))
            {
                return(null);
            }
            if (GeometRi3D.Greater(tzmin, tmin))
            {
                tmin = tzmin;
            }
            if (GeometRi3D.Smaller(tzmax, tmax))
            {
                tmax = tzmax;
            }

            // Now check the overlapping portion of the segments
            // This part is missing in the original algorithm
            if (GeometRi3D.Greater(tmin, t1))
            {
                return(null);
            }
            if (GeometRi3D.Smaller(tmax, t0))
            {
                return(null);
            }

            if (GeometRi3D.Smaller(tmin, t0))
            {
                tmin = t0;
            }
            if (GeometRi3D.Greater(tmax, t1))
            {
                tmax = t1;
            }

            if (GeometRi3D.AlmostEqual(tmin, tmax))
            {
                return(l.Point.Translate(tmin * l.Direction));
            }
            else
            {
                return(new Segment3d(l.Point.Translate(tmin * l.Direction), l.Point.Translate(tmax * l.Direction)));
            }
        }
Example #4
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 (GeometRi3D.AlmostEqual(det, 0))
                    {
                        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
                    {
                        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
                {
                    // 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);
                }
            }
        }
Example #5
0
        /// <summary>
        /// Determines whether two objects are equal.
        /// </summary>
        public override bool Equals(object obj)
        {
            if (obj == null || (!object.ReferenceEquals(this.GetType(), obj.GetType())))
            {
                return(false);
            }
            Ellipsoid e = (Ellipsoid)obj;

            if (GeometRi3D.UseAbsoluteTolerance)
            {
                if (this.Center != e.Center)
                {
                    return(false);
                }

                if (GeometRi3D.AlmostEqual(this.A, this.B) && GeometRi3D.AlmostEqual(this.A, this.C))
                {
                    // Ellipsoid is sphere
                    if (GeometRi3D.AlmostEqual(e.A, e.B) && GeometRi3D.AlmostEqual(e.A, e.C))
                    {
                        // Second ellipsoid also sphere
                        return(GeometRi3D.AlmostEqual(this.A, e.A));
                    }
                    else
                    {
                        return(false);
                    }
                }
                else if (GeometRi3D.AlmostEqual(this.A, this.B) && GeometRi3D.AlmostEqual(e.A, e.B))
                {
                    return(GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.C, e.C) &&
                           e.SemiaxisC.IsParallelTo(this.SemiaxisC));
                }
                else if (GeometRi3D.AlmostEqual(this.A, this.C) && GeometRi3D.AlmostEqual(e.A, e.C))
                {
                    return(GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B) &&
                           e.SemiaxisB.IsParallelTo(this.SemiaxisB));
                }
                else if (GeometRi3D.AlmostEqual(this.C, this.B) && GeometRi3D.AlmostEqual(e.C, e.B))
                {
                    return(GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.C, e.C) &&
                           e.SemiaxisA.IsParallelTo(this.SemiaxisA));
                }
                else
                {
                    return(GeometRi3D.AlmostEqual(this.A, e.A) && e.SemiaxisA.IsParallelTo(this.SemiaxisA) &&
                           GeometRi3D.AlmostEqual(this.B, e.B) && e.SemiaxisB.IsParallelTo(this.SemiaxisB) &&
                           GeometRi3D.AlmostEqual(this.C, e.C) && e.SemiaxisC.IsParallelTo(this.SemiaxisC));
                }
            }
            else
            {
                double tol = GeometRi3D.Tolerance;
                GeometRi3D.Tolerance            = tol * e.SemiaxisA.Norm;
                GeometRi3D.UseAbsoluteTolerance = true;

                if (this.Center != e.Center)
                {
                    GeometRi3D.UseAbsoluteTolerance = false;
                    GeometRi3D.Tolerance            = tol;
                    return(false);
                }

                if (GeometRi3D.AlmostEqual(this.A, this.B) && GeometRi3D.AlmostEqual(this.A, this.C))
                {
                    // Ellipsoid is sphere
                    if (GeometRi3D.AlmostEqual(e.A, e.B) && GeometRi3D.AlmostEqual(e.A, e.C))
                    {
                        // Second ellipsoid also sphere
                        bool res = GeometRi3D.AlmostEqual(this.A, e.A);
                        GeometRi3D.UseAbsoluteTolerance = false;
                        GeometRi3D.Tolerance            = tol;
                        return(res);
                    }
                    else
                    {
                        GeometRi3D.UseAbsoluteTolerance = false;
                        GeometRi3D.Tolerance            = tol;
                        return(false);
                    }
                }
                else if (GeometRi3D.AlmostEqual(this.A, this.B) && GeometRi3D.AlmostEqual(e.A, e.B))
                {
                    bool res1 = GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.C, e.C);
                    GeometRi3D.UseAbsoluteTolerance = false;
                    GeometRi3D.Tolerance            = tol;
                    bool res2 = e.SemiaxisC.IsParallelTo(this.SemiaxisC);
                    return(res1 && res2);
                }
                else if (GeometRi3D.AlmostEqual(this.A, this.C) && GeometRi3D.AlmostEqual(e.A, e.C))
                {
                    bool res1 = GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B);
                    GeometRi3D.UseAbsoluteTolerance = false;
                    GeometRi3D.Tolerance            = tol;
                    bool res2 = e.SemiaxisB.IsParallelTo(this.SemiaxisB);
                    return(res1 && res2);
                }
                else if (GeometRi3D.AlmostEqual(this.C, this.B) && GeometRi3D.AlmostEqual(e.C, e.B))
                {
                    bool res1 = GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.C, e.C);
                    GeometRi3D.UseAbsoluteTolerance = false;
                    GeometRi3D.Tolerance            = tol;
                    bool res2 = e.SemiaxisA.IsParallelTo(this.SemiaxisA);
                    return(res1 && res2);
                }
                else
                {
                    bool res1 = GeometRi3D.AlmostEqual(this.A, e.A) && GeometRi3D.AlmostEqual(this.B, e.B) && GeometRi3D.AlmostEqual(this.C, e.C);
                    GeometRi3D.UseAbsoluteTolerance = false;
                    GeometRi3D.Tolerance            = tol;
                    bool res2 = e.SemiaxisA.IsParallelTo(this.SemiaxisA) && e.SemiaxisB.IsParallelTo(this.SemiaxisB) && e.SemiaxisC.IsParallelTo(this.SemiaxisC);
                    return(res1 && res2);
                }
            }
        }
Example #6
0
        /// <summary>
        /// Calculates the point on the ellipsoid's boundary closest to given point.
        /// </summary>
        public Point3d ClosestPoint(Point3d p)
        {
            // Algorithm by Dr. Robert Nurnberg
            // http://wwwf.imperial.ac.uk/~rn/distance2ellipse.pdf

            Coord3d local_coord = new Coord3d(this.Center, this._v1, this._v2);

            p = p.ConvertTo(local_coord);

            if (GeometRi3D.AlmostEqual(p.X, 0) && GeometRi3D.AlmostEqual(p.Y, 0))
            {
                // Center point, choose any minor-axis
                return(new Point3d(0, C, 0, local_coord));
            }

            double  theta    = Atan2(A * p.Y, B * p.X);
            double  phi      = Atan2(p.Z, C * Sqrt((p.X * p.X) / (A * A) + (p.Y * p.Y) / (B * B)));
            int     iter     = 0;
            int     max_iter = 100;
            Point3d n0       = p.Copy();

            while (iter < max_iter)
            {
                iter += 1;
                double ct = Cos(theta);
                double st = Sin(theta);
                double cp = Cos(phi);
                double sp = Sin(phi);

                double F1 = (A * A - B * B) * ct * st * cp - p.X * A * st + p.Y * B * ct;
                double F2 = (A * A * ct * ct + B * B * st * st - C * C) * sp * cp - p.X * A * sp * ct - p.Y * B * sp * st + p.Z * C * cp;

                double a11 = (A * A - B * B) * (ct * ct - st * st) * cp - p.X * A * ct - p.Y * B * st;
                double a12 = -(A * A - B * B) * ct * st * sp;
                double a21 = -2.0 * (A * A - B * B) * ct * st * cp * sp + p.X * A * sp * st - p.Y * B * sp * ct;
                double a22 = (A * A * ct * ct + B * B * st * st - C * C) * (cp * cp - sp * sp) - p.X * A * cp * ct - p.Y * B * cp * st - p.Z * C * sp;

                double det = a11 * a22 - a12 * a21;
                if (det == 0)
                {
                    throw new Exception("Zero determinant");
                }
                // Calc reverse matrix B[ij] = A[ij]^-1
                double b11 = a22 / det;
                double b12 = -a12 / det;
                double b21 = -a21 / det;
                double b22 = a11 / det;

                theta = theta - (b11 * F1 + b12 * F2);
                phi   = phi - (b21 * F1 + b22 * F2);

                Point3d n = new Point3d(A * Cos(phi) * Cos(theta), B * Cos(phi) * Sin(theta), C * Sin(phi), local_coord);

                if (n0.DistanceTo(n) < GeometRi3D.Tolerance)
                {
                    return(n);
                }
                n0 = n.Copy();
            }

            return(n0);
        }
        /// <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);
                }

            }

        }
Example #8
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);
            }
        }
Example #9
0
        /// <summary>
        /// Intersection of ellipse with plane.
        /// Returns 'null' (no intersection) or object of type 'Ellipse', 'Point3d' or 'Segment3d'.
        /// </summary>
        public object IntersectionWith(Plane3d s)
        {
            if (this.Normal.IsParallelTo(s.Normal))
            {
                if (this.Center.BelongsTo(s))
                {
                    // coplanar objects
                    return(this.Copy());
                }
                else
                {
                    // parallel objects
                    return(null);
                }
            }
            else
            {
                Line3d   l           = (Line3d)s.IntersectionWith(new Plane3d(this.Center, this.Normal));
                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;
                }

                // Find intersection of line and ellipse (2D)
                // Solution from: http://www.ambrsoft.com/TrigoCalc/Circles2/Ellipse/EllipseLine.htm

                // 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 (GeometRi3D.AlmostEqual(det, 0))
                {
                    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
                {
                    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)));
                }
            }
        }