/// <summary> /// Check if point belongs to the circle /// </summary> /// <returns>True, if the point belongs to the circle</returns> public bool BelongsTo(Circle3d c) { if (GeometRi3D.UseAbsoluteTolerance) { return(GeometRi3D.AlmostEqual(this.DistanceTo(c.Center), c.R) && c.Normal.Normalized.IsOrthogonalTo(new Vector3d(c.Center, this))); } else { return(GeometRi3D.AlmostEqual((this.DistanceTo(c.Center) - c.R) / c.R, 0.0) && c.Normal.Normalized.IsOrthogonalTo(new Vector3d(c.Center, this))); } }
/// <summary> /// Shortest distance from box to circle /// </summary> public double DistanceTo(Circle3d c) { if (c.Center.IsInside(this)) { return(0); } double min_dist = Double.PositiveInfinity; foreach (Triangle triangle in ListOfTriangles) { double dist = c.DistanceTo(triangle); if (dist < min_dist) { min_dist = dist; } } return(min_dist); }
/// <summary> /// Shortest distance between two circles (including interior points) (approximate solution) /// </summary> public double DistanceTo(Circle3d c) { 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) { return(vdist); } else { 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; 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; return(Min(dist1, dist2)); }
/// <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); } Circle3d c = (Circle3d)obj; if (GeometRi3D.UseAbsoluteTolerance) { return(c.Center == this.Center && Abs(c.R - this.R) <= GeometRi3D.Tolerance && c.Normal.IsParallelTo(this.Normal)); } else { return(Abs(c.Center.DistanceTo(this.Center)) / this.R <= GeometRi3D.Tolerance && Abs(c.R - this.R) / this.R <= GeometRi3D.Tolerance && c.Normal.IsParallelTo(this.Normal)); } }
/// <summary> /// Intersection check between circle and box /// </summary> public bool Intersects(Circle3d c) { if (c.Center.IsInside(this)) { return(true); } if (c.Center.DistanceTo(this) > c.R) { return(false); } foreach (Triangle triangle in ListOfTriangles) { if (c.Intersects(triangle)) { return(true); } } return(false); }
/// <summary> /// Shortest distance between two circles (including interior points) (approximate solution) /// <para> The output points may be not unique in case of intersecting objects.</para> /// </summary> /// <param name="s">Target sphere</param> /// <param name="p1">Closest point on circle</param> /// <param name="p2">Closest point on sphere</param> public double DistanceTo(Sphere s, out Point3d p1, out Point3d p2) { Plane3d p = this.ToPlane; if (s.Center.ProjectionTo(p).BelongsTo(this)) { p1 = s.Center.ProjectionTo(p); if (s.Center == p1) { p2 = s.Center.Translate(s.R * this.Normal.Normalized); } else { p2 = s.Center.Translate(s.R * new Vector3d(s.Center, p1).Normalized); } return(s.DistanceTo(p)); } if (this.Intersects(s)) { Object obj = s.IntersectionWith(p); if (obj.GetType() == typeof(Point3d)) { p1 = (Point3d)obj; p2 = p1; } else { Circle3d c = (Circle3d)obj; p1 = this.Center.Translate(this.R * new Vector3d(this.Center, c.Center).Normalized); p2 = c.Center.Translate(c.R * new Vector3d(c.Center, this.Center).Normalized); } return(0); } double dist = _distance_cicle_to_sphere(this, s, out p1, out p2); return(dist); }
/// <summary> /// Intersection check between circle and box /// </summary> public bool Intersects(Circle3d c) { //if (c.Center.IsInside(this)) return true; double dist = c._point.DistanceTo(this); if (dist > c.R) { return(false); } if (dist < GeometRi3D.Tolerance) { return(true); } foreach (Triangle triangle in ListOfTriangles) { if (c.Intersects(triangle)) { return(true); } } return(false); }
/// <summary> /// Check if point is inside circle /// </summary> /// <returns>True, if the point is inside circle</returns> public bool IsInside(Circle3d c) { if (GeometRi3D.UseAbsoluteTolerance) { if (this.BelongsTo(new Plane3d(c.Center, c.Normal))) { return(GeometRi3D.Smaller(this.DistanceTo(c.Center), c.R)); } else { return(false); } } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * c.R; GeometRi3D.UseAbsoluteTolerance = true; bool result = this.IsInside(c); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
/// <summary> /// Closest point on circle (including interior points). /// </summary> public Point3d ClosestPoint(Circle3d c) { return(c.ClosestPoint(this)); }
private double _distance_cicle_to_circle(Circle3d c1, Circle3d c2, out Point3d p1, out Point3d p2) // Use quadratic interpolation to find closest point on one circle to other // p1 and p2 - closest points on both circles { double d1 = 1e20; double t1 = 0; Point3d p; for (int i = 0; i < 16; i++) { double t = i * Math.PI / 8; p = c1.ParametricForm(t); double dist = p.DistanceTo(c2); if (dist < d1) { d1 = dist; t1 = t; } } double t2 = t1 - Math.PI / 8; p = c1.ParametricForm(t2); double d2 = p.DistanceTo(c2); double t3 = t1 + Math.PI / 8; p = c1.ParametricForm(t3); double d3 = p.DistanceTo(c2); int iter = 0; bool flag = false; while (d2 - d1 > 0.2 * GeometRi3D.DefaultTolerance && d1 > GeometRi3D.DefaultTolerance) { if (++iter > 100) { break; } double ax = 2.0 * d1 / (t1 - t2) / (t1 - t3); double aa = 0.5 * ax * (t2 + t3); double bx = 2.0 * d2 / (t2 - t1) / (t2 - t3); double bb = 0.5 * bx * (t1 + t3); double cx = 2.0 * d3 / (t3 - t1) / (t3 - t2); double cc = 0.5 * cx * (t1 + t2); double t = (aa + bb + cc) / (ax + bx + cx); p = c1.ParametricForm(t); double d = p.DistanceTo(c2); if (d > d1) // Possible special case, non-smooth function ( f(t)=|t| ) { flag = true; break; } if (t > t2 & t < t1) { t3 = t1; d3 = d1; } else { t2 = t1; d2 = d1; } t1 = t; d1 = d; } if (flag) // Possible special case, non-smooth function ( f(t)=|t| ) { while (d2 - d1 > 0.2 * GeometRi3D.DefaultTolerance && d1 > GeometRi3D.DefaultTolerance) { if (++iter > 100) { break; } double t = (t2 + t1) / 2; p = c1.ParametricForm(t); double d = p.DistanceTo(c2); if (d < d1) { t3 = t1; d3 = d1; t1 = t; d1 = d; } else { t2 = t; d2 = d; } t = (t3 + t1) / 2; p = c1.ParametricForm(t); d = p.DistanceTo(c2); if (d < d1) { t2 = t1; d2 = d1; t1 = t; d1 = d; } else { t3 = t; d3 = d; } } } p1 = c1.ParametricForm(t1); p2 = c2.ClosestPoint(p1); return(d1); }
/// <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> /// Intersection of circle with plane. /// Returns 'null' (no intersection) or object of type 'Circle3d', 'Point3d' or 'Segment3d'. /// </summary> public object IntersectionWith(Circle3d c) { return(c.IntersectionWith(this)); }
/// <summary> /// Shortest distance between plane and circle (including interior points) /// </summary> /// <param name="c">Target circle</param> /// <param name="point_on_plane">Closest point on plane</param> /// <param name="point_on_circle">Closest point on circle</param> public double DistanceTo(Circle3d c, out Point3d point_on_plane, out Point3d point_on_circle) { return(c.DistanceTo(this, out point_on_circle, out point_on_plane)); }
/// <summary> /// Distance from plane to circle /// </summary> public double DistanceTo(Circle3d c) { return(c.DistanceTo(this)); }
/// <summary> /// Shortest distance between sphere and circle (including interior points) (approximate solution). /// <para> The output points may be not unique in case of intersecting objects.</para> /// </summary> /// <param name="c">Target circle</param> /// <param name="p1">Closest point on sphere</param> /// <param name="p2">Closest point on circle</param> public double DistanceTo(Circle3d c, out Point3d p1, out Point3d p2) { return(c.DistanceTo(this, out p2, out p1)); }
/// <summary> /// Intersection check between circle and triangle /// </summary> public bool Intersects(Circle3d c) { return(c.Intersects(this)); }
/// <summary> /// Shortest distance between triangle and circle (including interior points) /// </summary> public double DistanceTo(Circle3d c) { Point3d point_on_circle, point_on_triangle; return(c.DistanceTo(this, out point_on_circle, out point_on_triangle)); }
/// <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> /// Shortest distance between segment and circle (including interior points) /// </summary> /// <param name="c">Target circle</param> /// <param name="point_on_segment">Closest point on segment</param> /// <param name="point_on_circle">Closest point on circle</param> public double DistanceTo(Circle3d c, out Point3d point_on_segment, out Point3d point_on_circle) { return(c.DistanceTo(this, out point_on_circle, out point_on_segment)); }
/// <summary> /// Intersection check between segment and circle /// </summary> public bool Intersects(Circle3d c) { return(this.IntersectionWith(c) != null); }
private double _distance_cicle_to_sphere(Circle3d c1, Sphere c2, out Point3d p1, out Point3d p2) // Use quadratic interpolation to find closest point on circle // p1 and p2 - closest points on circle and sphere respectively { double d1 = 1e20; double t1 = 0; Point3d p; for (int i = 0; i < 16; i++) { double t = i * Math.PI / 8; p = c1.ParametricForm(t); double dist = p.DistanceTo(c2); if (dist < d1) { d1 = dist; t1 = t; } } double t2 = t1 - Math.PI / 8; p = c1.ParametricForm(t2); double d2 = p.DistanceTo(c2); double t3 = t1 + Math.PI / 8; p = c1.ParametricForm(t3); double d3 = p.DistanceTo(c2); int iter = 0; while (d2 - d1 > 0.2 * GeometRi3D.DefaultTolerance && d1 > GeometRi3D.DefaultTolerance) { if (++iter > 100) { break; } double ax = 2.0 * d1 / (t1 - t2) / (t1 - t3); double aa = 0.5 * ax * (t2 + t3); double bx = 2.0 * d2 / (t2 - t1) / (t2 - t3); double bb = 0.5 * bx * (t1 + t3); double cx = 2.0 * d3 / (t3 - t1) / (t3 - t2); double cc = 0.5 * cx * (t1 + t2); double t = (aa + bb + cc) / (ax + bx + cx); p = c1.ParametricForm(t); double d = p.DistanceTo(c2); if (d < d1) { if (t > t2 & t < t1) { t3 = t1; d3 = d1; } else { t2 = t1; d2 = d1; } t1 = t; d1 = d; } else { if (t < t1) { t2 = t; d2 = d; } else { t3 = t; d3 = d; } } } p1 = c1.ParametricForm(t1); p2 = c2.ClosestPoint(p1); return(d1); }