/// <summary> /// Shortest distance between triangle and point /// </summary> public double DistanceTo(Point3d p) { Point3d projection_point = p.ProjectionTo(this.ToPlane); double tol = GeometRi3D.Tolerance; bool mode = GeometRi3D.UseAbsoluteTolerance; GeometRi3D.Tolerance = GeometRi3D.DefaultTolerance; GeometRi3D.UseAbsoluteTolerance = true; int code = _PointLocation(projection_point); // Restore initial state GeometRi3D.UseAbsoluteTolerance = mode; GeometRi3D.Tolerance = tol; if (code >= 0) { return(p.DistanceTo(projection_point)); } Segment3d AB = new Segment3d(this._a, this._b); Segment3d BC = new Segment3d(this._b, this._c); Segment3d AC = new Segment3d(this._a, this._c); double dist = p.DistanceTo(AB); double dist2 = p.DistanceTo(BC); double dist3 = p.DistanceTo(AC); return(Min(dist, Min(dist2, dist3))); }
/// <summary> /// Shortest distance between sphere and segment /// </summary> public double DistanceTo(Segment3d s) { if (this.Center.ProjectionTo(s.ToLine).BelongsTo(s)) { return(this.DistanceTo(s.ToLine)); } else { return(Min(this.DistanceTo(s.P1), this.DistanceTo(s.P2))); } }
/// <summary> /// Return Axis Aligned Bounding Box (AABB) in given coordinate system. /// </summary> public Box3d BoundingBox(Coord3d coord = null) { coord = (coord == null) ? Coord3d.GlobalCS : coord; Line3d l1 = new Line3d(coord.Origin, coord.Xaxis); Line3d l2 = new Line3d(coord.Origin, coord.Yaxis); Line3d l3 = new Line3d(coord.Origin, coord.Zaxis); Segment3d s1 = this.ProjectionTo(l1); Segment3d s2 = this.ProjectionTo(l2); Segment3d s3 = this.ProjectionTo(l3); return new Box3d(_point, s1.Length, s2.Length, s3.Length, coord); }
/// <summary> /// Returns shortest distance from point to the segment /// </summary> public double DistanceTo(Segment3d s) { Point3d projection = this.ProjectionTo(s.ToLine); if (s._AxialPointLocation(projection) > 0) { return(this.DistanceTo(projection)); } else { return(Min(this.DistanceTo(s.P1), this.DistanceTo(s.P2))); } }
/// <summary> /// Calculates the point on the triangle closest to given point. /// </summary> public Point3d ClosestPoint(Point3d p) { Point3d projection_point = p.ProjectionTo(this.ToPlane); double tol = GeometRi3D.Tolerance; bool mode = GeometRi3D.UseAbsoluteTolerance; GeometRi3D.Tolerance = GeometRi3D.DefaultTolerance; GeometRi3D.UseAbsoluteTolerance = true; int code = _PointLocation(projection_point); // Restore initial state GeometRi3D.UseAbsoluteTolerance = mode; GeometRi3D.Tolerance = tol; if (code >= 0) { return(projection_point); } Segment3d AB = new Segment3d(this._a, this._b); Segment3d BC = new Segment3d(this._b, this._c); Segment3d AC = new Segment3d(this._a, this._c); double dist = p.DistanceTo(AB); Point3d closest_point = AB.ClosestPoint(p); double dist2 = p.DistanceTo(BC); if (dist2 < dist) { dist = dist2; closest_point = BC.ClosestPoint(p); } dist2 = p.DistanceTo(AC); if (dist2 < dist) { dist = dist2; closest_point = AC.ClosestPoint(p); } return(closest_point); }
/// <summary> /// Return Axis Aligned Bounding Box (AABB) in given coordinate system. /// </summary> public Box3d BoundingBox(Coord3d coord = null) { coord = (coord == null) ? Coord3d.GlobalCS : coord; Line3d l1 = new Line3d(coord.Origin, coord.Xaxis); Line3d l2 = new Line3d(coord.Origin, coord.Yaxis); Line3d l3 = new Line3d(coord.Origin, coord.Zaxis); double px, py, pz, lx, ly, lz; Segment3d s = this.ProjectionTo(l1); px = (0.5 * (s.P1 + s.P2)).ConvertTo(coord).X; lx = s.Length; s = this.ProjectionTo(l2); py = (0.5 * (s.P1 + s.P2)).ConvertTo(coord).Y; ly = s.Length; s = this.ProjectionTo(l3); pz = (0.5 * (s.P1 + s.P2)).ConvertTo(coord).Z; lz = s.Length; return(new Box3d(new Point3d(px, py, pz, coord), lx, ly, lz, coord)); }
/// <summary> /// Get intersection of segment with triangle. /// 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 * Max(s.Length, Max(AB, Max(BC, AC))); GeometRi3D.UseAbsoluteTolerance = true; object result = this.IntersectionWith(s); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } //==================================================== object obj = this.IntersectionWith(s.ToLine); if (obj == null) { return(null); } else if (obj.GetType() == typeof(Point3d)) { Point3d p = (Point3d)obj; if (p.BelongsTo(s)) { return(p); } else { return(null); } } else { return(s.IntersectionWith((Segment3d)obj)); } }
/// <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); } Segment3d s = (Segment3d)obj; if (GeometRi3D.UseAbsoluteTolerance) { return((this.P1 == s.P1 && this.P2 == s.P2) | (this.P1 == s.P2 && this.P2 == s.P1)); } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * this.Length; GeometRi3D.UseAbsoluteTolerance = true; bool result = (this.P1 == s.P1 && this.P2 == s.P2) | (this.P1 == s.P2 && this.P2 == s.P1); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
/// <summary> /// Intersection of circle with segment. /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'. /// </summary> public object IntersectionWith(Segment3d s) { Ellipse e = this.ToEllipse; return(e.IntersectionWith(s)); }
/// <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> /// Distance to a segment /// </summary> public double DistanceTo(Segment3d s) { return(s.DistanceTo(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)) { 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> /// Returns shortest distance between two segments /// </summary> public double DistanceTo(Segment3d s) { // Algorithm by Dan Sunday // http://geomalgorithms.com/a07-_distance.html double small = GeometRi3D.Tolerance; Vector3d u = this.ToVector; Vector3d v = s.ToVector; Vector3d w = new Vector3d(s.P1, this.P1); double a = u * u; double b = u * v; double c = v * v; double d = u * w; double e = v * w; double DD = a * c - b * b; double sc = 0; double sN = 0; double sD = 0; double tc = 0; double tN = 0; double tD = 0; sD = DD; tD = DD; if (DD < small) { // the lines are almost parallel, force using point Me.P1 to prevent possible division by 0.0 later sN = 0.0; sD = 1.0; tN = e; tD = c; } else { // get the closest points on the infinite lines sN = (b * e - c * d); tN = (a * e - b * d); if ((sN < 0.0)) { // sc < 0 => the s=0 edge Is visible sN = 0.0; tN = e; tD = c; } else if ((sN > sD)) { // sc > 1 => the s=1 edge Is visible sN = sD; tN = e + b; tD = c; } } if ((tN < 0.0)) { // tc < 0 => the t=0 edge Is visible tN = 0.0; // recompute sc for this edge if ((-d < 0.0)) { sN = 0.0; } else if ((-d > a)) { sN = sD; } else { sN = -d; sD = a; } } else if ((tN > tD)) { // tc > 1 => the t=1 edge Is visible tN = tD; // recompute sc for this edge if (((-d + b) < 0.0)) { sN = 0; } else if (((-d + b) > a)) { sN = sD; } else { sN = (-d + b); sD = a; } } // finally do the division to get sc And tc sc = Abs(sN) < small ? 0.0 : sN / sD; tc = Abs(tN) < small ? 0.0 : tN / tD; // get the difference of the two closest points Vector3d dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc) return(dP.Norm); }
/// <summary> /// Check if point belongs to the segment /// </summary> /// <returns>True, if the point belongs to the segment</returns> public bool BelongsTo(Segment3d s) { return(this.BelongsTo(s.ToRay) && this.BelongsTo(new Ray3d(s.P2, new Vector3d(s.P2, s.P1)))); }
/// <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); } } } }
/// <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> /// 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 segment. /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'. /// </summary> public object IntersectionWith(Segment3d s) { return(s.IntersectionWith(this)); }
/// <summary> /// Get intersection of segment with box. /// Returns 'null' (no intersection) or object of type 'Point3d' or 'Segment3d'. /// </summary> public object IntersectionWith(Segment3d s) { return(_line_intersection(s.ToLine, 0.0, s.Length)); }
/// <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); } }