public bool IsCoincident([NotNull] Plane3D other) { if (!IsParallel(other)) { return(false); } // They are parallel. Now check the distance to the origin: double thisDistance = GetDistanceSigned(0, 0, 0); double otherDistance = other.GetDistanceSigned(0, 0, 0); // get the sign of any non-zero component of the normal: var one = new Pnt3D(1, 1, 1); bool oppositeDirectionNormals = other.Normal.GetFactor(one) * Normal.GetFactor(one) < 0; if (oppositeDirectionNormals) { otherDistance *= -1; } double e = Math.Max(Epsilon, other.Epsilon); return(MathUtils.AreEqual(thisDistance, otherDistance, e)); }
public bool Equals(Plane3D other, double tolerance = 0) { return(MathUtils.AreEqual(A, other.A, tolerance) && MathUtils.AreEqual(B, other.B, tolerance) && MathUtils.AreEqual(C, other.C, tolerance) && MathUtils.AreEqual(D, other.D, tolerance)); }
public void AssignUndefinedZs([NotNull] Plane3D fromPlane) { foreach (Linestring linestring in Linestrings) { linestring.AssignUndefinedZs(fromPlane); } }
public bool IsParallel(Plane3D other) { double e = Math.Max(Epsilon, other.Epsilon); Vector crossProduct = GeomUtils.CrossProduct(Normal, other.Normal); return(MathUtils.AreEqual(crossProduct.X, 0, e) && MathUtils.AreEqual(crossProduct.Y, 0, e) && MathUtils.AreEqual(crossProduct[2], 0, e)); }
public void AssignUndefinedZs(Plane3D fromPlane) { foreach (Pnt3D point in GetPoints()) { if (double.IsNaN(point.Z)) { point.Z = fromPlane.GetZ(point.X, point.Y); } } // UpdateBounds() not needed because no XY values change }
/// <summary> /// Adjusts the given co-planarity tolerance for a plane based on a z and xy resolution. /// </summary> /// <param name="plane"></param> /// <param name="coplanarityTolerance"></param> /// <param name="zResolution"></param> /// <param name="xyResolution"></param> /// <returns></returns> public static double AdjustCoplanarityTolerance([NotNull] Plane3D plane, double coplanarityTolerance, double zResolution, double xyResolution) { if (coplanarityTolerance >= zResolution + xyResolution) { // value is large enough, use as is return(coplanarityTolerance); } var normal = plane.GetUnitNormal(); double dx = normal.X * xyResolution; double dy = normal.Y * xyResolution; double dz = normal[2] * zResolution; var minDistance = Math.Sqrt(dx * dx + dy * dy + dz * dz); return(Math.Max(minDistance, coplanarityTolerance)); }
public static Plane3D FitPlane([NotNull] IList <Pnt3D> points, bool isRing = false) { int n = isRing ? points.Count - 1 : points.Count; Assert.ArgumentCondition(n >= 3, "At least 3 points (4 points in a ring) are required to define a plane."); // Origin shift for better numerical accuracy: // Rather than just subtracting the first point, use the actual centroid to keep the coordinates close to the origin var sum = new Pnt3D(); for (var i = 0; i < n; i++) { Pnt3D point = points[i]; sum += point; } Pnt3D centroid = sum / n; // 3x3 covariance matrix (excluding symmetries): double xx = 0; double xy = 0; double xz = 0; double yy = 0; double yz = 0; double zz = 0; foreach (Pnt3D point in points) { Pnt3D r = point - centroid; double x = r.X; double y = r.Y; double z = r.Z; xx += x * x; xy += x * y; xz += x * z; yy += y * y; yz += y * z; zz += z * z; } // Avoid wasting significant digits by letting the numbers gow too large! // Otherwise the D-value easily grows to 10^15 if the the input points are spaced // by a few 100m. See CanDetermineInclinedPlaneCoincidenceMirroredAt0 // Consider using Kahan summation as well. double div = GetDivisorToImproveEpsilon(xx, yy, zz); xx /= div; xy /= div; xz /= div; yy /= div; yz /= div; zz /= div; // Use the largest determinant for better numerical conditioning double detX = yy * zz - yz * yz; double detY = xx * zz - xz * xz; double detZ = xx * yy - xy * xy; double maxDet = Math.Max(detX, Math.Max(detY, detZ)); var normal = new Vector(3); if (MathUtils.AreEqual(detZ, maxDet)) { normal[0] = xy * yz - xz * yy; normal[1] = xy * xz - yz * xx; normal[2] = detZ; } else if (MathUtils.AreEqual(detX, maxDet)) { normal[0] = detX; normal[1] = xz * yz - xy * zz; normal[2] = xy * yz - xz * yy; } else { normal[0] = xz * yz - xy * zz; normal[1] = detY; normal[2] = xy * xz - yz * xx; } normal = OrientNormal(normal, points, isRing); var result = new Plane3D(normal, centroid); // It is important to remember the worst-case epsilon, especially for collinear points result.Epsilon = Math.Max( result.Epsilon, MathUtils.GetDoubleSignificanceEpsilon(xx, xy, xz, yy, yz, zz)); return(result); }