/// <summary> /// Check if two objects are orthogonal /// </summary> public bool IsOrthogonalTo(ILinearObject obj) { Vector3d v = obj.Direction; if ((this._coord != v._coord)) { v = v.ConvertTo(this._coord); } double this_norm = this.Norm; double v_norm = v.Norm; if (GeometRi3D.UseAbsoluteTolerance) { if (GeometRi3D.Greater(this_norm, 0.0) && GeometRi3D.Greater(v_norm, 0.0)) { return(GeometRi3D.AlmostEqual(Abs(this * v), 0.0)); } else { return(false); } } else { if (this_norm > 0.0 && v_norm > 0.0) { return(GeometRi3D.AlmostEqual(Abs(this * v) / (this_norm * v_norm), 0.0)); } else { return(false); } } }
internal int _AxialPointLocation(Point3d p) { if (GeometRi3D.UseAbsoluteTolerance) { 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(p, this._p1).Normalized.AngleTo(new Vector3d(p, this._p2).Normalized)) < PI / 2) { return(-1); // Point is outside } else { return(1); // // Point is strictly inside } } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * this.Length; GeometRi3D.UseAbsoluteTolerance = true; int result = this._AxialPointLocation(p); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
/// <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); } Box3d b = (Box3d)obj; if (GeometRi3D.UseAbsoluteTolerance) { return(this.Center == b.Center && _r == b.Orientation && GeometRi3D.AlmostEqual(L1, b.L1) && GeometRi3D.AlmostEqual(L2, b.L2) && GeometRi3D.AlmostEqual(L3, b.L3)); } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * this.Diagonal; GeometRi3D.UseAbsoluteTolerance = true; bool result = this.Equals(b); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
internal override int _PointLocation(Point3d p) { Coord3d lc = new Coord3d(this.Center, this.SemiaxisA, this.SemiaxisB); p = p.ConvertTo(lc); if (GeometRi3D.UseAbsoluteTolerance) { double dist = this.ClosestPoint(p).DistanceTo(p); if (GeometRi3D.AlmostEqual(dist, 0)) { return(0); // Point is on boundary } if (GeometRi3D.Smaller(p.X * p.X / (A * A) + p.Y * p.Y / (B * B) + p.Z * p.Z / (C * C), 1.0)) { return(1); // Point is strictly inside box } return(-1); // Point is outside } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * this.A; GeometRi3D.UseAbsoluteTolerance = true; int result = this._PointLocation(p); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
/// <summary> /// Point on axis aligned box (including interior points) closest to target point "p". /// </summary> public Point3d AABBClosestPoint(Point3d p) { p = p.ConvertToGlobal(); double x = GeometRi3D.Clamp(p.X, this._center.X - _lx / 2, this._center.X + _lx / 2); double y = GeometRi3D.Clamp(p.Y, this._center.Y - _ly / 2, this._center.Y + _ly / 2); double z = GeometRi3D.Clamp(p.Z, this._center.Z - _lz / 2, this._center.Z + _lz / 2); return(new Point3d(x, y, z)); }
/// <summary> /// Intersection of circle with plane. /// Returns 'null' (no intersection) or object of type 'Circle3d', 'Point3d' or 'Segment3d'. /// </summary> public object IntersectionWith(Plane3d s) { // Relative tolerance ================================ if (!GeometRi3D.UseAbsoluteTolerance) { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * this.R; GeometRi3D.UseAbsoluteTolerance = true; object result = this.IntersectionWith(s); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return result; } //==================================================== 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, l.Direction, this.Normal.Cross(l.Direction)); Point3d p = l.Point.ConvertTo(local_coord); if (GeometRi3D.Greater(Abs(p.Y), this.R)) { return null; } else if (GeometRi3D.AlmostEqual(p.Y, this.R)) { return new Point3d(0, this.R, 0, local_coord); } else if (GeometRi3D.AlmostEqual(p.Y, -this.R)) { return new Point3d(0, -this.R, 0, local_coord); } else { double d = Sqrt(Math.Pow(this.R, 2) - Math.Pow(p.Y, 2)); Point3d p1 = new Point3d(-d, p.Y, 0, local_coord); Point3d p2 = new Point3d(d, p.Y, 0, local_coord); return new Segment3d(p1, p2); } } }
////////////////////////////////////////// #region "ParallelMethods" /// <summary> /// Check if two objects are parallel /// </summary> public bool IsParallelTo(ILinearObject obj) { Vector3d v = obj.Direction; if ((this._coord != v._coord)) { v = v.ConvertTo(this._coord); } return(GeometRi3D.AlmostEqual(this.Normalized.Cross(v.Normalized).Norm, 0.0)); }
/// <summary> /// Point on box (including interior points) closest to target point "p". /// </summary> public Point3d ClosestPoint(Point3d p) { Coord3d local_coord = this.LocalCoord(); p = p.ConvertTo(local_coord); double x = GeometRi3D.Clamp(p.X, -_lx / 2, _lx / 2); double y = GeometRi3D.Clamp(p.Y, -_ly / 2, _ly / 2); double z = GeometRi3D.Clamp(p.Z, -_lz / 2, _lz / 2); return(new Point3d(x, y, z, local_coord)); }
/// <summary> /// Check if point belongs to the sphere surface /// </summary> /// <returns>True, if the point belongs to the sphere surface</returns> public bool BelongsTo(Sphere s) { if (GeometRi3D.UseAbsoluteTolerance) { return(GeometRi3D.AlmostEqual(this.DistanceTo(s.Center), s.R)); } else { return(GeometRi3D.AlmostEqual((this.DistanceTo(s.Center) - s.R) / s.R, 0.0)); } }
/// <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> /// Check if two objects are orthogonal /// </summary> public bool IsOrthogonalTo(ILinearObject obj) { Vector3d v = obj.Direction; if ((this._coord != v._coord)) { v = v.ConvertTo(this._coord); } double this_norm = this.Norm; double v_norm = v.Norm; return(GeometRi3D.AlmostEqual(Abs(this * v) / (this_norm * v_norm), 0.0)); }
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> /// Intersection of circle with plane. /// Returns 'null' (no intersection) or object of type 'Circle3d', '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, l.Direction, this.Normal.Cross(l.Direction)); Point3d p = l.Point.ConvertTo(local_coord); if (GeometRi3D.Greater(Abs(p.Y), this.R)) { return(null); } else if (GeometRi3D.AlmostEqual(p.Y, this.R)) { return(new Point3d(0, this.R, 0, local_coord)); } else if (GeometRi3D.AlmostEqual(p.Y, -this.R)) { return(new Point3d(0, -this.R, 0, local_coord)); } else { double d = Sqrt(Math.Pow(this.R, 2) - Math.Pow(p.Y, 2)); Point3d p1 = new Point3d(-d, p.Y, 0, local_coord); Point3d p2 = new Point3d(d, p.Y, 0, local_coord); return(new Segment3d(p1, p2)); } } }
/// <summary> /// Check if point is inside ellipsoid /// </summary> public bool IsInside(Ellipsoid e) { Coord3d lc = new Coord3d(e.Center, e.SemiaxisA, e.SemiaxisB); Point3d p = this.ConvertTo(lc); if (GeometRi3D.UseAbsoluteTolerance) { return(GeometRi3D.Smaller(p.X * p.X / e.A / e.A + p.Y * p.Y / e.B / e.B + p.Z * p.Z / e.C / e.C, 1.0)); } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * e.SemiaxisA.Norm; GeometRi3D.UseAbsoluteTolerance = true; bool result = this.IsInside(e); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
////////////////////////////////////////// #region "ParallelMethods" /// <summary> /// Check if two objects are parallel /// </summary> public bool IsParallelTo(ILinearObject obj) { Vector3d v = obj.Direction; if ((this._coord != v._coord)) { v = v.ConvertTo(this._coord); } double this_norm = this.Norm; double v_norm = v.Norm; if (GeometRi3D.Greater(this_norm, 0.0) && GeometRi3D.Greater(v_norm, 0.0)) { return(GeometRi3D.AlmostEqual(this.Normalized.Cross(v.Normalized).Norm, 0.0)); } else { return(false); } }
/// <summary> /// Calculates the point on the ellipse'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 // Does not work for interior points 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, this.B, 0, local_coord)); } double theta = Atan2(this.A * p.Y, this.B * p.X); int iter = 0; int max_iter = 100; Point3d n0 = p.Copy(); while (iter < max_iter) { iter += 1; double f = (A * A - B * B) * Cos(theta) * Sin(theta) - p.X * A * Sin(theta) + p.Y * B * Cos(theta); double f_prim = (A * A - B * B) * (Cos(theta) * Cos(theta) - Sin(theta) * Sin(theta)) - p.X * A * Cos(theta) - p.Y * B * Sin(theta); theta = theta - f / f_prim; Point3d n = new Point3d(A * Cos(theta), B * Sin(theta), 0, local_coord); if (n0.DistanceTo(n) < GeometRi3D.Tolerance) { return(n); } n0 = n.Copy(); } return(n0); }
/// <summary> /// Check if two objects are orthogonal /// </summary> public bool IsOrthogonalTo(ILinearObject obj) { Vector3d v = obj.Direction; if ((this._coord != v._coord)) { v = v.ConvertTo(this._coord); } double this_norm = this.Norm; double v_norm = v.Norm; return(GeometRi3D.AlmostEqual(Abs(this * v) / (this_norm * v_norm), 0.0)); //if (GeometRi3D.Greater(this_norm, 0.0) && GeometRi3D.Greater(v_norm, 0.0)) //{ // return GeometRi3D.AlmostEqual(Abs(this * v) / (this_norm * v_norm), 0.0); //} //else //{ // return false; //} }
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); } }
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); } }
/// <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> /// Check if point is inside ellipse /// </summary> /// <returns>True, if the point is inside ellipse</returns> public bool IsInside(Ellipse e) { if (GeometRi3D.UseAbsoluteTolerance) { if (this.BelongsTo(new Plane3d(e.Center, e.MajorSemiaxis, e.MinorSemiaxis))) { return(GeometRi3D.Smaller(this.DistanceTo(e.F1) + this.DistanceTo(e.F2), 2 * e.A)); } else { return(false); } } else { double tol = GeometRi3D.Tolerance; GeometRi3D.Tolerance = tol * e.MajorSemiaxis.Norm; GeometRi3D.UseAbsoluteTolerance = true; bool result = this.IsInside(e); GeometRi3D.UseAbsoluteTolerance = false; GeometRi3D.Tolerance = tol; return(result); } }
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))); } }
/// <summary> /// Returns the hashcode for the object. /// </summary> public override int GetHashCode() { return(GeometRi3D.HashFunction(_point.GetHashCode(), _r.GetHashCode(), _normal.GetHashCode())); }
/// <summary> /// Angle between two objects in radians (0 < angle < Pi) /// </summary> public double AngleTo(IPlanarObject obj) { return(GeometRi3D.GetAngle(this, obj)); }
/// <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> /// Check if two objects are coplanar /// </summary> public bool IsCoplanarTo(ILinearObject obj) { return(GeometRi3D._coplanar(this, 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); } 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); } } }
/// <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))); } } }
/// <summary> /// Returns the hashcode for the object. /// </summary> public override int GetHashCode() { int hash_code = GeometRi3D.HashFunction(_lx.GetHashCode(), _ly.GetHashCode(), _lz.GetHashCode()); return(GeometRi3D.HashFunction(_center.GetHashCode(), _r.GetHashCode(), hash_code)); }
/// <summary> /// Returns the hashcode for the object. /// </summary> public override int GetHashCode() { return(GeometRi3D.HashFunction(_a.GetHashCode(), _b.GetHashCode(), _c.GetHashCode())); }