public void HashOfHull3d_Invalid_NotEquals_Empty()
        {
            var a = Hull3d.Invalid;
            var b = new Hull3d(new Plane3d[0]);

            Assert.IsTrue(a.ComputeMd5Hash() != b.ComputeMd5Hash());
        }
Exemple #2
0
        public void ComputeCorners_Frustum()
        {
            var hull = new Hull3d(new[]
            {
                new Plane3d(new V3d(0, 0, -1), V3d.OOO),
                new Plane3d(new V3d(0, 0, +1), new V3d(0, 0, 0.25)),
                new Plane3d(new V3d(-1, 0, +1).Normalized, V3d.OOO),
                new Plane3d(new V3d(+1, 0, +1).Normalized, V3d.IOO),
                new Plane3d(new V3d(0, -1, +1).Normalized, V3d.OOO),
                new Plane3d(new V3d(0, +1, +1).Normalized, V3d.OIO),
            });

            var expectedCorners = new []
            {
                V3d.OOO, V3d.IOO, V3d.IIO, V3d.OIO,
                new V3d(0.25, 0.25, 0.25),
                new V3d(0.75, 0.25, 0.25),
                new V3d(0.75, 0.75, 0.25),
                new V3d(0.25, 0.75, 0.25),
            };

            var corners = hull.ComputeCorners();

            Assert.IsTrue(corners.SetEquals(expectedCorners));
        }
        public void HashOfHull3d_FromBox_NotEquals_FromDifferentBox()
        {
            var a = Hull3d.Create(new Box3d(new V3d(1, 2, 3), new V3d(2, 3, 4.1)));
            var b = Hull3d.Create(new Box3d(new V3d(1, 2, 3), new V3d(2, 3, 4.2)));

            Assert.IsTrue(a.ComputeMd5Hash() != b.ComputeMd5Hash());
        }
        public void HashOfHull3d_FromBox_Equals_FromSameBox()
        {
            var a = Hull3d.Create(new Box3d(new V3d(1, 2, 3), new V3d(2, 3, 4.1)));
            var b = Hull3d.Create(new Box3d(new V3d(1, 2, 3), new V3d(2, 3, 4.1)));

            Assert.IsTrue(a.ComputeMd5Hash() == b.ComputeMd5Hash());
        }
 /// <summary>
 /// Counts points inside convex hull (approximately).
 /// Result is always equal or greater than exact number.
 /// </summary>
 internal static long CountPointsApproximatelyInsideConvexHull(
     this PointSetNode self, Hull3d query, int minCellExponent = int.MinValue
     )
 => CountPointsApproximately(self,
                             n => query.Contains(n.BoundingBox),
                             n => !query.Intersects(n.BoundingBox),
                             minCellExponent);
 /// <summary>
 /// Counts points outside convex hull (approximately).
 /// Result is always equal or greater than exact number.
 /// </summary>
 internal static long CountPointsApproximatelyOutsideConvexHull(
     this IPointCloudNode self, Hull3d query, int minCellExponent = int.MinValue
     )
 => CountPointsApproximately(self,
                             n => !query.Intersects(n.BoundingBoxExactGlobal),
                             n => query.Contains(n.BoundingBoxExactGlobal),
                             minCellExponent);
        public void HashOfHull3d_Empty_Equals_Empty()
        {
            var a = new Hull3d(new Plane3d[0]);
            var b = new Hull3d(new Plane3d[0]);

            Assert.IsTrue(a.ComputeMd5Hash() == b.ComputeMd5Hash());
        }
        public void HashOfHull3d_DefaultConstructorCreatesInvalidHull3d()
        {
            var a = new Hull3d();
            var b = Hull3d.Invalid;

            Assert.IsTrue(a.ComputeMd5Hash() == b.ComputeMd5Hash());
        }
        /// <summary>
        /// Calls action for each (node, fullyInside) in this tree that is intersecting the given hull.
        /// </summary>
        public static IEnumerable <CellQueryResult> ForEachNodeIntersecting(
            this IPointCloudNode self,
            Hull3d hull, bool doNotTraverseSubnodesWhenFullyInside, int minCellExponent = int.MinValue
            )
        {
            if (self == null)
            {
                yield break;
            }

            if (self.Cell.Exponent < minCellExponent)
            {
                yield break;
            }

            for (var i = 0; i < hull.PlaneCount; i++)
            {
                if (!self.IntersectsNegativeHalfSpace(hull.PlaneArray[i]))
                {
                    yield break;
                }
            }

            bool fullyInside = true;

            for (var i = 0; i < hull.PlaneCount; i++)
            {
                if (!self.InsideNegativeHalfSpace(hull.PlaneArray[i]))
                {
                    fullyInside = false;
                    break;
                }
            }

            yield return(new CellQueryResult(self, fullyInside));

            if (fullyInside && doNotTraverseSubnodesWhenFullyInside)
            {
                yield break;
            }

            if (self.Subnodes == null)
            {
                yield break;
            }
            for (var i = 0; i < 8; i++)
            {
                var n = self.Subnodes[i];
                if (n == null)
                {
                    continue;
                }
                var xs = ForEachNodeIntersecting(n.Value, hull, doNotTraverseSubnodesWhenFullyInside, minCellExponent);
                foreach (var x in xs)
                {
                    yield return(x);
                }
            }
        }
        public void ForEachNodeIntersecting_Works()
        {
            var storage    = PointCloud.CreateInMemoryStore();
            var pointcloud = CreateClusteredPointsInUnitCube(1000, 10);
            var ns         = pointcloud.Root.Value.ForEachNodeIntersecting(Hull3d.Create(Box3d.Unit), true).ToArray();

            Assert.IsTrue(ns.Length > 0);
        }
        public static FilterInsideConvexHull3d Deserialize(JObject json)
        {
            var arr    = (JArray)json["Array"];
            var planes = arr.Map(jt => new Plane3d(V3d.Parse((string)jt["Normal"]), V3d.Parse((string)jt["Point"])));
            var hull   = new Hull3d(planes);

            return(new FilterInsideConvexHull3d(hull));
        }
 /// <summary>
 /// All points inside convex hull (including boundary).
 /// </summary>
 public static IEnumerable <Chunk> QueryPointsInsideConvexHull(
     this IPointCloudNode self, Hull3d query, int minCellExponent = int.MinValue
     )
 => QueryPoints(self,
                n => query.Contains(n.BoundingBoxExactGlobal),
                n => !query.Intersects(n.BoundingBoxExactGlobal),
                p => query.Contains(p),
                minCellExponent);
        public void TestConvexClipped()
        {
            var points      = new[] { V3d.OOO, V3d.IOO, V3d.OIO };
            var poly        = new Polygon3d(points);
            var box         = Box3d.FromMinAndSize(-V3d.OOI, new V3d(1, 0.5, 2));
            var newHull     = Hull3d.Create(box).Reversed(); // requires non-intuitive reversed (or using obsolte Hull3d constructor that points inside)
            var polyClipped = poly.ConvexClipped(newHull);   // will return positive part of planes (outside of Hull3d)
            var clippedBox  = polyClipped.BoundingBox3d;
            var test        = new Box3d(0, 0, 0, 1, 0.5, 0);

            Test.IsTrue(clippedBox == test);
        }
Exemple #14
0
        /// <summary>Computes MD5 hash of given data.</summary>
        public static Guid ComputeMd5Hash(this Hull3d hull)
        {
            if (hull.PlaneArray == null)
            {
                return(Guid.Empty);
            }

            return(ComputeMd5Hash(bw => {
                foreach (var plane in hull.PlaneArray)
                {
                    bw.Write(plane.Point.X); bw.Write(plane.Point.Y); bw.Write(plane.Point.Z);
                    bw.Write(plane.Distance);
                }
            }));
        }
        public void VisualHullTest()
        {
            var view           = Trafo3d.ViewTrafoRH(V3d.III, V3d.OOI, V3d.IOO);
            var proj           = Trafo3d.PerspectiveProjectionOpenGl(-1, 1, -1, 1, 1, 100);
            var vpTrafo        = view * proj;
            var frustumCorners = new Box3d(-V3d.III, V3d.III).ComputeCorners();

            //Min,                             0 near left bottom
            //new V3d(Max.X, Min.Y, Min.Z),    1 near right bottom
            //new V3d(Min.X, Max.Y, Min.Z),    2 near left top
            //new V3d(Max.X, Max.Y, Min.Z),    3 near right top
            //new V3d(Min.X, Min.Y, Max.Z),    4 far left bottom
            //new V3d(Max.X, Min.Y, Max.Z),    5 far right bottom
            //new V3d(Min.X, Max.Y, Max.Z),    6 far left top
            //Max                              7 far right top

            // use inverse view-projection to get vertices in world space
            frustumCorners.Apply(c => vpTrafo.Backward.TransformPosProj(c));

            // hull planes should point outside, assume right-handed transformation to build planes
            var refHull = new Hull3d(new[]
            {
                new Plane3d(frustumCorners[0], frustumCorners[2], frustumCorners[4]), // left
                new Plane3d(frustumCorners[1], frustumCorners[5], frustumCorners[3]), // right
                new Plane3d(frustumCorners[0], frustumCorners[4], frustumCorners[1]), // bottom
                new Plane3d(frustumCorners[2], frustumCorners[3], frustumCorners[6]), // top
                new Plane3d(frustumCorners[0], frustumCorners[1], frustumCorners[2]), // near
                new Plane3d(frustumCorners[4], frustumCorners[6], frustumCorners[5]), // far
            });

            var newHull = vpTrafo.GetVisualHull();

            for (int i = 0; i < 6; i++)
            {
                Report.Line("OLD: {0} NEW: {1}", newHull.PlaneArray[i], refHull.PlaneArray[i]);
            }

            // camera position should have height 1.0 from near-plane
            var hRef = refHull.PlaneArray[4].Height(view.GetViewPosition());
            var hNew = newHull.PlaneArray[4].Height(view.GetViewPosition());

            Assert.True(hRef.ApproximateEquals(1.0, 1e-7) && hRef.ApproximateEquals(hNew, 1e-7));

            for (int i = 0; i < 6; i++)
            {
                Assert.True(newHull.PlaneArray[i].Coefficients.ApproxEqual(refHull.PlaneArray[i].Coefficients, 1e-7));
            }
        }
        public static Box3d IntersectionBounds(this Hull3d hull, Box3d box)
        {
            if (box.IsInvalid)
            {
                return(box);
            }

            var bh = Hull3d.Create(box);
            var pp = new Plane3d[6 + hull.PlaneCount];

            bh.PlaneArray.CopyTo(pp, 0);
            hull.PlaneArray.CopyTo(pp, 6);
            var h = new Hull3d(pp);

            return(new Box3d(h.ComputeCorners()));
        }
        /// <summary>
        /// Returns points inside view frustum (defined by viewProjection and canonicalViewVolume).
        /// </summary>
        public static IEnumerable <Chunk> QueryPointsInViewFrustum(
            this PointSet self, M44d viewProjection, Box3d canonicalViewVolume
            )
        {
            var t    = viewProjection.Inverse;
            var cs   = canonicalViewVolume.ComputeCorners().Map(t.TransformPosProj);
            var hull = new Hull3d(new[]
            {
                new Plane3d(cs[0], cs[2], cs[1]), // near
                new Plane3d(cs[5], cs[7], cs[4]), // far
                new Plane3d(cs[0], cs[1], cs[4]), // bottom
                new Plane3d(cs[1], cs[3], cs[5]), // left
                new Plane3d(cs[4], cs[6], cs[0]), // right
                new Plane3d(cs[3], cs[2], cs[7]), // top
            });

            return(QueryPointsInsideConvexHull(self, hull));
        }
Exemple #18
0
        public void ComputeCorners_Cube()
        {
            var hull = new Hull3d(new[]
            {
                new Plane3d(-V3d.XAxis, V3d.Zero),
                new Plane3d(-V3d.YAxis, V3d.Zero),
                new Plane3d(-V3d.ZAxis, V3d.Zero),
                new Plane3d(V3d.XAxis, V3d.One),
                new Plane3d(V3d.YAxis, V3d.One),
                new Plane3d(V3d.ZAxis, V3d.One)
            });

            var corners = hull.ComputeCorners();

            var expectedCorners = new [] { V3d.OOO, V3d.OOI, V3d.OIO, V3d.OII, V3d.IOO, V3d.IOI, V3d.IIO, V3d.III };

            Assert.IsTrue(corners.SetEquals(expectedCorners));
        }
 /// <summary>
 /// Counts points outside convex hull.
 /// </summary>
 internal static long CountPointsOutsideConvexHull(
     this IPointCloudNode self, Hull3d query, int minCellExponent = int.MinValue
     )
 => CountPointsInsideConvexHull(self, query.Reversed(), minCellExponent);
 /// <summary>
 /// Counts points outside convex hull.
 /// </summary>
 internal static long CountPointsOutsideConvexHull(
     this PointSet self, Hull3d query, int minCellExponent = int.MinValue
     )
 => CountPointsOutsideConvexHull(self.Root.Value, query, minCellExponent);
 /// <summary>
 /// All points outside convex hull (excluding boundary).
 /// </summary>
 public static IEnumerable <Chunk> QueryPointsOutsideConvexHull(
     this IPointCloudNode self, Hull3d query, int minCellExponent = int.MinValue
     )
 => QueryPointsInsideConvexHull(self, query.Reversed(), minCellExponent);
 /// <summary>
 /// All points outside convex hull (excluding boundary).
 /// </summary>
 public static IEnumerable <Chunk> QueryPointsOutsideConvexHull(
     this PointSet self, Hull3d query, int minCellExponent = int.MinValue
     )
 => QueryPointsOutsideConvexHull(self.Root.Value, query, minCellExponent);
        /// <summary>
        /// Calls action for each (node, fullyInside) in this pointset, that is intersecting the given hull.
        /// </summary>
        public static void ForEachIntersectingNode(
            this IPointCloudNode self, bool outOfCore, Hull3d hull, bool doNotTraverseSubnodesWhenFullyInside,
            Action <IPointCloudNode, bool> action, CancellationToken ct = default
            )
        {
            ct.ThrowIfCancellationRequested();

            for (var i = 0; i < hull.PlaneCount; i++)
            {
                if (!self.IntersectsNegativeHalfSpace(hull.PlaneArray[i]))
                {
                    return;
                }
            }

            bool fullyInside = true;

            for (var i = 0; i < hull.PlaneCount; i++)
            {
                if (!self.InsideNegativeHalfSpace(hull.PlaneArray[i]))
                {
                    fullyInside = false;
                    break;
                }
            }

            action(self, fullyInside);

            if (fullyInside && doNotTraverseSubnodesWhenFullyInside)
            {
                return;
            }

            if (self.Subnodes == null)
            {
                return;
            }

            if (outOfCore)
            {
                for (var i = 0; i < 8; i++)
                {
                    var n = self.Subnodes[i];
                    if (n != null)
                    {
                        n.Value.ForEachIntersectingNode(outOfCore, hull, doNotTraverseSubnodesWhenFullyInside, action, ct);
                    }
                }
            }
            else
            {
                for (var i = 0; i < 8; i++)
                {
                    var n = self.Subnodes[i];
                    if (n != null)
                    {
                        if (n.TryGetValue(out IPointCloudNode node))
                        {
                            node.ForEachIntersectingNode(outOfCore, hull, doNotTraverseSubnodesWhenFullyInside, action, ct);
                        }
                    }
                }
            }
        }
Exemple #24
0
        public static bool Contains(
            this Hull3d self, Box3d box)
        {
            var planes = self.PlaneArray;
            var imax   = self.PlaneCount;

            for (var i = 0; i < imax; i++)
            {
                if (planes[i].Height(box.Min) > 0)
                {
                    return(false);
                }
            }
            for (var i = 0; i < imax; i++)
            {
                if (planes[i].Height(box.Max) > 0)
                {
                    return(false);
                }
            }
            for (var i = 0; i < imax; i++)
            {
                if (planes[i].Height(new V3d(box.Max.X, box.Min.Y, box.Min.Z)) > 0)
                {
                    return(false);
                }
            }
            for (var i = 0; i < imax; i++)
            {
                if (planes[i].Height(new V3d(box.Max.X, box.Max.Y, box.Min.Z)) > 0)
                {
                    return(false);
                }
            }
            for (var i = 0; i < imax; i++)
            {
                if (planes[i].Height(new V3d(box.Min.X, box.Max.Y, box.Min.Z)) > 0)
                {
                    return(false);
                }
            }
            for (var i = 0; i < imax; i++)
            {
                if (planes[i].Height(new V3d(box.Min.X, box.Min.Y, box.Max.Z)) > 0)
                {
                    return(false);
                }
            }
            for (var i = 0; i < imax; i++)
            {
                if (planes[i].Height(new V3d(box.Max.X, box.Min.Y, box.Max.Z)) > 0)
                {
                    return(false);
                }
            }
            for (var i = 0; i < imax; i++)
            {
                if (planes[i].Height(new V3d(box.Min.X, box.Max.Y, box.Max.Z)) > 0)
                {
                    return(false);
                }
            }
            return(true);
        }
 /// <summary></summary>
 public FilterInsideConvexHull3d(Hull3d filter)
 {
     Hull = filter;
 }