bool SetBoundary() { { m_Mesh2D.DeleteInit(); int numBoundary = m_ArrayMeshBoundary.Count; for (int i = 0; i < numBoundary; i++) { if (m_ArrayMeshBoundary[i].FlagHole) { m_Mesh2D.SetBoundary(m_ArrayMeshBoundary[i]); } } // Elimina eventuali spigoli isolati for (int i = 0; i < m_Mesh2D.ArrayWEdges.Count; i++) { AM_Edge pedge = m_Mesh2D.ArrayWEdges[i].Edge(); if (pedge.CcwFace() == null && pedge.CwFace() == null) { m_Mesh2D.DeleteEdge(pedge); } } } return(true); }
internal static void SwapEdge(AM_Edge pedge) { Debug.Assert(pedge.CcwFace().NumEdges == 3); Debug.Assert(pedge.CwFace().NumEdges == 3); AM_Edge pstart = pedge; do { Point2d p1 = pedge.CcwEdge().DestCoord(); Point2d p2 = pedge.OrgCoord(); Point2d p3 = pedge.DestCoord(); Point2d p4 = pedge.Symm().CcwEdge().DestCoord(); //int n1 = pedge.CcwEdge().Destination().Index; //int n2 = pedge.Origin().Index; //int n3 = pedge.Destination().Index; //int n4 = pedge.Symm().CcwEdge().Destination().Index; //int v1 = pedge.CcwEdge().Symm().m_nVertex; //int v2 = pedge.m_nVertex; //int v3 = pedge.Symm().m_nVertex; //int v4 = pedge.Symm().CcwEdge().Symm().m_nVertex; AM_Edge poldPrev = pedge.Prev; AM_Edge poldNext = pedge.Next; AM_Edge pnewNext = pedge.Prev.Symm(); AM_Edge pnewPrev = pnewNext.Prev; AM_Face poldFace = pedge.Face; pedge.Origin().Edge = poldNext; pedge.Vertex = pnewNext.Vertex; // Ripristina l'origine... pedge.Origin().Edge = pedge; // e aggiorna il suo puntatore // ripristina i collegamenti corretti poldPrev.Next = poldNext; poldNext.Prev = poldPrev; pnewPrev.Next = pedge; pnewNext.Prev = pedge; pedge.Next = pnewNext; pedge.Prev = pnewPrev; Debug.Assert(pedge.Origin() != pedge.Destination()); // parte dallo spigolo che definisce la faccia sinistra // e che è precedente in senso antiorario pnewNext = poldNext.Symm(); for (int i = 0; i < 3; i++) { pnewNext.Face = poldFace; poldFace[i] = pnewNext; pnewNext = pnewNext.CcwEdge(); } pedge = pedge.Symm(); } while (pstart != pedge); }
void Swap(AM_Edge edge) { AM_Face face1 = (AM_Face)edge.CcwFace(); AM_Face face2 = (AM_Face)edge.CwFace(); if (face1 == null || face2 == null) { if (face1 != null && face1.FaceType == AM_Face.EFaceType.FT_ACTIVE) { DeleteActiveFace(face1); } if (face2 != null && face2.FaceType == AM_Face.EFaceType.FT_ACTIVE) { DeleteActiveFace(face2); } return; } Debug.Assert(edge.CwFace() != null); Debug.Assert(edge.CcwFace() != null); if (face1.FaceType == AM_Face.EFaceType.FT_ACTIVE) { DeleteActiveFace(face1); } if (face2.FaceType == AM_Face.EFaceType.FT_ACTIVE) { DeleteActiveFace(face2); } AM_Face.SwapEdge(edge); if (m_bFlagClassific) { face1.SetTriangleParameter(m_pSpaceFunction); face2.SetTriangleParameter(m_pSpaceFunction); Classific(face1); Classific(face2); } }
void RelaxMesh() { // Esegue la procedura di "Mesh Relaxation" bool bPrev = m_bFlagClassific; m_bFlagClassific = false; for (int DiffDegree = 3; DiffDegree >= 2; DiffDegree--) { for (int i = 0; i < m_ArrayWEdges.Count; i++) { AM_Edge edge = m_ArrayWEdges[i].Edge(); if (edge.CcwFace() != null && edge.CwFace() != null) { AM_Vertex [] Vertex = { edge.Origin(), edge.Destination(), edge.Next.Destination(), edge.Prev.Destination(), }; double [] degree = { 0, 0, 0, 0 }; for (int j = 0; j < degree.Length; j++) { degree[j] = Vertex[j].Degree(); } double R = 0; for (int j = 0; j < 4; j++) { R += (6 - degree[j]) * (6 - degree[j]); } // aggiorna il grado con l'ipotesi do swap degree[0] -= 1; degree[1] -= 1; degree[2] += 1; degree[3] += 1; double R1 = 0; for (int j = 0; j < 4; j++) { R1 += (6 - degree[j]) * (6 - degree[j]); } if (R - R1 >= DiffDegree) { Swap(edge); } } } } m_bFlagClassific = bPrev; }
internal double Degree(bool bSimple = false) { int degree = 0; if (m_Edge == null) { Debug.Assert(false); return(0); } // Il "grado" di un vertice è definito come il numero di vertici // ad esso conneesso. if (bSimple) { // Se bSimple = true si conta semplicemente il numero // di spigoli connessi AM_Edge pNext = m_Edge; do { degree++; pNext = pNext.Next; } while (pNext != m_Edge); return(degree); } double angle = 0; { AM_Edge pNext = m_Edge; do { degree++; if (pNext.CcwFace() != null) { Vector2d v0 = (pNext.DestCoord() - m_Coord); Vector2d v1 = (pNext.Next.DestCoord() - m_Coord); v0.Unitize(); v1.Unitize(); double cos_ang = Vector2d.Multiply(v0, v1); angle += Math.Acos(cos_ang); } pNext = pNext.Next; } while (pNext != m_Edge); } return(degree * 2 * Math.PI / angle); }
internal bool GetCoordZ(Point2d p, ref double Z) { // Localizza uno spigolo vicino AM_Edge edge = Locate(p); if (edge == null) { return(false); } AM_Face face = null; if (AM_Edge.LeftOf(p, edge)) { face = edge.CcwFace(); } else { face = edge.CwFace(); } Z = 0; if (face == null) { return(false); } Point2d p0 = face.Vertex(0).Coord; Point2d p1 = face.Vertex(1).Coord; Point2d p2 = face.Vertex(2).Coord; double det = AM_Util.TriArea(p0, p1, p2); Debug.Assert(det != 00); double alfa = AM_Util.TriArea(p0, p, p2) / det; double beta = AM_Util.TriArea(p0, p1, p) / det; double f0 = face.Vertex(0).Z; double f1 = face.Vertex(1).Z; double f2 = face.Vertex(2).Z; Z = f0 + alfa * (f1 - f0) + beta * (f2 - f0); return(true); }
bool BelongToBorder(AM_Vertex v) { AM_Edge start_edge = v.Edge; if (start_edge != null) { AM_Edge edge = start_edge.Next; while (edge != start_edge) { if (edge.CcwFace() == null || edge.CwFace() == null) { return(true); } edge = edge.Next; } } return(false); }
internal int NumConnectedFace() { if (m_Edge == null) { return(0); } int nFace = 0; AM_Edge pNext = m_Edge; do { if (pNext.CcwFace() != null) { nFace++; } pNext = pNext.Next; } while (pNext != m_Edge); return(nFace); }
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 RecoverGenEdge(AM_Mesh2d mesh, int num, List <Point3d> AddArray, bool bStraight = false) { // se viene inserito un punto per aggiustare la conformità // il flag baddFlag diventa true bool baddFlag = false; if (!m_bFlagHole && num >= m_GenVertexArray.Count) { return(true); } int v1 = m_GenVertexArray[num]; int v2 = m_GenVertexArray[(num + 1) % m_GenVertexArray.Count]; if (v2 < v1) { v2 += GetNumVertex(); } AM_Edge pbase; AM_Edge pprev = pbase = Vertex(v1).Edge; for (int i = v1 + 1; i <= v2; i++) { AM_Vertex pV1 = Vertex((i - 1) % (GetNumVertex())); AM_Vertex pV2 = Vertex((i) % (GetNumVertex())); Point2d orgCoord = pV1.Coord; // si controlla che tutti i vertici siano in sequenza while (true) { Point2d baseCoord = pbase.DestCoord(); Point2d prvCoord = new Point2d(m_ArrayCoord[(i - 1) % (GetNumVertex())]); Point2d destCoord = new Point2d(m_ArrayCoord[i % (GetNumVertex())]); if (baseCoord == destCoord) { // 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 if (!bStraight) { // 1. Algoritmo di ripristino del bordo con l'aggiunta del punto medio baddFlag = true; // si segnala l'aggiunta di un vertice Point3d p1 = m_ArrayCoord[i - 1]; Point3d p2 = (m_ArrayCoord[i % (GetNumVertex())]); Point3d mid = 0.5 * (p1 + p2); Point3d insPt = new Point3d(mid.X, mid.Y, 0); // si inserisce un vertice nel mezzo del AM_Vertex pvertex; mesh.InsertPoint(new Point2d(insPt), insPt.Z, out pvertex); if (pvertex == null) { Debug.Assert(false); //throw 6; } InsertVertex(i, pvertex); v2++; AddArray.Add(insPt); // si ricomincia il controllo pbase = Vertex(i - 1).Edge; pprev = pbase; } else { // 2. Algoritmo di ripristino del bordo con swap di spigoli AM_Edge pdest = Vertex(i).Edge; Vector2d dir = destCoord - orgCoord; dir.Unitize(); var m = AM_Util.AffineMatrix(orgCoord, dir); while (pV1.FindEdge(pV2) == null) { bool bCoinc = false; AM_Edge pSearch = pbase; // Si controllano situazioni di appartenenza al lato da ripristinare do { double cosang = Vector2d.Multiply(pSearch.GetVersor(), dir); if (AM_Util.IsEqual(cosang, 1, AM_Util.FLT_EPSILON)) { // Lo spigolo appartiene già al lato da ripristinare InsertVertex(i, pSearch.Destination()); v2++; Point2d dc = pSearch.DestCoord(); AddArray.Add(new Point3d(dc.X, dc.Y, 0)); // si ricomincia il controllo pbase = Vertex(i - 1).Edge; pprev = pbase; bCoinc = true; break; } pSearch = pSearch.Next; } while (pSearch != pbase); if (bCoinc) { break; } // Trova il lato di partenza pSearch = pbase; while (!AM_Util.IsInside(pSearch.GetVector(), pSearch.Next.GetVector(), dir)) { pSearch = pSearch.Next; if (pSearch == pprev) { Debug.Assert(false); //mesh.ExportMesh("RecoverSt7.txt"); return(false); } } AM_Edge pStartEdge = pSearch.CcwEdge(); List <AM_Edge> swapArray = new List <AM_Edge>(); while (pStartEdge.Destination() != pV2) { Point2d o = pStartEdge.OrgCoord(); Point2d d = pStartEdge.DestCoord(); swapArray.Add(pStartEdge); pStartEdge = pStartEdge.Prev; Point2d pt = AM_Util.ToLocal(m, pStartEdge.DestCoord()); if (pt.Y < -AM_Util.FLT_EPSILON) { pStartEdge = pStartEdge.CcwEdge(); Debug.Assert(AM_Util.ToLocal(m, pStartEdge.DestCoord()).Y > 0); } } for (int j = 0; j < swapArray.Count; j++) { AM_Edge pSwapEdge = swapArray[j]; // Vengono ruotati gli spigoli all'interno if (AM_Util.CheckSwapEdge(pSwapEdge)) { Debug.Assert(pSearch.CcwFace() != null && pSearch.Next.CwFace() != null); Debug.Assert(pSwapEdge.CcwFace() != null && pSwapEdge.CwFace() != null); AM_Face.SwapEdge(pSwapEdge); } } } } } } } pbase = Vertex(i % (GetNumVertex())).Edge; pprev = pbase; } return(baddFlag); }
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); }
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); }
bool RefineMeshStep() { AM_Face face = null; Point2d innerPoint; AM_Face triangleContaining = null; face = FindMaxActive(); if (face == null) { return(false); } m_StartingEdge = face.GetStartingEdge(); innerPoint = face.InsertPoint(m_pSpaceFunction); //localizzo il triangolo che contiene il punto per fare il test di spaziatura. AM_Edge e = Locate(innerPoint); triangleContaining = e != null? (AM_Edge.RightOf(innerPoint, e) ? e.CwFace() : e.CcwFace()) : null; if (triangleContaining == null) { DeleteActiveFace(face); } else { //innerPoint.Z = triangleContaining.SpaceFunction(innerPoint, m_pSpaceFunction); double s = triangleContaining.SpaceFunction(innerPoint, m_pSpaceFunction); if (triangleContaining.SpacingTest(innerPoint, m_pSpaceFunction)) { AM_Vertex vertex; if (!InsertPoint(innerPoint, s, out vertex)) { DeleteActiveFace(face); } } else { DeleteActiveFace(face); } } return(true); }