Beispiel #1
0
        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));
        }
Beispiel #2
0
 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));
 }
Beispiel #3
0
 public void AssignUndefinedZs([NotNull] Plane3D fromPlane)
 {
     foreach (Linestring linestring in Linestrings)
     {
         linestring.AssignUndefinedZs(fromPlane);
     }
 }
Beispiel #4
0
        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));
        }
Beispiel #5
0
        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
        }
Beispiel #6
0
        /// <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));
        }
Beispiel #7
0
        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);
        }