예제 #1
0
        // --- Attributi ---
        BoundingBox MaxRect()
        {
            BoundingBox rect = BoundingBox.Empty;

            for (int i = 0; i < m_ArrayVertexes.Count; i++)
            {
                AM_Vertex vertex = m_ArrayVertexes[i];
                rect.Union(new Point3d(vertex.Coord.X, vertex.Coord.Y, 0));
            }
            return(rect);
        }
예제 #2
0
        bool DeleteVertex(AM_Vertex vertex, bool bdelete = false)
        {
            // Cancella un vertice dall'array globale dei vertici
            if (vertex == null || vertex.Index < 0)
            {
                Debug.Assert(false);
                return(false);
            }

            int nindex = vertex.Index;
            int nlast  = m_ArrayVertexes.Count - 1;

            // La cancellazione dall'array globale degli vertici avviene
            // spostando l'ultimo vertice dell'array al posto di quello da cancellare
            m_ArrayVertexes[nindex]       = m_ArrayVertexes[nlast];
            m_ArrayVertexes[nindex].Index = nindex;
            m_ArrayVertexes.RemoveAt(nlast);

            if (nlast != nindex)
            {
                // è necessario aggiornare opportunamente l'anello del vertice
                // aggiornando il dato membro m_nVertex;
                AM_Edge pstartEdge = m_ArrayVertexes[nindex].Edge;
                AM_Edge edge       = pstartEdge;

                if (pstartEdge == null)
                {
                    Debug.Assert(false);
                    return(true);
                }

                do
                {
                    edge.Vertex = m_ArrayVertexes[nindex];
                    edge        = edge.Next;
                } while (edge != pstartEdge);

                if (bdelete)
                {
                    //delete vertex;
                    vertex.Edge  = null;
                    vertex.Index = -1;
                }
                else
                {
                    vertex.Edge  = null;
                    vertex.Index = -1;
                }
            }

            return(true);
        }
예제 #3
0
        internal int AddVertex(Point2d coord, double space, bool check = true)
        {
            // Questa routine è decisamente inefficiente;
            // è stata resa virtuale per essere adattata nei casi derivati

            if (check)
            {
                if (m_pRangeSearch != null)
                {
                    // Ricerca su albero
                    AM_Vertex vertex = m_pRangeSearch.Search(coord.X, coord.Y);
                    if (vertex != null)
                    {
                        return(vertex.Index);
                    }
                }
                else
                {
                    double tollerance = AM_Util.FLT_EPSILON;
                    for (int i = m_ArrayVertexes.Count - 1; i >= 0; i--)
                    {
                        if (m_ArrayVertexes[i].Coord.EpsilonEquals(coord, tollerance))
                        {
                            // Se il punto esiste già restituisce la sua posizione
                            // nell'array globale dei vertici
                            return(i);
                        }
                    }
                }
            }

            // Il vertice non esiste ne viene creato uno nuovo
            AM_Vertex pvertex = new AM_Vertex(coord, 0, space);

            if (pvertex == null)
            {
                Debug.Assert(false);
                //throw -1;
            }

            int nindex = m_ArrayVertexes.Count;

            m_ArrayVertexes.Add(pvertex);
            pvertex.Index = nindex;

            return(nindex);
        }
예제 #4
0
        AM_Edge FindEdge(AM_Vertex org, AM_Vertex dest)
        {
            AM_Edge pstart = org.Edge;

            if (pstart != null)
            {
                AM_Edge pnext = pstart;
                do
                {
                    if (pnext.Destination() == dest)
                    {
                        return(pnext); // lo spigolo esiste già
                    }
                    pnext = pnext.Next;
                } while (pnext != pstart);
            }
            return(null);
        }
예제 #5
0
        AM_Edge AddEdge(AM_Vertex org, AM_Vertex dest)
        {
            AM_Coedge pwEdge = new AM_Coedge(org, dest);

            if (pwEdge == null)
            {
                Debug.Assert(false);
                //throw -1;
            }

            pwEdge.Index = m_ArrayWEdges.Count;
            m_ArrayWEdges.Add(pwEdge);

            AM_Edge edge = pwEdge.Edge();

            //edge.m_pArrayVertex = &m_ArrayVertexes;
            //edge.Symm().m_pArrayVertex = &m_ArrayVertexes;
            return(edge);
        }
예제 #6
0
        bool IsBoundaryVertex(AM_Vertex pvertex)
        {
            AM_Edge start = pvertex.Edge;

            if (start == null)
            {
                Debug.Assert(false);
                return(false); // Indefinito
            }

            AM_Edge edge = start;

            do
            {
                if (edge.CwFace() == null || edge.CcwFace() == null)
                {
                    return(true);
                }

                edge = edge.Next;
            } while (start != edge);

            return(false);
        }
예제 #7
0
        internal bool InsertPoint(Point2d x, double space, out AM_Vertex pvertex)
        {
            pvertex = null;
            AM_Face face = null;

            // Localizza uno spigolo vicino
            AM_Edge edge = Locate(x);

            if (edge == null)
            {
                return(false);
            }

            // Localizza il triangolo che contiene il punto x
            // e imposta 'm_pStartingEdge', primo spigolo del triangolo o del quadrilatero
            // che deve essere riconnesso al punto x
            if (AM_Edge.LeftOf(x, edge))
            {
                face           = (AM_Face)(edge.CcwFace());
                m_StartingEdge = edge.CcwEdge();
            }
            else
            {
                face           = (AM_Face)(edge.CwFace());
                m_StartingEdge = edge.Symm().CcwEdge();
            }

            if (face == null)
            {
                return(false);
            }

            // Verifica dell'eventuale esistenza del punto
            if (x == edge.OrgCoord())
            {
                pvertex = edge.Origin();
                return(false);
            }

            if (x == edge.DestCoord())
            {
                pvertex = edge.Destination();
                return(false);
            }

            Point2d[] v1 = { face.Vertex(0).Coord, face.Vertex(1).Coord, face.Vertex(2).Coord, };

            //isOnEdge = OnEdge(x, edge);
            AM_Edge pOnEdge = OnFaceEdge(x, face);

            if (pOnEdge != null)
            {
                m_StartingEdge = pOnEdge.CcwEdge();

                // il punto si trova su un contorno!
                AM_Face pCwFace  = pOnEdge.CwFace();
                AM_Face pCcwFace = pOnEdge.CcwFace();

                if (pCwFace == null || pCcwFace == null)
                {
                    return(false);
                }
            }

            // Il punto è all'interno di un triangolo o su uno spigolo
            if (face.FaceType == AM_Face.EFaceType.FT_ACTIVE)
            {
                DeleteActiveFace(face);
            }

            DeleteFace(face);
            if (pOnEdge != null)
            {
                // Cancella lo spigolo su cui si appoggia e
                // conseguentemente anche l'altro spigolo

                AM_Face pCwFace  = pOnEdge.CwFace();
                AM_Face pCcwFace = pOnEdge.CcwFace();

                if (pCwFace != null && pCwFace.FaceType == AM_Face.EFaceType.FT_ACTIVE)
                {
                    DeleteActiveFace(pCwFace);
                }
                if (pCcwFace != null && pCcwFace.FaceType == AM_Face.EFaceType.FT_ACTIVE)
                {
                    DeleteActiveFace(pCcwFace);
                }

                DeleteEdge(pOnEdge);
            }

            // Inserisce il nuovo vertice nell'array globale
            pvertex = new AM_Vertex(x, 0, space);
            if (pvertex == null)
            {
                Debug.Assert(false);
                //throw -1;
            }


            int m_nVertex = m_ArrayVertexes.Count;

            pvertex.Index = m_ArrayVertexes.Count;
            m_ArrayVertexes.Add(pvertex);

            // Inserisce i nuovi triangoli (facce)
            edge = m_StartingEdge.CcwEdge();
            int numEdge = (pOnEdge != null? 4 : 3);

            for (int ne = 0; ne < numEdge; ne++)
            {
                AM_Face new_face = new AM_Face();
                if (new_face == null)
                {
                    Debug.Assert(false);
                    //throw -1;
                }

                AM_Edge actEdge = edge;
                edge = edge.CcwEdge();
                int [] nCoord = { m_nVertex, actEdge.Vertex.Index, actEdge.DestVertex().Index };
                AddFace(new_face, nCoord);

                if (m_bFlagClassific)
                {
                    new_face.SetTriangleParameter(m_pSpaceFunction);
                    Classific(new_face);
                }
            }

            // Esamina gli spigoli per assicurare che la condizione di
            // Delaunay sia soddisfatta
            edge           = m_StartingEdge;
            m_StartingEdge = m_StartingEdge.CcwEdge();
            do
            {
                //TRACE_EDGE(edge);
                AM_Edge t = edge.Prev;
                if (edge.CwFace() != null && AM_Edge.RightOf(t.DestCoord(), edge) &&
                    AM_Util.InCircle(edge.OrgCoord(), t.DestCoord(), edge.DestCoord(), x))
                {
                    //TRACE0("Faccia swap:  ");
                    //TRACE_EDGE(edge);
                    Swap(edge);
                    edge = edge.Prev;
                }
                else if (edge.Next == m_StartingEdge)
                {
                    // Non ci sono più spigoli
                    break;
                }
                else
                {
                    // Recupera un altro spigolo sospetto
                    edge = edge.Next.CwEdge();
                }
            } while (true);

            return(true);
        }
예제 #8
0
        bool RecoverBoundary(AM_Boundary boundary)
        {
            // se viene inserito un punto per aggiustare la conformità
            // il flag baddFlag diventa true
            bool baddFlag = false;

            AM_Edge pbase = null;
            AM_Edge pprev = pbase = boundary.Vertex(0).Edge;

            for (int i = 1; (boundary.FlagHole ? i <= boundary.GetNumVertex()
                       : i < boundary.GetNumVertex()); i++)
            {
                // si controlla che tutti i vertici siano in sequenza
                while (true)
                {
                    Point3d p1 = boundary[i - 1];
                    Point3d p2 = boundary[i % (boundary.GetNumVertex())];

                    if (pbase.DestCoord() == new Point2d(p2))
                    {
                        // il vertice è in sequenza: si continua con il successivo
                        break;
                    }
                    else
                    {
                        pbase = pbase.Next;

                        if (pbase == pprev)
                        {
                            // il ciclo dell'anello si è chiuso senza trovare il vertice
                            // successivo; è necessario inserire un vertice in mezzeria del
                            // lato mancante

                            baddFlag = true; // si segnala l'aggiunta di un vertice

                            Point3d mid = 0.5 * (p1 + p2);

                            // si inserisce un vertice nel mezzo dello spigolo
                            AM_Vertex pvertex = null;
                            InsertPoint(new Point2d(mid), mid.Z, out pvertex);

                            if (pvertex == null)
                            {
                                Debug.Assert(false);
                                //throw 6;
                            }

                            boundary.InsertVertex(i, pvertex);

                            // si ricomincia il controllo
                            pbase = boundary.Vertex(i - 1).Edge;
                            pprev = pbase;
                        }
                    }
                }
                pbase = boundary.Vertex(i % (boundary.GetNumVertex())).Edge;
                pprev = pbase;
            }

            return(baddFlag);
        }
예제 #9
0
        internal bool DeleteEdge(AM_Edge edge, bool bDelIsolatedVertex = false)
        {
            Debug.Assert(edge != null);
            // Cancella le facce collegate allo spigolo
            DeleteFace(edge.CwFace());
            DeleteFace(edge.CcwFace());

            AM_Coedge pwEdge        = edge.WingedEdge;
            AM_Coedge pdeletingEdge = m_ArrayWEdges[pwEdge.Index];
            int       nlast         = m_ArrayWEdges.Count - 1;

            Debug.Assert(pdeletingEdge == pwEdge);

            // La cancellazione dall'array globale degli spigoli avviene
            // spostando l'ultimo spigolo dell'array al posto di quello da cancellare
            m_ArrayWEdges[pwEdge.Index]       = m_ArrayWEdges[nlast];
            m_ArrayWEdges[pwEdge.Index].Index = pwEdge.Index;
            m_ArrayWEdges.RemoveAt(nlast);

            AM_Vertex pIsolated1 = null;
            AM_Vertex pIsolated2 = null;

            // ripristina le connessioni
            edge.Next.Prev = edge.Prev;
            edge.Prev.Next = edge.Next;
            if (edge.Next == edge && edge.Prev == edge)
            {
                // rimane un vertice isolato
                pIsolated1      = edge.Origin();
                pIsolated1.Edge = null;
            }
            else
            {
                edge.Origin().Edge = edge.Next;
            }

            // ripristina le connessioni del duale
            edge           = edge.Symm();
            edge.Next.Prev = edge.Prev;
            edge.Prev.Next = edge.Next;
            if (edge.Next == edge && edge.Prev == edge)
            {
                // rimane un vertice isolato
                pIsolated2      = edge.Origin();
                pIsolated2.Edge = null;
            }
            else
            {
                edge.Origin().Edge = edge.Next;
            }

            //delete pwEdge;

            if (bDelIsolatedVertex)
            {
                if (pIsolated1 != null)
                {
                    DeleteVertex(pIsolated1, true);
                }

                if (pIsolated2 != null)
                {
                    DeleteVertex(pIsolated2, true);
                }
            }

            edge.Next = null;
            edge.Prev = null;

            return(true);
        }
예제 #10
0
        internal bool DeleteVertex(Point2d coord, bool bdelete = false)
        {
            // Trova l'indice del vertice da eliminare

            double tollerance = AM_Util.FLT_EPSILON;
            int    nindex;

            for (nindex = 0; nindex < m_ArrayVertexes.Count; nindex++)
            {
                if (m_ArrayVertexes[nindex].Coord.EpsilonEquals(coord, tollerance))
                {
                    // Se il punto esiste già restituisce la sua posizione
                    // nell'array globale dei vertici
                    break;
                }
            }

            if (nindex == m_ArrayVertexes.Count)
            {
                // il vertice non esiste
                return(false);
            }

            AM_Vertex pvertex = m_ArrayVertexes[nindex];

            // se questa condizione non viene rispettata è evidente
            // che ci sono problemi di coerenza. Chiamare UpdateIndex eventualmente
            Debug.Assert(pvertex.Index == nindex);

            AM_Edge edge     = pvertex.Edge;
            AM_Edge pendEdge = edge.Prev;

            if (edge == pendEdge)
            {
                // Lo spigolo è isolato
                Debug.Assert(edge.CcwFace() == null);
                Debug.Assert(edge.CcwFace() == null);
                DeleteEdge(edge);
            }
            else
            {
                // cancella gli spigoli collegati e le facce relative
                while (true)
                {
                    AM_Edge pdeleteEdge = edge;
                    edge = pdeleteEdge.Next;

                    // SHOWEDGE(edge);
                    // SHOWEDGE(pdeleteEdge);
                    DeleteEdge(pdeleteEdge);

                    if (edge == pendEdge)
                    {
                        DeleteEdge(edge);
                        break;
                    }
                }
            }

            DeleteVertex(pvertex, bdelete);

            return(true);
        }
예제 #11
0
        internal double SmoothMesh()
        {
            double eps = 0;

            for (int n = 0; n < m_NumSmoothing; n++) //ripeto Num volte lo smoothing
            {
                eps = 0;
                for (int i = 0; i < m_ArrayVertexes.Count; i++)
                {
                    // ciclo per tutti i punti interni al dominio
                    AM_Vertex vertex = m_ArrayVertexes[i];

                    // Versione corretta (AC 16-01-03)
                    // Algoritmo di Optimal Smoothing (Borouchaki-George IJNME vol.40)
                    if (vertex.Flag == 0) // E' un punto smoothabile
                    {
                        Point2d p0     = vertex.Coord;
                        Point2d center = Point2d.Unset;
                        int     degree = (int)vertex.Degree(true);
                        if (degree < 2)
                        {
                            continue;
                        }

                        AM_Edge start    = vertex.Edge;
                        AM_Edge nextEdge = start;

                        Point2d newCoord   = Point2d.Unset;
                        double  oldQuality = double.MaxValue;

                        // Valuta la qualità dei triangoli prima dello spostamento
                        // e calcola il nuovo centro
                        for (int j = 0; j < degree; j++)
                        {
                            Debug.Assert(nextEdge.CcwFace() != null);
                            Point2d p1 = nextEdge.DestCoord();
                            Point2d p2 = nextEdge.Next.DestCoord();

                            // Punto del teorico triangolo equilatero di p1-p2
                            Vector2d v  = p2 - p1;
                            Point2d  mp = 0.5 * (p1 + p2);
                            Point2d  np = mp + Math.Sqrt(3d) * v.Length * AM_Util.NormalVersor(v);

                            newCoord += np;

                            double inRadius     = 0;
                            double circumRadius = 0;

                            AM_Util.CircumCircle(p0, p1, p2, ref center, ref circumRadius);
                            AM_Util.InCircle(p0, p1, p2, ref center, ref inRadius);
                            double sgnArea = AM_Util.TriArea(p0, p1, p2) > 0 ? 1 : -1;

                            double quality = sgnArea * inRadius / circumRadius;
                            oldQuality = Math.Min(oldQuality, quality);

                            nextEdge = nextEdge.Next;
                        }
                        Debug.Assert(nextEdge == start);

                        newCoord.X /= degree;
                        newCoord.Y /= degree;

                        // Controlla l'accettabilità del nuovo centro
                        double newQuality = double.MaxValue;

                        for (int j = 0; j < degree; j++)
                        {
                            Debug.Assert(nextEdge.CcwFace() != null);
                            Point2d p1 = nextEdge.DestCoord();
                            Point2d p2 = nextEdge.Next.DestCoord();

                            double inRadius     = 0;
                            double circumRadius = 0;
                            AM_Util.CircumCircle(newCoord, p1, p2, ref center, ref circumRadius);
                            AM_Util.InCircle(newCoord, p1, p2, ref center, ref inRadius);
                            double sgnArea = AM_Util.TriArea(newCoord, p1, p2) > 0? 1 : -1;

                            double quality = sgnArea * inRadius / circumRadius;
                            newQuality = Math.Min(quality, newQuality);

                            nextEdge = nextEdge.Next;
                        }

                        Debug.Assert(nextEdge == start);

                        if (newQuality > 0 && newQuality > oldQuality)
                        {
                            // La qualità viene migliorata, il vertice viene spostato
                            eps         += (newCoord - p0).Length;
                            vertex.Coord = newCoord;
                        }
                    }
                }
            }

            return(eps);
        }