EgtGeomKernel 2.3k1 :
- corretto offset di segmenti di retta singoli con estrusione - modifiche per calcolo taglio superfici TriMesh - modifiche a funzione SimplifyFacets di superfici TriMesh.
This commit is contained in:
+10
-11
@@ -23,33 +23,30 @@
|
||||
bool
|
||||
CalcMinDistPointPolyLine( const Point3d& ptP, PolyLine& PL, double dLinTol, MDCVECTOR& vApproxMin)
|
||||
{
|
||||
double dSqDist ;
|
||||
double dPar ;
|
||||
double dUIni ;
|
||||
double dUFin ;
|
||||
Point3d ptIni ;
|
||||
Point3d ptFin ;
|
||||
double dMinDist ;
|
||||
double dSqMinDist ;
|
||||
MinDistCalc approxMin ;
|
||||
|
||||
vApproxMin.reserve( 4) ;
|
||||
vApproxMin.clear() ;
|
||||
|
||||
bool bFound = false ;
|
||||
bool bOnEnd = false ;
|
||||
vApproxMin.reserve( 4) ;
|
||||
vApproxMin.clear() ;
|
||||
double dUIni, dUFin ;
|
||||
Point3d ptIni, ptFin ;
|
||||
double dMinDist, dSqMinDist ;
|
||||
for ( bool bLine = PL.GetFirstULine( &dUIni, &ptIni, &dUFin, &ptFin) ;
|
||||
bLine ;
|
||||
bLine = PL.GetNextULine( &dUIni, &ptIni, &dUFin, &ptFin)) {
|
||||
// calcolo la distanza del punto dal segmento
|
||||
DistPointLine dstPtLn( ptP, ptIni, ptFin) ;
|
||||
double dSqDist ;
|
||||
if ( ! dstPtLn.GetSqDist( dSqDist))
|
||||
continue ;
|
||||
// altro punto con la stessa minima distanza già trovata
|
||||
if ( bFound && abs( dSqDist - dSqMinDist) < 2 * dMinDist * dLinTol) {
|
||||
// salvo i dati nella struttura
|
||||
MinDistCalc approxMin ;
|
||||
approxMin.dDist = dMinDist ;
|
||||
dstPtLn.GetMinDistPoint( approxMin.ptQ) ;
|
||||
double dPar ;
|
||||
dstPtLn.GetParamAtMinDistPoint( dPar) ;
|
||||
approxMin.dPar = ( 1 - dPar) * dUIni + dPar * dUFin ;
|
||||
approxMin.dParMin = dUIni ;
|
||||
@@ -66,8 +63,10 @@ CalcMinDistPointPolyLine( const Point3d& ptP, PolyLine& PL, double dLinTol, MDCV
|
||||
dSqMinDist = dSqDist ;
|
||||
dMinDist = sqrt( dSqMinDist) ;
|
||||
// salvo i dati nella struttura
|
||||
MinDistCalc approxMin ;
|
||||
approxMin.dDist = dMinDist ;
|
||||
dstPtLn.GetMinDistPoint( approxMin.ptQ) ;
|
||||
double dPar ;
|
||||
dstPtLn.GetParamAtMinDistPoint( dPar) ;
|
||||
approxMin.dPar = ( 1 - dPar) * dUIni + dPar * dUFin ;
|
||||
approxMin.dParMin = dUIni ;
|
||||
|
||||
Binary file not shown.
+12
-1
@@ -68,9 +68,20 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType)
|
||||
{
|
||||
// pulisco tutto
|
||||
Reset() ;
|
||||
// verifico se la curva è un segmento di retta
|
||||
bool bIsLine = false ;
|
||||
const CurveLine* pLine = GetBasicCurveLine( pCrv) ;
|
||||
if ( pLine != nullptr)
|
||||
bIsLine = true ;
|
||||
else {
|
||||
const CurveComposite* pCompo = GetBasicCurveComposite( pCrv) ;
|
||||
Point3d ptStart, ptEnd ;
|
||||
if ( pCompo != nullptr && pCompo->IsALine( 10 * EPS_SMALL, ptStart, ptEnd))
|
||||
bIsLine = true ;
|
||||
}
|
||||
// verifico che la curva esista e sia piana
|
||||
Plane3d plPlane ;
|
||||
if ( pCrv == nullptr || ! pCrv->IsFlat( plPlane, false, 10 * EPS_SMALL))
|
||||
if ( pCrv == nullptr || ! pCrv->IsFlat( plPlane, bIsLine, 10 * EPS_SMALL))
|
||||
return false ;
|
||||
// recupero o assegno estrusione
|
||||
Vector3d vtExtr ;
|
||||
|
||||
+178
-437
@@ -21,8 +21,8 @@
|
||||
#include "GeoConst.h"
|
||||
#include "/EgtDev/Include/EGkPolyLine.h"
|
||||
#include "/EgtDev/Include/EGkPlane3d.h"
|
||||
#include "/EgtDev/Include/EGkPolygon3d.h"
|
||||
#include "/EgtDev/Include/EGnStringUtils.h"
|
||||
#include "/EgtDev/Include/EgtNumUtils.h"
|
||||
|
||||
using namespace std ;
|
||||
|
||||
@@ -830,12 +830,11 @@ PolyLine::MyChangeStart( int nPos)
|
||||
// solo per polilinee chiuse
|
||||
if ( ! IsClosed())
|
||||
return false ;
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
// cancello l'ultimo punto ( coincide con il primo)
|
||||
m_lUPoints.pop_back() ;
|
||||
// sposto la metà iniziale dei punti alla fine
|
||||
for ( int i = 0 ; i < nPos ; ++ i)
|
||||
m_lUPoints.splice( m_lUPoints.end(), m_lUPoints, m_lUPoints.begin()) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
// sposto la parte iniziale dei punti alla fine
|
||||
m_lUPoints.splice( m_lUPoints.end(), m_lUPoints, m_lUPoints.begin(), next( m_lUPoints.begin(), nPos)) ;
|
||||
// aggiungo il punto finale come copia dell'iniziale
|
||||
m_lUPoints.push_back( m_lUPoints.front()) ;
|
||||
|
||||
return true ;
|
||||
@@ -1298,478 +1297,220 @@ PolyLine::Trim( const Plane3d& plPlane, bool bInVsOut)
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop)
|
||||
DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dDist)
|
||||
{
|
||||
// Cerco il tratto del loop chiuso più vicino al punto
|
||||
int nMinSeg = - 1 ;
|
||||
double dMinSqDinst = DBL_MAX ;
|
||||
for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = Loop[nPt] ;
|
||||
Point3d ptSegEn = Loop[( nPt + 1) % int( Loop.size())] ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDinst) {
|
||||
dMinSqDinst = dSqDist ;
|
||||
nMinSeg = nPt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, errore
|
||||
if ( dMinSqDinst > SQ_EPS_SMALL)
|
||||
// La polilinea deve contenere almeno due punti
|
||||
if ( plPoly.GetPointNbr() < 2)
|
||||
return false ;
|
||||
// Verifico che il punto stia su un vertice, in tal caso non devo fare nulla
|
||||
bool bOnStart = AreSamePointApprox( Loop[nMinSeg], ptNewStart) ;
|
||||
bool bOnEnd = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptNewStart) ;
|
||||
if ( bOnStart || bOnEnd) {
|
||||
if ( bOnEnd) {
|
||||
++ nMinSeg ;
|
||||
if ( nMinSeg % int( Loop.size()) == 0)
|
||||
return true ;
|
||||
}
|
||||
PNTVECTOR vTempVec ;
|
||||
for ( int nPt = 0 ; nPt < nMinSeg ; ++ nPt)
|
||||
vTempVec.emplace_back( Loop[nPt]) ;
|
||||
int nSize = int( Loop.size()) ;
|
||||
for ( int nPt = 0 ; nPt < nSize - nMinSeg ; ++ nPt) {
|
||||
Loop[nPt] = Loop[nPt + nMinSeg] ;
|
||||
}
|
||||
for ( int nPt = 0 ; nPt < int( vTempVec.size()) ; ++ nPt) {
|
||||
Loop[nPt + nSize - nMinSeg] = vTempVec[nPt] ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
// Ridimensiono il loop
|
||||
Loop.resize( Loop.size() + 1) ;
|
||||
// Copio i primi punti
|
||||
PNTVECTOR LoopTemp ;
|
||||
for ( int nPt = 0 ; nPt <= nMinSeg ; ++ nPt)
|
||||
LoopTemp.emplace_back( Loop[nPt]) ;
|
||||
// Aggiungo il nuovo punto all'inizio
|
||||
Loop[0] = ptNewStart ;
|
||||
// Sposto gli ultimi in testa
|
||||
int nLastPointNum = int( Loop.size()) - 1 - nMinSeg ;
|
||||
for ( int nPt = 1 ; nPt <= nLastPointNum ; ++ nPt) {
|
||||
Loop[nPt] = Loop[nPt + nMinSeg] ;
|
||||
}
|
||||
// Porto i primi in fondo
|
||||
for ( int nPt = 0 ; nPt < int( LoopTemp.size()) ; ++ nPt) {
|
||||
Loop[nPt + nLastPointNum] = LoopTemp[nPt] ;
|
||||
// Ciclo sui punti della polilinea
|
||||
dDist = INFINITO ;
|
||||
Point3d ptStart, ptEnd ;
|
||||
plPoly.GetFirstPoint( ptStart) ;
|
||||
while ( plPoly.GetNextPoint( ptEnd)) {
|
||||
// distanza del punto dal segmento della polilinea
|
||||
DistPointLine PointLineDistCalc( ptP, ptStart, ptEnd) ;
|
||||
double dPlDist ;
|
||||
PointLineDistCalc.GetDist( dPlDist) ;
|
||||
if ( dPlDist < dDist)
|
||||
dDist = dPlDist ;
|
||||
// assegno nuovo inizio
|
||||
ptStart = ptEnd ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2)
|
||||
IsPointInsidePolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler)
|
||||
{
|
||||
// Cerco il tratto del loop chiuso più vicino al punto
|
||||
int nMinSeg = -1 ;
|
||||
double dMinSqDinst = DBL_MAX ;
|
||||
for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = Loop[nPt] ;
|
||||
Point3d ptSegEn = Loop[( nPt + 1) % int(Loop.size())] ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptStop, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDinst) {
|
||||
dMinSqDinst = dSqDist ;
|
||||
nMinSeg = nPt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, errore
|
||||
if ( dMinSqDinst > SQ_EPS_SMALL)
|
||||
// La polilinea deve essere chiusa e piatta, altrimenti non ha senso parlare di interno
|
||||
Plane3d plPlane ;
|
||||
double dArea ;
|
||||
if ( ! plPoly.IsClosedAndFlat( plPlane, dArea, 10 * EPS_SMALL))
|
||||
return false ;
|
||||
// Verifico che il punto stia su un vertice, in tal caso non devo aggiungerlo
|
||||
bool bFirst = AreSamePointApprox( Loop[nMinSeg], ptStop) ;
|
||||
bool bLast = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptStop) ;
|
||||
// Se il punto è sul vertice finale del segmento, aggiungo il vertice alla lista da inglobare al primo loop
|
||||
if ( bLast)
|
||||
++ nMinSeg ;
|
||||
// Inglobo fino a nSeg nel primo loop
|
||||
for ( int nPt = 0 ; nPt <= nMinSeg ; ++ nPt)
|
||||
Loop1.emplace_back( Loop[nPt]) ;
|
||||
// Se il punto è interno al segmento, lo inglobo in entrambi i loop
|
||||
if ( ! ( bFirst || bLast)) {
|
||||
Loop1.emplace_back( ptStop) ;
|
||||
Loop2.emplace_back( ptStop) ;
|
||||
}
|
||||
else {
|
||||
Loop2.emplace_back( Loop[nMinSeg]) ;
|
||||
}
|
||||
// Inglobo gli ultimi vertici in Loop2
|
||||
for ( int nPt = nMinSeg + 1 ; nPt < int( Loop.size()) ; ++ nPt)
|
||||
Loop2.emplace_back( Loop[nPt]) ;
|
||||
Loop2.emplace_back( Loop[0]) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
ChangePolyLineStart( const Point3d& ptNewStart, PolyLine& Loop)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
auto itMinDist = LoopList.end() ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDist = itSt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, errore
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
// Impongo l'orientamento CCW
|
||||
if ( dArea < 0)
|
||||
plPlane.Invert() ;
|
||||
// Il punto deve giacere nel piano della polilinea
|
||||
if ( ! PointInPlaneEpsilon( ptP, plPlane, 10 * EPS_SMALL))
|
||||
return false ;
|
||||
// Se il punto non sta su un vertice del segmento, lo aggiungo. Altrimenti non devo fare nulla.
|
||||
auto itNewPointSt = LoopList.begin() ;
|
||||
auto itNext = itMinDist ;
|
||||
++ itNext ;
|
||||
bool bOnStart = AreSamePointApprox( ptNewStart, itMinDist->first) ;
|
||||
bool bOnEnd = AreSamePointApprox( ptNewStart, itNext->first) ;
|
||||
itNewPointSt = LoopList.emplace( itNext, ptNewStart, 0) ;
|
||||
// Sposto i punti precedenti in coda.
|
||||
bool bStartRemoved = false ;
|
||||
auto it = LoopList.begin() ;
|
||||
while ( it != itNewPointSt) {
|
||||
if ( bStartRemoved) {
|
||||
LoopList.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
bStartRemoved = true ;
|
||||
it = LoopList.erase( it) ;
|
||||
}
|
||||
// Se il punto inserito non coincide con l'inizio del segmento chiudo il loop.
|
||||
if ( ! bOnStart) {
|
||||
LoopList.emplace_back( ptNewStart, 0) ;
|
||||
// Se coincide con la fine tolgo il punto di fine che diviene inutile.
|
||||
if ( bOnEnd) {
|
||||
//LoopList.erase( itNext) ;
|
||||
auto itNewStart = LoopList.begin() ;
|
||||
++ itNewStart ;
|
||||
LoopList.erase( itNewStart) ;
|
||||
}
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nSegNum 0-based
|
||||
bool
|
||||
PointPositionOnPolyLine( const Point3d& ptPoint, /*const*/ PolyLine& Loop, int& nSegNum, double& dParOnSeg)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
/*const*/ PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
nSegNum = - 1 ;
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
int nS = 0 ;
|
||||
auto itMinDistSt = LoopList.end() ;
|
||||
auto itMinDistEn = itMinDistSt ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn, ++ nS) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
nSegNum = nS ;
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDistSt = itSt ;
|
||||
itMinDistEn = itEn ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, lo segnalo.
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Calcolo il parametro lungo il segmento.
|
||||
Vector3d vtSeg = itMinDistEn->first - itMinDistSt->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
if ( dSegLen < EPS_SMALL)
|
||||
return false ;
|
||||
vtSeg /= dSegLen ;
|
||||
dParOnSeg = Clamp( ( ptPoint - itMinDistSt->first) * vtSeg, 0., dSegLen) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
IsPointInsidePolyLine( const Point3d& ptP, /*const*/ PolyLine& plPoly)
|
||||
{
|
||||
// Se la PolyLine non è chiusa, il punto non può essere interno.
|
||||
if ( ! plPoly.IsClosed())
|
||||
return false ;
|
||||
// Lista dei punti
|
||||
/*const*/ PNTULIST& List = plPoly.GetUPointList() ;
|
||||
// Ciclo sui segmenti della PolyLine per cercarne il tratto più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
// Riferimento alla lista dei punti
|
||||
PNTULIST& List = const_cast<PolyLine&>( plPoly).GetUPointList() ;
|
||||
// Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto
|
||||
double dMinSqDist = SQ_INFINITO ;
|
||||
Point3d ptMinDist ;
|
||||
auto itMinDistSt = List.end() ;
|
||||
auto itSt = List.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != List.end() && itEn != List.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptP, ptSegSt, ptSegEn) ;
|
||||
auto itMinDistEnd = List.end() ;
|
||||
auto itStart = List.begin() ;
|
||||
auto itEnd = next( itStart) ;
|
||||
for ( ; itEnd != List.end() ; ++ itStart, ++ itEnd) {
|
||||
// Distanza del punto dal segmento corrente
|
||||
DistPointLine dDistCalc( ptP, itStart->first, itEnd->first) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
dDistCalc.GetMinDistPoint( ptMinDist) ;
|
||||
itMinDistSt = itSt ;
|
||||
itMinDistEnd = itEnd ;
|
||||
}
|
||||
}
|
||||
// Termine del segmento di minima distanza.
|
||||
auto itMinDistEn = itMinDistSt ;
|
||||
++ itMinDistEn ;
|
||||
// Punto di minima distanza nell'estremo iniziale del segento
|
||||
if ( AreSamePointApprox( ptMinDist, itMinDistSt->first)) {
|
||||
auto itPrevSt = List.begin() ;
|
||||
if ( itMinDistSt == List.begin()) {
|
||||
auto itAuxNext = itPrevSt ;
|
||||
++ ( ++ itAuxNext) ;
|
||||
for ( ; itAuxNext != List.end() ; ++ itPrevSt, ++ itAuxNext)
|
||||
;
|
||||
}
|
||||
else {
|
||||
auto itAuxNext = itPrevSt ;
|
||||
++ itAuxNext ;
|
||||
for (; itAuxNext != itMinDistSt; ++itPrevSt, ++itAuxNext)
|
||||
;
|
||||
}
|
||||
Vector3d vtPrevTan = itMinDistSt->first - itPrevSt->first ;
|
||||
vtPrevTan.Normalize() ;
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtPrevOut = vtPrevTan ^ vtPolyNorm ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
// Caso concavo
|
||||
if ( vtTan * vtPrevOut > 0) {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtPrevOut < 0 || vtTest * vtOut < 0)
|
||||
return true ;
|
||||
}
|
||||
// Caso convesso
|
||||
else {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtPrevOut < 0 && vtTest * vtOut < 0)
|
||||
return true ;
|
||||
}
|
||||
// Determino tangente di riferimento
|
||||
Vector3d vtTang ;
|
||||
// se minima distanza nell'estremo iniziale del segmento
|
||||
if ( AreSamePointApprox( ptMinDist, prev( itMinDistEnd)->first)) {
|
||||
// direzione del segmento
|
||||
Vector3d vtCurrTg = itMinDistEnd->first - prev( itMinDistEnd)->first ;
|
||||
vtCurrTg.Normalize() ;
|
||||
// direzione del segmento precedente
|
||||
Vector3d vtPrevTg ;
|
||||
if ( prev( itMinDistEnd) != List.begin())
|
||||
vtPrevTg = prev( itMinDistEnd)->first - prev( itMinDistEnd, 2)->first ;
|
||||
else
|
||||
vtPrevTg = prev( itMinDistEnd)->first - prev( List.rbegin())->first ;
|
||||
vtPrevTg.Normalize() ;
|
||||
// tangente media
|
||||
vtTang = vtPrevTg + vtCurrTg ;
|
||||
vtTang.Normalize() ;
|
||||
}
|
||||
// Punto di minima distanza nell'estremo finale del segento
|
||||
else if ( AreSamePointApprox( ptMinDist, itMinDistEn->first)) {
|
||||
auto itNextEn = itMinDistEn ;
|
||||
++ itNextEn ;
|
||||
if ( itNextEn == List.end()) {
|
||||
itNextEn = List.begin() ;
|
||||
++ itNextEn ;
|
||||
}
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Vector3d vtNextTan = itNextEn->first - itMinDistEn->first ;
|
||||
vtNextTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
Vector3d vtNextOut = vtNextTan ^ vtPolyNorm ;
|
||||
// Caso concavo
|
||||
if ( vtNextTan * vtOut > 0) {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtOut < 0 || vtTest * vtNextOut < 0)
|
||||
return true ;
|
||||
}
|
||||
// Caso convesso
|
||||
else {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtOut < 0 && vtTest * vtNextOut < 0)
|
||||
return true ;
|
||||
}
|
||||
// se altrimenti minima distanza nell'estremo finale del segmento
|
||||
else if ( AreSamePointApprox( ptMinDist, itMinDistEnd->first)) {
|
||||
// direzione del segmento
|
||||
Vector3d vtCurrTg = itMinDistEnd->first - prev( itMinDistEnd)->first ;
|
||||
vtCurrTg.Normalize() ;
|
||||
// direzione del segmento successivo
|
||||
Vector3d vtNextTg ;
|
||||
if ( next( itMinDistEnd) != List.end())
|
||||
vtNextTg = next( itMinDistEnd)->first - itMinDistEnd->first ;
|
||||
else
|
||||
vtNextTg = next( List.begin())->first - itMinDistEnd->first ;
|
||||
vtNextTg.Normalize() ;
|
||||
// tangente media
|
||||
vtTang = vtCurrTg + vtNextTg ;
|
||||
vtTang.Normalize() ;
|
||||
}
|
||||
// Punto di minima distanza interno al segmeno
|
||||
// altrimenti minima distanza con l'interno
|
||||
else {
|
||||
Vector3d vtP = ptP - itMinDistSt->first ;
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
vtP -= ( vtP * vtTan) * vtTan ;
|
||||
if ( vtP * vtOut < - EPS_SMALL)
|
||||
return true ;
|
||||
vtTang = itMinDistEnd->first - prev( itMinDistEnd)->first ;
|
||||
}
|
||||
return false ;
|
||||
// Determino la posizione del punto
|
||||
Vector3d vtDiff = ptP - ptMinDist ;
|
||||
Vector3d vtOut = vtTang ^ plPlane.GetVersN() ;
|
||||
vtOut.Normalize() ;
|
||||
return ( vtDiff * vtOut < -dToler) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dPointPolyLineDist)
|
||||
GetPointParamOnPolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler, double& dPar)
|
||||
{
|
||||
if ( plPoly.GetPointNbr() == 0)
|
||||
// La polilinea deve contenere almeno due punti
|
||||
if ( plPoly.GetPointNbr() < 2)
|
||||
return false ;
|
||||
dPointPolyLineDist = DBL_MAX ;
|
||||
Point3d ptSt, ptEn ;
|
||||
bool bContinue = plPoly.GetFirstPoint( ptSt) && plPoly.GetNextPoint( ptEn) ;
|
||||
while ( bContinue) {
|
||||
double dPoinLineDist ;
|
||||
DistPointLine PointLineDistCalc( ptP, ptSt, ptEn) ;
|
||||
PointLineDistCalc.GetDist( dPoinLineDist) ;
|
||||
if ( dPoinLineDist < dPointPolyLineDist)
|
||||
dPointPolyLineDist = dPoinLineDist ;
|
||||
ptSt = ptEn ;
|
||||
bContinue = plPoly.GetNextPoint( ptEn) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Una faccia di una trimesh ha una sola componente connessa.
|
||||
// Si assume che i loop siano corretti e rispettino tale proprietà.
|
||||
bool
|
||||
DistPointFacet( const Point3d& ptP, /*const*/ POLYLINEVECTOR& vPolyVec, double& dPointFacetDist)
|
||||
{
|
||||
// Vedo se la proiezione del punto sul piano della faccia è interno ad essa.
|
||||
Point3d ptPlaneP ;
|
||||
Vector3d vtPlaneN ;
|
||||
double dPointPlaneSignedDist ;
|
||||
Point3d ptProjP ;
|
||||
bool bPointIsInside = true ;
|
||||
for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) && bPointIsInside ; ++ nLoop) {
|
||||
Plane3d plPlane ;
|
||||
double dArea ;
|
||||
if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea))
|
||||
return false ;
|
||||
if ( nLoop == 0) {
|
||||
ptPlaneP = plPlane.GetPoint() ;
|
||||
vtPlaneN = plPlane.GetVersN() ;
|
||||
dPointPlaneSignedDist = ( ptP - ptPlaneP) * vtPlaneN ;
|
||||
ptProjP = ptP + dPointPlaneSignedDist * vtPlaneN ;
|
||||
}
|
||||
if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop]))
|
||||
bPointIsInside = false ;
|
||||
}
|
||||
// Se la proiezione del punto sul piano della faccia è interno, ho finito.
|
||||
// La distanza del punto dalla faccia è pari alla distanza dello stesso dal piano
|
||||
// in cui giace quest'ultima.
|
||||
if ( bPointIsInside) {
|
||||
dPointFacetDist = abs( dPointPlaneSignedDist) ;
|
||||
return bPointIsInside ;
|
||||
}
|
||||
// Calcolo la minima distanza del punto dalle polilinee del contorno.
|
||||
dPointFacetDist = DBL_MAX ;
|
||||
for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) ; ++ nLoop) {
|
||||
double dDist ;
|
||||
if ( DistPointPolyLine( ptP, vPolyVec[nLoop], dDist) && dDist < dPointFacetDist)
|
||||
dPointFacetDist = dDist ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SplitPolyLineAtPoint( const Point3d& ptPoint, /*const*/ PolyLine& Loop, PolyLine& Loop1, PolyLine& Loop2)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
/*const*/ PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
auto itMinDistSt = LoopList.end() ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ;
|
||||
// Ciclo sui punti della polilinea
|
||||
int nSeg = -1 ;
|
||||
double dMinSqDist = SQ_INFINITO ;
|
||||
double dMinPar = -1 ;
|
||||
Point3d ptStart, ptEnd ;
|
||||
plPoly.GetFirstPoint( ptStart) ;
|
||||
while ( plPoly.GetNextPoint( ptEnd)) {
|
||||
// aggiorno l'indice
|
||||
++ nSeg ;
|
||||
// distanza del punto dal segmento della polilinea
|
||||
DistPointLine dDistCalc( ptP, ptStart, ptEnd) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDistSt = itSt ;
|
||||
double dSegPar ;
|
||||
dDistCalc.GetParamAtMinDistPoint( dSegPar) ;
|
||||
dMinPar = nSeg + dSegPar ;
|
||||
}
|
||||
// assegno nuovo inizio
|
||||
ptStart = ptEnd ;
|
||||
}
|
||||
// Il punto è sulla linea se la sua distanza rispetta la tolleranza
|
||||
return ( dMinSqDist < dToler * dToler) ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
ChangePolyLineStart( PolyLine& plPoly, const Point3d& ptNewStart, double dToler)
|
||||
{
|
||||
// La polilinea deve essere chiusa
|
||||
if ( ! plPoly.IsClosed())
|
||||
return false ;
|
||||
// Riferimento alla lista dei punti
|
||||
PNTULIST& LoopList = const_cast<PolyLine&>( plPoly).GetUPointList() ;
|
||||
// Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto
|
||||
double dMinSqDist = SQ_INFINITO ;
|
||||
auto itMinDistEnd = LoopList.end() ;
|
||||
auto itStart = LoopList.begin() ;
|
||||
auto itEnd = next( itStart) ;
|
||||
for ( ; itEnd != LoopList.end() ; ++ itStart, ++ itEnd) {
|
||||
// Distanza del punto dal segmento corrente
|
||||
DistPointLine dDistCalc( ptNewStart, itStart->first, itEnd->first) ;
|
||||
double dSqDist ;
|
||||
if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDistEnd = itEnd ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, lo segnalo.
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
// Se il punto non sta sulla polilinea, non ha senso cambiare l'inizio
|
||||
if ( dMinSqDist > dToler * dToler)
|
||||
return false ;
|
||||
// Se il punto di stop sta su un vertice non devo aggiungerlo e il
|
||||
// punto di stop sarà uno degli estremi del segmento su cui giace.
|
||||
auto itStop = itMinDistSt ;
|
||||
auto itNext = itMinDistSt ;
|
||||
++ itNext ;
|
||||
if ( AreSamePointApprox( ptPoint, itStop->first))
|
||||
;
|
||||
else if ( AreSamePointApprox( ptPoint, itNext->first))
|
||||
itStop = itNext ;
|
||||
else {
|
||||
itStop = LoopList.emplace( itNext, ptPoint, 0.) ;
|
||||
}
|
||||
// Creo i due loop
|
||||
PNTULIST& LoopList1 = Loop1.GetUPointList() ;
|
||||
PNTULIST& LoopList2 = Loop2.GetUPointList() ;
|
||||
for ( auto it = LoopList.begin() ; it != itStop ; ++ it) {
|
||||
LoopList1.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
LoopList1.emplace_back( itStop->first, itStop->second) ;
|
||||
for ( auto it = itStop ; it != LoopList.end() ; ++ it) {
|
||||
LoopList2.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
// Se il punto non coincide con un vertice, lo aggiungo
|
||||
auto itNewStart = LoopList.end() ;
|
||||
if ( AreSamePointApprox( ptNewStart, prev( itMinDistEnd)->first))
|
||||
itNewStart = prev( itMinDistEnd) ;
|
||||
else if ( AreSamePointApprox( ptNewStart, itMinDistEnd->first))
|
||||
itNewStart = itMinDistEnd ;
|
||||
else
|
||||
itNewStart = LoopList.emplace( itMinDistEnd, ptNewStart, 0) ;
|
||||
// Cancello l'ultimo punto ( coincide con il primo)
|
||||
LoopList.pop_back() ;
|
||||
// Sposto la parte iniziale dei punti alla fine
|
||||
LoopList.splice( LoopList.end(), LoopList, LoopList.begin(), itNewStart) ;
|
||||
// Aggiungo il punto finale come copia dell'iniziale
|
||||
LoopList.push_back( LoopList.front()) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
AddPolyLineToPolyLine( PolyLine& Poly, PolyLine& PolyToAdd)
|
||||
SplitPolyLineAtPoint( const PolyLine& plPoly, const Point3d& ptP, double dToler, PolyLine& plPoly1, PolyLine& plPoly2)
|
||||
{
|
||||
// Se la PolyLine a cui devo aggiungere l'altra è chiusa, non posso aggiungere nulla.
|
||||
if ( Poly.IsClosed())
|
||||
// La polilinea deve contenere almeno due punti
|
||||
if ( plPoly.GetPointNbr() < 2)
|
||||
return false ;
|
||||
// Se la PolyLina che devo aggiungere è vuota, ho finito.
|
||||
PNTULIST& PolyToAddList = PolyToAdd.GetUPointList() ;
|
||||
if ( int( PolyToAddList.size()) == 0)
|
||||
return true ;
|
||||
// Se Poly non è vuota e la sua fine non coincide con l'inizio di PolyToAdd, non è possibile aggiungere nulla.
|
||||
Point3d ptLast ;
|
||||
Poly.GetLastPoint( ptLast) ;
|
||||
auto it = PolyToAddList.begin() ;
|
||||
if ( Poly.GetPointNbr() != 0 && ! AreSamePointEpsilon( it->first, ptLast, 10 * EPS_SMALL))
|
||||
return false ;
|
||||
/*if ( Poly.GetPointNbr() == 0)
|
||||
Poly.AddUPoint( 0., it->first) ;
|
||||
++ it ;*/
|
||||
// Aggiungo i punti.
|
||||
for ( ; it != PolyToAddList.end() ; ++ it) {
|
||||
Poly.AddUPoint( 0., it->first) ;
|
||||
// Riferimento alla lista dei punti
|
||||
const PNTULIST& LoopList = const_cast<PolyLine&>( plPoly).GetUPointList() ;
|
||||
// Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto
|
||||
double dMinSqDist = SQ_INFINITO ;
|
||||
auto itMinDistEnd = LoopList.end() ;
|
||||
auto itStart = LoopList.begin() ;
|
||||
auto itEnd = next( itStart) ;
|
||||
for ( ; itEnd != LoopList.end() ; ++ itStart, ++ itEnd) {
|
||||
// Distanza del punto dal segmento corrente
|
||||
DistPointLine dDistCalc( ptP, itStart->first, itEnd->first) ;
|
||||
double dSqDist ;
|
||||
if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDistEnd = itEnd ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sulla polilinea, non ha senso spezzare
|
||||
if ( dMinSqDist > dToler * dToler)
|
||||
return false ;
|
||||
// Copio i punti opportuni nella prima parte
|
||||
PNTULIST& LoopList1 = plPoly1.GetUPointList() ;
|
||||
for ( auto it = LoopList.begin() ; it != itMinDistEnd ; ++ it)
|
||||
LoopList1.emplace_back( it->first, it->second) ;
|
||||
plPoly1.AddUPoint( 0, ptP) ;
|
||||
// Copio i punti opportuni nella seconda parte
|
||||
PNTULIST& LoopList2 = plPoly2.GetUPointList() ;
|
||||
for ( auto it = itMinDistEnd ; it != LoopList.end() ; ++ it)
|
||||
LoopList2.emplace_back( it->first, it->second) ;
|
||||
plPoly2.AddUPoint( 0, ptP, false) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
+11
-4
@@ -3701,7 +3701,11 @@ SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq)
|
||||
if ( m_nStatus != OK)
|
||||
return false ;
|
||||
|
||||
// eseguo il taglio con il metodo delle faccette
|
||||
// recupero il numero originale di triangoli e di facce
|
||||
int nTriaOriCnt = GetTriangleCount() ;
|
||||
int nFacetOriCnt = GetFacetCount() ;
|
||||
|
||||
// eseguo il taglio con il metodo delle faccette o dei triangoli (per ora solo coi triangoli)
|
||||
bool bModif = false ;
|
||||
if ( true || ! CutByFacets( plPlane, bSaveOnEq, bModif)) {
|
||||
bModif = false ;
|
||||
@@ -3711,13 +3715,16 @@ SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq)
|
||||
|
||||
// se effettuate modifiche
|
||||
if ( bModif) {
|
||||
// aggiorno tutto
|
||||
// aggiorno tutto
|
||||
if ( ! AdjustVertices() || ! DoCompacting())
|
||||
return false ;
|
||||
// se superficie originale a facce, cerco di semplificarle
|
||||
if ( nFacetOriCnt < 200 || double( nTriaOriCnt) / nFacetOriCnt > 4) {
|
||||
if ( ! SimplifyFacets( 500.0))
|
||||
LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::Cut")
|
||||
}
|
||||
}
|
||||
|
||||
SimplifyFacets( 20) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
+262
-600
File diff suppressed because it is too large
Load Diff
+207
-183
@@ -1,8 +1,8 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// EgalTech 2015-2015
|
||||
// EgalTech 2021-2021
|
||||
//----------------------------------------------------------------------------
|
||||
// File : SurfTriMeshUtilities.cpp Data : 25.10.21 Versione :
|
||||
// Contenuto : Implementazione della classe Superfici TriMesh.
|
||||
// File : SurfTriMeshUtilities.cpp Data : 01.11.21 Versione : 2.3k1
|
||||
// Contenuto : Implementazione funzioni di utilità di Superfici TriMesh.
|
||||
//
|
||||
//
|
||||
//
|
||||
@@ -19,208 +19,232 @@
|
||||
|
||||
using namespace std ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
IsVertex( PNTULIST& PointList, PNTULIST::const_iterator itCurr)
|
||||
{
|
||||
// recupero il punto precedente
|
||||
PNTULIST::const_iterator itPrev ;
|
||||
if ( itCurr == PointList.begin())
|
||||
itPrev = prev( PointList.end(), 2) ;
|
||||
else
|
||||
itPrev = prev( itCurr) ;
|
||||
// recupero il punto successivo
|
||||
auto itNext = next( itCurr) ;
|
||||
if ( itNext == PointList.end())
|
||||
itNext = next( PointList.begin()) ;
|
||||
// se cambia faccia adiacente tra prima e dopo, va bene
|
||||
if ( itPrev->second != itCurr->second)
|
||||
return true ;
|
||||
// se lati aperti e cambia direzione tra prima e dopo, va bene
|
||||
if ( itPrev->second == -1) {
|
||||
DistPointLine PointLineDistCalc( itCurr->first, itPrev->first, itNext->first) ;
|
||||
double dDist ;
|
||||
if ( PointLineDistCalc.GetDist( dDist) && dDist > EPS_SMALL)
|
||||
return true ;
|
||||
}
|
||||
// altrimenti non va bene
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
ChooseGoodStartPoint( PNTULIST& PointList)
|
||||
{
|
||||
// se il punto iniziale è un vertice, non devo fare alcunché
|
||||
if ( IsVertex( PointList, PointList.begin()))
|
||||
return true ;
|
||||
// altrimenti cerco il vertice più vicino
|
||||
for ( auto it = next( PointList.begin()) ; it != PointList.end() ; ++it) {
|
||||
if ( IsVertex( PointList, it)) {
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
PointList.pop_back() ;
|
||||
// sposto la parte iniziale dei punti alla fine
|
||||
PointList.splice( PointList.end(), PointList, PointList.begin(), it) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
PointList.push_back( PointList.front()) ;
|
||||
// ho finito
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif)
|
||||
{
|
||||
// Ciclo sui punti del loop
|
||||
auto itLast = PointList.begin() ;
|
||||
for ( auto it = next( itLast) ; it != PointList.end() ; ++ it) {
|
||||
|
||||
// Se dal punto corrente inizia un segmento adiacente a un'altra faccia
|
||||
if ( itLast->second != it->second) {
|
||||
// Elimino i punti interni
|
||||
auto itNextToLast = next( itLast) ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bModif = true ;
|
||||
}
|
||||
// Se la lunghezza del segmento supera il limite imposto
|
||||
double dSegLen = Dist( it->first, itLast->first) ;
|
||||
if ( dSegLen > dMaxEdgeLen) {
|
||||
// determino il numero di step
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepCount = int( dRatio) + 1 ;
|
||||
// inserisco i punti
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepCount ; ++ nP) {
|
||||
double dCoeff = nP / nStepCount ;
|
||||
itAdd = PointList.insert( itAdd, POINTU( Media( itLast->first, it->first, dCoeff), itLast->second)) ;
|
||||
bModif = true ;
|
||||
}
|
||||
}
|
||||
// Nuovo punto di riferimento
|
||||
itLast = it ;
|
||||
}
|
||||
|
||||
// Se sono due segmenti liberi non allineati
|
||||
else if ( itLast->second == - 1) {
|
||||
// Calcolo se i punti compresi fra gli estremi sono allineati
|
||||
bool bAreAligned = true ;
|
||||
auto itNextToLast = next( itLast) ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it && bAreAligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, it->first) ;
|
||||
double dDist ;
|
||||
if ( PointLineDistCalc.GetDist( dDist))
|
||||
bAreAligned = ( dDist < EPS_SMALL) ;
|
||||
}
|
||||
// Se i punti sono allineati
|
||||
if ( bAreAligned) {
|
||||
// Verifico se il successivo punto non è più allineato
|
||||
auto itNextToCurr = next( it) ;
|
||||
if ( itNextToCurr != PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, itNextToCurr->first) ;
|
||||
double dDist ;
|
||||
if ( PointLineDistCalc.GetDist( dDist))
|
||||
bAreAligned = ( dDist < EPS_SMALL) ;
|
||||
}
|
||||
}
|
||||
// Se ho trovato un insieme massimale di punti allineati li processo
|
||||
if ( ! bAreAligned || itNextToCurr == PointList.end()) {
|
||||
// Elimino i punti interni
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bModif = true ;
|
||||
}
|
||||
// Se la lunghezza del segmento supera il limite imposto
|
||||
double dSegLen = Dist( it->first, itLast->first) ;
|
||||
if ( dSegLen > dMaxEdgeLen) {
|
||||
// determino il numero di step
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepCount = int( dRatio) + 1 ;
|
||||
// inserisco i punti
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepCount ; ++ nP) {
|
||||
double dCoeff = nP / nStepCount ;
|
||||
itAdd = PointList.insert( itAdd, POINTU( Media( itLast->first, it->first, dCoeff), itLast->second)) ;
|
||||
bModif = true ;
|
||||
}
|
||||
}
|
||||
// Nuovo punto di riferimento
|
||||
itLast = it ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfTriMesh::SimplifyFacets( double dMaxEdgeLen)
|
||||
{
|
||||
// Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, ho finito.
|
||||
// La trimesh deve essere valida
|
||||
if ( ! IsValid())
|
||||
return false ;
|
||||
// Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, non devo fare alcunché
|
||||
if ( dMaxEdgeLen < EPS_SMALL)
|
||||
return true ;
|
||||
|
||||
// Le superfici devono essere valide.
|
||||
if ( ! IsValid())
|
||||
return false ;
|
||||
// Recupero il numero delle facce (esegue anche una verifica delle stesse)
|
||||
int nFacetCnt = GetFacetCount() ;
|
||||
|
||||
// Verifico la definizione delle facce.
|
||||
VerifyFaceting() ;
|
||||
// Ciclo sulle facce della mesh per trovare quelle da ritriangolare
|
||||
unordered_map< int, pair< PNTVECTOR, INTVECTOR>> FacetMap ;
|
||||
for ( int nF = 0 ; nF < nFacetCnt ; ++ nF) {
|
||||
|
||||
// Ciclo sulle facce delle mesh.
|
||||
unordered_map<int, POLYLINEVECTOR> FacetMap ;
|
||||
int nFacetNum = GetFacetCount() ;
|
||||
for ( int nF = 0 ; nF < nFacetNum ; ++ nF) {
|
||||
bool bFacetToRetriangulate = false ;
|
||||
// Recupero i loop della faccia.
|
||||
// Recupero i loop della faccia (il parametro indica la faccia adiacente)
|
||||
POLYLINEVECTOR LoopVec ;
|
||||
GetFacetLoops( nF, LoopVec) ;
|
||||
// Recupero le adiacenze della faccia.
|
||||
INTMATRIX vAdj ;
|
||||
GetFacetAdjacencies( nF, vAdj) ;
|
||||
// Ciclo sui loop della faccia.
|
||||
|
||||
// Ciclo sui loop della faccia
|
||||
bool bToRetriangulate = false ;
|
||||
for ( int nL = 0 ; nL < int( LoopVec.size()) ; ++ nL) {
|
||||
// Lista dei punti del loop.
|
||||
|
||||
// Lista dei punti del loop
|
||||
PNTULIST& PointList = LoopVec[nL].GetUPointList() ;
|
||||
// Mi assicuro che il punto finale non sia all'interno di un segmento.
|
||||
auto itFirst = PointList.begin() ;
|
||||
int nNewStartPos = 0 ;
|
||||
for ( auto it = itFirst ; it != PointList.end() ; ++ it, ++ nNewStartPos) {
|
||||
if ( itFirst->second != it->second) {
|
||||
{
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
PointList.pop_back() ;
|
||||
// sposto la metà iniziale dei punti alla fine
|
||||
for ( int i = 0 ; i < nNewStartPos ; ++ i)
|
||||
PointList.splice( PointList.end(), PointList, PointList.begin()) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
PointList.push_back( PointList.front()) ;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
else if ( itFirst->second == - 1 && it != itFirst) {
|
||||
// Valuto se i punti compresi fra gli estremi sono allinati.
|
||||
bool bAreAlligned = true ;
|
||||
auto itNextToLast = itFirst ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itFirst->first, it->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
// I punti sono allineati.
|
||||
if ( bAreAlligned) {
|
||||
// Valuto se includendo anche il punto successivo non ci sarebbe più allineamento,
|
||||
// ovvero avrei trovato un insieme massimale di punti allineati.
|
||||
auto itNextToCurr = it ;
|
||||
++ itNextToCurr ;
|
||||
// Se il punto corrente è l'ultimo, ho trovato un insieme massimale di punti allineati.
|
||||
if ( itNextToCurr != PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itFirst->first, itNextToCurr->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
}
|
||||
// Se ho trovato un insieme massimale di punti allineati li ridistribuisco,
|
||||
// altrimenti procedo per includere il punto successivo nell'insieme.
|
||||
if ( ! bAreAlligned || itNextToCurr == PointList.end()) {
|
||||
{
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
PointList.pop_back() ;
|
||||
// sposto la metà iniziale dei punti alla fine
|
||||
for ( int i = 0 ; i < nNewStartPos ; ++ i)
|
||||
PointList.splice( PointList.end(), PointList, PointList.begin()) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
PointList.push_back( PointList.front()) ;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ciclo sui punti del loop.
|
||||
auto itLast = PointList.begin() ;
|
||||
for ( auto it = itLast ; it != PointList.end() ; ++ it) {
|
||||
// Dal punto corrente spicca un segmento adiacente a una nuova faccia.
|
||||
if ( itLast->second != it->second) {
|
||||
// Elimino punti interni.
|
||||
auto itNextToLast = itLast ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
// Versore direzione del segmento e sua lunghezza.
|
||||
Vector3d vtSeg = it->first - itLast->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
vtSeg /= dSegLen ;
|
||||
// Calcolo numero dei punti da inserire.
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepNum = ( dRatio < 1 + EPS_SMALL ? int( dRatio) : int( dRatio) + 1) ;
|
||||
// Aggiungo i nuovi punti.
|
||||
double dMyLen = dSegLen / nStepNum ;
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepNum ; ++ nP) {
|
||||
itAdd = PointList.insert( itAdd, POINTU( it->first - nP * dMyLen * vtSeg, itLast->second)) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
itLast = it ;
|
||||
}
|
||||
// Possono essere due segmenti liberi non allineati.
|
||||
else if ( itLast->second == - 1 && it != itLast) {
|
||||
// Valuto se i punti compresi fra gli estremi sono allinati.
|
||||
bool bAreAlligned = true ;
|
||||
auto itNextToLast = itLast ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, it->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
// I punti sono allineati.
|
||||
if ( bAreAlligned) {
|
||||
// Valuto se includendo anche il punto successivo non ci sarebbe più allineamento,
|
||||
// ovvero avrei trovato un insieme massimale di punti allineati.
|
||||
auto itNextToCurr = it ;
|
||||
++ itNextToCurr ;
|
||||
// Se il punto corrente è l'ultimo, ho trovato un insieme massimale di punti allineati.
|
||||
if ( itNextToCurr != PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, itNextToCurr->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
}
|
||||
// Se ho trovato un insieme massimale di punti allineati li ridistribuisco,
|
||||
// altrimenti procedo per includere il punto successivo nell'insieme.
|
||||
if ( ! bAreAlligned || itNextToCurr == PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
// Versore direzione del segmento e sua lunghezza.
|
||||
Vector3d vtSeg = it->first - itLast->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
vtSeg /= dSegLen ;
|
||||
// Calcolo numero dei punti da inserire.
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepNum = ( dRatio < 1 + EPS_SMALL ? int( dRatio) : int( dRatio) + 1) ;
|
||||
// Aggiungo i nuovi punti.
|
||||
double dMyLen = dSegLen / nStepNum ;
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepNum ; ++ nP) {
|
||||
itAdd = PointList.insert( itAdd, POINTU( it->first - nP * dMyLen * vtSeg, itLast->second)) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
itLast = it ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mi assicuro che il punto iniziale/finale non sia all'interno di un possibile segmento
|
||||
if ( ! ChooseGoodStartPoint( PointList))
|
||||
return false ;
|
||||
|
||||
// Sistemo il loop
|
||||
bool bModif = false ;
|
||||
if ( ! AdjustLoop( PointList, dMaxEdgeLen, bModif))
|
||||
return false ;
|
||||
if ( bModif)
|
||||
bToRetriangulate = true ;
|
||||
}
|
||||
if ( bFacetToRetriangulate) {
|
||||
FacetMap.emplace( nF, LoopVec) ;
|
||||
|
||||
// Se da ritriangolare,
|
||||
if ( bToRetriangulate) {
|
||||
// Eseguo la ritriangolazione della faccia
|
||||
PNTVECTOR vPt ;
|
||||
INTVECTOR vTr ;
|
||||
if ( Triangulate().Make( LoopVec, vPt, vTr)) {
|
||||
FacetMap.emplace( nF, make_pair( vPt, vTr)) ;
|
||||
}
|
||||
// Se non riesco a triangolare anche solo questa faccia, interrompo tutto
|
||||
else
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
|
||||
// Ciclo sulle facce da ritriangolare per eliminare i triangoli.
|
||||
// Ciclo sulle facce da ritriangolare per eliminare i triangoli (nel contempo salvo flag colore)
|
||||
unordered_map< int, int> ColorMap ;
|
||||
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
|
||||
// Cancello i triangoli della faccia.
|
||||
// Recupero i triangoli della faccia
|
||||
INTVECTOR vFacetTria ;
|
||||
GetAllTriaInFacet( itF->first, vFacetTria) ;
|
||||
for ( int& nT : vFacetTria)
|
||||
// Salvo il colore della faccia da flag di un suo triangolo
|
||||
ColorMap.emplace( itF->first, m_vTria[m_vFacet[itF->first]].nTFlag) ;
|
||||
// Cancello i triangoli della faccia.
|
||||
for ( int nT : vFacetTria)
|
||||
RemoveTriangle( nT) ;
|
||||
}
|
||||
// Ritriangolo le facce.
|
||||
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
|
||||
// Ritriangolo la faccia.
|
||||
PNTVECTOR vPt ;
|
||||
INTVECTOR vTr ;
|
||||
if ( Triangulate().Make( itF->second, vPt, vTr)) {
|
||||
// Inserisco i nuovi triangoli.
|
||||
for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) {
|
||||
int nNewTriaVertId[3] = { vTr[n], vTr[n + 1], vTr[n + 2] } ;
|
||||
int nNewId[3] = { AddVertex(vPt[nNewTriaVertId[0]]),
|
||||
AddVertex(vPt[nNewTriaVertId[1]]),
|
||||
AddVertex(vPt[nNewTriaVertId[2]]) } ;
|
||||
// Il colore passato nel secondo parametro è definito perché il vettore delle facce ha ancora salvato l'indice di un suo triangolo e
|
||||
// il triangolo è cancellato semplicente assegnadno la costante apposita VT_DEL (-2) a nIdVert[0]; ma il suo colore resta definito.
|
||||
int nNewTriaNum = AddTriangle( nNewId, m_vTria[m_vFacet[itF->first]].nTFlag) ;
|
||||
}
|
||||
|
||||
// Applico le nuove triangolazioni delle facce
|
||||
for ( auto itFac = FacetMap.begin() ; itFac != FacetMap.end() ; ++ itFac) {
|
||||
const PNTVECTOR& vPt = itFac->second.first ;
|
||||
const INTVECTOR& vTr = itFac->second.second ;
|
||||
// Inserisco i nuovi triangoli
|
||||
for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) {
|
||||
int nNewId[3] = { AddVertex( vPt[vTr[n]]),
|
||||
AddVertex( vPt[vTr[n + 1]]),
|
||||
AddVertex( vPt[vTr[n + 2]])} ;
|
||||
auto itCol = ColorMap.find( itFac->first) ;
|
||||
int nTFlag = ( itCol != ColorMap.end() ? itCol->second : 0) ;
|
||||
int nNewTriaId = AddTriangle( nNewId, nTFlag) ;
|
||||
}
|
||||
}
|
||||
|
||||
return AdjustVertices() && DoCompacting() ;
|
||||
}
|
||||
// dichiaro necessità ricalcolo della grafica e di hashgrids3d
|
||||
m_OGrMgr.Reset() ;
|
||||
ResetHashGrids3d() ;
|
||||
|
||||
// Eseguo aggiustamenti
|
||||
return ( AdjustVertices() && DoCompacting()) ;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user