예제 #1
0
        //Vertices need to be reduced to 2D
        //see Akenine-Möller, Tomas; Haines, Eric; Hoffman, Naty (2016): Real-Time Rendering, p. 754
        /// <summary>
        /// Tests if a point/vertex lies inside or outside a face - Only use this if you know the face AND vertex lie in the same plane and this plane is parallel to xy or xz or yz!
        /// </summary>
        /// <param name="geometry">The geometry the polygon (here: face) belongs to.</param>
        /// <param name="face">The faces to be tested. It will not be Reduced2D!</param>
        /// <param name="v">The vertex to be tested.</param>
        /// <returns></returns>
        public static bool IsPointInPolygon(this Geometry geometry, Face face, float3 v)
        {
            var inside    = false;
            var faceVerts = geometry.GetFaceVertices(face.Handle).ToList();

            var v1    = geometry.GetVertexByHandle(faceVerts.Last().Handle);
            var v1Pos = geometry.Get2DVertPos(face, v1.Handle);

            var y0 = v1Pos.y >= v.y;

            foreach (var vert in faceVerts)
            {
                var e1Pos = geometry.Get2DVertPos(face, vert.Handle);

                var y1 = e1Pos.y >= v.y;
                if (y0 != y1)
                {
                    if ((e1Pos.y - v.y) * (v1Pos.x - e1Pos.x) >=
                        (e1Pos.x - v.x) * (v1Pos.y - e1Pos.y) == y1)
                    {
                        inside = !inside;
                    }
                }
                y0    = y1;
                v1Pos = e1Pos;
            }
            return(inside);
        }
예제 #2
0
        private static Dictionary <int, Vertex> GetEdgeVertices(Geometry geometry, Dictionary <int, Vertex> faceVertices)
        {
            var allEdges = geometry.GetAllHalfEdges();

            var doneHe = new int[allEdges.Count() + 1];

            var allEdgeVertices = new Dictionary <int, Vertex>();

            foreach (var edge in allEdges)
            {
                if (doneHe[edge.Handle] == edge.TwinHalfEdge)
                {
                    continue;
                }
                var face1 = edge.IncidentFace;
                var twin  = geometry.GetHalfEdgeByHandle(edge.TwinHalfEdge);
                var face2 = twin.IncidentFace;

                var vertex1 = geometry.GetVertexByHandle(edge.OriginVertex);
                var vertex2 = geometry.GetVertexByHandle(twin.OriginVertex);

                var cVertex1 = faceVertices[face1];
                var cVertex2 = faceVertices[face2];

                var temp = new List <Vertex> {
                    vertex1, vertex2, cVertex1, cVertex2
                };

                var finalVertex = new Vertex(edge.Handle, GeometricOperations.GetVerticesMeanPos(temp))
                {
                    IncidentHalfEdge = edge.Handle
                };

                allEdgeVertices.Add(edge.Handle, finalVertex);
                doneHe[edge.TwinHalfEdge] = edge.Handle;
            }
            return(allEdgeVertices);
        }
예제 #3
0
        private static void AssignFaceHandle(this Geometry geometry, int heHandle, Face newFace)
        {
            var oldFaceHandle = geometry.GetHalfEdgeByHandle(heHandle).IncidentFace;
            var currentHe     = geometry.GetHalfEdgeByHandle(heHandle);

            do
            {
                currentHe.IncidentFace = newFace.Handle;

                geometry.DictHalfEdges[currentHe.Handle] = currentHe;

                currentHe = geometry.GetHalfEdgeByHandle(currentHe.NextHalfEdge);
            } while (currentHe.Handle != heHandle);

            //Assign newFace to possible holes in the "old" face.
            var oldFace = geometry.GetFaceByHandle(oldFaceHandle);

            if (oldFace.InnerHalfEdges.Count == 0)
            {
                return;
            }

            var inner = new List <int>();

            inner.AddRange(oldFace.InnerHalfEdges);

            foreach (var heh in inner)
            {
                var origin = geometry.GetHalfEdgeByHandle(heh).OriginVertex;

                if (!geometry.IsPointInPolygon(newFace, geometry.GetVertexByHandle(origin)))
                {
                    continue;
                }

                oldFace.InnerHalfEdges.Remove(heh);
                newFace.InnerHalfEdges.Add(heh);

                var curHe = geometry.GetHalfEdgeByHandle(heh);
                do
                {
                    curHe.IncidentFace = newFace.Handle;

                    geometry.DictHalfEdges[curHe.Handle] = curHe;

                    curHe = geometry.GetHalfEdgeByHandle(curHe.NextHalfEdge);
                } while (curHe.Handle != heh);
            }
        }
예제 #4
0
        private static IEnumerable <Vertex> GetLeftChain(IList <Vertex> sortedVerts, Face face)
        {
            var heHandle   = new int();
            var endOfChain = sortedVerts.Last();

            var startingAtFirstV = _geometry.GetVertexStartingHalfEdges(sortedVerts[0].Handle).ToList();

            if (startingAtFirstV.Count > 1)
            {
                foreach (var heh in startingAtFirstV)
                {
                    var he = heh;
                    if (he.IncidentFace == face.Handle)
                    {
                        heHandle = heh.Handle;
                    }
                }
            }
            else
            {
                heHandle = sortedVerts[0].IncidentHalfEdge;
            }

            do
            {
                var halfEdge = _geometry.GetHalfEdgeByHandle(heHandle);
                yield return(_geometry.GetVertexByHandle(halfEdge.OriginVertex));

                heHandle = halfEdge.NextHalfEdge;
            } while (_geometry.GetHalfEdgeByHandle(heHandle).OriginVertex != endOfChain.Handle);
        }
예제 #5
0
        private static Geometry ExtrudeFaceByHandle(Geometry geometry, int faceHandle, float offset, float3 extrusionVector)
        {
            var face = geometry.GetFaceByHandle(faceHandle);

            //get HE of Face
            var start = geometry.GetHalfEdgeByHandle(face.OuterHalfEdge);
            var next  = start;

            var vertexIncHe     = new Dictionary <int, List <HalfEdge> >();
            var allFaceVertices = geometry.GetFaceVertices(faceHandle);

            foreach (var vertex in allFaceVertices)
            {
                vertexIncHe.Add(vertex.Handle, geometry.GetVertexStartingHalfEdges(vertex.Handle).ToList());
            }
            var allH2NEdges = new List <HalfEdge>();

            do
            {
                var nextOriginV = geometry.GetVertexByHandle(next.OriginVertex);
                var newVertex   = new Vertex(geometry.CreateVertHandleId(), nextOriginV.VertData.Pos);

                var twinEdge     = geometry.GetHalfEdgeByHandle(next.TwinHalfEdge);
                var prevEdge     = geometry.GetHalfEdgeByHandle(next.PrevHalfEdge);
                var prevTwinEdge = geometry.GetHalfEdgeByHandle(prevEdge.TwinHalfEdge);

                nextOriginV.VertData.Pos = nextOriginV.VertData.Pos + extrusionVector * offset;

                var h4  = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var h2n = new HalfEdge(geometry.CreateHalfEdgeHandleId());

                var h1 = new HalfEdge(geometry.CreateHalfEdgeHandleId());

                var currentList = vertexIncHe[nextOriginV.Handle];
                foreach (var halfEdge in currentList)
                {
                    if (halfEdge == next)
                    {
                        continue;
                    }
                    var edge = GeomEditing.UpdateHalfEdgeOrigin(halfEdge, newVertex.Handle);
                    geometry.ReplaceHalfEdge(edge);
                }

                nextOriginV.IncidentHalfEdge = next.Handle;

                h4.OriginVertex  = nextOriginV.Handle;
                h2n.OriginVertex = newVertex.Handle;
                h1.OriginVertex  = newVertex.Handle;

                h4.TwinHalfEdge  = h2n.Handle;
                h2n.TwinHalfEdge = h4.Handle;

                h4.NextHalfEdge = h1.Handle;
                h1.PrevHalfEdge = h4.Handle;

                h1.TwinHalfEdge       = next.TwinHalfEdge;
                twinEdge.TwinHalfEdge = h1.Handle;

                prevTwinEdge.OriginVertex = newVertex.Handle;

                newVertex.IncidentHalfEdge = h2n.Handle;

                geometry.ReplaceHalfEdge(twinEdge);
                geometry.ReplaceHalfEdge(prevTwinEdge);
                geometry.ReplaceVertex(nextOriginV);
                geometry.DictVertices.Add(newVertex.Handle, newVertex);
                geometry.DictHalfEdges.Add(h4.Handle, h4);
                geometry.DictHalfEdges.Add(h1.Handle, h1);
                geometry.DictHalfEdges.Add(h2n.Handle, h2n);

                allH2NEdges.Add(h2n);

                next = geometry.GetHalfEdgeByHandle(next.NextHalfEdge);
            } while (start != next);

            start = geometry.GetHalfEdgeByHandle(face.OuterHalfEdge);
            next  = start;
            do
            {
                var newFace = new Face(geometry.CreateFaceHandleId());

                var twinEdge = geometry.GetHalfEdgeByHandle(next.TwinHalfEdge);

                var h1 = geometry.GetHalfEdgeByHandle(twinEdge.TwinHalfEdge);
                var h2 = allH2NEdges.First(n => n.OriginVertex == twinEdge.OriginVertex);
                var h3 = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var h4 = geometry.GetHalfEdgeByHandle(h1.PrevHalfEdge);

                //set Face
                h1.IncidentFace = newFace.Handle;
                h2.IncidentFace = newFace.Handle;
                h3.IncidentFace = newFace.Handle;
                h4.IncidentFace = newFace.Handle;

                h1.NextHalfEdge = h2.Handle;
                h2.NextHalfEdge = h3.Handle;
                h3.NextHalfEdge = h4.Handle;
                h4.NextHalfEdge = h1.Handle;

                h1.PrevHalfEdge = h4.Handle;
                h2.PrevHalfEdge = h1.Handle;
                h3.PrevHalfEdge = h2.Handle;
                h4.PrevHalfEdge = h3.Handle;

                h3.TwinHalfEdge       = next.Handle;
                h3.OriginVertex       = geometry.GetHalfEdgeByHandle(next.NextHalfEdge).OriginVertex;
                next.TwinHalfEdge     = h3.Handle;
                newFace.OuterHalfEdge = h1.Handle;

                //write all changes
                geometry.ReplaceHalfEdge(h1);
                geometry.ReplaceHalfEdge(h2);
                geometry.ReplaceHalfEdge(h4);
                geometry.ReplaceHalfEdge(next);

                geometry.DictHalfEdges.Add(h3.Handle, h3);
                geometry.DictFaces.Add(newFace.Handle, newFace);

                newFace.FaceData.FaceNormal = GeometricOperations.CalculateFaceNormal(geometry.GetFaceVertices(newFace.Handle).ToList());

                geometry.ReplaceFace(newFace);

                next = geometry.GetHalfEdgeByHandle(next.NextHalfEdge);
            } while (start != next);

            return(geometry);
        }
예제 #6
0
        /// <summary>
        /// Insets a Face with a given offset. The new, center Face has the same Handle as the original Face.
        /// </summary>
        /// <param name="geometry">The geometry on which to perform a face inset.</param>
        /// <param name="faceHandle">The Handle of the face, the new one will be inseted to.</param>
        /// <param name="insetOffset">The offset of the inset in percent. Use values between 0 and 1. A value of 0.5f means 50% of the original face remains.</param>
        /// <returns>Returns the geometry with edited faces.</returns>
        public static Geometry InsetFace(this Geometry geometry, int faceHandle, float insetOffset)
        {
            if (insetOffset >= 1)
            {
                throw new ArgumentException("insetOffset can not be greate or equal to 1.");
            }
            if (insetOffset <= 0)
            {
                throw new ArgumentException("insetOffset can not be smaller or equal to 0.");
            }

            var face            = geometry.GetFaceByHandle(faceHandle);
            var allFaceVertices = geometry.GetFaceVertices(faceHandle).ToList();
            var meanPos         = GeometricOperations.GetVerticesMeanPos(allFaceVertices);

            //Dict sotres countEdges; [0] = edge1.handle, [1] = edge2twin.handle, [2] = edge3.handle, [3] = vertex.Handle
            var edgeStorage = new Dictionary <int, int[]>();

            var countEdges = 0;

            var start = geometry.GetHalfEdgeByHandle(face.OuterHalfEdge);
            var next  = start;

            do
            {
                var nextEdge      = next.NextHalfEdge;
                var currentVertex = geometry.GetVertexByHandle(next.OriginVertex);

                var currentPos = currentVertex.VertData.Pos;
                var newPos     = (currentPos - meanPos) * insetOffset + meanPos;

                var newVertex = new Vertex(geometry.CreateVertHandleId(), newPos);
                var nextNext  = geometry.GetHalfEdgeByHandle(next.NextHalfEdge);
                var edge1     = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var edge2Twin = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var edge2     = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var edge3     = new HalfEdge(geometry.CreateHalfEdgeHandleId());
                var newFace   = new Face(geometry.CreateFaceHandleId());

                //store info
                edgeStorage.Add(countEdges, new[] { edge1.Handle, edge2Twin.Handle, edge3.Handle, newVertex.Handle });

                newVertex.IncidentHalfEdge = edge3.Handle;
                newFace.OuterHalfEdge      = edge1.Handle;
                edge1.OriginVertex         = nextNext.OriginVertex;
                edge3.OriginVertex         = newVertex.Handle;
                edge2Twin.OriginVertex     = newVertex.Handle;
                //twins
                edge2.TwinHalfEdge     = edge2Twin.Handle;
                edge2Twin.TwinHalfEdge = edge2.Handle;
                //nexts
                edge1.NextHalfEdge = edge2.Handle;
                edge2.NextHalfEdge = edge3.Handle;
                edge3.NextHalfEdge = next.Handle;
                next.NextHalfEdge  = edge1.Handle;
                //prevs
                edge1.PrevHalfEdge = next.Handle;
                edge2.PrevHalfEdge = edge1.Handle;
                edge3.PrevHalfEdge = edge2.Handle;
                next.PrevHalfEdge  = edge3.Handle;
                //face
                edge1.IncidentFace          = newFace.Handle;
                edge2.IncidentFace          = newFace.Handle;
                edge3.IncidentFace          = newFace.Handle;
                next.IncidentFace           = newFace.Handle;
                edge2Twin.IncidentFace      = face.Handle;
                newFace.FaceData.FaceNormal = face.FaceData.FaceNormal;

                //write changes
                geometry.DictVertices.Add(newVertex.Handle, newVertex);
                geometry.DictFaces.Add(newFace.Handle, newFace);
                geometry.DictHalfEdges.Add(edge1.Handle, edge1);
                geometry.DictHalfEdges.Add(edge2Twin.Handle, edge2Twin);
                geometry.DictHalfEdges.Add(edge2.Handle, edge2);
                geometry.DictHalfEdges.Add(edge3.Handle, edge3);
                geometry.ReplaceHalfEdge(next);

                countEdges++;
                next = geometry.GetHalfEdgeByHandle(nextEdge);
            } while (start != next);

            for (var i = 0; i < countEdges; i++)
            {
                var prevFace = i - 1;
                var nextFace = i + 1;

                var faceData = edgeStorage[i];

                if (i == 0)
                {
                    prevFace = countEdges - 1;
                }
                if (i == countEdges - 1)
                {
                    nextFace           = 0;
                    face.OuterHalfEdge = faceData[1];
                    geometry.ReplaceFace(face);
                }

                var prevFaceData = edgeStorage[prevFace];
                var nextFaceData = edgeStorage[nextFace];

                var edge2Twin = geometry.GetHalfEdgeByHandle(faceData[1]);
                var edge3     = geometry.GetHalfEdgeByHandle(faceData[2]);
                var edge3Twin = geometry.GetHalfEdgeByHandle(prevFaceData[0]);
                var edge2     = geometry.GetHalfEdgeByHandle(edge2Twin.TwinHalfEdge);

                edge2Twin.PrevHalfEdge = prevFaceData[1];
                edge2Twin.NextHalfEdge = nextFaceData[1];
                edge2.OriginVertex     = nextFaceData[3];
                edge3Twin.TwinHalfEdge = edge3.Handle;
                edge3.TwinHalfEdge     = edge3Twin.Handle;

                //write
                geometry.ReplaceHalfEdge(edge2Twin);
                geometry.ReplaceHalfEdge(edge2);
                geometry.ReplaceHalfEdge(edge3Twin);
                geometry.ReplaceHalfEdge(edge3);
            }

            return(geometry);
        }
예제 #7
0
        /// <summary>
        /// Inserts a new Vertex between two given exsisting Vertices.
        /// </summary>
        /// <param name="geometry">The Geometry to insert a Vertex.</param>
        /// <param name="p">Handle of Vertex one.</param>
        /// <param name="q">Handle of Vertex two.</param>
        /// <param name="pos">Position of the new Vertex</param>
        /// <returns>New Vertex Handle.</returns>
        public static int InsertVertex(this Geometry geometry, int p, int q, float3 pos)
        {
            var adjacentVertices = geometry.GetVertexAdjacentVertices(p).ToList();

            for (var i = 0; i < adjacentVertices.Count; i++)
            {
                if (adjacentVertices[i].Handle == q)
                {
                    break;
                }
                if (i == adjacentVertices.Count - 1)
                {
                    throw new ArgumentException("Vertices with Handle q=" + q + " and p=" + p + " are not adjacent!");
                }
            }

            var newVertex = new Vertex(geometry.CreateVertHandleId(), pos);

            //add two new Half Edges
            var newHalfEdge1 = new HalfEdge(geometry.CreateHalfEdgeHandleId());
            var newHalfEdge2 = new HalfEdge(geometry.CreateHalfEdgeHandleId());

            //set origin to new Vertex
            newHalfEdge1.OriginVertex = newVertex.Handle;
            newHalfEdge2.OriginVertex = newVertex.Handle;

            newVertex.IncidentHalfEdge = newHalfEdge2.Handle;

            var vertexP = geometry.GetVertexByHandle(p);
            var vertexQ = geometry.GetVertexByHandle(q);

            //Find Half Edge between p and q
            var incomingEdges = geometry.GetVertexStartingHalfEdges(vertexP.Handle);

            var he1 = new HalfEdge();
            var he2 = new HalfEdge();

            foreach (var halfEdge in incomingEdges)
            {
                var twinEdge = geometry.GetHalfEdgeByHandle(halfEdge.TwinHalfEdge);
                if (twinEdge.OriginVertex != vertexQ.Handle)
                {
                    continue;
                }
                he1 = halfEdge;
                he2 = twinEdge;
            }
            var next1 = geometry.GetHalfEdgeByHandle(he2.NextHalfEdge);
            var next2 = geometry.GetHalfEdgeByHandle(he1.NextHalfEdge);

            //change Handels
            he1.TwinHalfEdge          = newHalfEdge1.Handle;
            newHalfEdge1.TwinHalfEdge = he1.Handle;
            newHalfEdge1.NextHalfEdge = he2.NextHalfEdge;
            he2.NextHalfEdge          = newHalfEdge1.Handle;
            newHalfEdge1.PrevHalfEdge = he2.Handle;
            next1.PrevHalfEdge        = newHalfEdge1.Handle;

            he2.TwinHalfEdge          = newHalfEdge2.Handle;
            newHalfEdge2.TwinHalfEdge = he2.Handle;
            newHalfEdge2.NextHalfEdge = he1.NextHalfEdge;
            he1.NextHalfEdge          = newHalfEdge2.Handle;
            newHalfEdge2.PrevHalfEdge = he1.Handle;
            next2.PrevHalfEdge        = newHalfEdge2.Handle;

            //reconnect faces
            newHalfEdge1.IncidentFace = he2.IncidentFace;
            newHalfEdge2.IncidentFace = he1.IncidentFace;

            //replace exsisnting Edges
            geometry.ReplaceHalfEdge(he1);
            geometry.ReplaceHalfEdge(he2);

            geometry.ReplaceHalfEdge(next1);
            geometry.ReplaceHalfEdge(next2);

            //add to dict
            geometry.DictVertices.Add(newVertex.Handle, newVertex);
            geometry.DictHalfEdges.Add(newHalfEdge1.Handle, newHalfEdge1);
            geometry.DictHalfEdges.Add(newHalfEdge2.Handle, newHalfEdge2);

            return(newVertex.Handle);
        }
예제 #8
0
        private static void AddFaceVerticesAndNewFaces(Geometry geometry, Geometry newGeometry, Dictionary <int, Vertex> allFaceVertices)
        {
            var allFaces = geometry.GetAllFaces();

            foreach (var face in allFaces)
            {
                Vertex   faceVertex = new Vertex(newGeometry.CreateVertHandleId(), allFaceVertices[face.Handle].VertData.Pos);
                HalfEdge startEdge  = geometry.GetHalfEdgeByHandle(face.OuterHalfEdge);
                HalfEdge nextEdge   = startEdge;

                //stores Halfedges without Twin
                Dictionary <int, HalfEdge> halfEdges2 = new Dictionary <int, HalfEdge>();
                Dictionary <int, HalfEdge> halfEdges1 = new Dictionary <int, HalfEdge>();

                newGeometry.DictVertices.Add(faceVertex.Handle, faceVertex);
                int i = 0;
                do
                {
                    HalfEdge h1 = new HalfEdge(newGeometry.CreateHalfEdgeHandleId());
                    HalfEdge h2 = new HalfEdge(newGeometry.CreateHalfEdgeHandleId());
                    HalfEdge h3 = newGeometry.GetHalfEdgeByHandle(nextEdge.PrevHalfEdge);
                    HalfEdge h4 = newGeometry.GetHalfEdgeByHandle(nextEdge.Handle);

                    //create new quad face
                    Face newFace;
                    newFace  = i == 0 ? face : new Face(newGeometry.CreateFaceHandleId());
                    nextEdge = geometry.GetHalfEdgeByHandle(nextEdge.NextHalfEdge);

                    h1.NextHalfEdge = h2.Handle;
                    h2.NextHalfEdge = h3.Handle;
                    h3.NextHalfEdge = h4.Handle;
                    h4.NextHalfEdge = h1.Handle;

                    h1.PrevHalfEdge = h4.Handle;
                    h2.PrevHalfEdge = h1.Handle;
                    h3.PrevHalfEdge = h2.Handle;
                    h4.PrevHalfEdge = h3.Handle;

                    h1.OriginVertex = nextEdge.OriginVertex;
                    h2.OriginVertex = faceVertex.Handle;

                    h1.IncidentFace = newFace.Handle;
                    h2.IncidentFace = newFace.Handle;
                    h3.IncidentFace = newFace.Handle;
                    h4.IncidentFace = newFace.Handle;

                    faceVertex.IncidentHalfEdge = h2.Handle;
                    newFace.OuterHalfEdge       = h1.Handle;

                    //add and replace changed
                    newGeometry.DictHalfEdges.Add(h1.Handle, h1);
                    newGeometry.DictHalfEdges.Add(h2.Handle, h2);

                    newGeometry.ReplaceHalfEdge(h3);
                    newGeometry.ReplaceHalfEdge(h4);

                    newGeometry.ReplaceVertex(faceVertex);

                    if (i == 0) // the old face becomes the first quad, so no new face to create
                    {
                        newGeometry.ReplaceFace(newFace);
                    }
                    else //create new face
                    {
                        newGeometry.DictFaces.Add(newFace.Handle, newFace);
                    }

                    //Stores Vertices to get the face normal
                    List <Vertex> faceVertices = new List <Vertex>
                    {
                        newGeometry.GetVertexByHandle(h1.OriginVertex),
                        newGeometry.GetVertexByHandle(h2.OriginVertex),
                        newGeometry.GetVertexByHandle(h3.OriginVertex),
                        newGeometry.GetVertexByHandle(h4.OriginVertex)
                    };

                    newGeometry.SetFaceNormal(faceVertices, newFace);

                    halfEdges2.Add(i, h2);
                    halfEdges1.Add(i, h1);

                    //for the second Edge per Face connect the twin
                    if (i > 0)
                    {
                        HalfEdge h1N = halfEdges1[i - 1];
                        h1N.TwinHalfEdge = halfEdges2[i].Handle;

                        HalfEdge h2N = halfEdges2[i];
                        h2N.TwinHalfEdge = h1N.Handle;

                        newGeometry.ReplaceHalfEdge(h1N);
                        newGeometry.ReplaceHalfEdge(h2N);
                    }

                    i++;
                    nextEdge = geometry.GetHalfEdgeByHandle(nextEdge.NextHalfEdge);
                } while (startEdge != nextEdge);

                //set Twin of firsts and lasts of each new Face
                var h2Firts = halfEdges2[0];
                var h1Last  = halfEdges1[i - 1];

                h2Firts.TwinHalfEdge = h1Last.Handle;
                h1Last.TwinHalfEdge  = h2Firts.Handle;

                newGeometry.ReplaceHalfEdge(h2Firts);
                newGeometry.ReplaceHalfEdge(h1Last);
            }
        }
예제 #9
0
        /// <summary>
        /// Creates and returns a UV-Sphere as a DCEL with the specified dimensions centered in the worlds coordinate system.
        /// </summary>
        /// <param name="radius">Radius of the sphere.</param>
        /// <param name="horizontalResolution">Lines of latitude, smallest value is 3.</param>
        /// <param name="verticalResolution">Lines of longitude, smallest value is 3.</param>
        /// <returns>A UV-Sphere centered in the world coordinate system as a DCEL.</returns>
        public static Geometry CreateSpehreGeometry(float radius, int horizontalResolution, int verticalResolution)
        {
            //check input
            if (radius <= 0)
            {
                throw new ArgumentException("Radius can not be <= 0");
            }
            if (horizontalResolution <= 3)
            {
                horizontalResolution = 3;
            }
            if (verticalResolution <= 2)
            {
                verticalResolution = 2;
            }

            var sphere    = new Geometry();
            var northPole = new Vertex(sphere.CreateVertHandleId(), new float3(0, radius, 0));
            var southPole = new Vertex(sphere.CreateVertHandleId(), new float3(0, -radius, 0));

            var horizontalAngleStep = System.Math.PI * 2 / horizontalResolution; // s
            var verrticalAngleStep  = System.Math.PI / verticalResolution;       // t

            var currentLatitudeVerticesHandles = new int[horizontalResolution];
            var lastlatitudeVerticesHandles    = new int[horizontalResolution]; //stores last vertices to connect them later with the next latitude vertices

            for (var i = 1; i < verticalResolution + 1; i++)
            {
                //create all vertices
                if (i < verticalResolution)
                {
                    for (var j = 0; j < horizontalResolution; j++)
                    {
                        //create all Vertices of current latitude
                        var xPos = (float)(radius * System.Math.Sin(horizontalAngleStep * j) * System.Math.Sin(verrticalAngleStep * i));
                        var yPos = (float)(radius * System.Math.Cos(verrticalAngleStep * (i)));
                        var zPos = (float)(radius * System.Math.Cos(horizontalAngleStep * j) * System.Math.Sin(verrticalAngleStep * i));

                        var circleVertex = new Vertex(sphere.CreateVertHandleId(), new float3(xPos, yPos, zPos));
                        sphere.DictVertices.Add(circleVertex.Handle, circleVertex);
                        currentLatitudeVerticesHandles[j] = circleVertex.Handle;
                    }
                }

                //create faces
                var topHeHandles = new int[horizontalResolution];
                for (var j = 0; j < horizontalResolution; j++)
                {
                    // bottom triangles of sphere
                    if (i == verticalResolution)
                    {
                        var bottomTriangle = new Face(sphere.CreateFaceHandleId());

                        var h1 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        var h2 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        var h3 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        topHeHandles[j] = h1.Handle;

                        h1.NextHalfEdge = h2.Handle;
                        h2.NextHalfEdge = h3.Handle;
                        h3.NextHalfEdge = h1.Handle;
                        h1.PrevHalfEdge = h3.Handle;
                        h2.PrevHalfEdge = h1.Handle;
                        h3.PrevHalfEdge = h2.Handle;
                        h1.IncidentFace = bottomTriangle.Handle;
                        h2.IncidentFace = bottomTriangle.Handle;
                        h3.IncidentFace = bottomTriangle.Handle;
                        h1.OriginVertex = currentLatitudeVerticesHandles[j];
                        h2.OriginVertex = j == horizontalResolution - 1 ? currentLatitudeVerticesHandles[0] : currentLatitudeVerticesHandles[j + 1];
                        h3.OriginVertex = southPole.Handle;
                        bottomTriangle.OuterHalfEdge = h1.Handle;

                        southPole.IncidentHalfEdge = h3.Handle;

                        //write changes
                        sphere.DictHalfEdges.Add(h1.Handle, h1);
                        sphere.DictHalfEdges.Add(h2.Handle, h2);
                        sphere.DictHalfEdges.Add(h3.Handle, h3);
                        sphere.DictFaces.Add(bottomTriangle.Handle, bottomTriangle);
                    }

                    // top triangles of sphere
                    else if (i == 1)
                    {
                        var topTriangle = new Face(sphere.CreateFaceHandleId());

                        var h1 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        var h2 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        var h3 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        topHeHandles[j] = h1.Handle;

                        h1.NextHalfEdge           = h2.Handle;
                        h2.NextHalfEdge           = h3.Handle;
                        h3.NextHalfEdge           = h1.Handle;
                        h1.PrevHalfEdge           = h3.Handle;
                        h2.PrevHalfEdge           = h1.Handle;
                        h3.PrevHalfEdge           = h2.Handle;
                        h1.IncidentFace           = topTriangle.Handle;
                        h2.IncidentFace           = topTriangle.Handle;
                        h3.IncidentFace           = topTriangle.Handle;
                        h1.OriginVertex           = j == horizontalResolution - 1 ? currentLatitudeVerticesHandles[0] : currentLatitudeVerticesHandles[j + 1];
                        h2.OriginVertex           = currentLatitudeVerticesHandles[j];
                        h3.OriginVertex           = northPole.Handle;
                        topTriangle.OuterHalfEdge = h1.Handle;

                        var currentVertex = sphere.GetVertexByHandle(currentLatitudeVerticesHandles[j]);
                        currentVertex.IncidentHalfEdge = h2.Handle;
                        northPole.IncidentHalfEdge     = h3.Handle;

                        //write changes
                        sphere.DictHalfEdges.Add(h1.Handle, h1);
                        sphere.DictHalfEdges.Add(h2.Handle, h2);
                        sphere.DictHalfEdges.Add(h3.Handle, h3);
                        sphere.DictFaces.Add(topTriangle.Handle, topTriangle);
                        sphere.ReplaceVertex(currentVertex);
                    }
                    // middle quads of sphere
                    else
                    {
                        var quad = new Face(sphere.CreateFaceHandleId());

                        var h1 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        var h2 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        var h3 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        var h4 = new HalfEdge(sphere.CreateHalfEdgeHandleId());
                        topHeHandles[j] = h1.Handle;

                        h1.NextHalfEdge    = h2.Handle;
                        h2.NextHalfEdge    = h3.Handle;
                        h3.NextHalfEdge    = h4.Handle;
                        h4.NextHalfEdge    = h1.Handle;
                        h1.PrevHalfEdge    = h4.Handle;
                        h2.PrevHalfEdge    = h1.Handle;
                        h3.PrevHalfEdge    = h2.Handle;
                        h4.PrevHalfEdge    = h3.Handle;
                        h1.IncidentFace    = quad.Handle;
                        h2.IncidentFace    = quad.Handle;
                        h3.IncidentFace    = quad.Handle;
                        h4.IncidentFace    = quad.Handle;
                        quad.OuterHalfEdge = h1.Handle;

                        h4.OriginVertex = currentLatitudeVerticesHandles[j];
                        h3.OriginVertex = j == horizontalResolution - 1 ? currentLatitudeVerticesHandles[0] : currentLatitudeVerticesHandles[j + 1];
                        h2.OriginVertex = j == horizontalResolution - 1 ? lastlatitudeVerticesHandles[0] : lastlatitudeVerticesHandles[j + 1];
                        h1.OriginVertex = lastlatitudeVerticesHandles[j];

                        var currentVertex = sphere.GetVertexByHandle(currentLatitudeVerticesHandles[j]);
                        currentVertex.IncidentHalfEdge = h4.Handle;

                        //write changes
                        sphere.DictFaces.Add(quad.Handle, quad);
                        sphere.DictHalfEdges.Add(h1.Handle, h1);
                        sphere.DictHalfEdges.Add(h2.Handle, h2);
                        sphere.DictHalfEdges.Add(h3.Handle, h3);
                        sphere.DictHalfEdges.Add(h4.Handle, h4);
                        sphere.ReplaceVertex(currentVertex);
                    }
                }

                //set twins
                for (int j = 0; j < horizontalResolution; j++)
                {
                    //set twins of adjacent triangles bottom
                    if (i == 1)
                    {
                        int nextH1Index;
                        nextH1Index = j == 0 ? horizontalResolution - 1 : j - 1;
                        var h1     = sphere.GetHalfEdgeByHandle(topHeHandles[j]);
                        var h2     = sphere.GetHalfEdgeByHandle(h1.NextHalfEdge);
                        var nextH1 = sphere.GetHalfEdgeByHandle(topHeHandles[nextH1Index]);
                        var nextH3 = sphere.GetHalfEdgeByHandle(nextH1.PrevHalfEdge);
                        nextH3.TwinHalfEdge = h2.Handle;
                        h2.TwinHalfEdge     = nextH3.Handle;

                        sphere.ReplaceHalfEdge(nextH3);
                        sphere.ReplaceHalfEdge(h2);
                    }
                    else if (i == verticalResolution)
                    {
                        int nextH1Index;
                        nextH1Index = j == 0 ? horizontalResolution - 1 : j - 1;
                        var h1     = sphere.GetHalfEdgeByHandle(topHeHandles[j]);
                        var h3     = sphere.GetHalfEdgeByHandle(h1.PrevHalfEdge);
                        var nextH1 = sphere.GetHalfEdgeByHandle(topHeHandles[nextH1Index]);
                        var nextH2 = sphere.GetHalfEdgeByHandle(nextH1.NextHalfEdge);
                        nextH2.TwinHalfEdge = h3.Handle;
                        h3.TwinHalfEdge     = nextH2.Handle;

                        sphere.ReplaceHalfEdge(nextH2);
                        sphere.ReplaceHalfEdge(h3);
                    }
                    else //set twins of adjacent quads
                    {
                        var h1 = sphere.GetHalfEdgeByHandle(topHeHandles[j]);
                        var h4 = sphere.GetHalfEdgeByHandle(h1.PrevHalfEdge);

                        int nextH1Index;

                        nextH1Index = j == 0 ? horizontalResolution - 1 : j - 1;

                        var nextH1 = sphere.GetHalfEdgeByHandle(topHeHandles[nextH1Index]);
                        var nextH2 = sphere.GetHalfEdgeByHandle(nextH1.NextHalfEdge);

                        nextH2.TwinHalfEdge = h4.Handle;
                        h4.TwinHalfEdge     = nextH2.Handle;

                        sphere.ReplaceHalfEdge(nextH2);
                        sphere.ReplaceHalfEdge(h4);
                    }

                    //set twin of face on top
                    if (i > 1)
                    {
                        var h1         = sphere.GetHalfEdgeByHandle(topHeHandles[j]);
                        var lastVertex = sphere.GetVertexByHandle(lastlatitudeVerticesHandles[j]);
                        var topH1      = sphere.GetHalfEdgeByHandle(lastVertex.IncidentHalfEdge);
                        while (true)
                        {
                            if (topH1.TwinHalfEdge == 0)
                            {
                                break;
                            }
                            topH1 = sphere.GetHalfEdgeByHandle(topH1.NextHalfEdge);
                        }
                        topH1.TwinHalfEdge = h1.Handle;
                        h1.TwinHalfEdge    = topH1.Handle;
                        sphere.ReplaceHalfEdge(h1);
                        sphere.ReplaceHalfEdge(topH1);
                    }
                }

                Array.Copy(currentLatitudeVerticesHandles, lastlatitudeVerticesHandles,
                           currentLatitudeVerticesHandles.Length);
            }
            sphere.DictVertices.Add(northPole.Handle, northPole);
            sphere.DictVertices.Add(southPole.Handle, southPole);

            //calculate normals
            var allFaces = sphere.GetAllFaces().ToList();

            foreach (var face in allFaces)
            {
                sphere.SetFaceNormal(sphere.GetFaceVertices(face.Handle).ToList(), face);
            }

            return(sphere);
        }
예제 #10
0
        /// <summary>
        /// Creates and returns a cone with the given dimensions.
        /// </summary>
        /// <param name="baseRadius">The radius of the base circle.</param>
        /// <param name="dimensionY">The height of the cone.</param>
        /// <param name="sliceCount">The horizontal resolution of the base circle. Min value is 3. For a basic cone 15.</param>
        /// <returns></returns>
        public static Geometry CreateConeGeometry(float baseRadius, float dimensionY, int sliceCount)
        {
            //check input
            if (sliceCount < 3)
            {
                sliceCount = 3;
            }
            if (baseRadius <= 0 || dimensionY <= 0)
            {
                throw new ArgumentException("You can not input parameters <= 0");
            }

            var cone      = new Geometry();
            var northPole = new Vertex(cone.CreateVertHandleId(), new float3(0, dimensionY / 2, 0));
            var southPole = new Vertex(cone.CreateVertHandleId(), new float3(0, -dimensionY / 2, 0));

            var angleStep = System.Math.PI * 2 / sliceCount;
            var yPos      = -dimensionY / 2.0f;

            int[] firstHandles = null; //stores the handles of the first slice to connect it later with the last slice

            var lastH3     = new HalfEdge();
            var lastH2     = new HalfEdge();
            var lastVertex = southPole;

            for (var i = 1; i < sliceCount + 1; i++)
            {
                var x = (float)System.Math.Cos(angleStep * i) * baseRadius;
                var z = (float)System.Math.Sin(angleStep * i) * baseRadius;

                var tempVertex = new Vertex(cone.CreateVertHandleId(), new float3(x, yPos, z));

                //south to temp
                var h1 = new HalfEdge(cone.CreateHalfEdgeHandleId());
                var h2 = new HalfEdge(cone.CreateHalfEdgeHandleId()); //twin of h1

                tempVertex.IncidentHalfEdge = h2.Handle;
                h1.OriginVertex             = southPole.Handle;
                h2.OriginVertex             = tempVertex.Handle;
                h1.TwinHalfEdge             = h2.Handle;
                h2.TwinHalfEdge             = h1.Handle;

                //temp to north
                var h3 = new HalfEdge(cone.CreateHalfEdgeHandleId());
                var h4 = new HalfEdge(cone.CreateHalfEdgeHandleId());

                northPole.IncidentHalfEdge = h3.Handle;
                southPole.IncidentHalfEdge = h1.Handle;

                h3.OriginVertex = northPole.Handle;
                h4.OriginVertex = tempVertex.Handle;
                h3.TwinHalfEdge = h4.Handle;
                h4.TwinHalfEdge = h3.Handle;

                if (lastVertex == southPole)
                {
                    firstHandles = new[] { tempVertex.Handle, h1.Handle, h4.Handle };
                    lastH3       = h3;
                    lastH2       = h2;
                    cone.DictVertices.Add(tempVertex.Handle, tempVertex);
                    cone.DictHalfEdges.Add(h1.Handle, h1);
                    cone.DictHalfEdges.Add(h2.Handle, h2);
                    cone.DictHalfEdges.Add(h3.Handle, h3);
                    cone.DictHalfEdges.Add(h4.Handle, h4);
                    lastVertex = tempVertex;
                    continue;
                }

                //temp to last
                var h5 = new HalfEdge(cone.CreateHalfEdgeHandleId());
                var h6 = new HalfEdge(cone.CreateHalfEdgeHandleId());

                h5.OriginVertex = lastVertex.Handle;
                h6.OriginVertex = tempVertex.Handle;
                h5.TwinHalfEdge = h6.Handle;
                h6.TwinHalfEdge = h5.Handle;

                //create top triangles south-temp-last
                var triangle1 = new Face(cone.CreateFaceHandleId());
                h5.NextHalfEdge         = h4.Handle;
                triangle1.OuterHalfEdge = h5.Handle;
                h4.NextHalfEdge         = lastH3.Handle;
                lastH3.NextHalfEdge     = h5.Handle;
                h5.IncidentFace         = triangle1.Handle;
                h4.IncidentFace         = triangle1.Handle;
                lastH3.IncidentFace     = triangle1.Handle;
                h5.PrevHalfEdge         = lastH3.Handle;
                lastH3.PrevHalfEdge     = h4.Handle;
                h4.PrevHalfEdge         = h5.Handle;

                //north-last-temp
                var triangle2 = new Face(cone.CreateFaceHandleId());
                h6.NextHalfEdge         = lastH2.Handle;
                triangle2.OuterHalfEdge = h6.Handle;
                lastH2.NextHalfEdge     = h1.Handle;
                h1.NextHalfEdge         = h6.Handle;
                h6.IncidentFace         = triangle2.Handle;
                lastH2.IncidentFace     = triangle2.Handle;
                h1.IncidentFace         = triangle2.Handle;
                h6.PrevHalfEdge         = h1.Handle;
                h1.PrevHalfEdge         = lastH2.Handle;
                lastH2.PrevHalfEdge     = h6.Handle;

                //write
                cone.DictVertices.Add(tempVertex.Handle, tempVertex);
                cone.DictHalfEdges.Add(h1.Handle, h1);
                cone.DictHalfEdges.Add(h2.Handle, h2);
                cone.DictHalfEdges.Add(h3.Handle, h3);
                cone.DictHalfEdges.Add(h4.Handle, h4);
                cone.DictHalfEdges.Add(h5.Handle, h5);
                cone.DictHalfEdges.Add(h6.Handle, h6);
                cone.ReplaceHalfEdge(lastH2);
                cone.ReplaceHalfEdge(lastH3);
                cone.DictFaces.Add(triangle1.Handle, triangle1);
                cone.DictFaces.Add(triangle2.Handle, triangle2);


                lastH2     = h2;
                lastH3     = h3;
                lastVertex = tempVertex;
            }
            //add south and north pole
            cone.DictVertices.Add(southPole.Handle, southPole);
            cone.DictVertices.Add(northPole.Handle, northPole);

            //create last 2 triangles
            var firstVertex = cone.GetVertexByHandle(firstHandles[0]);
            var firtstH1    = cone.GetHalfEdgeByHandle(firstHandles[1]);
            var firstH4     = cone.GetHalfEdgeByHandle(firstHandles[2]);

            var lastH5 = new HalfEdge(cone.CreateHalfEdgeHandleId());
            var lastH6 = new HalfEdge(cone.CreateHalfEdgeHandleId());

            lastH5.OriginVertex = lastVertex.Handle;
            lastH6.OriginVertex = firstVertex.Handle;
            lastH5.TwinHalfEdge = lastH6.Handle;
            lastH6.TwinHalfEdge = lastH5.Handle;

            //create to triangles south-temp-last, north-last-temp
            var triangleL1 = new Face(cone.CreateFaceHandleId())
            {
                OuterHalfEdge = lastH5.Handle
            };

            lastH5.NextHalfEdge  = firstH4.Handle;
            firstH4.NextHalfEdge = lastH3.Handle;
            lastH3.NextHalfEdge  = lastH5.Handle;
            lastH5.IncidentFace  = triangleL1.Handle;
            firstH4.IncidentFace = triangleL1.Handle;
            lastH3.IncidentFace  = triangleL1.Handle;
            lastH5.PrevHalfEdge  = lastH3.Handle;
            lastH3.PrevHalfEdge  = firstH4.Handle;
            firstH4.PrevHalfEdge = lastH5.Handle;

            var triangleL2 = new Face(cone.CreateFaceHandleId())
            {
                OuterHalfEdge = lastH6.Handle
            };

            lastH6.NextHalfEdge   = lastH2.Handle;
            lastH2.NextHalfEdge   = firtstH1.Handle;
            firtstH1.NextHalfEdge = lastH6.Handle;
            lastH6.IncidentFace   = triangleL2.Handle;
            lastH2.IncidentFace   = triangleL2.Handle;
            firtstH1.IncidentFace = triangleL2.Handle;
            lastH6.PrevHalfEdge   = firtstH1.Handle;
            firtstH1.PrevHalfEdge = lastH2.Handle;
            lastH2.PrevHalfEdge   = lastH6.Handle;

            //write
            cone.ReplaceHalfEdge(firtstH1);
            cone.DictHalfEdges.Add(lastH5.Handle, lastH5);
            cone.DictHalfEdges.Add(lastH6.Handle, lastH6);
            cone.ReplaceHalfEdge(lastH2);
            cone.ReplaceHalfEdge(lastH3);
            cone.ReplaceHalfEdge(firstH4);
            cone.DictFaces.Add(triangleL1.Handle, triangleL1);
            cone.DictFaces.Add(triangleL2.Handle, triangleL2);

            //face normals
            var allFaces = cone.GetAllFaces().ToList();

            foreach (var face in allFaces)
            {
                cone.SetFaceNormal(cone.GetFaceVertices(face.Handle).ToList(), face);
            }

            return(cone);
        }