//////////////////////////////////////////////////////////////////////////////// // // File: hgrid.cxx // Created by: Jerzy Majewski - jmajewsk@meil.pw.edu.pl // Modified by: // 2005-04-19 JM: mbIsOutside flag for HGrdTri was not initialized; // CheckBoundIntegr was creating flat or negative triangles // // Copyright notice: // Copyright (C) 2000-2003 Jerzy Majewski // // This is free software. You can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License // as published by the Free Software Foundation. // // This software is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY. See the GNU Lesser General Public License // for more details. // //////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include "hgrid.h" #include "EarThwormDef.h" MGFloat Angle( const Vect2D &nd, const Vect2D &nd1, const Vect2D &nd2) { static Vect2D v1, v2; static MGFloat dvect, dsin, dcos; //v1 = nd1 - nd; //v2 = nd2 - nd; v1 = (nd1 - nd).module(); v2 = (nd2 - nd).module(); dsin = v1.X()*v2.Y() - v2.X()*v1.Y(); dcos = v1.X()*v2.X() + v1.Y()*v2.Y(); if ( fabs( dsin) < ZERO && fabs( dcos) < ZERO) return M_PI_2; dvect = atan2( dsin, dcos); return dvect; } bool CheckCrossing( const Vect2D& v1, const Vect2D& v2, const Vect2D& v3, const Vect2D& v4) { Vect2D vv, vv1, vv2; MGFloat t1, t2, t; MGFloat h1, h2; vv = v2 - v1; vv1 = v3 - v1; vv2 = v4 - v1; ASSERT( fabs( vv.module() ) > ZERO ); t1 = vv * vv1 / vv.module(); t2 = vv * vv2 / vv.module(); h1 = (vv.X()*vv1.Y() - vv.Y()*vv1.X()) / vv.module(); h2 = (vv.X()*vv2.Y() - vv.Y()*vv2.X()) / vv.module(); if ( fabs( h2 - h1) < ZERO) return false; t = t1 - (t2 - t1)/(h2 - h1) * h1; if ( t > 0.0 && t < vv.module() && h1 * h2 < ZERO ) return true; else return false; } bool AreNeigbours( const IterGCell& ic1, const IterGCell& ic2) { char sbuf[256]; bool b1, b2; // TRACE2( "itrcl = %d %d", ic1, *ic1); // (*ic1)->DumpTri(); // TRACE2( "itrcl = %d %d", ic2, *ic2); // (*ic2)->DumpTri(); b1 = b2 = false; for ( int i=0; iCell(i) != NULL) if ( (*ic1)->Cell(i) == ic2 ) b1 = true; // if ( (*ic2)->Cell(i) != NULL) if ( (*ic2)->Cell(i) == ic1 ) b2 = true; } sprintf( sbuf, " b1 = %d b2 = %d", static_cast(b1), static_cast(b2) ); TRACE( sbuf); if ( !b1 || !b2) THROW_INTERNAL( "Not neighbours found"); return true; } ////////////////////////////////////////////////////////////////////// /// class HGrdTri ////////////////////////////////////////////////////////////////////// HGrdTri::HGrdTri() : mbIsOutside( false) { for ( MGInt i=0; i ZERO && d1 < -ZERO) ) return false; else return true; } bool HGrdTri::IsVisibleDump( const IterGCell& icl, const Vect2D& vct) { // static Vect2D vfac, v1, v2; // static MGFloat d1, d2; // static char sbuf[1024]; Vect2D vfac, v1, v2; MGFloat d1, d2; THROW_INTERNAL("Should not be used !!!"); if ( Cell(0) == icl ) { v1 = *( (*Node(0)) ) - *( (*Node(2)) ); v2 = *( (*Node(1)) ) - *( (*Node(2)) ); vfac = vct - *( (*Node(2)) ); } else if ( Cell(1) == icl ) { v1 = *( (*Node(1)) ) - *( (*Node(0)) ); v2 = *( (*Node(2)) ) - *( (*Node(0)) ); vfac = vct - *( (*Node(0)) ); } else if ( Cell(2) == icl ) { v1 = *( (*Node(2)) ) - *( (*Node(1)) ); v2 = *( (*Node(0)) ) - *( (*Node(1)) ); vfac = vct - *( (*Node(1)) ); } else { ASSERT( 0); } d1 = v1.X()*vfac.Y() - v1.Y()*vfac.X(); d2 = v2.X()*vfac.Y() - v2.Y()*vfac.X(); if ( d1 * d2 > ZERO ) { TRACE2( "v1 = (%lg %lg)", v1.X(), v1.Y() ); TRACE2( "v2 = (%lg %lg)", v2.X(), v2.Y() ); TRACE2( "vf = (%lg %lg)", vfac.X(), vfac.Y() ); TRACE2( "d1 = %lg d1 = %lg", d1, d2 ); return false; } else return true; } void HGrdTri::SetNeighbour( const IterGCell& itrcl) { static HGrdTri *ptr; ASSERT( itrcl != NULL); ptr = (*itrcl); ASSERT( ptr); if ( ( ptr->Node(1) == Node(0) && ptr->Node(0) == Node(1) ) || ( ptr->Node(0) == Node(0) && ptr->Node(2) == Node(1) ) || ( ptr->Node(2) == Node(0) && ptr->Node(1) == Node(1) ) ) { rCell(0) = itrcl; } else if ( ( ptr->Node(1) == Node(1) && ptr->Node(0) == Node(2) ) || ( ptr->Node(0) == Node(1) && ptr->Node(2) == Node(2) ) || ( ptr->Node(2) == Node(1) && ptr->Node(1) == Node(2) ) ) { rCell(1) = itrcl; } else if ( ( ptr->Node(1) == Node(2) && ptr->Node(0) == Node(0) ) || ( ptr->Node(0) == Node(2) && ptr->Node(2) == Node(0) ) || ( ptr->Node(2) == Node(2) && ptr->Node(1) == Node(0) ) ) { rCell(2) = itrcl; } } void HGrdTri::NullifyThis( HGrdTri *pcl) { for ( MGInt i=0; iPntLf() == Node(0) && pseg->PntLf() == Node(1) ) || ( pseg->PntRt() == Node(0) && pseg->PntRt() == Node(1) ) ) { rCell(0) = IterGCell(); } else if ( ( pseg->PntLf() == Node(1) && pseg->PntLf() == Node(2) ) || ( pseg->PntRt() == Node(1) && pseg->PntRt() == Node(2) ) ) { rCell(1) = IterGCell(); } else if ( ( pseg->PntLf() == Node(2) && pseg->PntLf() == Node(0) ) || ( pseg->PntRt() == Node(2) && pseg->PntRt() == Node(0) ) ) { rCell(2) = IterGCell(); } } void HGrdTri::InvalidateNeighb() { for ( MGInt i=0; iNullifyThis( this); } } bool HGrdTri::IsInside( const Vect2D& vct) { // ::TODO:: new and faster algorithm should be introduced MGFloat alf; alf = ::Angle( vct, *(*Node(0)), *(*Node(1)) ); alf += ::Angle( vct, *(*Node(1)), *(*Node(2)) ); alf += ::Angle( vct, *(*Node(2)), *(*Node(0)) ); if ( fabs(alf) < M_PI ) return false; else return true; } bool HGrdTri::SetCircCenter() { static MGFloat x1, y1, x2, y2, x3, y3; static MGFloat xr, yr, d; x1 = (*Node(0))->X(); y1 = (*Node(0))->Y(); x2 = (*Node(1))->X(); y2 = (*Node(1))->Y(); x3 = (*Node(2))->X(); y3 = (*Node(2))->Y(); d = y3*(x2 - x1) + y2*(x1 - x3) + y1*(x3 - x2); if ( fabs( d) < ZERO) { DumpTri(); TRACE1( "d = %lg", d); return true; // THROW_INTERNAL( "Problem inside SetCircCenter() !!!"); } xr = x1*x1*(y3-y2) + x2*x2*(y1-y3) + x3*x3*(y2-y1) + y1*y1*(y3-y2) + y2*y2*(y1-y3) + y3*y3*(y2-y1); xr *= -0.5/d; yr = x1*x1*(x3-x2) + x2*x2*(x1-x3) + x3*x3*(x2-x1) + y1*y1*(x3-x2) + y2*y2*(x1-x3) + y3*y3*(x2-x1); yr *= 0.5/d; mCircCenter = Vect2D( xr, yr); return false; } Vect2D HGrdTri::Center() { return ( *(*Node(0)) + *(*Node(1)) + *(*Node(2)) )/3.0; } IterGCell HGrdTri::NextCell( const Vect2D& vct) { static Vect2D v1, v2; if ( Cell(0) != IterGCell()) { v1 = *(*Node(1)) - *(*Node(0)); v1 = Vect2D( -v1.Y(), v1.X() ); v2 = ( *(*Node(1)) + *(*Node(0)) )/2.0; v2 = vct - v2; if ( v1 * v2 < 0.0 ) return Cell(0); } if ( Cell(1) != IterGCell()) { v1 = *(*Node(2)) - *(*Node(1)); v1 = Vect2D( -v1.Y(), v1.X() ); v2 = ( *(*Node(2)) + *(*Node(1)) )/2.0; v2 = vct - v2; if ( v1 * v2 < 0.0 ) return Cell(1); } if ( Cell(2) != IterGCell()) { v1 = *(*Node(0)) - *(*Node(2)); v1 = Vect2D( -v1.Y(), v1.X() ); v2 = ( *(*Node(0)) + *(*Node(2)) )/2.0; v2 = vct - v2; if ( v1 * v2 < 0.0 ) return Cell(2); } return IterGCell(); } IterGCell HGrdTri::NextCell( HFroSeg *pseg, const IterGCell& iclprv) { IterGCell itrnb, itr1, itr2; Vect2D v1, v2, v3, v4; v1 = *(*(pseg->PntLf())); v2 = *(*(pseg->PntRt())); if ( iclprv == IterGCell()) { if ( Node(0) == pseg->PntLf() ) { v3 = *(*Node(1)); v4 = *(*Node(2)); itrnb = Cell(1); if ( Node(1) == pseg->PntRt() || Node(2) == pseg->PntRt() ) return IterGCell(); } else if ( Node(1) == pseg->PntLf() ) { v3 = *(*Node(2)); v4 = *(*Node(0)); itrnb = Cell(2); if ( Node(2) == pseg->PntRt() || Node(0) == pseg->PntRt() ) return IterGCell(); } else if ( Node(2) == pseg->PntLf() ) { v3 = *(*Node(0)); v4 = *(*Node(1)); itrnb = Cell(0); if ( Node(0) == pseg->PntRt() || Node(1) == pseg->PntRt() ) return IterGCell(); } else { THROW_INTERNAL("NextCell - seg: node not found"); } if ( ::CheckCrossing( v1, v2, v3, v4 ) == true) { return itrnb; } else return IterGCell(); } else { int k; for ( int i=0; iPntLf(); ipnt2 = (*itr)->PntRt(); alf += ::Angle( vct, *(*ipnt1), *(*ipnt2) ); } return alf; } ////////////////////////////////////////////////////////////////////// // class HGrid ////////////////////////////////////////////////////////////////////// HGrid::~HGrid() { CollGPnt::iterator itrpnt; CollGCell::iterator itrcell; for ( itrpnt = mcolPnt.begin(); itrpnt != mcolPnt.end(); itrpnt++) if ( (*itrpnt) != NULL) DELETE_PTR((*itrpnt)); for ( itrcell = mcolCell.begin(); itrcell != mcolCell.end(); itrcell++) if ( (*itrcell) != NULL) DELETE_PTR((*itrcell)); } void HGrid::Init( const std::vector& tabp, const std::vector& tabn ) { MGInt i, j, nprev; IterFro ifro; HGrdPnt *ppnt; IterGPnt ip0, ipp, ipa; HFroSeg *pfro; Vect2D v0, v1, v2; std::map< Vect2D, IterGPnt> mapNod; std::map< Vect2D, IterGPnt>::iterator imap; // char sbuf[512]; double d; nprev = 0; for ( i=0; i<(MGInt)tabn.size(); ++i) { v1 = tabp[nprev]; v2 = tabp[nprev+tabn[i]-1]; d = (v2-v1).module(); // sprintf( sbuf, "front %d closure(%lg %lg) (%lg %lg) = %lg ", i, v1.X(), v1.Y(), v2.X(), v2.Y(), d); // TRACE( sbuf); if ( (v2-v1).module() < ZERO) { ifro = mcolFro.insert( mcolFro.end(), HFront() ); imap = mapNod.find( tabp[nprev]); if ( imap != mapNod.end() ) { ip0 = ipp = ipa = (*imap).second; } else { ppnt = MGNEW HGrdPnt( tabp[nprev]); ppnt->rIndex() = nprev; ip0 = ipp = ipa = InsertPoint( ppnt); mapNod.insert( std::map< Vect2D, IterGPnt>::value_type( *ppnt, ipa) ); } v0 = *(*ip0); for ( j=1; j ZERO) { if ( j != tabn[i]-1 || (tabp[nprev+j] - v0 ).module() > ZERO) { imap = mapNod.find( tabp[nprev+j]); if ( imap != mapNod.end() ) { ipa = (*imap).second; ppnt = *ipa; } else { ppnt = MGNEW HGrdPnt( tabp[nprev+j]); ppnt->rIndex() = nprev+j; ipa = InsertPoint( ppnt); mapNod.insert( std::map< Vect2D, IterGPnt>::value_type( *ppnt, ipa) ); } pfro = MGNEW HFroSeg( ipp, ipa); (*ifro).insert( (*ifro).end(), pfro); ipp = ipa; } } } v1 = *(*ipp); v2 = *(*ip0); if ( (v2 - v1).module() > ZERO) { pfro = MGNEW HFroSeg( ipp, ip0); (*ifro).insert( (*ifro).end(), pfro); } } nprev += tabn[i]; } IterFro itrfro; IterFSeg itrsg; IterGPnt ip1, ip2; for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); ++itrfro) { // TRACE1( "Front size = %d\n", (*itrfro).size() ); itrsg = (*itrfro).begin(); ip0 = (*itrsg)->PntLf(); ip1 = (*itrsg)->PntRt(); for ( ++itrsg; itrsg != (*itrfro).end(); ++itrsg) { if ( (*itrsg)->PntLf() != ip1 ) { TRACE( "Front not consistent !!!\n"); } ip1 = (*itrsg)->PntRt(); v1 = *(*(*itrsg)->PntLf()); v2 = *(*(*itrsg)->PntRt()); if ( (v2 - v1).module() < ZERO) TRACE1( "seg length = %24.16lg\n", (v2 - v1).module() ); } if ( ip0 != ip1 ) { TRACE( "Front not consistent (closure problem) !!!\n"); } } // ASSERT(0); #ifdef _DEBUG FILE *f = fopen( "front.plt", "wt"); int isize = 0; for ( isize = 0, itrfro = mcolFro.begin(); itrfro != mcolFro.end(); ++itrfro, ++isize) { fprintf( f, "VARIABLES = \"X\", \"Y\"\n" ); fprintf( f, "ZONE I=%d F=POINT\n", (*itrfro).size()+1); for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); ++itrsg) { v1 = *(*(*itrsg)->PntLf()); v2 = *(*(*itrsg)->PntRt()); fprintf( f, "%lg %lg\n", v1.X(), v1.Y() ); } fprintf( f, "%lg %lg\n", v2.X(), v2.Y() ); } fclose( f); #endif // _DEBUG } HFroSeg* HGrid::NewFace( MGInt i, IterGCell icl) { HFroSeg* psg; THROW_ALLOC( psg = MGNEW HFroSeg() ); switch ( i) { case 0: psg->rPntLf() = (*icl)->Node(0); psg->rPntRt() = (*icl)->Node(1); if ( icl != IterGCell()) { psg->rCellUp() = icl; psg->rCellLo() = (*icl)->Cell(0); } break; case 1: psg->rPntLf() = (*icl)->Node(1); psg->rPntRt() = (*icl)->Node(2); if ( icl != IterGCell()) { psg->rCellUp() = icl; psg->rCellLo() = (*icl)->Cell(1); } break; case 2: psg->rPntLf() = (*icl)->Node(2); psg->rPntRt() = (*icl)->Node(0); if ( icl != IterGCell()) { psg->rCellUp() = icl; psg->rCellLo() = (*icl)->Cell(2); } break; default: if ( psg) DELETE_PTR(psg); ASSERT( 0); return NULL; }; return psg; } bool HGrid::CheckNeighb( IterGCell icl, CollFSeg& lstsg, const Vect2D& vct, const IterGCell& ipvcl) { HGrdTri *pthis; pthis = (HGrdTri*)( (*icl) ); if ( pthis->IsInsideCirc( vct ) == true ) { HGrdTri *ptri; HFroSeg *pseg; IterGCell itri; IterGPnt ipnt; bool bVis; for ( int i=0; iCell(i) != ipvcl || ipvcl == IterGCell()) { pseg = NewFace( i, icl); // this allocate memory for pseg !!! itri = (*icl)->Cell(i); bVis = false; if ( itri != IterGCell()) if ( (*itri)->IsOutside() == true) itri = IterGCell(); if ( itri != IterGCell()) { ptri = (HGrdTri*)( (*itri) ); ASSERT( ptri); bVis = ptri->IsVisible( icl, vct); } if ( itri != IterGCell() && bVis) { if ( CheckNeighb( itri, lstsg, vct, icl ) == true ) { DELETE_PTR(pseg); } else { lstsg.insert( lstsg.end(), pseg ); pseg->rCellUp() = IterGCell(); } } else { lstsg.insert( lstsg.end(), pseg ); pseg->rCellUp() = IterGCell(); } } } ptri = (HGrdTri*)( (*icl) ); ptri->InvalidateNeighb(); mcolCell.erase( icl); DELETE_PTR(ptri); return true; } return false; } MGInt HGrid::InsertPointIntoMesh( IterGPnt pntitr) { Vect2D vct; IterGCell itrcl, itrcl2, itrcl0, itrclout; HGrdTri *ptri; CollFSeg *plstsg; IterFSeg itrsg, itrsg2; HFroSeg *pseg; static int num = 0; ++num; vct = *(*pntitr); // sprintf( sbuf, "POINT No = %d; x=%14.8lg, y=%14.8lg", num , vct.X(), vct.Y() ); // TRACE1( "%s", sbuf); itrcl = mcolCell.begin(); do { itrcl0 = (*itrcl)->NextCell( vct); if ( itrcl0 == IterGCell()) break; itrcl = itrcl0; } while ( true); THROW_ALLOC( plstsg = MGNEW CollFSeg ); // next function creates segments bounding Delaunay cavity (stored in plstsg) // removes cavity triangles from mcolCell; // ALL ITERATORS TO THOSE CELLS ARE THEN INVALID !!! // iterators to those cells are set to NULL CheckNeighb( itrcl, *plstsg, vct, IterGCell()); // sorting segments stored in plstsg itrsg = plstsg->end(); itrsg--; do { for ( itrsg2 = plstsg->begin(); itrsg2 != plstsg->end(); itrsg2++) { if ( (*itrsg)->PntLf() == (*itrsg2)->PntRt() ) { pseg = (*itrsg2); plstsg->erase( itrsg2); itrsg = plstsg->insert( itrsg, pseg ); break; } } } while ( itrsg != plstsg->begin() ); // creating new triangles and connections between triangles in Delaunay cavity itrcl0 = itrcl2 = IterGCell(); for ( itrsg = plstsg->begin(); itrsg != plstsg->end(); itrsg++) { THROW_ALLOC( ptri = MGNEW HGrdTri ); itrclout = (*itrsg)->CellLo(); ptri->rNode(0) = (*itrsg)->PntLf(); ptri->rNode(1) = (*itrsg)->PntRt(); ptri->rNode(2) = pntitr; ptri->rCell(0) = itrclout; if ( ptri->SetCircCenter() ) { FILE *f = fopen( "cavity.plt", "wt"); ExportTECTmp( f); fclose( f); TRACE1( "num = %d", num); TRACE2( "new point = %lg %lg", vct.X(), vct.Y() ); TRACE1( "no of segs bounding cavity = %d", plstsg->size() ); FILE *ff = fopen( "cavity_front.plt", "wt"); fprintf( ff, "VARIABLES = \"X\", \"Y\"\n"); fprintf( ff, "ZONE I=%d F=POINT\n", plstsg->size()+1 ); fprintf( ff, "%lg %lg\n", (*(*plstsg->begin())->PntLf())->X(), (*(*plstsg->begin())->PntLf())->Y() ); for ( itrsg = plstsg->begin(); itrsg != plstsg->end(); itrsg++) fprintf( ff, "%lg %lg\n", (*(*itrsg)->PntRt())->X(), (*(*itrsg)->PntRt())->Y() ); fclose( ff); THROW_INTERNAL("Flat triangle !!!"); } itrcl = InsertCell( ptri); if ( itrclout != IterGCell()) (*itrclout)->SetNeighbour( itrcl); if ( itrcl0 == IterGCell()) itrcl0 = itrcl; if ( itrcl2 != IterGCell()) { (*itrcl)->rCell(2) = itrcl2; (*itrcl2)->rCell(1) = itrcl; } itrcl2 = itrcl; } if ( itrcl2 != IterGCell() && itrcl0 != IterGCell()) { (*itrcl0)->rCell(2) = itrcl2; (*itrcl2)->rCell(1) = itrcl0; } // removing all segments stored in plstsg for ( itrsg = plstsg->begin(); itrsg != plstsg->end(); itrsg++) if ( (*itrsg) != NULL ) DELETE_PTR((*itrsg)); if ( plstsg) DELETE_PTR(plstsg); return num; } bool HGrid::PointExists( const Vect2D& vct) { // Leaf *pndlf; // IterFacGPnt ipn; // // pndlf = mPntQTree.ClosestItem( vct ); // if ( pndlf != NULL) // { // ipn = pndlf->Data(); // // if ( fabs( (*ipn)->X() - vct.X() ) < ZERO && // fabs( (*ipn)->Y() - vct.Y() ) < ZERO ) // { // return true; // } // } // return false; } // creates basic trinagulation (two triangles) and inserts all boundary points void HGrid::InitTriangles() { CollGPnt::iterator itr; Vect2D vmin, vmax, vct; bool bFirst = true; HGrdPnt *pnd1, *pnd2, *pnd3, *pnd4; HGrdTri *ptri1, *ptri2; IterGPnt ind1, ind2, ind3, ind4; IterGCell itri1, itri2; ind1 = ind2 = ind3 = ind4 = IterGPnt(); itri1 = itri2 = IterGCell(); // finding limits for ( itr = mcolPnt.begin(); itr != mcolPnt.end(); itr++) { vct = *(*itr); if ( bFirst) { vmin = vmax = vct; bFirst = false; } else { if ( vct.X() > vmax.X() ) vmax.rX() = vct.X(); if ( vct.Y() > vmax.Y() ) vmax.rY() = vct.Y(); if ( vct.X() < vmin.X() ) vmin.rX() = vct.X(); if ( vct.Y() < vmin.Y() ) vmin.rY() = vct.Y(); } } vct = (vmax - vmin)/1.5; vmax += vct; vmin -= vct; mBox = HRect( vmin.X(), vmin.Y(), vmax.X(), vmax.Y() ); // creating starting triangulation containing two cells and four points THROW_ALLOC( pnd1 = MGNEW HGrdPnt( vmin) ); THROW_ALLOC( pnd2 = MGNEW HGrdPnt( vmax.X(), vmin.Y()) ); THROW_ALLOC( pnd3 = MGNEW HGrdPnt( vmax) ); THROW_ALLOC( pnd4 = MGNEW HGrdPnt( vmin.X(), vmax.Y()) ); THROW_ALLOC( ptri1 = MGNEW HGrdTri() ); THROW_ALLOC( ptri2 = MGNEW HGrdTri() ); mind1 = ind1 = InsertPoint( pnd1); mind2 = ind2 = InsertPoint( pnd2); mind3 = ind3 = InsertPoint( pnd3); mind4 = ind4 = InsertPoint( pnd4); itri1 = InsertCell( ptri1); itri2 = InsertCell( ptri2); ptri1->rNode(0) = ind1; ptri1->rNode(1) = ind2; ptri1->rNode(2) = ind3; ptri2->rNode(0) = ind3; ptri2->rNode(1) = ind4; ptri2->rNode(2) = ind1; ptri1->rCell(2) = itri2; ptri2->rCell(2) = itri1; ptri1->SetCircCenter(); ptri2->SetCircCenter(); // inserting frontal points into mesh IterFro itrfro; IterFSeg itrsg; std::map mapNod; std::map::iterator imap; for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++) { for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++) { itr = (*itrsg)->rPntRt(); if ( ( imap = mapNod.find( *itr) ) == mapNod.end() ) { InsertPointIntoMesh( itr); mapNod.insert( std::map::value_type( *itr, 0) ); } } } #ifdef _DEBUG FILE *ftmp = fopen( "initial.plt", "wt"); ExportTECTmp( ftmp); fclose( ftmp); #endif // _DEBUG } bool HGrid::IsOutside( const Vect2D& vct) { IterFro itrfro; IterFSeg itrsg; Vect2D v1, v2; double x; //// winding algorithm // MGFloat alf; // for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++) // { // alf += (*itrfro).Angle( vct); // } // if ( fabs(alf) < M_PI ) // return true; // else // return false; // ray casting algorithm MGInt cross = 0; for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++) for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++) { v1 = *(*(*itrsg)->PntLf()); v2 = *(*(*itrsg)->PntRt()); if ( ( v1.Y() > vct.Y() && v2.Y() <= vct.Y() ) || ( v2.Y() > vct.Y() && v1.Y() <= vct.Y() ) ) { // x = ( v1.X()*v2.Y() - v1.Y()*v2.X() ) / ( v2.Y() - v1.Y() ); x = ( v2.X() - v1.X() ) * ( vct.Y() - v1.Y() ) / ( v2.Y() - v1.Y() ) + v1.X(); if ( x > vct.X() ) ++cross; } } if ( (cross % 2) == 1 ) return false; else return true; } void HGrid::FlagOuterTris() { IterFro itrfro; IterFSeg itrsg; IterGCell itr, itrnb, itrcl;; Vect2D vout, vcnt, vc1, vc2; CollGCell colCell; // // flaging all triangles lying outside domain using N^2 algo // for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++) // { // if( IsOutside( (*itr)->Center() ) ) // (*itr)->rIsOutside() = true; // else // (*itr)->rIsOutside() = false; // } Vect2D v1, v2, vct; MGInt cross = 0; HGrdTri *ptri; MGFloat x, y1, y2; std::multimap mapCell; std::multimap::iterator imap, ifirst, ilast; for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++) { vct = (*itr)->Center(); (*itr)->rCross() = 0; mapCell.insert( std::multimap::value_type( vct.Y(), (*itr) ) ); } for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++) for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++) { v1 = *(*(*itrsg)->PntLf()); v2 = *(*(*itrsg)->PntRt()); if ( v1.Y() > v2.Y() ) { y1 = v2.Y(); y2 = v1.Y(); } else { y1 = v1.Y(); y2 = v2.Y(); } ifirst = mapCell.lower_bound( y1 ); ilast = mapCell.upper_bound( y2 ); for ( imap = ifirst; imap != ilast; ++imap) { ptri = (*imap).second; vct = ptri->Center(); if ( ( v1.Y() > vct.Y() && v2.Y() <= vct.Y() ) || ( v2.Y() > vct.Y() && v1.Y() <= vct.Y() ) ) { x = ( v2.X() - v1.X() ) * ( vct.Y() - v1.Y() ) / ( v2.Y() - v1.Y() ) + v1.X(); if ( x > vct.X() ) ++(ptri->rCross()); } } } for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++) { if ( ((*itr)->rCross() % 2) == 1 ) (*itr)->rIsOutside() = false; else (*itr)->rIsOutside() = true; } } void HGrid::RemoveOuterTris() { IterGCell itr, itr2; HGrdTri *ptri; itr2 = IterGCell(); for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++) { if ( itr2 != IterGCell()) { ptri = *itr2; (*itr2)->InvalidateNeighb(); mcolCell.erase( itr2); DELETE_PTR(ptri); itr2 = IterGCell(); } if ( (*itr)->IsOutside() ) itr2 = itr; } if ( itr2 != IterGCell()) { ptri = *itr2; (*itr2)->InvalidateNeighb(); mcolCell.erase( itr2); DELETE_PTR(ptri); itr2 = IterGCell(); } if ( *mind1) DELETE_PTR(*mind1); if ( *mind2) DELETE_PTR(*mind2); if ( *mind3) DELETE_PTR(*mind3); if ( *mind4) DELETE_PTR(*mind4); mcolPnt.erase( mind1); mcolPnt.erase( mind2); mcolPnt.erase( mind3); mcolPnt.erase( mind4); mind1 = IterGPnt(); mind2 = IterGPnt(); mind3 = IterGPnt(); mind4 = IterGPnt(); } bool HGrid::CheckSwapTriangles( HGrdTri *ptri1, HGrdTri *ptri2) { HGrdTri tri1, tri2; tri1 = *ptri1; tri2 = *ptri2; SwapTriangles( &tri1, &tri2, false); if ( !tri1.Check() || !tri2.Check() ) return false; if ( tri1.Area() < 0 || tri2.Area() < 0 ) return false; return true; } void HGrid::SwapTriangles( HGrdTri *ptri1, HGrdTri *ptri2, bool bgo) { MGInt ifc1, ifc2; IterGPnt ip1, ip2, ip3, ip4; IterGCell ic1, ic2, ic3, ic4; IterGCell itri1, itri2; // TRACE( "--- swapping !!!"); if ( ptri2->Node(1) == ptri1->Node(0) && ptri2->Node(0) == ptri1->Node(1) ) { ip1 = ptri2->Node(1); ip2 = ptri2->Node(2); ip3 = ptri2->Node(0); ip4 = ptri1->Node(2); ifc1 = 0; ifc2 = 0; ic1 = ptri2->Cell(1); ic2 = ptri2->Cell(2); ic3 = ptri1->Cell(1); ic4 = ptri1->Cell(2); itri1 = ptri2->Cell(0); itri2 = ptri1->Cell(0); } else if ( ptri2->Node(0) == ptri1->Node(0) && ptri2->Node(2) == ptri1->Node(1) ) { ip1 = ptri2->Node(0); ip2 = ptri2->Node(1); ip3 = ptri2->Node(2); ip4 = ptri1->Node(2); ifc1 = 0; ifc2 = 2; ic1 = ptri2->Cell(0); ic2 = ptri2->Cell(1); ic3 = ptri1->Cell(1); ic4 = ptri1->Cell(2); itri1 = ptri2->Cell(2); itri2 = ptri1->Cell(0); } else if ( ptri2->Node(2) == ptri1->Node(0) && ptri2->Node(1) == ptri1->Node(1) ) { ip1 = ptri2->Node(2); ip2 = ptri2->Node(0); ip3 = ptri2->Node(1); ip4 = ptri1->Node(2); ifc1 = 0; ifc2 = 1; ic1 = ptri2->Cell(2); ic2 = ptri2->Cell(0); ic3 = ptri1->Cell(1); ic4 = ptri1->Cell(2); itri1 = ptri2->Cell(1); itri2 = ptri1->Cell(0); } else if ( ptri2->Node(1) == ptri1->Node(2) && ptri2->Node(0) == ptri1->Node(0) ) { ip1 = ptri2->Node(1); ip2 = ptri2->Node(2); ip3 = ptri2->Node(0); ip4 = ptri1->Node(1); ifc1 = 2; ifc2 = 0; ic1 = ptri2->Cell(1); ic2 = ptri2->Cell(2); ic3 = ptri1->Cell(0); ic4 = ptri1->Cell(1); itri1 = ptri2->Cell(0); itri2 = ptri1->Cell(2); } else if ( ptri2->Node(0) == ptri1->Node(2) && ptri2->Node(2) == ptri1->Node(0) ) { ip1 = ptri2->Node(0); ip2 = ptri2->Node(1); ip3 = ptri2->Node(2); ip4 = ptri1->Node(1); ifc1 = 2; ifc2 = 2; ic1 = ptri2->Cell(0); ic2 = ptri2->Cell(1); ic3 = ptri1->Cell(0); ic4 = ptri1->Cell(1); itri1 = ptri2->Cell(2); itri2 = ptri1->Cell(2); } else if ( ptri2->Node(2) == ptri1->Node(2) && ptri2->Node(1) == ptri1->Node(0) ) { ip1 = ptri2->Node(2); ip2 = ptri2->Node(0); ip3 = ptri2->Node(1); ip4 = ptri1->Node(1); ifc1 = 2; ifc2 = 1; ic1 = ptri2->Cell(2); ic2 = ptri2->Cell(0); ic3 = ptri1->Cell(0); ic4 = ptri1->Cell(1); itri1 = ptri2->Cell(1); itri2 = ptri1->Cell(2); } else if ( ptri2->Node(1) == ptri1->Node(1) && ptri2->Node(0) == ptri1->Node(2) ) { ip1 = ptri2->Node(1); ip2 = ptri2->Node(2); ip3 = ptri2->Node(0); ip4 = ptri1->Node(0); ifc1 = 1; ifc2 = 0; ic1 = ptri2->Cell(1); ic2 = ptri2->Cell(2); ic3 = ptri1->Cell(2); ic4 = ptri1->Cell(0); itri1 = ptri2->Cell(0); itri2 = ptri1->Cell(1); } else if ( ptri2->Node(0) == ptri1->Node(1) && ptri2->Node(2) == ptri1->Node(2) ) { ip1 = ptri2->Node(0); ip2 = ptri2->Node(1); ip3 = ptri2->Node(2); ip4 = ptri1->Node(0); ifc1 = 1; ifc2 = 2; ic1 = ptri2->Cell(0); ic2 = ptri2->Cell(1); ic3 = ptri1->Cell(2); ic4 = ptri1->Cell(0); itri1 = ptri2->Cell(2); itri2 = ptri1->Cell(1); } else if ( ptri2->Node(2) == ptri1->Node(1) && ptri2->Node(1) == ptri1->Node(2) ) { ip1 = ptri2->Node(2); ip2 = ptri2->Node(0); ip3 = ptri2->Node(1); ip4 = ptri1->Node(0); ifc1 = 1; ifc2 = 1; ic1 = ptri2->Cell(2); ic2 = ptri2->Cell(0); ic3 = ptri1->Cell(2); ic4 = ptri1->Cell(0); itri1 = ptri2->Cell(1); itri2 = ptri1->Cell(1); } ASSERT( itri1 != NULL && itri2 != NULL); ptri1->rNode(0) = ip2; ptri1->rNode(1) = ip4; ptri1->rNode(2) = ip1; ptri1->rCell(0) = itri2; ptri1->rCell(1) = ic4; ptri1->rCell(2) = ic1; ptri2->rNode(0) = ip4; ptri2->rNode(1) = ip2; ptri2->rNode(2) = ip3; ptri2->rCell(0) = itri1; ptri2->rCell(1) = ic2; ptri2->rCell(2) = ic3; if ( bgo) { if ( ic1 != IterGCell() ) { if ( (*ic1)->Cell(0) == itri2) (*ic1)->rCell(0) = itri1; else if ( (*ic1)->Cell(1) == itri2) (*ic1)->rCell(1) = itri1; else if ( (*ic1)->Cell(2) == itri2) (*ic1)->rCell(2) = itri1; else ASSERT(0); } if ( ic3 != IterGCell()) { if ( (*ic3)->Cell(0) == itri1) (*ic3)->rCell(0) = itri2; else if ( (*ic3)->Cell(1) == itri1) (*ic3)->rCell(1) = itri2; else if ( (*ic3)->Cell(2) == itri1) (*ic3)->rCell(2) = itri2; else ASSERT(0); } } } void HGrid::CheckBoundIntegr() { // char sbuf[256]; IterFro itrfro; IterFSeg itrsg; Vect2D v1, v2, v3, v4; // CollGCell colCell; CollGCell colPath; CollFSeg colSeg; IterFSeg iseg; IterGCell itr, itrnb, itrcl; Vect2D vcnt; bool bReady, bFound; MGInt k, i=0; std::list lstCell; std::list::iterator itrtmp; std::multimap< HGrdPnt*, IterGCell > mapNod; std::pair< std::multimap< HGrdPnt*, IterGCell >::iterator, std::multimap< HGrdPnt*, IterGCell >::iterator> range[2]; // no of points per froseg std::multimap< HGrdPnt*, IterGCell >::iterator itrmap1, itrmap2; // getting number of front segments int no = 0; for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++) for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++) ++no; for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++) for ( k=0; k::value_type( *(*itr)->Node(k), itr) ); int iii=0; int nrec = 0; for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++) for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++) { ++iii; //if ( iii - 1000*(iii/1000) == 0) // printf( "triang. iter = %d / %d nrec = %d\n", iii, no, nrec); range[0] = mapNod.equal_range( *(*itrsg)->PntLf() ); range[1] = mapNod.equal_range( *(*itrsg)->PntRt() ); bReady = false; for ( itrmap1=range[0].first; itrmap1!=range[0].second; itrmap1++) { itrcl = (*itrmap1).second; lstCell.insert( lstCell.begin(), itrcl ); for ( itrmap2=range[1].first; itrmap2!=range[1].second; itrmap2++) { if ( *itrcl == *(*itrmap2).second ) { bReady = true; goto out_of_loops; } } } out_of_loops: // the segment is missing - must be recovered if ( ! bReady) { ++nrec; //printf( "triang. iter = %d / %d nrec = %d\n", iii, no, nrec); v1 = *(*((*itrsg)->PntLf())); v2 = *(*((*itrsg)->PntRt())); // TRACE( "\n" ); // sprintf( sbuf, "seg (%lg, %lg) (%lg, %lg) - lstCell.size = %d", v1.X(), v1.Y(), v2.X(), v2.Y(), lstCell.size() ); // TRACE( sbuf); bFound = false; for ( itrtmp = lstCell.begin(); itrtmp != lstCell.end(); ++itrtmp) { itr = *itrtmp; if ( ( itrnb = (*itr)->NextCell( *itrsg, IterGCell()) ) != IterGCell()) { bFound = true; break; } } if ( bFound) { IterGCell itr1, itr2, itro1=IterGCell(), itro2=IterGCell(); std::stack stackCell; // CheckGrid(); itr1 = itr; itr2 = itrnb; // TRACE2( "v1 = %lg %lg", v1.X(), v1.Y() ); // TRACE2( "v2 = %lg %lg", v2.X(), v2.Y() ); int niter = 0; do { ++niter; // TRACE( "--- loop start"); // TRACE2( "itrcl = %d / %d", itr1, *itr1); // (*itr1)->DumpTri(); // TRACE2( "itrcl = %d / %d", itr2, *itr2); // (*itr2)->DumpTri(); // check if swap is possible if not then try with another triangles while ( /*! (*itr2)->IsVisible( itr1, v1) ||*/ ! CheckSwapTriangles( *itr1, *itr2 ) || ( itr1 == itro1 && itr2 == itro2 ) ) // avoid swaping the same triangles again { stackCell.push( itr1); itr = itr2; itr2 = (*itr)->NextCell( *itrsg, itr1); itr1 = itr; ASSERT( itr2 != NULL); } itro1 = itr1; itro2 = itr2; // pre swapping - remove itr1 and itr2 from map for ( k=0; k< NUM_TRI; ++k) { range[0] = mapNod.equal_range( *(*itr1)->Node(k) ); for ( itrmap1=range[0].first; itrmap1!=range[0].second; itrmap1++) { if ( (*itrmap1).second == itr1 ) { mapNod.erase( itrmap1); break; } } range[0] = mapNod.equal_range( *(*itr2)->Node(k) ); for ( itrmap1=range[0].first; itrmap1!=range[0].second; itrmap1++) { if ( (*itrmap1).second == itr2 ) { mapNod.erase( itrmap1); break; } } } if ( ! CheckSwapTriangles( *itr1, *itr2 ) ) THROW_INTERNAL( "Recovery: Swap not possible !!!"); SwapTriangles( *itr1, *itr2 ); // post swapping - insert modified itr1 and itr2 into map for ( k=0; k< NUM_TRI; ++k) { mapNod.insert(std:: multimap::value_type( *(*itr1)->Node(k), itr1) ); mapNod.insert( std::multimap::value_type( *(*itr2)->Node(k), itr2) ); } if ( stackCell.empty() ) { itrcl = IterGCell(); itrnb = IterGCell(); if ( (itr = (*itr1)->NextCell( (*itrsg), IterGCell() )) != IterGCell()) { itrcl = itr1; itrnb = itr; } if ( (itr = (*itr2)->NextCell( (*itrsg), IterGCell() )) != IterGCell()) { itrcl = itr2; itrnb = itr; } itr1 = itrcl; itr2 = itrnb; } else { itr1 = stackCell.top(); stackCell.pop(); if ( stackCell.empty() ) itr2 = (*itr1)->NextCell( *itrsg, IterGCell()); else itr2 = (*itr1)->NextCell( *itrsg, stackCell.top()); } } while ( itr1 != IterGCell() && itr2 != IterGCell() ); (*itrsg)->mbtmp = true; } else { char sbuf[1024]; sprintf( sbuf, "recovery problem with seg (%lg, %lg) (%lg, %lg)", v1.X(), v1.Y(), v2.X(), v2.Y() ); TRACE( sbuf); TRACE1( "recovwry lstCell.size = %d", lstCell.size() ); TRACE1( "%d edges already recovered", nrec); FILE *ff = fopen( "lstcell.plt", "wt"); for ( itrtmp = lstCell.begin(); itrtmp != lstCell.end(); ++itrtmp) { (*(*itrtmp))->DumpTEC( ff); } fclose( ff); //printf( "%s\n", sbuf); //printf( "recovery lstCell.size = %d\n", lstCell.size() ); (*itrsg)->mbtmp = true; FILE *f = fopen( "recovery.plt", "wt"); ExportTECTmp( f); fclose( f); THROW_INTERNAL( "Recovery problem !!!"); } } lstCell.erase( lstCell.begin(), lstCell.end() ); } //printf( "%d edges recovered\n", nrec); } void HGrid::Generate() { clock_t start, tstart, finish; double duration; try { tstart = clock(); start = clock(); InitTriangles(); finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; //printf( "InitTriangles() - %2.1f seconds\n\n", duration ); //FILE *f = fopen( "ini.plt", "wt"); //ExportTECTmp( f); //fclose( f); TRACE( "CheckBoundIntegr()"); //printf( "CheckBoundIntegr()\n"); start = clock(); CheckBoundIntegr(); finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; //printf( "CheckBoundIntegr() - %2.1f seconds\n\n", duration ); TRACE( "FlagOuterTris()"); //printf( "FlagOuterTris()\n"); FlagOuterTris(); TRACE( "RemoveOuterTris()"); //printf( "RemoveOuterTris()\n"); RemoveOuterTris(); finish = clock(); duration = (double)(finish - tstart) / CLOCKS_PER_SEC; //printf( "Generation total - %2.1f seconds\n\n", duration ); // FILE *f = fopen( "param.plt", "wt"); // ExportTECTmp( f); // fclose( f); } catch ( Except *pe) { ASSERT( pe); TRACE_EXCEPTION( *pe); TRACE_TO_STDERR( *pe); DELETE_PTR(pe); } } void HGrid::ExportTECTmp( FILE *f) { IterGPnt pntitr; Vect2D vct; IterGCell cellitr, itrcl; MGInt id1, id2, id3, id4; MGInt ltri, ltmp; std::map > tmpMap; TRACE( "ExportTEC"); fprintf( f, "TITLE = \"surface\"\n"); fprintf( f, "VARIABLES = \"X\", \"Y\"\n"); fprintf( f, "ZONE T=\"TRIANGLES\", "); fprintf( f, "N=%2ld, ", mcolPnt.size() ); fprintf( f, "E=%2ld, F=FEPOINT, ET=QUADRILATERAL C=BLACK\n ", ltri = (MGInt)mcolCell.size() ); ltmp = 0; for ( pntitr = mcolPnt.begin(); pntitr != mcolPnt.end(); pntitr++) { ltmp++; vct = *(*pntitr); fprintf( f, "%20.10lg %20.10lg\n", vct.X(), vct.Y() ); tmpMap.insert( std::map >::value_type( (void*)(*pntitr), ltmp )); } TRACE( "after Pnt"); ltri = 0; for ( cellitr = mcolCell.begin(); cellitr != mcolCell.end(); cellitr++) { ltri++; pntitr = (*cellitr)->Node(0); id1 = tmpMap[ (*pntitr)]; pntitr = (*cellitr)->Node(1); id2 = tmpMap[ (*pntitr)]; pntitr = (*cellitr)->Node(2); id4 = id3 = tmpMap[ (*pntitr)]; fprintf( f, "%9ld %9ld %9ld %9ld\n", id1, id2, id3, id4 ); } TRACE( "after Cells"); } void HGrid::CheckGrid() { // char sbuf[256]; bool bFound; IterGCell itr, itrnb; // TRACE("CheckGrid()\n"); for ( itr = mcolCell.begin(); itr != mcolCell.end(); ++itr) { // sprintf( sbuf, "cel = %d | %d %d %d", itr, (*itr)->Cell(0), (*itr)->Cell(1), (*itr)->Cell(2) ); // TRACE( sbuf); for ( int i=0; iCell(i); if ( itrnb != IterGCell()) { ASSERT( *itrnb ); bFound = false; for ( int k=0; kCell(k) == itr ) bFound = true; } } if ( ! bFound) { THROW_INTERNAL( "Cells pointers are not consistent !"); } } } } void HGrid::WriteFrontTEC( const char name[]) { }