/// <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> /// Orthogonal projection of the circle to line /// </summary> public Segment3d ProjectionTo(Line3d l) { double s = _r * Cos(l.AngleTo(this)); Vector3d v = l.Direction.Normalized; Point3d p = _point.ProjectionTo(l); return new Segment3d(p.Translate(-s * v), p.Translate(s * v)); }
/// <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> /// Orthogonal projection of the ellipse to plane /// </summary> public Ellipse ProjectionTo(Plane3d s) { Point3d c = _point.ProjectionTo(s); Point3d q = _point.Translate(_v1).ProjectionTo(s); Point3d p = _point.Translate(_v2).ProjectionTo(s); Vector3d f1 = new Vector3d(c, p); Vector3d f2 = new Vector3d(c, q); double t0 = 0.5 * Atan2(2 * f1 * f2, f1 * f1 - f2 * f2); Vector3d v1 = f1 * Cos(t0) + f2 * Sin(t0); Vector3d v2 = f1 * Cos(t0 + PI / 2) + f2 * Sin(t0 + PI / 2); return(new Ellipse(c, v1, v2)); }
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> /// 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> /// 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); } } }
internal override int _PointLocation(Point3d p) { if (GeometRi3D.UseAbsoluteTolerance) { Plane3d s = new Plane3d(this.Center, this.Normal); Point3d proj = p.ProjectionTo(s); if (GeometRi3D.AlmostEqual(p.DistanceTo(proj), 0)) { if (GeometRi3D.Smaller(p.DistanceTo(this.Center), this.R)) { return(1); // Point is strictly inside } else if (GeometRi3D.AlmostEqual(p.DistanceTo(this.Center), this.R)) { return(0); // Point is on boundary } else { return(-1); // Point is outside } } else { return(-1); // Point is outside } } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * this.R; GeometRi3D.UseAbsoluteTolerance = true; int result = this._PointLocation(p); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
internal override int _PointLocation(Point3d p) { if (GeometRi3D.UseAbsoluteTolerance) { Point3d proj = p.ProjectionTo(this.ToLine); if (GeometRi3D.AlmostEqual(p.DistanceTo(proj), 0)) { if (GeometRi3D.AlmostEqual(p.DistanceTo(this.P1), 0) || GeometRi3D.AlmostEqual(p.DistanceTo(this.P2), 0)) { return(0); // Point is on boundary } else if (Abs(new Vector3d(proj, this.P1).AngleTo(new Vector3d(proj, this.P2))) < 2e-8) // Need to decrease accuracy due to Acos calculations { return(-1); // Point is outside } else { return(1); // // Point is strictly inside } } else { return(-1); // Point is outside } } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * this.Length; GeometRi3D.UseAbsoluteTolerance = true; int result = this._PointLocation(p); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
/// <summary> /// Orthogonal projection of the triangle to line /// </summary> public Segment3d ProjectionTo(Line3d l) { double d12, d23, d13; Point3d p1, p2, p3; p1 = _a.ProjectionTo(l); p2 = _b.ProjectionTo(l); p3 = _c.ProjectionTo(l); d12 = p1.DistanceTo(p2); d13 = p1.DistanceTo(p3); d23 = p2.DistanceTo(p3); if (d12 >= d13 && d12 >= d23) { return(new Segment3d(p1, p2)); } else if (d13 >= d23) { return(new Segment3d(p1, p3)); } else { return(new Segment3d(p2, p3)); } }
internal override int _PointLocation(Point3d p) { if (GeometRi3D.UseAbsoluteTolerance) { Point3d proj = p.ProjectionTo(this.ToLine); if (GeometRi3D.AlmostEqual(p.DistanceTo(proj), 0)) { if (GeometRi3D.AlmostEqual(p.DistanceTo(this._p1), 0) || GeometRi3D.AlmostEqual(p.DistanceTo(this._p2), 0)) { return(0); // Point is on boundary } else if (Abs(new Vector3d(proj, this._p1).Normalized.AngleTo(new Vector3d(proj, this._p2).Normalized)) < PI / 2) { return(-1); // Point is outside } else { return(1); // // Point is strictly inside } } else { return(-1); // Point is outside } } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * this.Length; GeometRi3D.UseAbsoluteTolerance = true; int result = this._PointLocation(p); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
/// <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)); }