Esempio n. 1
0
 /// <summary>
 ///     Stores the face with negligible area.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="face">The face.</param>
 private static void StoreFaceWithNegligibleArea(TessellatedSolid ts, PolygonalFace face)
 {
     //This is not truly an error, to don't change the NoErrors boolean.
     if (ts.Errors.FacesWithNegligibleArea == null)
     {
         ts.Errors.FacesWithNegligibleArea = new List <PolygonalFace> {
             face
         }
     }
     ;
     else if (!ts.Errors.FacesWithNegligibleArea.Contains(face))
     {
         ts.Errors.FacesWithNegligibleArea.Add(face);
     }
 }
Esempio n. 2
0
 /// <summary>
 ///     Stores the edge has bad angle.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="edge">The edge.</param>
 private static void StoreEdgeHasBadAngle(TessellatedSolid ts, Edge edge)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.EdgesWithBadAngle == null)
     {
         ts.Errors.EdgesWithBadAngle = new List <Edge> {
             edge
         }
     }
     ;
     else if (!ts.Errors.EdgesWithBadAngle.Contains(edge))
     {
         ts.Errors.EdgesWithBadAngle.Add(edge);
     }
 }
Esempio n. 3
0
 /// <summary>
 ///     Stores the face with one vertex.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="face">The face.</param>
 private static void StoreFaceWithOneVertex(TessellatedSolid ts, PolygonalFace face)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.FacesWithOneVertex == null)
     {
         ts.Errors.FacesWithOneVertex = new List <PolygonalFace> {
             face
         }
     }
     ;
     else
     {
         ts.Errors.FacesWithOneVertex.Add(face);
     }
 }
Esempio n. 4
0
 /// <summary>
 ///     Stores the duplicate face.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="faceVertexIndices">The face vertex indices.</param>
 internal static void StoreDuplicateFace(TessellatedSolid ts, int[] faceVertexIndices)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.DuplicateFaces == null)
     {
         ts.Errors.DuplicateFaces = new List <int[]> {
             faceVertexIndices
         }
     }
     ;
     else
     {
         ts.Errors.DuplicateFaces.Add(faceVertexIndices);
     }
 }
Esempio n. 5
0
 /// <summary>
 ///     Stores the single sided edge.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="singledSidedEdge">The singled sided edge.</param>
 internal static void StoreSingleSidedEdge(TessellatedSolid ts, Edge singledSidedEdge)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.SingledSidedEdges == null)
     {
         ts.Errors.SingledSidedEdges = new List <Edge> {
             singledSidedEdge
         }
     }
     ;
     else
     {
         ts.Errors.SingledSidedEdges.Add(singledSidedEdge);
     }
 }
Esempio n. 6
0
 /// <summary>
 ///     Stores the vert does not link back to edge.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="edge">The edge.</param>
 /// <param name="vert">The vert.</param>
 private static void StoreVertDoesNotLinkBackToEdge(TessellatedSolid ts, Edge edge, Vertex vert)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.VertsThatDoNotLinkBackToEdge == null)
     {
         ts.Errors.VertsThatDoNotLinkBackToEdge
             = new List <(Edge, Vertex)> {
             (edge, vert)
             }
     }
     ;
     else
     {
         ts.Errors.VertsThatDoNotLinkBackToEdge.Add((edge, vert));
     }
 }
Esempio n. 7
0
 /// <summary>
 ///     Stores the edge does not link back to vertex.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="vertex">The vertex.</param>
 /// <param name="edge">The edge.</param>
 private static void StoreEdgeDoesNotLinkBackToVertex(TessellatedSolid ts, Vertex vertex, Edge edge)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.EdgesThatDoNotLinkBackToVertex == null)
     {
         ts.Errors.EdgesThatDoNotLinkBackToVertex
             = new List <(Vertex, Edge)> {
             (vertex, edge)
             }
     }
     ;
     else
     {
         ts.Errors.EdgesThatDoNotLinkBackToVertex.Add((vertex, edge));
     }
 }
Esempio n. 8
0
 /// <summary>
 ///     Stores the face does not link back to vertex.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="vertex">The vertex.</param>
 /// <param name="face">The face.</param>
 private static void StoreFaceDoesNotLinkBackToVertex(TessellatedSolid ts, Vertex vertex, PolygonalFace face)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.FacesThatDoNotLinkBackToVertex == null)
     {
         ts.Errors.FacesThatDoNotLinkBackToVertex
             = new List <(Vertex, PolygonalFace)> {
             (vertex, face)
             }
     }
     ;
     else
     {
         ts.Errors.FacesThatDoNotLinkBackToVertex.Add((vertex, face));
     }
 }
Esempio n. 9
0
 /// <summary>
 ///     Stores the vertex does not link back to face.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="face">The face.</param>
 /// <param name="vertex">The vertex.</param>
 private static void StoreVertexDoesNotLinkBackToFace(TessellatedSolid ts, PolygonalFace face, Vertex vertex)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.VertsThatDoNotLinkBackToFace == null)
     {
         ts.Errors.VertsThatDoNotLinkBackToFace
             = new List <(PolygonalFace, Vertex)> {
             (face, vertex)
             }
     }
     ;
     else
     {
         ts.Errors.VertsThatDoNotLinkBackToFace.Add((face, vertex));
     }
 }
Esempio n. 10
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="Edge" /> class.
 /// </summary>
 /// <param name="fromVertex">From vertex.</param>
 /// <param name="toVertex">To vertex.</param>
 /// <param name="ownedFace">The face.</param>
 /// <param name="otherFace">The other face.</param>
 /// <param name="doublyLinkedVertices">if set to <c>true</c> [doubly linked vertices].</param>
 /// <param name="edgeReference">The edge reference.</param>
 /// <exception cref="Exception"></exception>
 public Edge(Vertex fromVertex, Vertex toVertex, PolygonalFace ownedFace, PolygonalFace otherFace,
             bool doublyLinkedVertices, long edgeReference = 0) : this(fromVertex, toVertex, doublyLinkedVertices)
 {
     if (edgeReference > 0)
     {
         EdgeReference = edgeReference;
     }
     else
     {
         TessellatedSolid.SetAndGetEdgeChecksum(this);
     }
     _ownedFace = ownedFace;
     _otherFace = otherFace;
     ownedFace?.AddEdge(this);
     otherFace?.AddEdge(this);
 }
Esempio n. 11
0
 /// <summary>
 ///     Stores the face does not link back to edge.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="edge">The edge.</param>
 /// <param name="face">The face.</param>
 private static void StoreFaceDoesNotLinkBackToEdge(TessellatedSolid ts, Edge edge, PolygonalFace face)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.FacesThatDoNotLinkBackToEdge == null)
     {
         ts.Errors.FacesThatDoNotLinkBackToEdge
             = new List <(Edge, PolygonalFace)> {
             (edge, face)
             }
     }
     ;
     else
     {
         ts.Errors.FacesThatDoNotLinkBackToEdge.Add((edge, face));
     }
 }
Esempio n. 12
0
 /// <summary>
 ///     Stores the edge does not link back to face.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="face">The face.</param>
 /// <param name="edge">The edge.</param>
 private static void StoreEdgeDoesNotLinkBackToFace(TessellatedSolid ts, PolygonalFace face, Edge edge)
 {
     ts.Errors.NoErrors = false;
     if (ts.Errors.EdgesThatDoNotLinkBackToFace == null)
     {
         ts.Errors.EdgesThatDoNotLinkBackToFace
             = new List <(PolygonalFace, Edge)> {
             (face, edge)
             }
     }
     ;
     else
     {
         ts.Errors.EdgesThatDoNotLinkBackToFace.Add((face, edge));
     }
 }
Esempio n. 13
0
        /// <summary>
        /// Makes the model visual3 d.
        /// </summary>
        /// <param name="ts">The ts.</param>
        /// <returns>Visual3D.</returns>
        private static Visual3D MakeModelVisual3D(TessellatedSolid ts)
        {
            var defaultMaterial = MaterialHelper.CreateMaterial(
                new System.Windows.Media.Color
            {
                A = ts.SolidColor.A,
                B = ts.SolidColor.B,
                G = ts.SolidColor.G,
                R = ts.SolidColor.R
            });

            if (ts.HasUniformColor)
            {
                return(MakeModelVisual3DSameColorFaces(ts.Faces, defaultMaterial));
            }
            return(MakeModelVisual3DMultiColorFaces(ts.Faces, defaultMaterial));
        }
Esempio n. 14
0
        /// <summary>
        /// Shows the specified tessellated solid in a Helix toolkit window.
        /// </summary>
        /// <param name="tessellatedSolid">The tessellated solid.</param>
        /// <param name="seconds">The seconds.</param>
        public static void Show(TessellatedSolid tessellatedSolid, int seconds = 0)
        {
            var window = new Window3DPlot();

            window.view1.Children.Add(MakeModelVisual3D(tessellatedSolid));
            window.view1.FitView(window.view1.Camera.LookDirection, window.view1.Camera.UpDirection);
            if (seconds > 0)
            {
                window.Show();
                Thread.Sleep(seconds * 1000);
                window.Close();
            }
            else
            {
                window.Show();
            }
        }
        /// <summary>
        ///     Finds the minimum bounding box oriented along a particular Direction.
        /// </summary>
        /// <param name="ts">The ts.</param>
        /// <param name="times"></param>
        /// <param name="volumes"></param>
        /// <returns>BoundingBox.</returns>
        //private
        public static BoundingBox OrientedBoundingBox_Test(TessellatedSolid ts, out List <double> times,
                                                           out List <double> volumes) //, out List<List<double[]>> volumeData2)
        {
            var vertices = ts.ConvexHull.Vertices.Any() ? ts.ConvexHull.Vertices : ts.Vertices;

            times   = new List <double>();
            volumes = new List <double>();
            //var flats = ListFunctions.Flats(ts.Faces.ToList());
            var now = DateTime.Now;

            Message.output("Beginning OBB Test", 2);
            var boundingBox1 = OrientedBoundingBox(vertices);

            times.Add((DateTime.Now - now).TotalMilliseconds);
            volumes.Add(boundingBox1.Volume);
            //Message.output("Time Elapsed for PCA Approach = " ,4);
            //Message.output("Volume for PCA Approach= " + boundingBox1.Volume,4);
            now = DateTime.Now;
            Message.output("Beginning OBB Test", 2);

            var boundingBox12 = Find_via_PCA_ApproachNR(vertices);

            times.Add((DateTime.Now - now).TotalMilliseconds);
            volumes.Add(boundingBox12.Volume);
            //Message.output("Time Elapsed for PCA Approach = " ,4 );
            //Message.output("Volume for PCA Approach= " + boundingBox1.Volume);
            now = DateTime.Now;
            var boundingBox2 = Find_via_ChanTan_AABB_Approach(vertices);

            times.Add((DateTime.Now - now).TotalMilliseconds);
            volumes.Add(boundingBox2.Volume);
            Message.output("Time Elapsed for ChanTan Approach = " + (DateTime.Now - now), 4);
            Message.output("Volume for ChanTan Approach = " + boundingBox2.Volume, 4);
            //now = DateTime.Now;
            //Message.output("Beginning OBB Test");
            //var boundingBox1 = Find_via_MC_ApproachOne(ts, out volumeData1);
            //Message.output("Time Elapsed for MC Approach One = " + (DateTime.Now - now),4);
            //now = DateTime.Now;
            //var boundingBox2 = Find_via_BM_ApproachTwo(ts, out volumeData2);
            //Message.output("Time Elapsed for BM Approach Two = " + (DateTime.Now - now),4);

            return(boundingBox2);
        }
Esempio n. 16
0
        public void CompletePostSerialization(TessellatedSolid ts)
        {
            Faces = new List <PolygonalFace>();
            var stringList = _faceIndices.Split(',');
            var listLength = stringList.Length;

            for (int i = 0; i < listLength; i++)
            {
                var face = ts.Faces[int.Parse(stringList[i])];
                Faces.Add(face);
                face.BelongsToPrimitive = this;
            }

            Vertices   = new List <Vertex>();
            stringList = _vertexIndices.Split(',');
            listLength = stringList.Length;
            for (int i = 0; i < listLength; i++)
            {
                Vertices.Add(ts.Vertices[int.Parse(stringList[i])]);
            }

            if (!string.IsNullOrWhiteSpace(_innerEdgeIndices))
            {
                _innerEdges = new List <Edge>();
                stringList  = _innerEdgeIndices.Split(',');
                listLength  = stringList.Length;
                for (int i = 0; i < listLength; i++)
                {
                    _innerEdges.Add(ts.Edges[int.Parse(stringList[i])]);
                }
            }
            if (!string.IsNullOrWhiteSpace(_outerEdgeIndices))
            {
                _outerEdges = new List <Edge>();
                stringList  = _outerEdgeIndices.Split(',');
                listLength  = stringList.Length;
                for (int i = 0; i < listLength; i++)
                {
                    _outerEdges.Add(ts.Edges[int.Parse(stringList[i])]);
                }
            }
            Area = Faces.Sum(f => f.Area);
        }
        /// <summary>
        /// Find the volume of a tesselated solid with a slower method.
        /// This method could be exteded to find partial volumes of a solid (e.g. volume between two planes)
        /// </summary>
        /// <param name="ts"></param>
        /// <returns></returns>
        private static double VolumeViaAreaDecomposition(TessellatedSolid ts)
        {
            var normal   = new[] { 1.0, 0.0, 0.0 }; //Direction is irrellevant
            var stepSize = 0.01;
            var volume   = 0.0;
            var areas    = DirectionalDecomposition.NonUniformAreaDecomposition(ts, normal, stepSize);

            //Trapezoidal approximation. This should be accurate since the lines betweens data points are linear
            for (var i = 1; i < areas.Count; i++)
            {
                var deltaX = areas[i][0] - areas[i - 1][0];
                if (deltaX < 0)
                {
                    throw new Exception("Error in your implementation. This should never occur");
                }
                volume = volume + .5 * (areas[i][1] + areas[i - 1][1]) * deltaX;
            }
            return(volume);
        }
Esempio n. 18
0
        internal TVGLConvexHull(IList <Vertex> allVertices, IList <Vertex> convexHullPoints,
                                IList <int> convexHullFaceIndices, double tolerance)
        {
            Vertices = convexHullPoints.ToArray();
            var numCvxHullFaces = convexHullFaceIndices.Count / 3;

            Faces = new PolygonalFace[numCvxHullFaces];
            var checkSumMultipliers = new long[3];

            for (var i = 0; i < 3; i++)
            {
                checkSumMultipliers[i] = (long)Math.Pow(Constants.CubeRootOfLongMaxValue, i);
            }
            var alreadyCreatedFaces = new HashSet <long>();

            for (int i = 0; i < numCvxHullFaces; i++)
            {
                var orderedIndices = new List <int>
                {
                    convexHullFaceIndices[3 * i], convexHullFaceIndices[3 * i + 1], convexHullFaceIndices[3 * i + 2]
                };
                orderedIndices.Sort();
                var checksum = orderedIndices.Select((t, j) => t * checkSumMultipliers[j]).Sum();
                if (alreadyCreatedFaces.Contains(checksum))
                {
                    continue;
                }
                alreadyCreatedFaces.Add(checksum);
                var faceVertices = new[]
                {
                    allVertices[convexHullFaceIndices[3 * i]],
                    allVertices[convexHullFaceIndices[3 * i + 1]],
                    allVertices[convexHullFaceIndices[3 * i + 2]],
                };
                Faces[i] = new PolygonalFace(faceVertices, false);
            }
            Edges       = MakeEdges(Faces, Vertices);
            SurfaceArea = Faces.Sum(face => face.Area);
            TessellatedSolid.CalculateVolumeAndCenter(Faces, tolerance, out Volume, out Center);
        }
Esempio n. 19
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="Edge" /> class.
 /// </summary>
 /// <param name="fromVertex">From vertex.</param>
 /// <param name="toVertex">To vertex.</param>
 /// <param name="ownedFace">The face.</param>
 /// <param name="otherFace">The other face.</param>
 /// <param name="doublyLinkedVertices">if set to <c>true</c> [doubly linked vertices].</param>
 /// <param name="edgeReference">The edge reference.</param>
 /// <exception cref="Exception"></exception>
 public Edge(Vertex fromVertex, Vertex toVertex, PolygonalFace ownedFace, PolygonalFace otherFace,
             bool doublyLinkedVertices, long edgeReference = 0) : this(fromVertex, toVertex, doublyLinkedVertices)
 {
     if (edgeReference > 0)
     {
         EdgeReference = edgeReference;
     }
     else
     {
         TessellatedSolid.SetAndGetEdgeChecksum(this);
     }
     _ownedFace = ownedFace;
     _otherFace = otherFace;
     if (ownedFace != null)
     {
         ownedFace.AddEdge(this);
     }
     if (otherFace != null)
     {
         otherFace.AddEdge(this);
     }
     DefineInternalEdgeAngle();
 }
Esempio n. 20
0
        /// <summary>
        /// Shows vertex paths. Assumes paths are closed.
        /// </summary>
        /// <param name="vertices">The vertices.</param>
        /// <param name="colors">The colors.</param>
        /// <param name="ts">The ts.</param>
        public static void ShowGaussSphereWithIntensity(IList <Vertex> vertices, IList <Color> colors, TessellatedSolid ts)
        {
            var window = new Window3DPlot();
            var pt0    = new Point3D(ts.Center[0], ts.Center[1], ts.Center[2]);
            var x      = ts.XMax - ts.XMin;
            var y      = ts.YMax - ts.YMin;
            var z      = ts.ZMax - ts.ZMin;
            var radius = System.Math.Max(System.Math.Max(x, y), z) / 2;

            //Add the solid to the visual
            var model = MakeModelVisual3D(ts);

            window.view1.Children.Add(model);

            //Add a transparent unit sphere to the visual
            var sphere = new SphereVisual3D();

            sphere.Radius   = radius;
            sphere.Center   = pt0;
            sphere.Material = MaterialHelper.CreateMaterial(new System.Windows.Media.Color {
                A = 15, R = 200, G = 200, B = 200
            });
            //window.view1.Children.Add(sphere);

            var i = 0;

            foreach (var point in vertices)
            {
                var color = colors[i];
                var pt1   = new Point3D(pt0.X + point.X * radius, pt0.Y + point.Y * radius, pt0.Z + point.Z * radius);


                //No create a line collection by doubling up the points
                var lineCollection = new List <Point3D>();
                lineCollection.Add(pt0);
                lineCollection.Add(pt1);

                var systemColor = new System.Windows.Media.Color();
                systemColor.A = 255;
                systemColor.R = color.R;
                systemColor.G = color.G;
                systemColor.B = color.B;


                var lines = new LinesVisual3D {
                    Points = new Point3DCollection(lineCollection), Color = systemColor, Thickness = 5
                };


                var pointsVisual = new PointsVisual3D {
                    Color = systemColor, Size = 5
                };
                pointsVisual.Points = new Point3DCollection()
                {
                    pt1
                };
                window.view1.Children.Add(pointsVisual);
                window.view1.Children.Add(lines);
                i++;
            }



            window.view1.FitView(window.view1.Camera.LookDirection, window.view1.Camera.UpDirection);
            window.ShowDialog();
        }
Esempio n. 21
0
        /// <summary>
        /// Shows the vertex paths with solid.
        /// </summary>
        /// <param name="paths"></param>
        /// <param name="closePaths"></param>
        /// <param name="solid"></param>
        public static void ShowVertexPaths(IList <List <double[]> > paths, bool closePaths = true, TessellatedSolid solid = null)
        {
            var window = new Window3DPlot();
            var models = new List <Visual3D>();

            if (solid != null)
            {
                var model = MakeModelVisual3D(solid);
                models.Add(model);
                window.view1.Children.Add(model);
            }

            foreach (var path in paths)
            {
                var contour = path.Select(point => new Point3D(point[0], point[1], point[2])).ToList();

                //Now create a line collection by doubling up the points
                var lineCollection = new List <Point3D>();
                foreach (var t in contour)
                {
                    lineCollection.Add(t);
                    lineCollection.Add(t);
                }
                lineCollection.RemoveAt(0);

                if (closePaths)
                {
                    lineCollection.Add(lineCollection.First());
                }

                var lines = new LinesVisual3D {
                    Points = new Point3DCollection(lineCollection)
                };
                window.view1.Children.Add(lines);
            }
            window.view1.FitView(window.view1.Camera.LookDirection, window.view1.Camera.UpDirection);
            window.ShowDialog();
        }
Esempio n. 22
0
        /// <summary>
        /// Complexifies the tessellation so that no edge is longer than provided the maximum edge length
        /// or for adding the provided number of faces - whichever comes first
        /// </summary>
        /// <param name="ts">The ts.</param>
        /// <param name="numberOfFaces">The number of new faces to add.</param>
        /// <param name="maxLength">The maximum length.</param>
        public static void Complexify(TessellatedSolid ts, int numberOfFaces, double maxLength)
        {
            var edgeQueue = new SimplePriorityQueue <Edge, double>(new ReverseSort());

            foreach (var e in ts.Edges)
            {
                edgeQueue.Enqueue(e, e.Length);
            }
            var addedEdges    = new List <Edge>();
            var addedVertices = new List <Vertex>();
            var addedFaces    = new List <PolygonalFace>();
            var edge          = edgeQueue.Dequeue();
            var iterations    = numberOfFaces > 0 ? (int)Math.Ceiling(numberOfFaces / 2.0) : numberOfFaces;

            while (iterations-- != 0 && edge.Length >= maxLength)
            {
                var origLeftFace   = edge.OtherFace;
                var origRightFace  = edge.OwnedFace;
                var leftFarVertex  = origLeftFace.OtherVertex(edge);
                var rightFarVertex = origRightFace.OtherVertex(edge);
                var fromVertex     = edge.From;
                var toVertex       = edge.To;
                var addedVertex    = new Vertex(DetermineIntermediateVertexPosition(fromVertex, toVertex));
                // modify original faces with new intermediate vertex
                var index = origLeftFace.Vertices.IndexOf(toVertex);
                origLeftFace.Vertices[index] = addedVertex;
                origLeftFace.Update();
                addedVertex.Faces.Add(origLeftFace);
                index = origRightFace.Vertices.IndexOf(toVertex);
                origRightFace.Vertices[index] = addedVertex;
                origRightFace.Update();
                addedVertex.Faces.Add(origRightFace);

                var newLeftFace  = new PolygonalFace(new[] { toVertex, addedVertex, leftFarVertex });
                var newRightFace = new PolygonalFace(new[] { addedVertex, toVertex, rightFarVertex });
                toVertex.Faces.Remove(origLeftFace);
                toVertex.Faces.Remove(origRightFace);

                var inlineEdge = new Edge(addedVertex, toVertex, newRightFace, newLeftFace, true);
                toVertex.Edges.Remove(edge);
                edge.To = addedVertex;
                addedVertex.Edges.Add(edge);
                edge.Update();
                var newLeftEdge  = new Edge(leftFarVertex, addedVertex, origLeftFace, newLeftFace, true);
                var newRightEdge = new Edge(rightFarVertex, addedVertex, newRightFace, origRightFace, true);
                origLeftFace.AddEdge(newLeftEdge);
                origRightFace.AddEdge(newRightEdge);
                var bottomEdge = toVertex.Edges.First(e => e.OtherVertex(toVertex) == leftFarVertex);
                if (bottomEdge.OwnedFace == origLeftFace)
                {
                    bottomEdge.OwnedFace = newLeftFace;
                }
                else
                {
                    bottomEdge.OtherFace = newLeftFace;
                }
                newLeftFace.AddEdge(bottomEdge);
                bottomEdge.Update();

                bottomEdge = toVertex.Edges.First(e => e.OtherVertex(toVertex) == rightFarVertex);
                if (bottomEdge.OwnedFace == origRightFace)
                {
                    bottomEdge.OwnedFace = newRightFace;
                }
                else
                {
                    bottomEdge.OtherFace = newRightFace;
                }
                newRightFace.AddEdge(bottomEdge);
                bottomEdge.Update();


                // need to re-add the edge. It was modified in the SplitEdge function (now, half the lenght), but
                // it may still be met by this criteria
                edgeQueue.Enqueue(edge, edge.Length);
                edgeQueue.Enqueue(inlineEdge, inlineEdge.Length);
                addedEdges.Add(inlineEdge);
                edgeQueue.Enqueue(newLeftEdge, newLeftEdge.Length);
                addedEdges.Add(newLeftEdge);
                edgeQueue.Enqueue(newRightEdge, newRightEdge.Length);
                addedEdges.Add(newRightEdge);
                addedFaces.Add(newLeftFace);
                addedFaces.Add(newRightFace);
                addedVertices.Add(addedVertex);
                edge = edgeQueue.First();
            }
            ts.AddVertices(addedVertices);
            ts.AddEdges(addedEdges);
            ts.AddFaces(addedFaces);
        }
Esempio n. 23
0
 /// <summary>
 /// Complexifies the tessellation so that no edge is longer than provided the maximum edge length.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="maxLength">The tolerance.</param>
 public static void Complexify(this TessellatedSolid ts, double maxLength)
 {
     Complexify(ts, -1, maxLength);
 }
Esempio n. 24
0
 /// <summary>
 /// Complexifies the tessellation by adding more faces of the provided number.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="numberOfNewFaces">The number of faces.</param>
 public static void Complexify(this TessellatedSolid ts, int numberOfNewFaces)
 {
     Complexify(ts, numberOfNewFaces, 0.0);
 }
Esempio n. 25
0
 /// <summary>
 /// Complexifies the model by splitting the any edges that are half or more than the longest edge.
 /// </summary>
 /// <param name="ts">The ts.</param>
 public static void Complexify(this TessellatedSolid ts)
 {
     Complexify(ts, ts.NumberOfFaces / 2, ts.Edges.Max(x => x.Length) * 0.5);
 }
Esempio n. 26
0
        /// <summary>
        /// Simplifies the tessellation so that no edge are shorter than provided the minimum edge length
        /// or until the provided number of faces are removed - whichever comes first.
        /// </summary>
        /// <param name="ts">The ts.</param>
        /// <param name="numberOfFaces">The number of faces to remove.</param>
        /// <param name="minLength">The minimum length.</param>
        public static void Simplify(TessellatedSolid ts, int numberOfFaces, double minLength)
        {
            if (ts.Errors != null)
            {
                Message.output(
                    "** The model should be free of errors before running this routine (run TessellatedSolid.Repair()).",
                    1);
            }
            var sortedEdges     = ts.Edges.OrderBy(e => e.Length).ToList();
            var removedEdges    = new SortedSet <Edge>(new SortByIndexInList());
            var removedVertices = new SortedSet <Vertex>(new SortByIndexInList());
            var removedFaces    = new SortedSet <PolygonalFace>(new SortByIndexInList());

            var edge       = sortedEdges[0];
            var iterations = numberOfFaces > 0 ? (int)Math.Ceiling(numberOfFaces / 2.0) : numberOfFaces;

            while (iterations != 0 && edge.Length <= minLength)
            {
                sortedEdges.RemoveAt(0);
                // naming conventions to ease the latter topological changes
                var removedVertex   = edge.From;
                var keepVertex      = edge.To;
                var leftFace        = edge.OtherFace;
                var rightFace       = edge.OwnedFace;
                var leftRemoveEdge  = leftFace.OtherEdge(keepVertex);
                var rightRemoveEdge = rightFace.OtherEdge(keepVertex);
                var leftKeepEdge    = leftFace.OtherEdge(removedVertex);
                var rightKeepEdge   = rightFace.OtherEdge(removedVertex);
                var leftFarVertex   = leftFace.OtherVertex(edge);
                var rightFarVertex  = rightFace.OtherVertex(edge);

                // this is a topologically important check. It ensures that the edge is not deleted if
                // it serves an important role in ensuring the proper topology of the solid
                var otherEdgesOnTheKeepSide = keepVertex.Edges.Where(e => e != edge && e != leftKeepEdge && e != rightKeepEdge).ToList();
                otherEdgesOnTheKeepSide.Remove(edge);
                var otherEdgesOnTheRemoveSide = removedVertex.Edges.Where(e => e != edge && e != leftRemoveEdge && e != rightRemoveEdge).ToList();
                otherEdgesOnTheRemoveSide.Remove(edge);
                if (leftFarVertex != rightFarVertex &&
                    !otherEdgesOnTheKeepSide.Select(e => e.OtherVertex(keepVertex))
                    .Intersect(otherEdgesOnTheRemoveSide.Select(e => e.OtherVertex(removedVertex)))
                    .Any())
                {
                    iterations--; //now that we passed that test, we can be assured that the reduction will go through
                                  // move the keepVertex
                    keepVertex.Position = DetermineIntermediateVertexPosition(removedVertex, keepVertex);
                    // add and remove to the lists at the top of this method
                    removedEdges.Add(edge);
                    removedEdges.Add(leftRemoveEdge);
                    sortedEdges.Remove(leftRemoveEdge);
                    removedEdges.Add(rightRemoveEdge);
                    sortedEdges.Remove(rightRemoveEdge);
                    removedFaces.Add(leftFace);
                    removedFaces.Add(rightFace);
                    removedVertices.Add(removedVertex);

                    keepVertex.Faces.Remove(leftFace);
                    keepVertex.Faces.Remove(rightFace);
                    // the keepVertex's other faces need to be updated given the change in position of keepVertex
                    foreach (var face in keepVertex.Faces)
                    {
                        face.Update();
                    }
                    // remove the removedVertex from the faces and update their positions with the keepVertex
                    foreach (var face in removedVertex.Faces)
                    {
                        if (face == leftFace || face == rightFace)
                        {
                            continue;
                        }
                        var index = face.Vertices.IndexOf(removedVertex);
                        face.Vertices[index] = keepVertex;
                        face.Update();
                        keepVertex.Faces.Add(face);
                    }

                    keepVertex.Edges.Remove(edge);
                    // update the edges since the keepVertex moved
                    foreach (var currentEdge in keepVertex.Edges)
                    {
                        if (currentEdge != leftKeepEdge && currentEdge != rightKeepEdge)
                        {
                            currentEdge.Update();
                        }
                    }
                    // transfer the edges from the removedVertex to the keepVertex
                    foreach (var transferEdge in removedVertex.Edges)
                    {
                        if (transferEdge == leftRemoveEdge || transferEdge == rightRemoveEdge)
                        {
                            continue;
                        }
                        if (transferEdge.From == removedVertex)
                        {
                            transferEdge.From = keepVertex;
                        }
                        else
                        {
                            transferEdge.To = keepVertex;
                        }
                        transferEdge.Update();
                        keepVertex.Edges.Add(transferEdge);
                    }

                    leftFarVertex.Edges.Remove(leftRemoveEdge);
                    leftFarVertex.Faces.Remove(leftFace);
                    rightFarVertex.Edges.Remove(rightRemoveEdge);
                    rightFarVertex.Faces.Remove(rightFace);

                    var upperFace = leftRemoveEdge.OwnedFace == leftFace
                        ? leftRemoveEdge.OtherFace
                        : leftRemoveEdge.OwnedFace;
                    if (leftKeepEdge.OwnedFace == leftFace)
                    {
                        leftKeepEdge.OwnedFace = upperFace;
                    }
                    else
                    {
                        leftKeepEdge.OtherFace = upperFace;
                    }
                    upperFace.AddEdge(leftKeepEdge);
                    leftKeepEdge.Update();

                    upperFace = rightRemoveEdge.OwnedFace == rightFace
                        ? rightRemoveEdge.OtherFace
                        : rightRemoveEdge.OwnedFace;
                    if (rightKeepEdge.OwnedFace == rightFace)
                    {
                        rightKeepEdge.OwnedFace = upperFace;
                    }
                    else
                    {
                        rightKeepEdge.OtherFace = upperFace;
                    }
                    upperFace.AddEdge(rightKeepEdge);
                    rightKeepEdge.Update();
                }
                if (sortedEdges.Any())
                {
                    edge = sortedEdges[0];
                }
                else
                {
                    break;
                }
            }
            ts.RemoveEdges(removedEdges.Select(e => e.IndexInList).ToList());
            ts.RemoveFaces(removedFaces.Select(f => f.IndexInList).ToList());
            ts.RemoveVertices(removedVertices.Select(v => v.IndexInList).ToList());
        }
Esempio n. 27
0
 /// <summary>
 /// Simplifies the tessellation so that no edge are shorter than provided the minimum edge length.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="minLength">The minimum length.</param>
 public static void Simplify(this TessellatedSolid ts, double minLength)
 {
     Simplify(ts, -1, minLength);
 }
Esempio n. 28
0
 /// <summary>
 /// Simplifies the tessellation by removing the provided number of faces.
 /// </summary>
 /// <param name="ts">The ts.</param>
 /// <param name="numberOfFacesToRemove">The number of faces.</param>
 public static void Simplify(this TessellatedSolid ts, int numberOfFacesToRemove)
 {
     Simplify(ts, numberOfFacesToRemove, double.PositiveInfinity);
 }
Esempio n. 29
0
        /// <summary>
        /// Makes the model visual3 d.
        /// </summary>
        /// <param name="ts">The ts.</param>
        /// <returns>Visual3D.</returns>
        private static Visual3D MakeModelVisual3D(TessellatedSolid ts)
        {
            var defaultMaterial = MaterialHelper.CreateMaterial(
                new System.Windows.Media.Color
            {
                A = ts.SolidColor.A,
                B = ts.SolidColor.B,
                G = ts.SolidColor.G,
                R = ts.SolidColor.R
            });

            if (ts.HasUniformColor)
            {
                var positions =
                    ts.Faces.SelectMany(
                        f => f.Vertices.Select(v => new Point3D(v.Position[0], v.Position[1], v.Position[2])));
                var normals =
                    ts.Faces.SelectMany(f => f.Vertices.Select(v => new Vector3D(f.Normal[0], f.Normal[1], f.Normal[2])));
                return(new ModelVisual3D
                {
                    Content =
                        new GeometryModel3D
                    {
                        Geometry = new MeshGeometry3D
                        {
                            Positions = new Point3DCollection(positions),
                            // TriangleIndices = new Int32Collection(triIndices),
                            Normals = new Vector3DCollection(normals)
                        },
                        Material = defaultMaterial
                    }
                });
            }
            var result = new ModelVisual3D();

            foreach (var f in ts.Faces)
            {
                var vOrder = new Point3DCollection();
                for (var i = 0; i < 3; i++)
                {
                    vOrder.Add(new Point3D(f.Vertices[i].X, f.Vertices[i].Y, f.Vertices[i].Z));
                }

                var c = f.Color == null
                    ? defaultMaterial
                    : MaterialHelper.CreateMaterial(new System.Windows.Media.Color
                {
                    A = f.Color.A,
                    B = f.Color.B,
                    G = f.Color.G,
                    R = f.Color.R
                });
                result.Children.Add(new ModelVisual3D
                {
                    Content =
                        new GeometryModel3D
                    {
                        Geometry = new MeshGeometry3D {
                            Positions = vOrder
                        },
                        Material = c
                    }
                });
            }
            return(result);
        }
Esempio n. 30
0
        /// <summary>
        /// Simplifies the model by merging the eliminating edges that are closer together
        /// than double the shortest edge length
        /// </summary>
        /// <param name="ts">The ts.</param>
        public static void SimplifyFlatPatches(this TessellatedSolid ts)
        {
            //   throw new NotImplementedException();
            var edgesToRemove    = new List <Edge>();
            var edgesToAdd       = new List <Edge>();
            var facesToRemove    = new List <PolygonalFace>();
            var facesToAdd       = new List <PolygonalFace>();
            var verticesToRemove = new List <Vertex>();
            var flats            = TVGL.MiscFunctions.FindFlats(ts.Faces);

            if (ts.Primitives == null)
            {
                ts.Primitives = new List <PrimitiveSurface>();
            }
            foreach (var flat in flats)
            {
                if (flat.InnerEdges.Count < flat.Faces.Count)
                {
                    continue;
                }
                var newFaces         = new List <PolygonalFace>();
                var outerEdgeHashSet = new HashSet <Edge>(flat.OuterEdges);
                facesToRemove.AddRange(flat.Faces);
                edgesToRemove.AddRange(flat.InnerEdges);
                var innerVertices = new HashSet <Vertex>(flat.InnerEdges.Select(e => e.To));
                innerVertices.UnionWith(flat.InnerEdges.Select(e => e.From));
                innerVertices.RemoveWhere(v => outerEdgeHashSet.Overlaps(v.Edges));
                verticesToRemove.AddRange(innerVertices);
                var vertexLoops = OrganizeIntoLoop(flat.OuterEdges, flat.Normal);
                List <List <Vertex[]> > triangulatedListofLists = TriangulatePolygon.Run(new[] { vertexLoops }, flat.Normal);
                var triangulatedList  = triangulatedListofLists.SelectMany(tl => tl).ToList();
                var oldEdgeDictionary = flat.OuterEdges.ToDictionary(TessellatedSolid.SetAndGetEdgeChecksum);
                Dictionary <long, Edge> newEdgeDictionary = new Dictionary <long, Edge>();
                foreach (var triangle in triangulatedList)
                {
                    var newFace = new PolygonalFace(triangle, flat.Normal);
                    if (newFace.Area.IsNegligible() && newFace.Normal.Any(double.IsNaN))
                    {
                        continue;
                    }
                    newFaces.Add(newFace);
                    for (var j = 0; j < 3; j++)
                    {
                        var fromVertex = newFace.Vertices[j];
                        var toVertex   = newFace.NextVertexCCW(fromVertex);
                        var checksum   = TessellatedSolid.GetEdgeChecksum(fromVertex, toVertex);
                        if (oldEdgeDictionary.ContainsKey(checksum))
                        {
                            //fix up old outer edge.
                            var edge = oldEdgeDictionary[checksum];
                            if (fromVertex == edge.From)
                            {
                                edge.OwnedFace = newFace;
                            }
                            else
                            {
                                edge.OtherFace = newFace;
                            }
                            newFace.AddEdge(edge);
                            oldEdgeDictionary.Remove(checksum);
                        }
                        else if (newEdgeDictionary.ContainsKey(checksum))
                        {
                            //Finish creating edge.
                            var newEdge = newEdgeDictionary[checksum];
                            newEdge.OtherFace = newFace;
                            newFace.AddEdge(newEdge);
                            newEdgeDictionary.Remove(checksum);
                            edgesToAdd.Add(newEdge);
                        }
                        else
                        {
                            newEdgeDictionary.Add(checksum, new Edge(fromVertex, toVertex, newFace, null, false, checksum));
                        }
                    }
                }
                ts.Primitives.Add(new Flat(newFaces));
            }
            ts.RemoveVertices(verticesToRemove);  //todo: check if the order of these five commands
            ts.RemoveFaces(facesToRemove);        // matters. There may be an ordering that is more efficient
            ts.AddFaces(facesToAdd);
            ts.RemoveEdges(edgesToRemove);
            ts.AddEdges(edgesToAdd);
        }