Exemple #1
0
        /// <summary>
        /// Updates the "inner" half edges clockwise so the next pointers are correct.
        /// Is called after a face is inserted.
        /// </summary>
        /// <param name="edgeList">A list of edges that belong to a specific face</param>
        private void UpdateCWHedges(List<HandleEdge> edgeList)
        {
            // Proceed the loop for every edge and connect "hedge1" to the next hedge.
            for (int i = 0; i < edgeList.Count; i++)
            {
                // Test if the hedge1 or hedge2 is used. Decide by looking at their face pointers.
                int indexhedge1 = _LedgePtrCont[edgeList[i]._DataIndex]._he1;
                int indexhedge2 = _LedgePtrCont[edgeList[i]._DataIndex]._he2;
                HEdgePtrCont hedgePtrCont1 = _LhedgePtrCont[indexhedge1];
                HEdgePtrCont hedgePtrCont2 = _LhedgePtrCont[indexhedge2];

                if (hedgePtrCont1._f == _LfacePtrCont.Count - 1)
                {
                    #region UseHEdge1
                    // The face the edge1 points to is the active face - hurray! use this edge and move on.
                    if (i + 1 < edgeList.Count)
                    {
                        // Just use the next hedge
                        HEdgePtrCont nextHedgePtrCont = _LhedgePtrCont[_LedgePtrCont[edgeList[i + 1]._DataIndex]._he1];
                        if (nextHedgePtrCont._f == _LfacePtrCont.Count - 1)
                        {
                            // use first
                            hedgePtrCont1._nhe._DataIndex = hedgePtrCont1._nhe._DataIndex == -1 ? nextHedgePtrCont._he._DataIndex - 1 : hedgePtrCont1._nhe._DataIndex;
                        }
                        else
                        {
                            // use second
                            hedgePtrCont1._nhe._DataIndex = hedgePtrCont1._nhe._DataIndex == -1 ? nextHedgePtrCont._he._DataIndex : hedgePtrCont1._nhe._DataIndex;
                        }
                        _LhedgePtrCont[indexhedge1] = new HEdgePtrCont()
                        {
                            _f = hedgePtrCont1._f,
                            _he = hedgePtrCont1._he,
                            _nhe = hedgePtrCont1._nhe,
                            _v = hedgePtrCont1._v,
                            _vn = hedgePtrCont1._vn,
                            _vuv = hedgePtrCont1._vuv
                        };
                    }
                    else
                    {
                        // Connect to the first hedge in the list because the current is the last one in the face
                        HEdgePtrCont nextHedgePtrCont = _LhedgePtrCont[_LedgePtrCont[edgeList[0]._DataIndex]._he1];
                        if (nextHedgePtrCont._f == _LfacePtrCont.Count - 1)
                        {
                            // use first
                            hedgePtrCont1._nhe._DataIndex = hedgePtrCont1._nhe._DataIndex == -1 ? nextHedgePtrCont._he._DataIndex - 1 : hedgePtrCont1._nhe._DataIndex;
                        }
                        else
                        {
                            // use second
                            hedgePtrCont1._nhe._DataIndex = hedgePtrCont1._nhe._DataIndex == -1 ? nextHedgePtrCont._he._DataIndex : hedgePtrCont1._nhe._DataIndex;
                        }
                        _LhedgePtrCont[indexhedge1] = new HEdgePtrCont()
                        {
                            _f = hedgePtrCont1._f,
                            _he = hedgePtrCont1._he,
                            _nhe = hedgePtrCont1._nhe,
                            _v = hedgePtrCont1._v,
                            _vn = hedgePtrCont1._vn,
                            _vuv = hedgePtrCont1._vuv
                        };
                    }
                    #endregion UseHEdge1
                }
                else if (hedgePtrCont2._f == _LfacePtrCont.Count - 1 || hedgePtrCont2._f == -1)
                {
                    #region UseHEdge2
                    hedgePtrCont2._f._DataIndex = _LfacePtrCont.Count - 1;
                    // The face the edge2 points to is the current face - let's use the second one then
                    if (i + 1 < edgeList.Count)
                    {
                        // Just use the next hedge
                        HEdgePtrCont nextHedgePtrCont = _LhedgePtrCont[_LedgePtrCont[edgeList[i + 1]._DataIndex]._he1];
                        if (nextHedgePtrCont._f == _LfacePtrCont.Count - 1)
                        {
                            // use first
                            hedgePtrCont2._nhe._DataIndex = hedgePtrCont2._nhe._DataIndex == -1 ? nextHedgePtrCont._he._DataIndex - 1 : hedgePtrCont2._nhe._DataIndex;
                        }
                        else
                        {
                            // use second
                            hedgePtrCont2._nhe._DataIndex = hedgePtrCont2._nhe._DataIndex == -1 ? nextHedgePtrCont._he._DataIndex : hedgePtrCont2._nhe._DataIndex;
                        }
                        _LhedgePtrCont[indexhedge2] = new HEdgePtrCont()
                        {
                            _f = hedgePtrCont2._f,
                            _he = hedgePtrCont2._he,
                            _nhe = hedgePtrCont2._nhe,
                            _v = hedgePtrCont2._v,
                            _vn = hedgePtrCont2._vn,
                            _vuv = hedgePtrCont2._vuv
                        };
                    }
                    else
                    {
                        // Connect to the first hedge in the list because the current is the last one in the face
                        HEdgePtrCont nextHedgePtrCont = _LhedgePtrCont[_LedgePtrCont[edgeList[0]._DataIndex]._he1];
                        if (nextHedgePtrCont._f == _LfacePtrCont.Count - 1)
                        {
                            // use first
                            hedgePtrCont2._nhe._DataIndex = hedgePtrCont2._nhe._DataIndex == -1 ? nextHedgePtrCont._he._DataIndex - 1 : hedgePtrCont2._nhe._DataIndex;
                        }
                        else
                        {
                            // use second
                            hedgePtrCont2._nhe._DataIndex = hedgePtrCont2._nhe._DataIndex == -1 ? nextHedgePtrCont._he._DataIndex : hedgePtrCont2._nhe._DataIndex;
                        }
                        _LhedgePtrCont[indexhedge2] = new HEdgePtrCont()
                        {
                            _f = hedgePtrCont2._f,
                            _he = hedgePtrCont2._he,
                            _nhe = hedgePtrCont2._nhe,
                            _v = hedgePtrCont2._v,
                            _vn = hedgePtrCont2._vn,
                            _vuv = hedgePtrCont2._vuv
                        };
                    }
                    #endregion UseHEdge2
                }
                else
                {
                    /* It's an edge shared by more than two faces. So we need to do something.
                     * TODO:
                     *
                     * Insert new edge between the two vertices.
                     * Update the pointers of the edge
                     */

                    Debug.WriteLine("Both edges are already in use and don't point to the current face. Do something different.");
                    HEdgePtrCont hedge1 = hedgePtrCont1;
                    HEdgePtrCont hedge2 = hedgePtrCont2;

                    hedge1._f._DataIndex = _LfacePtrCont.Count - 1;
                    hedge1._he._DataIndex = _LhedgePtrCont.Count + 1;
                    hedge2._he._DataIndex = _LhedgePtrCont.Count;

                    if (i + 1 < edgeList.Count)
                    {
                        int nextIndex = _LedgePtrCont[edgeList[i + 1]._DataIndex]._he1._DataIndex;
                        hedge1._nhe._DataIndex = nextIndex;
                    }
                    else
                    {
                        int firstHEdgeIndex = _LedgePtrCont[edgeList[0]._DataIndex]._he1._DataIndex;
                        hedge1._nhe._DataIndex = firstHEdgeIndex;
                    }

                    // Add the hedges to the global list
                    _LhedgePtrCont.Add(hedge1);
                    _LhedgePtrCont.Add(hedge2);

                    // Add an edge to the global list
                    _LedgePtrCont.Add(
                            new EdgePtrCont()
                            {
                                _he1 = new HandleHalfEdge() { _DataIndex = _LhedgePtrCont.Count - 2 },
                                _he2 = new HandleHalfEdge() { _DataIndex = _LhedgePtrCont.Count - 1 }
                            }
                        );

                    _LedgeHndl.Add(new HandleEdge() { _DataIndex = _LedgePtrCont.Count - 1 }
                        );

                    // Change the current edgelist
                    edgeList.RemoveAt(i);
                    edgeList.Insert(i, _LedgeHndl[_LedgeHndl.Count - 1]);

                    // Change the next pointer for the edge before the current one
                    int indexPrevhedge1 = i == 0 ? _LedgePtrCont[edgeList[i]._DataIndex]._he1 : _LedgePtrCont[edgeList[i - 1]._DataIndex]._he1;
                    int indexPrevhedge2 = i == 0 ? _LedgePtrCont[edgeList[i]._DataIndex]._he2 : _LedgePtrCont[edgeList[i - 1]._DataIndex]._he2;
                    HEdgePtrCont prevhedge1 = _LhedgePtrCont[indexhedge1];
                    HEdgePtrCont prevhedge2 = _LhedgePtrCont[indexhedge2];

                    if (prevhedge1._f._DataIndex == hedge1._f._DataIndex)
                    {
                        // use the first hedge
                        prevhedge1._nhe._DataIndex = _LhedgePtrCont.Count - 2;
                        _LhedgePtrCont[indexPrevhedge1] = new HEdgePtrCont()
                        {
                            _f = prevhedge1._f,
                            _he = prevhedge1._he,
                            _nhe = prevhedge1._nhe,
                            _v = prevhedge1._v,
                            _vn = prevhedge1._vn,
                            _vuv = prevhedge1._vuv
                        };
                    }
                    else
                    {
                        // use the second hedge
                        prevhedge2._nhe._DataIndex = _LhedgePtrCont.Count - 2;
                        _LhedgePtrCont[indexPrevhedge2] = new HEdgePtrCont()
                        {
                            _f = prevhedge2._f,
                            _he = prevhedge2._he,
                            _nhe = prevhedge2._nhe,
                            _v = prevhedge2._v,
                            _vn = prevhedge2._vn,
                            _vuv = prevhedge2._vuv
                        };
                    }

                }

            }
        }
Exemple #2
0
        /// <summary>
        /// This method converts a quad based 'Geometry' object to a triangle based one.
        /// </summary>
        private void TriangulateGeometry()
        {
            List<HandleFace> LtmpFaces = new List<HandleFace>();

            foreach (HandleFace currentFace in _LfaceHndl)
            {
                // Pruefe zuerst ob man das face triangulaten sollte oder nicht.
                if (EnFaceAdjacentHalfEdges(currentFace).Count() == 3)
                    continue;

                // Hole aktuelles face und merke den index.
                FacePtrCont currentFaceCont = _LfacePtrCont[currentFace];
                // Merke erste hedge h0.
                HandleHalfEdge h0H = currentFaceCont._h;
                HEdgePtrCont h0Cont = _LhedgePtrCont[h0H];
                // Merke ersten vert v0.
                HandleVertex v0H = _LhedgePtrCont[h0Cont._he]._v;
                // Merke die letzte hedge im face hl.
                //HandleHalfEdge hlH = RetLastHalfEdgeInFaceCw(currentFace);
                HandleHalfEdge hlH = EnFaceAdjacentHalfEdges(currentFace).Last();
                HEdgePtrCont hlCont = _LhedgePtrCont[hlH];
                // Lege zwei neue hedges an und fülle sie korrekt.
                int hedgeCount = _LhedgePtrCont.Count;
                HandleHalfEdge hedge0H = new HandleHalfEdge() { _DataIndex = hedgeCount };
                HandleHalfEdge hedge1H = new HandleHalfEdge() { _DataIndex = hedgeCount + 1 };
                HandleEdge edgeHNew = new HandleEdge() { _DataIndex = _LedgeHndl.Count };
                EdgePtrCont edgeContNew = new EdgePtrCont() { _he1 = hedge0H, _he2 = hedge1H };

                HEdgePtrCont newhedge0 = new HEdgePtrCont()
                {
                    _nhe = h0H,
                    _v = v0H,
                    _he = hedge1H,
                    _f = currentFace,
                    _vn = hlCont._vn,
                    _vuv = hlCont._vuv
                };
                // Hole h1 und h2 zum Merken.
                HandleHalfEdge h1H = h0Cont._nhe;
                HEdgePtrCont h1Cont = _LhedgePtrCont[h1H];
                HandleHalfEdge h2H = h1Cont._nhe;
                HEdgePtrCont h2Cont = _LhedgePtrCont[h2H];

                HEdgePtrCont newhedge1 = new HEdgePtrCont()
                {
                    _nhe = h1Cont._nhe,
                    _v = h1Cont._v,
                    _he = hedge0H,
                    _f = new HandleFace(-1),
                    _vn = h1Cont._vn,
                    _vuv = h1Cont._vuv,
                };
                // Update die jeweiligen next pointer der angrenzenden hedges.
                h1Cont._nhe = hedge0H;
                hlCont._nhe = hedge1H;
                // Lege ein neues face an für das triangle 2.
                HandleFace f1H = new HandleFace() { _DataIndex = (_LfaceHndl.Count - 1) + LtmpFaces.Count + 1 };
                FacePtrCont f1Cont = new FacePtrCont() { _fn = currentFaceCont._fn, _h = hlH };
                // Update das neue triangle bezüglich des neuen faces. Dazu erstmal h2 holen noch.
                newhedge1._f = f1H;
                h2Cont._f = f1H;
                hlCont._f = f1H;
                // Sichere die Änderungen in den listen.
                _LedgeHndl.Add(edgeHNew);
                _LedgePtrCont.Add(edgeContNew);
                _LhedgePtrCont.Add(newhedge0);
                _LhedgePtrCont.Add(newhedge1);

                // Speichere das face handle erstmal in tmp faces wegen der iteration.
                LtmpFaces.Add(f1H);
                _LfacePtrCont.Add(f1Cont);

                _LhedgePtrCont[h1H] = new HEdgePtrCont()
                {
                    _f = h1Cont._f,
                    _he = h1Cont._he,
                    _nhe = h1Cont._nhe,
                    _v = h1Cont._v,
                    _vn = h1Cont._vn,
                    _vuv = h1Cont._vuv
                };

                _LhedgePtrCont[h2H] = new HEdgePtrCont()
                {
                    _f = h2Cont._f,
                    _he = h2Cont._he,
                    _nhe = h2Cont._nhe,
                    _v = h2Cont._v,
                    _vn = h2Cont._vn,
                    _vuv = h2Cont._vuv
                };

                _LhedgePtrCont[hlH] = new HEdgePtrCont()
                {
                    _f = hlCont._f,
                    _he = hlCont._he,
                    _nhe = hlCont._nhe,
                    _v = hlCont._v,
                    _vn = hlCont._vn,
                    _vuv = hlCont._vuv
                };
            }

            foreach (HandleFace handleFace in LtmpFaces)
            {
                _LfaceHndl.Add(handleFace);
            }
            LtmpFaces.Clear();
        }
Exemple #3
0
        /// <summary>
        /// For testing only now.
        /// </summary>
        /// <param name="existingEdge"></param>
        /// <param name="fromVert"></param>
        /// <param name="toVert"></param>
        /// <returns></returns>
        private HandleHalfEdge ReuseExistingConnection(HandleEdge existingEdge, HandleVertex fromVert, HandleVertex toVert)
        {
            // Check half-edge 1 and 2 if one points to the actual face. This is the one we use for our face then. If no one we build a new connection.
            HEdgePtrCont hedge1 = _LhedgePtrCont[_LedgePtrCont[existingEdge]._he1];
            HEdgePtrCont hedge2 = _LhedgePtrCont[_LedgePtrCont[existingEdge]._he2];

            HandleHalfEdge hedgeToUse = new HandleHalfEdge(-1);

            if (hedge2._f == -1)
            {
                // It is hedge 2 that is free. We should use it.
                hedgeToUse = _LedgePtrCont[existingEdge]._he2;

            }
            else if (hedge1._f == -1)
            {
                // It is hedge 1 that is free. We should use it. Should never happen. TODO: Exception throw?
                hedgeToUse = _LedgePtrCont[existingEdge]._he1;
            }
            else
            {
                // Neither one of the faces of the existing half-edges was free so we build a new edge.
                return CreateAllNewConnection(fromVert, toVert);
            }
            // Updating the face pointer.
            HEdgePtrCont hedge = _LhedgePtrCont[hedgeToUse];
            hedge._f = new HandleFace(_LfacePtrCont.Count - 1);

            _LhedgePtrCont[hedgeToUse] = new HEdgePtrCont()
            {
                _f = hedge._f,
                _he = hedge._he,
                _nhe = hedge._nhe,
                _v = hedge._v,
                _vn = hedge._vn,
                _vuv = hedge._vuv
            };

            return hedgeToUse;
        }
Exemple #4
0
        /// <summary>
        /// For testing now only.
        /// </summary>
        /// <returns></returns>
        private HandleHalfEdge CreateAllNewConnection(HandleVertex fromVert, HandleVertex toVert)
        {
            HEdgePtrCont hedge1 = new HEdgePtrCont()
            {
                _f = new HandleFace(_LfacePtrCont.Count - 1),
                _he = new HandleHalfEdge(_LedgePtrCont.Count == 0 ? 1 : _LhedgePtrCont.Count + 1),
                _v = new HandleVertex(toVert),
                _vn = new HandleVertexNormal(-1),
                _vuv = new HandleVertexUV(-1),
                _nhe = new HandleHalfEdge(-1)
            };

            HEdgePtrCont hedge2 = new HEdgePtrCont()
            {
                _f = new HandleFace(-1),
                _he = new HandleHalfEdge(_LedgePtrCont.Count == 0 ? 0 : _LhedgePtrCont.Count),
                _v = new HandleVertex(fromVert),
                _vn = new HandleVertexNormal(-1),
                _vuv = new HandleVertexUV(-1),
                _nhe = new HandleHalfEdge(-1)
            };

            _LhedgePtrCont.Add(hedge1);
            _LhedgePtrCont.Add(hedge2);

            _LedgePtrCont.Add(
                new EdgePtrCont()
                {
                    _he1 = new HandleHalfEdge(_LhedgePtrCont.Count - 2),
                    _he2 = new HandleHalfEdge(_LhedgePtrCont.Count - 1)
                }
                );
            _LedgeHndl.Add(
                new HandleEdge() { _DataIndex = _LedgePtrCont.Count - 1 }
                );

            // Update the vertices.
            VertexPtrCont vertFrom = _LvertexPtrCont[fromVert._DataIndex];
            VertexPtrCont vertTo = _LvertexPtrCont[toVert._DataIndex];

            if (!vertFrom._h.isValid)
            {
                vertFrom._h = _LedgePtrCont[_LedgePtrCont.Count - 1]._he1;
                _LvertexPtrCont[fromVert] = new VertexPtrCont() { _h = vertFrom._h };
            }
            if (!vertTo._h.isValid)
            {
                vertTo._h = _LedgePtrCont[_LedgePtrCont.Count - 1]._he2;
                _LvertexPtrCont[toVert] = new VertexPtrCont() { _h = vertTo._h };
            }

            return _LedgePtrCont.Last()._he1;
        }
Exemple #5
0
        /// <summary>
        /// Adds a face from the importer to the geometry container
        /// </summary>
        /// <param name="gf">GeoFace object from the importer</param>
        private void AddFace(GeoFace gf)
        {
            // Add a face container.
            _LfacePtrCont.Add(
                new FacePtrCont()
                {
                    _h = new HandleHalfEdge()
                    {
                        _DataIndex = -1
                    }
                }
                );
            // Add a face handle.
            _LfaceHndl.Add(
                new HandleFace() { _DataIndex = _LfacePtrCont.Count - 1 }
                );

            // Insert all the vertices for the face.
            List<HandleVertex> LHandleVertsForFace = new List<HandleVertex>();
            foreach (float3 vVal in gf._LFVertices)
            {
                LHandleVertsForFace.Add(
                    AddVertex(vVal)
                    );
            }
            // Insert all the uv coordinates for the face.
            List<HandleVertexUV> LHandleUVsForFace = new List<HandleVertexUV>();
            foreach (float2 uvVal in gf._UV)
            {
                _LuvCoordinates.Add(uvVal);
                LHandleUVsForFace.Add(new HandleVertexUV() { _DataIndex = _LuvCoordinates.Count - 1 });
            }

            // Build up the half-edge connections for the face
            List<HandleHalfEdge> LHandleHEForFace = new List<HandleHalfEdge>();
            for (int i = 0; i < LHandleVertsForFace.Count; i++)
            {
                HandleVertex fromVert = LHandleVertsForFace[i];
                HandleVertex toVert = i + 1 < LHandleVertsForFace.Count ? LHandleVertsForFace[i + 1] : LHandleVertsForFace[0];

                LHandleHEForFace.Add(
                        CreateConnection(fromVert, toVert)
                    );
            }

            // Loop over all the half-edges for the face and concat them and set the correct uv coordinates.
            for (int i = 0; i < LHandleHEForFace.Count; i++)
            {
                HandleHalfEdge currentHedge = LHandleHEForFace[i];
                HEdgePtrCont hedge = _LhedgePtrCont[currentHedge];
                HandleHalfEdge nextHedge = i + 1 < LHandleHEForFace.Count ? LHandleHEForFace[i + 1] : LHandleHEForFace[0];
                hedge._nhe = nextHedge;
                if (LHandleUVsForFace.Count > 0)
                {
                    HandleVertexUV currentUV = i + 1 < LHandleUVsForFace.Count ? LHandleUVsForFace[i + 1] : LHandleUVsForFace[0];
                    hedge._vuv = currentUV;
                }
                //_LhedgePtrCont.RemoveAt(currentHedge);
                //_LhedgePtrCont.Insert(currentHedge, hedge);
                _LhedgePtrCont[currentHedge] = new HEdgePtrCont()
                {
                    _f = hedge._f,
                    _he = hedge._he,
                    _nhe = hedge._nhe,
                    _v = hedge._v,
                    _vn = hedge._vn,
                    _vuv = hedge._vuv
                };
            }

            // Set the half-edge the face points to.
            FacePtrCont face = _LfacePtrCont.Last();
            face._h = new HandleHalfEdge(LHandleHEForFace.First());
            _LfacePtrCont.RemoveAt(_LfacePtrCont.Count - 1);
            _LfacePtrCont.Add(face);
        }
Exemple #6
0
        /// <summary>
        /// This method calculates vertex normals for a specific vertex in the geometry and inserts them at the corresponding half-edges on the correct faces.
        /// This method uses an angle based algorithm to determine whether to calculate with another faces normal or not.
        /// </summary>
        /// <param name="vertexHandle">A handle for the vertex to calc the normals for.</param>
        public void CalcVertexNormal(HandleVertex vertexHandle)
        {
            List<HandleHalfEdge> EincomingHEdges = EnVertexIncomingHalfEdge(vertexHandle).ToList();

            // Loop over every incoming half-edge.
            foreach (HandleHalfEdge handleHedge in EincomingHEdges)
            {
                int hedgeIndex = handleHedge;
                // Check if the half-edge is pointing to a face.
                int faceIndex = _LhedgePtrCont[hedgeIndex]._f;
                if (faceIndex == -1)
                    return;

                float3 currentFaceNormal = _LfaceNormals[_LfacePtrCont[faceIndex]._fn];
                float3 normalAggregate = new float3();
                // Loop over every incoming half-edge again, so we can compare the angles between the current one and all the others.
                // We do this to decide which normal should be added to the sum and which not.
                foreach (int eincomingHEdge in EincomingHEdges)
                {
                    // Add the current normal if the index is on it and do not compare any angles etc.
                    if (eincomingHEdge == hedgeIndex)
                    {
                        normalAggregate += currentFaceNormal;
                        continue;
                    }
                    // Stop when the current half-edge is not pointing to a face.
                    int faceIndex2 = _LhedgePtrCont[eincomingHEdge]._f;
                    if (faceIndex2 == -1)
                        continue;

                    float3 normalToCompare = _LfaceNormals[_LfacePtrCont[faceIndex2]._fn];

                    float dot = float3.Dot(currentFaceNormal, normalToCompare);
                    if (System.Math.Acos(dot) * _constPiFactor < _SmoothingAngle)
                        normalAggregate += float3.Add(normalAggregate, normalToCompare);
                }

                _LVertexNormals.Add(float3.NormalizeFast(normalAggregate));

                HEdgePtrCont currentHedge = _LhedgePtrCont[hedgeIndex];
                _LhedgePtrCont[hedgeIndex] = new HEdgePtrCont()
                {
                    _f = currentHedge._f,
                    _he = currentHedge._he,
                    _nhe = currentHedge._nhe,
                    _v = currentHedge._v,
                    _vn = new HandleVertexNormal(_LVertexNormals.Count - 1),
                    _vuv = currentHedge._vuv
                };
            }
        }