public void CanGetZOfNearlyHorizontalPlane3D() { var points = new List <Pnt3D>(); points.Add(new Pnt3D { X = 2723729.625, Y = 1251631.61625, Z = 601 }); points.Add(new Pnt3D { X = 2723531.44625, Y = 1251727.94, Z = 601 }); points.Add(new Pnt3D { X = 2723633.2675, Y = 1251824.26375, Z = 601 }); points[0].Z += 0.001; points.Add(points[0]); Plane3D plane = Plane3D.FitPlane(points, true); foreach (Pnt3D point in points) { double z = plane.GetZ(point.X, point.Y); Console.WriteLine(@"{0}: {1}", point, z); Assert.AreEqual(point.Z, z, plane.Epsilon); } const double farAwayX = -1000000.12345; const double farAwayY = -1000000.6789; double z0 = plane.GetZ(farAwayX, farAwayY); Assert.AreEqual(0, plane.GetDistanceSigned(farAwayX, farAwayY, z0), plane.Epsilon); }
public static bool?AreCoplanar([NotNull] IList <Pnt3D> points, [NotNull] Plane3D plane, double tolerance, out double maxDeviationFromPlane, out string message) { message = null; if (!plane.IsDefined) { message = $"The plane is not sufficiently defined by the input points {StringUtils.Concatenate(points, ", ")}."; maxDeviationFromPlane = double.NaN; return(null); } if (MathUtils.AreEqual( 0, GeomUtils.GetArea3D(points, new Pnt3D(plane.Normal)))) { // Technically, the plane could be defined, but it is quite random message = $"The ring is degenerate without 3D area {StringUtils.Concatenate(points, ", ")}."; maxDeviationFromPlane = double.NaN; return(null); } var coplanar = true; double maxDistance = 0; Pnt3D maxDistancePoint = null; foreach (Pnt3D pnt3D in points) { double d = plane.GetDistanceSigned(pnt3D); if (!MathUtils.AreEqual(d, 0, tolerance)) { if (Math.Abs(d) > Math.Abs(maxDistance)) { maxDistance = d; maxDistancePoint = pnt3D; } coplanar = false; } } if (!coplanar) { _msg.VerboseDebug( $"Coplanarity of point {maxDistancePoint} with plane {plane} is violated: {maxDistance}m"); message = $"Coplanarity of the plane is violated by {maxDistance} at point {maxDistancePoint}"; } maxDeviationFromPlane = Math.Abs(maxDistance); return(coplanar); }
private int InitPlaneOffsets(bool reportErrors, [CanBeNull] IFeature involvedFeature) { const int noError = 0; if (_minOffset <= 0 && _maxOffset >= 0) { return(noError); } Plane3D plane = Plane; var unitNormal = UnitNormal; // double nf = plane.Nf; _minOffset = 0; _maxOffset = 0; var segmentsCount = 0; foreach (SegmentProxy segment in SegmentsPlane.Segments) { segmentsCount++; IPnt point = segment.GetStart(true); // double f = normal.X * point.X + normal.Y * point.Y + normal.Z * point[2] + nf; double distanceSigned = plane.GetDistanceSigned(point.X, point.Y, point[2]); double offset = Math.Abs(distanceSigned); if (distanceSigned > 0 == unitNormal[2] > 0 ) // oriented same as normal { _maxOffset = Math.Max(offset, _maxOffset); } else { _minOffset = Math.Min(-offset, _minOffset); } } var coplanarityTolerance = GeomUtils.AdjustCoplanarityTolerance( plane, _parent.CoplanarityTolerance, _parent._zSrTolerance, _parent._xySrTolerance); double maxOffset = Math.Max(Math.Abs(_maxOffset), Math.Abs(_minOffset)); _coplanar = maxOffset < coplanarityTolerance; if (_coplanar || !reportErrors || involvedFeature == null) { return(noError); } IMultiPatch errorGeometry = SegmentUtils.CreateMultiPatch(SegmentsPlane.Segments); return(_parent.ReportNonCoplanarFace(segmentsCount, maxOffset, errorGeometry, involvedFeature)); }