// --- 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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }