/// <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); } } }
/// <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); } }
/// <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"); } }
/// <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); } } }
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); } }
/// <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); } }
/// <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)); } }
/// <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)); } }
/// <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); } }
/// <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); } }
/// <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))); }
/// <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)); } }
/// <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); } } }
/// <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); } }
/// <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)); }
/// <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); } } }
/// <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); } } }
/// <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); } } } }
/// <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); } }
/// <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); } } }
/// <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)); } } }
/// <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); } } } }