Beispiel #1
0
        public void CopyConstructor()
        {
            // Try copying empty mesh.
            var a = new DcelMesh(null);
            var b = new DcelMesh(new DcelMesh());

            // Create a mesh.
            var mesh = DcelMesh.CreateCube();

            mesh.CutConvex(new Plane(new Vector3F(1, 2, 3).Normalized, 0.6f));
            mesh.CutConvex(new Plane(new Vector3F(-2, -3, 1).Normalized, 0.8f));

            // Create clone with copy constructor and compare.
            var clone = new DcelMesh(mesh);

            Assert.AreEqual(mesh.Vertices.Count, clone.Vertices.Count);
            Assert.AreEqual(mesh.Edges.Count, clone.Edges.Count);
            Assert.AreEqual(mesh.Faces.Count, clone.Faces.Count);
            var tm  = mesh.ToTriangleMesh();
            var tmc = clone.ToTriangleMesh();

            for (int i = 0; i < tm.Vertices.Count; i++)
            {
                Assert.AreEqual(tm.Vertices[i], tmc.Vertices[i]);
            }
            for (int i = 0; i < tm.Indices.Count; i++)
            {
                Assert.AreEqual(tm.Indices[i], tmc.Indices[i]);
            }
        }
Beispiel #2
0
        public void IsConvex()
        {
            DcelMesh mesh = new DcelMesh();

            Assert.IsFalse(mesh.IsConvex());

            mesh.Vertex = new DcelVertex(new Vector3F(1, 2, 3), null);
            Assert.IsTrue(mesh.IsConvex());

            mesh = DcelMesh.FromTriangleMesh(new BoxShape(1, 2, 3).GetMesh(0.01f, 1));
            Assert.IsTrue(mesh.IsConvex());

            // Remove fifth triangle.
            var triangleMesh = new BoxShape(1, 2, 3).GetMesh(0.01f, 1);

            triangleMesh.Indices.RemoveRange(4 * 3, 3);
            mesh = DcelMesh.FromTriangleMesh(triangleMesh);
            Assert.IsFalse(mesh.IsConvex());

            mesh = DcelMesh.FromTriangleMesh(new SphereShape(10).GetMesh(0.01f, 3));
            Assert.IsTrue(mesh.IsConvex());

            // Move any sphere vertex more inside.
            var v = mesh.Vertices[10];

            v.Position = v.Position * 0.9f;
            Assert.IsFalse(mesh.IsConvex());
        }
Beispiel #3
0
        public void CutConvex()
        {
            var mesh = new BoxShape(1, 2, 3).GetMesh(0.01f, 1);
            var dcel = DcelMesh.FromTriangleMesh((ITriangleMesh)mesh);

            Assert.IsTrue(dcel.IsValid());
            Assert.IsTrue(dcel.IsConvex());
            Assert.IsTrue(dcel.IsClosed());

            bool result = dcel.CutConvex(new Plane(new Vector3F(0, 0, 1), 1.5f));

            Assert.IsFalse(result);

            result = dcel.CutConvex(new Plane(new Vector3F(0, 0, 1), -1.5f));
            Assert.IsTrue(result);
            Assert.IsNull(dcel.Vertex);
            Assert.AreEqual(0, dcel.Vertices.Count);

            dcel   = DcelMesh.FromTriangleMesh((ITriangleMesh)mesh);
            result = dcel.CutConvex(new Plane(new Vector3F(0, 0, 1), 1f));
            Assert.IsTrue(result);
            Assert.IsTrue(dcel.IsValid());
            Assert.IsTrue(dcel.IsConvex());
            Assert.IsTrue(dcel.IsClosed());
            Assert.AreEqual(12, dcel.Vertices.Count);
            Assert.AreEqual(6 + 8 + 7 * 4, dcel.Edges.Count); // Bottom = 6 edges, new cap = 8 edges, cut sides = each 7 edges.
            Assert.AreEqual(12 - 1, dcel.Faces.Count);
        }
Beispiel #4
0
        public void FromTriangleMesh2()
        {
            var mesh = new TriangleMesh();

            mesh.Vertices.Add(new Vector3F(0, 0, 0));
            mesh.Vertices.Add(new Vector3F(1, 1, 1));
            mesh.Vertices.Add(new Vector3F(2, 2, 2));
            mesh.Vertices.Add(new Vector3F(3, 3, 3));
            //mesh.Vertices.Add(new Vector3F(405, 322, 0));

            mesh.Indices.Add(0);
            mesh.Indices.Add(1);
            mesh.Indices.Add(2);

            mesh.Indices.Add(1);
            mesh.Indices.Add(3);
            mesh.Indices.Add(2);

            var dcel = DcelMesh.FromTriangleMesh((ITriangleMesh)mesh);

            Assert.AreEqual(4, dcel.Vertices.Count);
            Assert.AreEqual(2, dcel.Faces.Count);
            Assert.AreEqual(10, dcel.Edges.Count);
            Assert.IsTrue(dcel.IsValid());
            Assert.IsFalse(dcel.IsClosed());
            Assert.IsTrue(dcel.IsTriangleMesh());
        }
Beispiel #5
0
        /// <summary>
        /// Called when a mesh should be generated for the shape.
        /// </summary>
        /// <param name="absoluteDistanceThreshold">The absolute distance threshold.</param>
        /// <param name="iterationLimit">The iteration limit.</param>
        /// <returns>The triangle mesh for this shape.</returns>
        /// <remarks>
        /// <para>
        /// <see cref="ConvexShape"/> provides a base implementation for <see cref="OnGetMesh"/> that
        /// samples the support mapping and automatically generates a mesh. But derived classes should
        /// override <see cref="OnGetMesh"/> if they can provide a more efficient implementation.
        /// </para>
        /// </remarks>
        protected override TriangleMesh OnGetMesh(float absoluteDistanceThreshold, int iterationLimit)
        {
            // Use SupportMappingSampler to get surface points.
            IList <Vector3F> points = GeometryHelper.SampleConvexShape(this, absoluteDistanceThreshold, iterationLimit);
            DcelMesh         mesh   = GeometryHelper.CreateConvexHull(points);

            return(mesh.ToTriangleMesh());
        }
Beispiel #6
0
        public void FromTriangleMeshNotSupported()
        {
            var mesh = new BoxShape(1, 2, 3).GetMesh(0.01f, 1);

            // Add a stray triangle. - Only fully connected meshes are supported!
            mesh.Add(new Triangle(new Vector3F(10, 10, 10), new Vector3F(20, 20, 20), new Vector3F(30, 30, 30)), false);

            var dcel = DcelMesh.FromTriangleMesh((ITriangleMesh)mesh);
        }
Beispiel #7
0
        public void CreateCube()
        {
            var dcel = DcelMesh.CreateCube();

            Assert.IsTrue(dcel.IsValid());
            Assert.IsTrue(dcel.IsConvex());
            Assert.IsTrue(dcel.IsClosed());
            Assert.AreEqual(8, dcel.Vertices.Count);
            Assert.AreEqual(4 * 6, dcel.Edges.Count); // Bottom = 6 edges, new cap = 8 edges, cut sides = each 7 edges.
            Assert.AreEqual(6, dcel.Faces.Count);
        }
Beispiel #8
0
        public void FromTriangleMesh()
        {
            var mesh = new BoxShape(1, 2, 3).GetMesh(0.01f, 1);
            var dcel = DcelMesh.FromTriangleMesh((ITriangleMesh)mesh);

            Assert.IsTrue(dcel.IsValid());
            Assert.IsTrue(dcel.IsClosed());
            Assert.IsTrue(dcel.IsTriangleMesh());
            Assert.AreEqual(8, dcel.Vertices.Count);
            Assert.AreEqual(12, dcel.Faces.Count);
            Assert.AreEqual(36, dcel.Edges.Count);
        }
        public ConvexHullSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            SampleFramework.IsMouseVisible = false;
            GraphicsScreen.ClearBackground = true;
            GraphicsScreen.BackgroundColor = Color.CornflowerBlue;
            SetCamera(new Vector3F(0, 1, 10), 0, 0);

            // Generate random points.
            var points = new List <Vector3F>();

            for (int i = 0; i < 100; i++)
            {
                points.Add(RandomHelper.Random.NextVector3F(-1, 1));
            }

            // Apply random transformation to points to make this sample more interesting.
            Matrix44F transform = new Matrix44F(
                Matrix33F.CreateRotation(RandomHelper.Random.NextQuaternionF()) * Matrix33F.CreateScale(RandomHelper.Random.NextVector3F(0.1f, 2f)),
                RandomHelper.Random.NextVector3F(-1, 1));

            for (int i = 0; i < points.Count; i++)
            {
                points[i] = transform.TransformPosition(points[i]);
            }

            // Compute convex hull. The result is the mesh of the hull represented as a
            // Doubly-Connected Edge List (DCEL).
            DcelMesh convexHull = GeometryHelper.CreateConvexHull(points);

            // We don't need the DCEL representation. Let's store the hull as a simpler triangle mesh.
            TriangleMesh convexHullMesh = convexHull.ToTriangleMesh();

            // Compute a tight-fitting oriented bounding box.
            Vector3F boundingBoxExtent; // The bounding box dimensions (widths in X, Y and Z).
            Pose     boundingBoxPose;   // The pose (world space position and orientation) of the bounding box.

            GeometryHelper.ComputeBoundingBox(points, out boundingBoxExtent, out boundingBoxPose);
            // (Note: The GeometryHelper also contains methods to compute a bounding sphere.)

            var debugRenderer = GraphicsScreen.DebugRenderer;

            foreach (var point in points)
            {
                debugRenderer.DrawPoint(point, Color.White, true);
            }

            debugRenderer.DrawShape(new TriangleMeshShape(convexHullMesh), Pose.Identity, Vector3F.One, Color.Violet, false, false);
            debugRenderer.DrawBox(boundingBoxExtent.X, boundingBoxExtent.Y, boundingBoxExtent.Z, boundingBoxPose, Color.Red, true, false);
        }
Beispiel #10
0
        public void ModifyConvexVertexLimit()
        {
            var mesh = DcelMesh.CreateCube();

            mesh.CutConvex(new Plane(new Vector3F(1, 2, 3).Normalized, 0.6f));
            mesh.CutConvex(new Plane(new Vector3F(-2, -3, 1).Normalized, 0.8f));

            Assert.IsTrue(mesh.Vertices.Count > 10);

            mesh.ModifyConvex(10, 0.3f);

            Assert.IsTrue(mesh.IsConvex());
            Assert.IsTrue(mesh.Vertices.Count <= 10);
        }
Beispiel #11
0
        public void FromTriangleMeshWithOpenMesh()
        {
            var mesh = new BoxShape(1, 2, 3).GetMesh(0.01f, 1);

            // Remove fifth triangle.
            mesh.Indices.RemoveRange(4 * 3, 3);

            var dcel = DcelMesh.FromTriangleMesh((ITriangleMesh)mesh);

            Assert.IsTrue(dcel.IsValid());
            Assert.IsFalse(dcel.IsClosed());
            Assert.IsTrue(dcel.IsTriangleMesh());
            Assert.AreEqual(8, dcel.Vertices.Count);
            Assert.AreEqual(11, dcel.Faces.Count);
            Assert.AreEqual(36, dcel.Edges.Count);
        }
Beispiel #12
0
        public void CreateConvexHull1()
        {
            DcelMesh mesh = new DcelMesh();
              mesh = GeometryHelper.CreateConvexHull(new[] { new Vector3F(0, 0, 0),
                                                       new Vector3F(0, 0, 0),
                                                       new Vector3F(1, 0, 0),
                                                       new Vector3F(1, 1, 0),
                                                       new Vector3F(0, 0, 1),
                                                       new Vector3F(0, 0, -1),
                                                       new Vector3F(-1, 1, 0),
                                                       new Vector3F(-1, -1, 0)
                                                     });

              Assert.AreEqual(6, mesh.Vertices.Count);
              Assert.AreEqual(24, mesh.Edges.Count);
              Assert.AreEqual(8, mesh.Faces.Count);
        }
Beispiel #13
0
        public void CreateConvexHull1()
        {
            DcelMesh mesh = new DcelMesh();

            mesh = GeometryHelper.CreateConvexHull(new[] { new Vector3F(0, 0, 0),
                                                           new Vector3F(0, 0, 0),
                                                           new Vector3F(1, 0, 0),
                                                           new Vector3F(1, 1, 0),
                                                           new Vector3F(0, 0, 1),
                                                           new Vector3F(0, 0, -1),
                                                           new Vector3F(-1, 1, 0),
                                                           new Vector3F(-1, -1, 0) });

            Assert.AreEqual(6, mesh.Vertices.Count);
            Assert.AreEqual(24, mesh.Edges.Count);
            Assert.AreEqual(8, mesh.Faces.Count);
        }
Beispiel #14
0
        public void ToTriangleMesh()
        {
            // Build DCEL mesh for tetrahedron.
            var vertices = new[] { new Vector3F(0, 0, 0),
                                   new Vector3F(1, 0, 0),
                                   new Vector3F(0, 1, 0),
                                   new Vector3F(0, 0, 1) };
            DcelMesh dcelMesh = GeometryHelper.CreateConvexHull(vertices);

            TriangleMesh triangleMesh = dcelMesh.ToTriangleMesh();

            Assert.AreEqual(4, triangleMesh.NumberOfTriangles);
            Assert.IsTrue(new List <Vector3F>(triangleMesh.Vertices).Contains(new Vector3F(0, 0, 0)));
            Assert.IsTrue(new List <Vector3F>(triangleMesh.Vertices).Contains(new Vector3F(1, 0, 0)));
            Assert.IsTrue(new List <Vector3F>(triangleMesh.Vertices).Contains(new Vector3F(0, 1, 0)));
            Assert.IsTrue(new List <Vector3F>(triangleMesh.Vertices).Contains(new Vector3F(0, 0, 1)));
        }
Beispiel #15
0
        public void TestDcelMeshDirty()
        {
            DcelMesh mesh = new DcelMesh();

            DcelVertex v0 = new DcelVertex();
            DcelVertex v1 = new DcelVertex();
            DcelVertex v2 = new DcelVertex();

            DcelEdge e0 = new DcelEdge();
            DcelEdge e1 = new DcelEdge();
            DcelEdge e2 = new DcelEdge();

            DcelFace f = new DcelFace();

            // Link features
            v0.Edge     = e0;
            e0.Origin   = v0;
            mesh.Vertex = v0;

            Assert.AreEqual(1, mesh.Vertices.Count);
            Assert.AreEqual(1, mesh.Edges.Count);
            Assert.AreEqual(0, mesh.Faces.Count);

            // Link more
            e0.Next    = e1;
            e1.Next    = e2;
            mesh.Dirty = true;
            Assert.AreEqual(3, mesh.Edges.Count);

            e1.Origin  = v1;
            e2.Origin  = v2;
            mesh.Dirty = true;
            Assert.AreEqual(3, mesh.Vertices.Count);

            e0.Face    = f;
            f.Boundary = e1;
            mesh.Dirty = true;
            Assert.AreEqual(1, mesh.Faces.Count);
        }
Beispiel #16
0
        public void CopyConstructor()
        {
            // Try copying empty mesh.
              var a = new DcelMesh(null);
              var b = new DcelMesh(new DcelMesh());

              // Create a mesh.
              var mesh = DcelMesh.CreateCube();
              mesh.CutConvex(new Plane(new Vector3F(1, 2, 3).Normalized, 0.6f));
              mesh.CutConvex(new Plane(new Vector3F(-2, -3, 1).Normalized, 0.8f));

              // Create clone with copy constructor and compare.
              var clone = new DcelMesh(mesh);
              Assert.AreEqual(mesh.Vertices.Count, clone.Vertices.Count);
              Assert.AreEqual(mesh.Edges.Count, clone.Edges.Count);
              Assert.AreEqual(mesh.Faces.Count, clone.Faces.Count);
              var tm = mesh.ToTriangleMesh();
              var tmc = clone.ToTriangleMesh();
              for (int i = 0; i < tm.Vertices.Count; i++)
            Assert.AreEqual(tm.Vertices[i], tmc.Vertices[i]);
              for (int i = 0; i < tm.Indices.Count; i++)
            Assert.AreEqual(tm.Indices[i], tmc.Indices[i]);
        }
Beispiel #17
0
        /// <summary>
        /// Initializes the convex polyhedron.
        /// </summary>
        /// <param name="points">The points.</param>
        /// <exception cref="NotSupportedException">
        /// Too many vertices in convex hull. Max. 65534 vertices in a convex polyhedron are supported.
        /// </exception>
        private void BuildConvexPolyhedron(IEnumerable <Vector3F> points)
        {
            // Build convex hull and throw away inner points.
            DcelMesh convexHull       = GeometryHelper.CreateConvexHull(points);
            int      numberOfVertices = (convexHull != null) ? convexHull.Vertices.Count : 0;

            if (numberOfVertices >= ushort.MaxValue)
            {
                throw new NotSupportedException("Too many vertices in convex hull. Max. 65534 vertices in convex hull are supported.");
            }

            _vertices = (convexHull != null) ? convexHull.Vertices.Select(v => v.Position).ToArray() : new Vector3F[0];
            CacheAabb();
            CacheInnerPoint();

            Debug.Assert(VertexThreshold > 4, "Vertex threshold should be greater than 4.");
            if (numberOfVertices > VertexThreshold)
            {
                // Use an internal lookup table and vertex adjacency lists for speed up.
                BuildLookupTable();
                BuildVertexAdjacencyLists(convexHull);
            }
        }
Beispiel #18
0
        public void ModifyConvexSkinWidth()
        {
            // Create a mesh.
            var mesh = DcelMesh.CreateCube();

            mesh.CutConvex(new Plane(new Vector3F(1, 2, 3).Normalized, 0.6f));
            mesh.CutConvex(new Plane(new Vector3F(-2, -3, 1).Normalized, 0.8f));

            var aabb = mesh.GetAabb();

            var skinWidth = 0.3f;

            mesh.ModifyConvex(100, skinWidth);

            var aabb2 = mesh.GetAabb();

            Assert.IsTrue(mesh.IsConvex());
            Assert.IsTrue(Numeric.AreEqual(aabb.Minimum.X - skinWidth, aabb2.Minimum.X));
            Assert.IsTrue(Numeric.AreEqual(aabb.Minimum.Y - skinWidth, aabb2.Minimum.Y));
            Assert.IsTrue(Numeric.AreEqual(aabb.Minimum.Z - skinWidth, aabb2.Minimum.Z));
            Assert.IsTrue(Numeric.AreEqual(aabb.Maximum.X + skinWidth, aabb2.Maximum.X));
            Assert.IsTrue(Numeric.AreEqual(aabb.Maximum.Y + skinWidth, aabb2.Maximum.Y));
            Assert.IsTrue(Numeric.AreEqual(aabb.Maximum.Z + skinWidth, aabb2.Maximum.Z));
        }
Beispiel #19
0
        public override void Update(GameTime gameTime)
        {
            var lastFileIndex = _fileIndex;

            if (InputService.IsPressed(Keys.NumPad7, true))
            {
                _fileIndex++;
            }
            if (InputService.IsPressed(Keys.NumPad4, true))
            {
                _fileIndex--;
            }
            if (_fileIndex < 0)
            {
                _fileIndex = MaxFileIndex;
            }
            if (_fileIndex > MaxFileIndex)
            {
                _fileIndex = 0;
            }
            if (lastFileIndex != _fileIndex)
            {
                LoadFile();
                _pointIndex = -1;
            }

            var lastPointIndex = _pointIndex;

            if (InputService.IsPressed(Keys.Right, true))
            {
                _pointIndex++;
            }
            if (InputService.IsPressed(Keys.Left, true))
            {
                _pointIndex--;
            }
            if (_pointIndex <= 0)
            {
                _pointIndex = _points.Count;
            }
            if (_pointIndex > _points.Count)
            {
                _pointIndex = 1;
            }

            var lastSkinWidth = _skinWidth;

            if (InputService.IsDown(Keys.Up))
            {
                _skinWidth *= 1.1f;
            }
            if (InputService.IsDown(Keys.Down))
            {
                _skinWidth /= 1.1f;
            }

            if (lastPointIndex != _pointIndex || _skinWidth != lastSkinWidth)
            {
                var      watch = Stopwatch.StartNew();
                DcelMesh hull  = GeometryHelper.CreateConvexHull(_points.Take(_pointIndex), int.MaxValue, _skinWidth);
                watch.Stop();
                _loadTime        = (float)watch.Elapsed.TotalMilliseconds;
                _mesh            = hull.ToTriangleMesh();
                _geometricObject = new GeometricObject(new TriangleMeshShape(_mesh));
            }

            var debugRenderer = GraphicsScreen.DebugRenderer;

            debugRenderer.Clear();
            debugRenderer.DrawAxes(Pose.Identity, 1, false);
            debugRenderer.DrawObject(_geometricObject, new Color(0.5f, 0.5f, 0.5f, 0.8f), false, false);
            debugRenderer.DrawObject(_geometricObject, Color.Black, true, true);
            foreach (var point in _points)
            {
                debugRenderer.DrawPoint(point, Color.White, false);
            }

            debugRenderer.DrawText(
                "\n\nFile: " + _fileIndex + "\n" +
                "Point Index: " + _pointIndex + "\n" +
                "Time: " + _loadTime + "\n");
        }
Beispiel #20
0
        public void IsConvex()
        {
            DcelMesh mesh = new DcelMesh();
              Assert.IsFalse(mesh.IsConvex());

              mesh.Vertex = new DcelVertex(new Vector3F(1, 2, 3), null);
              Assert.IsTrue(mesh.IsConvex());

              mesh = DcelMesh.FromTriangleMesh(new BoxShape(1, 2, 3).GetMesh(0.01f, 1));
              Assert.IsTrue(mesh.IsConvex());

              // Remove fifth triangle.
              var triangleMesh = new BoxShape(1, 2, 3).GetMesh(0.01f, 1);
              triangleMesh.Indices.RemoveRange(4 * 3, 3);
              mesh = DcelMesh.FromTriangleMesh(triangleMesh);
              Assert.IsFalse(mesh.IsConvex());

              mesh = DcelMesh.FromTriangleMesh(new SphereShape(10).GetMesh(0.01f, 3));
              Assert.IsTrue(mesh.IsConvex());

              // Move any sphere vertex more inside.
              var v = mesh.Vertices[10];
              v.Position = v.Position * 0.9f;
              Assert.IsFalse(mesh.IsConvex());
        }
Beispiel #21
0
        public static void ComputeBoundingCapsule(IList <Vector3> points, out float radius, out float height, out Pose pose)
        {
            if (points == null)
            {
                throw new ArgumentNullException("points");
            }

            // Covariance matrix.
            MatrixF cov = null;

            // ReSharper disable EmptyGeneralCatchClause
            try
            {
                if (points.Count > 4)
                {
                    // Reduce point list to convex hull.
                    DcelMesh     dcelMesh = CreateConvexHull(points);
                    TriangleMesh mesh     = dcelMesh.ToTriangleMesh();

                    // Use reduced point list - if we have found a useful one. (Line objects
                    // have not useful triangle mesh.)
                    if (mesh.Vertices.Count > 0)
                    {
                        points = mesh.Vertices;
                    }

                    cov = ComputeCovarianceMatrixFromSurface(mesh);
                }
            }
            catch
            {
            }
            // ReSharper restore EmptyGeneralCatchClause

            // If anything happens in the convex hull creation, we can still go on including the
            // interior points and compute the covariance matrix for the points instead of the
            // surface.
            if (cov == null || Numeric.IsNaN(cov.Determinant()))
            {
                cov = ComputeCovarianceMatrixFromPoints(points);
            }

            // Perform Eigenvalue decomposition.
            EigenvalueDecompositionF evd = new EigenvalueDecompositionF(cov);

            // v transforms from local coordinate space of the capsule into world space.
            var v = evd.V.ToMatrix();

            Debug.Assert(v.GetColumn(0).IsNumericallyNormalized);
            Debug.Assert(v.GetColumn(1).IsNumericallyNormalized);
            Debug.Assert(v.GetColumn(2).IsNumericallyNormalized);

            // v is like a rotation matrix, but the coordinate system is not necessarily right handed.
            // --> Make sure it is right-handed.
            v.SetColumn(2, Vector3.Cross(v.GetColumn(0), v.GetColumn(1)));

            // Make local Y the largest axis. (Y is the long capsule axis.)
            Vector3 eigenValues           = evd.RealEigenvalues.ToVector3();
            int     largestComponentIndex = eigenValues.IndexOfLargestComponent;

            if (largestComponentIndex != 1)
            {
                // Swap two columns to create a right handed rotation matrix.
                Vector3 colLargest = v.GetColumn(largestComponentIndex);
                Vector3 col1       = v.GetColumn(1);
                v.SetColumn(1, colLargest);
                v.SetColumn(largestComponentIndex, col1);
                v.SetColumn(2, Vector3.Cross(v.GetColumn(0), v.GetColumn(1)));
            }

            // Compute capsule for the orientation given by v.
            Vector3 center;

            ComputeBoundingCapsule(points, v, out radius, out height, out center);
            pose = new Pose(center, v);
        }
        public static void ComputeBoundingBox(IList <Vector3> points, out Vector3 extent, out Pose pose)
        {
            // PCA of the convex hull is used (see "Physics-Based Animation", pp. 483, and others.)
            // in addition to a brute force search. The optimum is returned.

            if (points == null)
            {
                throw new ArgumentNullException("points");
            }
            if (points.Count == 0)
            {
                throw new ArgumentException("The list of 'points' is empty.");
            }

            // Covariance matrix.
            MatrixF cov = null;

            // ReSharper disable EmptyGeneralCatchClause
            try
            {
                if (points.Count > 4)
                {
                    // Reduce point list to convex hull.
                    DcelMesh     dcelMesh = CreateConvexHull(points);
                    TriangleMesh mesh     = dcelMesh.ToTriangleMesh();

                    // Use reduced point list - if we have found a useful one. (Line objects do not have
                    // a useful triangle mesh.)
                    if (mesh.Vertices.Count > 0)
                    {
                        points = mesh.Vertices;
                        cov    = ComputeCovarianceMatrixFromSurface(mesh);
                    }
                }
            }
            catch
            {
            }
            // ReSharper restore EmptyGeneralCatchClause

            // If anything happens in the convex hull creation, we can still go on including the
            // interior points and compute the covariance matrix for the points instead of the
            // surface.
            if (cov == null || Numeric.IsNaN(cov.Determinant()))
            {
                // Make copy of points list because ComputeBoundingBox() will reorder the points.
                points = points.ToList();
                cov    = ComputeCovarianceMatrixFromPoints(points);
            }

            // Perform Eigenvalue decomposition.
            EigenvalueDecompositionF evd = new EigenvalueDecompositionF(cov);

            // v transforms from local coordinate space of the box into world space.
            var v = evd.V.ToMatrix();

            Debug.Assert(v.GetColumn(0).IsNumericallyNormalized);
            Debug.Assert(v.GetColumn(1).IsNumericallyNormalized);
            Debug.Assert(v.GetColumn(2).IsNumericallyNormalized);

            // v is like a rotation matrix, but the coordinate system is not necessarily right handed.
            // --> Make sure it is right-handed.
            v.SetColumn(2, Vector3.Cross(v.GetColumn(0), v.GetColumn(1)));

            // Another way to do this:
            //// Make sure that V is a rotation matrix. (V could be an orthogonal matrix that
            //// contains a mirror operation. In other words, V could be a rotation matrix for
            //// a left handed coordinate system.)
            //if (!v.IsRotation)
            //{
            //  // Swap two columns to create a right handed rotation matrix.
            //  Vector3 col1 = v.GetColumn(2);
            //  Vector3 col2 = v.GetColumn(2);
            //  v.SetColumn(1, col2);
            //  v.SetColumn(2, col1);
            //}

            // If the box axes are parallel to the world axes, create a box with NO rotation.
            TryToMakeIdentityMatrix(ref v);

            Vector3 center;
            float   volume = ComputeBoundingBox(points, v, float.PositiveInfinity, out extent, out center);

            // Brute force search for better box.
            // This was inspired by the OBB algorithm of John Ratcliff, www.codesuppository.com.

            Vector3     αBest         = Vector3.Zero;             // Search for optimal angles.
            float       αMax          = MathHelper.ToRadians(45); // On each axis we rotate from -αMax to +αMax.
            float       αMin          = MathHelper.ToRadians(1);  // We abort when αMax == 1°.
            const float numberOfSteps = 7;                        // In each iteration we divide αMax in this number of steps.

            // In each loop we test angles between -αMax and +αMax.
            // Then we half αMax and search again.
            while (αMax >= αMin)
            {
                bool  foundBetterAngles = false; // Better angles found?
                float αStep             = αMax / numberOfSteps;

                // We test around this angle:
                Vector3 α = αBest;

                for (float αX = α.X - αMax; αX <= α.X + αMax; αX += αStep)
                {
                    for (float αY = α.Y - αMax; αY <= α.Y + αMax; αY += αStep)
                    {
                        for (float αZ = α.Z - αMax; αZ <= α.Z + αMax; αZ += αStep)
                        {
                            Vector3 centerNew;
                            Vector3 boxExtentNew;
                            Matrix  vNew      = Quaternion.CreateFromRotationMatrix(αX, Vector3.UnitX, αY, Vector3.UnitY, αZ, Vector3.UnitZ, true).ToRotationMatrix33();
                            float   volumeNew = ComputeBoundingBox(points, vNew, volume, out boxExtentNew, out centerNew);
                            if (volumeNew < volume)
                            {
                                foundBetterAngles = true;
                                center            = centerNew;
                                extent            = boxExtentNew;
                                v      = vNew;
                                volume = volumeNew;
                                αBest  = new Vector3(αX, αY, αZ);
                            }
                        }
                    }
                }

                // Search again in half the interval around the best angles or abort.
                if (foundBetterAngles)
                {
                    αMax *= 0.5f;
                }
                else
                {
                    αMax = 0;
                }
            }

            pose = new Pose(center, v);
        }
Beispiel #23
0
        public void TestDcelMeshDirty()
        {
            DcelMesh mesh = new DcelMesh();

              DcelVertex v0 = new DcelVertex();
              DcelVertex v1 = new DcelVertex();
              DcelVertex v2 = new DcelVertex();

              DcelEdge e0 = new DcelEdge();
              DcelEdge e1 = new DcelEdge();
              DcelEdge e2 = new DcelEdge();

              DcelFace f = new DcelFace();

              // Link features
              v0.Edge = e0;
              e0.Origin = v0;
              mesh.Vertex = v0;

              Assert.AreEqual(1, mesh.Vertices.Count);
              Assert.AreEqual(1, mesh.Edges.Count);
              Assert.AreEqual(0, mesh.Faces.Count);

              // Link more
              e0.Next = e1;
              e1.Next = e2;
              mesh.Dirty = true;
              Assert.AreEqual(3, mesh.Edges.Count);

              e1.Origin = v1;
              e2.Origin = v2;
              mesh.Dirty = true;
              Assert.AreEqual(3, mesh.Vertices.Count);

              e0.Face = f;
              f.Boundary = e1;
              mesh.Dirty = true;
              Assert.AreEqual(1, mesh.Faces.Count);
        }
        /// <summary>
        /// Called when a mesh should be generated for the shape.
        /// </summary>
        /// <param name="absoluteDistanceThreshold">The absolute distance threshold.</param>
        /// <param name="iterationLimit">The iteration limit.</param>
        /// <returns>The triangle mesh for this shape.</returns>
        protected override TriangleMesh OnGetMesh(float absoluteDistanceThreshold, int iterationLimit)
        {
            DcelMesh mesh = GeometryHelper.CreateConvexHull(Points);

            return(mesh.ToTriangleMesh());
        }
Beispiel #25
0
 private void BuildVertexAdjacencyLists(DcelMesh convexHull)
 {
     _vertexAdjacency = new VertexAdjacency(convexHull);
 }
Beispiel #26
0
        public static DcelMesh ToDCEL(Mesh mesh)
        {
            var dcel = new DcelMesh();

            var vertices = new HVertex[mesh.vertices.Count];
            var faces    = new Face[mesh.triangles.Count];

            dcel.HalfEdges.Capacity = 2 * mesh.NumberOfEdges;

            mesh.Renumber();

            HVertex vertex;

            foreach (var v in mesh.vertices.Values)
            {
                vertex       = new HVertex(v.x, v.y);
                vertex.id    = v.id;
                vertex.label = v.label;

                vertices[v.id] = vertex;
            }

            // Maps a triangle to its 3 edges (used to set next pointers).
            var map = new List <HalfEdge> [mesh.triangles.Count];

            Face face;

            foreach (var t in mesh.triangles)
            {
                face    = new Face(null);
                face.id = t.id;

                faces[t.id] = face;

                map[t.id] = new List <HalfEdge>(3);
            }

            Otri tri = default(Otri), neighbor = default(Otri);

            TriangleNet.Geometry.Vertex org, dest;

            int id, nid, count = mesh.triangles.Count;

            HalfEdge edge, twin, next;

            var edges = dcel.HalfEdges;

            // Count half-edges (edge ids).
            int k = 0;

            // Maps a vertex to its leaving boundary edge.
            var boundary = new Dictionary <int, HalfEdge>();

            foreach (var t in mesh.triangles)
            {
                id = t.id;

                tri.tri = t;

                for (int i = 0; i < 3; i++)
                {
                    tri.orient = i;
                    tri.Sym(ref neighbor);

                    nid = neighbor.tri.id;

                    if (id < nid || nid < 0)
                    {
                        face = faces[id];

                        // Get the endpoints of the current triangle edge.
                        org  = tri.Org();
                        dest = tri.Dest();

                        // Create half-edges.
                        edge = new HalfEdge(vertices[org.id], face);
                        twin = new HalfEdge(vertices[dest.id], nid < 0 ? Face.Empty : faces[nid]);

                        map[id].Add(edge);

                        if (nid >= 0)
                        {
                            map[nid].Add(twin);
                        }
                        else
                        {
                            boundary.Add(dest.id, twin);
                        }

                        // Set leaving edges.
                        edge.origin.leaving = edge;
                        twin.origin.leaving = twin;

                        // Set twin edges.
                        edge.twin = twin;
                        twin.twin = edge;

                        edge.id = k++;
                        twin.id = k++;

                        edges.Add(edge);
                        edges.Add(twin);
                    }
                }
            }

            // Set next pointers for each triangle face.
            foreach (var t in map)
            {
                edge = t[0];
                next = t[1];

                if (edge.twin.origin.id == next.origin.id)
                {
                    edge.next = next;
                    next.next = t[2];
                    t[2].next = edge;
                }
                else
                {
                    edge.next = t[2];
                    next.next = edge;
                    t[2].next = next;
                }
            }

            // Resolve boundary edges.
            foreach (var e in boundary.Values)
            {
                e.next = boundary[e.twin.origin.id];
            }

            dcel.Vertices.AddRange(vertices);
            dcel.Faces.AddRange(faces);

            return(dcel);
        }