5163 lines
248 KiB
C++
5163 lines
248 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2019-2020
|
|
//----------------------------------------------------------------------------
|
|
// File : SurfTriMeshBooleans.cpp Data : 01.10.20 Versione : 2.2j1
|
|
// Contenuto : Implementazione delle funzioni booleane per SurfFTrimesh.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 10.05.19 LM Creazione modulo.
|
|
// 01.10.20 LM Aggiunte scalature 1024x.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "SurfTriMesh.h"
|
|
#include "CurveLine.h"
|
|
#include "CurveComposite.h"
|
|
#include "SurfFlatRegion.h"
|
|
#include "DistPointLine.h"
|
|
#include "Triangulate.h"
|
|
#include "GeoConst.h"
|
|
#include "IntersLineLine.h"
|
|
//#include "/EgtDev/Include/EgtNumUtils.h"
|
|
#include "/EgtDev/Include/EgkCurve.h"
|
|
#include "/EgtDev/Include/EgkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EgkDistPointTria.h"
|
|
#include "/EgtDev/Include/EgkIntersLineTria.h"
|
|
#include "/EgtDev/Include/EgkIntersLineBox.h"
|
|
#include "/EgtDev/Include/EgkIntersPlanePlane.h"
|
|
#include "/EgtDev/Include/EgkIntersTriaTria.h"
|
|
#include "/EgtDev/Include/EgkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkChainCurves.h"
|
|
#include "/EgtDev/Include/EGkGeoCollection.h"
|
|
#include "/EgtDev/Include/EGkPolygon3d.h"
|
|
#include "/EgtDev/Include/EgtPerfCounter.h"
|
|
#include "/EgtDev/Include/EgtNumUtils.h"
|
|
#include "/EgtDev/Include/EgnStringUtils.h"
|
|
#include <algorithm>
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
const double BOOLEAN_SCALE = 1024 ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
static int
|
|
IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3d& vtL2,
|
|
const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg)
|
|
{
|
|
// Definisco i due triangoli formanti il rettangolo
|
|
Triangle3d trTriaA ;
|
|
trTriaA.Set( ptP, ptP + vtL1, ptP + vtL2) ;
|
|
if ( ! trTriaA.Validate())
|
|
return -1 ;
|
|
Triangle3d trTriaB ;
|
|
trTriaB.Set( ptP + vtL1, ptP + vtL1 + vtL2, ptP + vtL2) ;
|
|
if ( ! trTriaB.Validate())
|
|
return -1 ;
|
|
// Interseco il triangolo con il primo dei due triangoli del rettangolo
|
|
int nIntA = 0 ;
|
|
Point3d ptIntA1, ptIntA2 ;
|
|
TRIA3DVECTOR vTriaA ;
|
|
int nIntTypeA = IntersTriaTria( trTria, trTriaA, ptIntA1, ptIntA2, vTriaA) ;
|
|
if ( nIntTypeA == ITTT_VERT_VERT || nIntTypeA == ITTT_VERT_EDGE || nIntTypeA == ITTT_VERT_INT || nIntTypeA == ITTT_EDGE_VERT || nIntTypeA == ITTT_EDGE_EDGE_PNT || nIntTypeA == ITTT_INT_VERT)
|
|
nIntA = 1 ;
|
|
else if ( nIntTypeA == ITTT_EDGE_EDGE_SEG || nIntTypeA == ITTT_EDGE_INT || nIntTypeA == ITTT_INT_EDGE || nIntTypeA == ITTT_INT_INT_SEG) {
|
|
nIntA = 2 ;
|
|
}
|
|
// Interseco il triangolo con il secondo dei due triangoli del rettangolo
|
|
int nIntB = 0 ;
|
|
Point3d ptIntB1, ptIntB2 ;
|
|
TRIA3DVECTOR vTriaB ;
|
|
int nIntTypeB = IntersTriaTria( trTria, trTriaB, ptIntB1, ptIntB2, vTriaB) ;
|
|
if ( nIntTypeB == ITTT_VERT_VERT || nIntTypeB == ITTT_VERT_EDGE || nIntTypeB == ITTT_VERT_INT || nIntTypeB == ITTT_EDGE_VERT || nIntTypeB == ITTT_EDGE_EDGE_PNT || nIntTypeB == ITTT_INT_VERT)
|
|
nIntB = 1 ;
|
|
else if ( nIntTypeB == ITTT_EDGE_EDGE_SEG || nIntTypeB == ITTT_EDGE_INT || nIntTypeB == ITTT_INT_EDGE || nIntTypeB == ITTT_INT_INT_SEG) {
|
|
nIntB = 2 ;
|
|
}
|
|
// Unisco le due intersezioni
|
|
int nIntTot = nIntA + nIntB ;
|
|
if ( nIntTot == 4) {
|
|
if ( AreSamePointApprox( ptIntA2, ptIntB1)) {
|
|
ptStSeg = ptIntA1 ;
|
|
ptEnSeg = ptIntB2 ;
|
|
}
|
|
else {
|
|
ptStSeg = ptIntB1 ;
|
|
ptEnSeg = ptIntA2 ;
|
|
}
|
|
return 2 ;
|
|
}
|
|
else if ( nIntTot == 3) {
|
|
if ( nIntA == 2) {
|
|
ptStSeg = ptIntA1 ;
|
|
ptEnSeg = ptIntA2 ;
|
|
}
|
|
else {
|
|
ptStSeg = ptIntB1 ;
|
|
ptEnSeg = ptIntB2 ;
|
|
}
|
|
return 2 ;
|
|
}
|
|
else if ( nIntTot == 2) {
|
|
if ( nIntA == 2) {
|
|
ptStSeg = ptIntA1 ;
|
|
ptEnSeg = ptIntA2 ;
|
|
}
|
|
else if ( nIntA == 1) {
|
|
ptStSeg = ptIntA1 ;
|
|
ptEnSeg = ptIntB1 ;
|
|
}
|
|
else {
|
|
ptStSeg = ptIntB1 ;
|
|
ptEnSeg = ptIntB2 ;
|
|
}
|
|
return 2 ;
|
|
}
|
|
else if ( nIntTot == 1) {
|
|
if ( nIntA == 1)
|
|
ptStSeg = ptIntA1 ;
|
|
else
|
|
ptStSeg = ptIntB1 ;
|
|
return 1 ;
|
|
}
|
|
else
|
|
return 0 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop)
|
|
{
|
|
// 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)
|
|
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] ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2)
|
|
{
|
|
// 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)
|
|
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 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
static bool
|
|
AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain)
|
|
{
|
|
// Se la catena da aggiungere � vuota, non devo fare alcunch�
|
|
if ( ChainToAdd.size() == 0)
|
|
return true ;
|
|
// Se la catena originale � vuota, non � possibile aggiungere nulla
|
|
if ( OrigChain.size() == 0)
|
|
return false ;
|
|
// Se la catena originale � chiusa non posso aggiungere nulla
|
|
int nLastOrig = max( int( OrigChain.size()) - 1, 0) ;
|
|
if ( AreSamePointApprox( OrigChain[0], OrigChain[nLastOrig]))
|
|
return false ;
|
|
int nLastToAdd = max( int( ChainToAdd.size()) - 1, 0) ;
|
|
if ( AreSamePointApprox( OrigChain[nLastOrig], ChainToAdd[0].ptSt)) {
|
|
for ( int nPt = 1 ; nPt <= nLastToAdd ; ++ nPt) {
|
|
if ( nPt == nLastToAdd) {
|
|
if ( ! AreSamePointApprox(OrigChain[0], ChainToAdd[nPt].ptSt))
|
|
OrigChain.emplace_back( ChainToAdd[nPt].ptSt) ;
|
|
}
|
|
else if ( nPt == 1) {
|
|
if ( ! AreSamePointApprox( OrigChain[nLastOrig], ChainToAdd[nPt].ptSt))
|
|
OrigChain.emplace_back( ChainToAdd[nPt].ptSt) ;
|
|
}
|
|
else
|
|
OrigChain.emplace_back( ChainToAdd[nPt].ptSt) ;
|
|
}
|
|
return true ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq)
|
|
{
|
|
// La superficie deve essere valida
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
// La curva deve essere valida e chiusa, il vettore estrusione deve essere non nullo
|
|
Vector3d vtExtr ;
|
|
if ( ! cvCurve.GetExtrusion( vtExtr) || vtExtr.IsSmall() || ! cvCurve.IsClosed())
|
|
return false ;
|
|
// Approssimo la curva con segmenti
|
|
CurveComposite cvCompo ;
|
|
PolyLine PL ;
|
|
if ( ! cvCurve.ApproxWithLines( LIN_TOL_MIN, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) || ! cvCompo.FromPolyLine( PL))
|
|
return false ;
|
|
// Appiattisco la polilinea nel piano perpendicolare all'estrusione
|
|
Frame3d frCurve ;
|
|
Point3d ptStart ; cvCompo.GetStartPoint( ptStart) ;
|
|
frCurve.Set( ptStart, vtExtr) ;
|
|
cvCompo.ToLoc( frCurve) ;
|
|
if ( ! cvCompo.Scale( GLOB_FRM, 1, 1, 0))
|
|
return false ;
|
|
double dArea ;
|
|
cvCompo.GetAreaXY( dArea) ;
|
|
BBox3d b3Crv ;
|
|
cvCompo.GetLocalBBox( b3Crv) ;
|
|
cvCompo.ToGlob( frCurve) ;
|
|
// Assegno il senso di rotazione della curva (visto dalla punta del vettore estrusione)
|
|
bool bCCW = ( dArea > 0) ;
|
|
// Recupero Bounding-box della trimesh
|
|
BBox3d b3SurfBox ;
|
|
GetLocalBBox( b3SurfBox) ;
|
|
// Trovo minima e massima distanza dei vertici del bounding-box della TriMesh dal piano della curva
|
|
b3SurfBox.ToLoc( frCurve) ;
|
|
Point3d ptMin, ptMax ;
|
|
b3SurfBox.GetMinMax( ptMin, ptMax) ;
|
|
Vector3d vtMax = ( ptMax.z + 10) * vtExtr ;
|
|
Vector3d vtMin = ( ptMin.z - 10) * vtExtr ;
|
|
|
|
// Ciclo sui triangoli
|
|
bool bModif = false ;
|
|
int nNumTria = GetTriangleSize() ;
|
|
for ( int nT = 0 ; nT < nNumTria ; ++ nT) {
|
|
// Recupero il triangolo
|
|
Triangle3d trTria ;
|
|
if ( ! GetTriangle( nT, trTria))
|
|
continue ;
|
|
// Box del triangolo nel riferimento locale della curva
|
|
BBox3d b3Tria ;
|
|
trTria.GetLocalBBox( b3Tria) ;
|
|
b3Tria.ToLoc( frCurve) ;
|
|
// Se il box del triangolo non interseca quello locale della curva
|
|
if ( ! b3Crv.OverlapsXY( b3Tria)) {
|
|
// Se la parte da conservare � quella all'interno della curva, elimino il triangolo
|
|
if ( bCCW) {
|
|
RemoveTriangle( nT) ;
|
|
bModif = true ;
|
|
}
|
|
continue ;
|
|
}
|
|
// Determino il numero di vertici del triangolo che cadono all'interno della curva
|
|
int nVertInside = 0 ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
// Determino se il vertice cade dentro la curva
|
|
DistPointCurve dstPC( trTria.GetP( nV), cvCompo) ;
|
|
int nSide ;
|
|
dstPC.GetSideAtMinDistPoint( 0, vtExtr, nSide) ;
|
|
if ( nSide == MDS_LEFT || nSide == MDS_ON)
|
|
++ nVertInside ;
|
|
}
|
|
// Vettore di catene di punti
|
|
CHAINVECTOR vChain ;
|
|
// Ciclo sui segmenti
|
|
int nChainCnt = 0 ;
|
|
bool bChain = false ;
|
|
Point3d ptChSt, ptChEn ;
|
|
const ICurve* pCrv = cvCompo.GetFirstCurve() ;
|
|
while ( pCrv != nullptr) {
|
|
// estremi del segmento
|
|
Point3d ptSt ; pCrv->GetStartPoint( ptSt) ;
|
|
Point3d ptEn ; pCrv->GetEndPoint( ptEn) ;
|
|
// Intersezione fra il rettangolo (ottenuto dall'estrusione del segmento corrente) e il triangolo
|
|
Point3d ptSegSt, ptSegEn ;
|
|
int nInt = IntersRectangleTriangle( ptSt + vtMin, ptEn - ptSt, vtMax - vtMin, trTria, ptSegSt, ptSegEn) ;
|
|
if ( nInt != 0) {
|
|
// Creo nuova catena se non c'� gi� o se discontinuit�
|
|
if ( ! bChain || ( ! AreSamePointApprox( ptSegSt, ptChEn) && ! AreSamePointApprox( ptSegEn, ptChSt))) {
|
|
++ nChainCnt ;
|
|
vChain.resize( nChainCnt) ;
|
|
bChain = false ;
|
|
}
|
|
// Assegno i dati di intersezione
|
|
IntSegment CurInters ;
|
|
if ( nInt == 2) {
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegEn ;
|
|
CurInters.bDegenerate = false ;
|
|
}
|
|
else {
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegSt ;
|
|
CurInters.bDegenerate = true ;
|
|
}
|
|
CurInters.vtOuter = ( ptEn - ptSt) ^ vtExtr ;
|
|
CurInters.vtOuter.Normalize() ;
|
|
// Inserisco nella catena
|
|
if ( ! bChain) {
|
|
vChain[nChainCnt - 1].emplace_back( CurInters) ;
|
|
ptChSt = CurInters.ptSt ;
|
|
ptChEn = CurInters.ptEn ;
|
|
}
|
|
else if ( AreSamePointApprox( ptSegSt, ptChEn)) {
|
|
vChain[nChainCnt - 1].emplace_back( CurInters) ;
|
|
ptChEn = CurInters.ptEn ;
|
|
}
|
|
else {
|
|
vChain[nChainCnt - 1].insert( vChain[nChainCnt - 1].begin(), CurInters) ;
|
|
ptChSt = CurInters.ptSt ;
|
|
}
|
|
bChain = true ;
|
|
}
|
|
else {
|
|
bChain = false ;
|
|
}
|
|
pCrv = cvCompo.GetNextCurve() ;
|
|
}
|
|
// unisco eventuali catene estreme che sono parte di una stessa catena
|
|
if ( nChainCnt > 1) {
|
|
if ( AreSamePointApprox( vChain[0].front().ptSt, vChain[nChainCnt-1].back().ptEn)) {
|
|
vChain[0].insert( vChain[0].begin(), vChain[nChainCnt-1].begin(), vChain[nChainCnt-1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
else if ( AreSamePointApprox( vChain[0].back().ptEn, vChain[nChainCnt-1].front().ptSt)) {
|
|
vChain[0].insert( vChain[0].end(), vChain[nChainCnt-1].begin(), vChain[nChainCnt-1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
}
|
|
// semplifico catene formate da punti degeneri
|
|
for ( int nCh = 0 ; nCh < nChainCnt ; ++ nCh) {
|
|
if ( vChain[nCh].size() == 2 && ( vChain[nCh][0].bDegenerate || vChain[nCh][1].bDegenerate)) {
|
|
vChain[nCh][0].ptEn = vChain[nCh][1].ptEn ;
|
|
vChain[nCh][0].vtOuter = ( vChain[nCh][0].bDegenerate ? vChain[nCh][1].vtOuter : vChain[nCh][0].vtOuter) ;
|
|
vChain[nCh][0].bDegenerate = AreSamePointApprox( vChain[nCh][0].ptSt, vChain[nCh][0].ptEn) ;
|
|
vChain[nCh].resize( 1) ;
|
|
}
|
|
}
|
|
// Elimino la seconda copia di catene doppie
|
|
for ( int nI = 0 ; nI < nChainCnt ; ++ nI) {
|
|
for ( int nJ = nI + 1 ; nJ < nChainCnt ; ++ nJ) {
|
|
if ( vChain[nI].size() == vChain[nJ].size()) {
|
|
bool bSame = true ;
|
|
for ( int nK = 0 ; nK < int( vChain[nI].size()) ; ++ nK) {
|
|
if ( ! AreSamePointApprox( vChain[nI][nK].ptSt, vChain[nJ][nK].ptSt) ||
|
|
! AreSamePointApprox( vChain[nI][nK].ptEn, vChain[nJ][nK].ptEn)) {
|
|
bSame = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bSame) {
|
|
vChain.erase( vChain.begin() + nJ) ;
|
|
-- nChainCnt ;
|
|
-- nJ ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fra le catene trovate separo le aperte dalle chiuse
|
|
int nDegenerateChainNum = 0 ;
|
|
INTVECTOR vnDegVec ;
|
|
CHAINVECTOR cvClosedChain ;
|
|
CHAINVECTOR cvOpenChain ;
|
|
for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) {
|
|
bool bChainDegenerate = false ;
|
|
if ( vChain[nL].size() == 1 && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][0].ptEn)) {
|
|
bChainDegenerate = true ;
|
|
}
|
|
|
|
if ( bChainDegenerate)
|
|
++ nDegenerateChainNum ;
|
|
int nCurLoopLast = max( int( vChain[nL].size()) - 1, 0) ;
|
|
if ( ( ! bChainDegenerate) && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn))
|
|
cvClosedChain.emplace_back( vChain[nL]) ;
|
|
else {
|
|
cvOpenChain.emplace_back( vChain[nL]) ;
|
|
if ( bChainDegenerate)
|
|
vnDegVec.emplace_back( 0) ;
|
|
else
|
|
vnDegVec.emplace_back( 1) ;
|
|
}
|
|
}
|
|
|
|
// Se pi� di una catena chiusa oppure catene chiuse e aperte, errore
|
|
if ( cvClosedChain.size() > 1 ||
|
|
( cvClosedChain.size() > 0 && int( cvOpenChain.size()) > nDegenerateChainNum))
|
|
return false ;
|
|
|
|
// Se c'� una catena chiusa
|
|
if ( cvClosedChain.size() == 1) {
|
|
// Ne ricavo una PolyLine
|
|
PolyLine plInLoop ;
|
|
for ( int nLine = 0 ; nLine < int( cvClosedChain[0].size()) ; ++ nLine) {
|
|
plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptSt) ;
|
|
plInLoop.AddUPoint( 0., cvClosedChain[0][nLine].ptEn) ;
|
|
}
|
|
// I tre vertici sono dalla parte interna della curva (triangolo con buco)
|
|
if ( ! bCCW) {
|
|
// Rimuovo il triangolo corrente
|
|
RemoveTriangle( nT) ;
|
|
// Definisco il loop esterno (� il triangolo)
|
|
PolyLine plExtLoop ;
|
|
plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ;
|
|
plExtLoop.AddUPoint( 0., trTria.GetP( 1)) ;
|
|
plExtLoop.AddUPoint( 0., trTria.GetP( 2)) ;
|
|
plExtLoop.AddUPoint( 0., trTria.GetP( 0)) ;
|
|
// Eseguo triangolazione
|
|
POLYLINEVECTOR vPL ;
|
|
vPL.emplace_back( plExtLoop) ;
|
|
vPL.emplace_back( plInLoop) ;
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vPL, vPt, vTr, TrgType::TRG_STANDARD)) {
|
|
// 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]]) } ;
|
|
AddTriangle( nNewId) ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
// Se nessun vertice dalla parte interna della curva (rimane solo l'area della curva)
|
|
else {
|
|
// Rimuovo il triangolo corrente
|
|
RemoveTriangle( nT) ;
|
|
// Eseguo triangolazione
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( plInLoop, 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]]) } ;
|
|
AddTriangle( nNewId) ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop aperti, devo chiuderli
|
|
else if ( cvOpenChain.size() > 0) {
|
|
|
|
// Creo il loop chiuso padre di tutti, il perimetro del triangolo.
|
|
// Questo viene diviso in sotto-loop chiusi mediante quelli aperti.
|
|
// I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop
|
|
// chiusi di cui � formato il perimetro.
|
|
PNTVECTOR cvFirstLoop ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 0)) ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 1)) ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 2)) ;
|
|
|
|
PNTMATRIX cvBoundClosedLoopVec ;
|
|
cvBoundClosedLoopVec.emplace_back(cvFirstLoop);
|
|
BOOLVECTOR vbInOut ;
|
|
vbInOut.push_back( true) ;
|
|
// Divido il loop di partenza in sotto-loop
|
|
while ( cvOpenChain.size() > 0) {
|
|
int nLastOpenLoopN = int( cvOpenChain.size()) - 1 ;
|
|
if ( vnDegVec[nLastOpenLoopN] == 1) {
|
|
for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) {
|
|
// Estremi del loop aperto
|
|
int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ;
|
|
Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ;
|
|
Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][nLastOpenLoopPoint].ptEn ;
|
|
PNTVECTOR Loop1, Loop2 ;
|
|
bool bChangedStart = ChangeStart( ptOpenLoopStP, cvBoundClosedLoopVec[nLoop]) ;
|
|
bool bSplitted = SplitAtPoint( ptOpenLoopEnP, cvBoundClosedLoopVec[nLoop], Loop1, Loop2) ;
|
|
if ( ! ( bChangedStart && bSplitted))
|
|
continue ;
|
|
Chain cvCounterChain ;
|
|
for ( int nPt = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nPt >= 0 ; -- nPt) {
|
|
IntSegment CurSeg ;
|
|
CurSeg.ptSt = cvOpenChain[nLastOpenLoopN][nPt].ptEn ;
|
|
CurSeg.ptEn = cvOpenChain[nLastOpenLoopN][nPt].ptSt ;
|
|
CurSeg.vtOuter = - cvOpenChain[nLastOpenLoopN][nPt].vtOuter ;
|
|
CurSeg.bDegenerate = cvOpenChain[nLastOpenLoopN][nPt].bDegenerate ;
|
|
cvCounterChain.emplace_back( CurSeg) ;
|
|
}
|
|
bool bAdded1 = AddChainToChain( cvCounterChain, Loop1) ;
|
|
bool bAdded2 = AddChainToChain( cvOpenChain[nLastOpenLoopN], Loop2) ;
|
|
if ( ! ( bAdded1 && bAdded2))
|
|
continue ;
|
|
// Aggiungo i nuovi loop nel vettore
|
|
int nCurSize = int( cvBoundClosedLoopVec.size()) ;
|
|
cvBoundClosedLoopVec.resize( nCurSize + 1) ;
|
|
vbInOut.resize( nCurSize + 1) ;
|
|
for ( int nCL = nCurSize - 1 ; nCL > nLoop ; -- nCL) {
|
|
cvBoundClosedLoopVec[nCL + 1] = cvBoundClosedLoopVec[nCL] ;
|
|
vbInOut[nCL + 1] = vbInOut[nCL] ;
|
|
}
|
|
Vector3d vtTest = Loop1[1] - Loop1[0] ;
|
|
vtTest.Normalize() ;
|
|
bool bSecondInside = vtTest * cvOpenChain[nLastOpenLoopN][0].vtOuter < 0. ;
|
|
cvBoundClosedLoopVec[nLoop] = Loop1 ;
|
|
cvBoundClosedLoopVec[nLoop + 1] = Loop2 ;
|
|
vbInOut[nLoop] = bSecondInside ;
|
|
vbInOut[nLoop + 1] = ! bSecondInside ;
|
|
++ nLoop ;
|
|
}
|
|
}
|
|
// Degenere
|
|
else {
|
|
Point3d ptProva = 0.5 * ( cvOpenChain[nLastOpenLoopN][0].ptSt + cvOpenChain[nLastOpenLoopN][0].ptEn) ;
|
|
Vector3d vtVecProva = cvOpenChain[nLastOpenLoopN][0].vtOuter ;
|
|
vtVecProva.Normalize( EPS_ZERO) ;
|
|
for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) {
|
|
// Cerco se esistono dei tratti del loop chiuso corrente che sono
|
|
// toccati dagli estremi del loop aperto corrente
|
|
int nCvFirst = -1 ;
|
|
int nCvSecond = -1 ;
|
|
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) && nCvSecond == -1 ; ++ nLine) {
|
|
// Estremi del segmento corrente del loop chiuso corrente
|
|
Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
|
|
Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][( nLine + 1) % int( cvBoundClosedLoopVec[nLoop].size())] ;
|
|
// Vettore congiungente i su definiti punti
|
|
Vector3d vtClosedLoopSeg = ptSegEn - ptSegSt ;
|
|
vtClosedLoopSeg.Normalize() ;
|
|
// Vedo se gli estremi del loop aperto stanno su un segmento del chiuso
|
|
DistPointLine DistCalc( ptProva, ptSegSt, ptSegEn) ;
|
|
double dSqDist ;
|
|
DistCalc.GetSqDist( dSqDist) ;
|
|
if ( dSqDist < 2 * SQ_EPS_SMALL) {
|
|
if ( nCvFirst == -1)
|
|
nCvFirst = nLine ;
|
|
else
|
|
nCvSecond = nLine ;
|
|
}
|
|
}
|
|
|
|
if ( nCvFirst != nCvSecond && nCvSecond != -1) {
|
|
// li ordino in senso crescente
|
|
if ( nCvFirst > nCvSecond)
|
|
swap( nCvFirst, nCvSecond) ;
|
|
// punto medio tra primo e secondo
|
|
int nCount = 0 ;
|
|
Point3d ptM12 ;
|
|
for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) {
|
|
ptM12 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
ptM12 /= nCount ;
|
|
// Distanza quadrata media dei punti tra primo e secondo dal baricentro
|
|
double dVar12 = 0. ;
|
|
for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) {
|
|
dVar12 += ( cvBoundClosedLoopVec[nLoop][i] - ptM12) * ( cvBoundClosedLoopVec[nLoop][i] - ptM12) ;
|
|
}
|
|
dVar12 /= nCount ;
|
|
// punto medio fra secondo e primo
|
|
nCount = 0 ;
|
|
Point3d ptM21 ;
|
|
for ( int i = nCvSecond + 1 ; i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) {
|
|
ptM21 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
for ( int i = 0 ; i <= nCvFirst ; ++ i) {
|
|
ptM21 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
ptM21 /= nCount ;
|
|
// Distanza quadrata media dei punti tra secondo e primo dal baricentro
|
|
double dVar21 = 0. ;
|
|
for ( int i = nCvSecond ; i < i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) {
|
|
dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ;
|
|
++ nCount ;
|
|
}
|
|
for ( int i = 0 ; i <= nCvFirst ; ++ i) {
|
|
dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ;
|
|
++ nCount ;
|
|
}
|
|
dVar21 /= nCount ;
|
|
// elimino i punti dalla parte non valida
|
|
if ( dVar12 > dVar21) {
|
|
// assegno i nuovi valori
|
|
cvBoundClosedLoopVec[nLoop][nCvFirst] = ptProva ;
|
|
cvBoundClosedLoopVec[nLoop][( nCvSecond + 1) % int(cvBoundClosedLoopVec[nLoop].size())] = ptProva ;
|
|
// numero totale di punti
|
|
int nPntTot = int( cvBoundClosedLoopVec[nLoop].size());
|
|
// elimino i punti superflui dopo
|
|
for ( int i = nPntTot - 1 ; i > nCvSecond + 1 ; -- i)
|
|
cvBoundClosedLoopVec[nLoop].pop_back() ;
|
|
// elimino i punti superflui prima
|
|
for ( int i = 0 ; i < nCvFirst ; ++ i)
|
|
cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin()) ;
|
|
// verifico se questo punto � dalla parte valida o no
|
|
bool bC12 = ( ( ptM12 - ptProva) * vtVecProva < 0) ;
|
|
vbInOut[nLoop] = bC12 ;
|
|
}
|
|
else {
|
|
// assegno i nuovi valori
|
|
cvBoundClosedLoopVec[nLoop][nCvFirst + 1] = ptProva ;
|
|
cvBoundClosedLoopVec[nLoop][nCvSecond] = ptProva ;
|
|
// elimino i punti superflui intermedi
|
|
for ( int i = nCvFirst + 2 ; i < nCvSecond ; ++ i)
|
|
cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin() + nCvFirst + 2) ;
|
|
// verifico se questo punto � dalla parte valida o no
|
|
bool bC21 = ( ( ptM21 - ptProva) * vtVecProva < 0) ;
|
|
vbInOut[nLoop] = bC21 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vnDegVec.resize( nLastOpenLoopN) ;
|
|
cvOpenChain.resize( nLastOpenLoopN) ;
|
|
}
|
|
// Rimuovo il triangolo corrente
|
|
RemoveTriangle( nT) ;
|
|
// Trasformo i loop compositi in loop polyline
|
|
POLYLINEVECTOR vplPolyVec ;
|
|
vplPolyVec.resize( cvBoundClosedLoopVec.size()) ;
|
|
for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) {
|
|
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) ; ++ nLine) {
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ;
|
|
}
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][0]) ;
|
|
if ( vbInOut[nLoop]) {
|
|
// Eseguo triangolazione
|
|
Triangulate CreateTriangulation ;
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vplPolyVec[nLoop], vPt, vTr, TrgType::TRG_STANDARD)) {
|
|
// 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]]) } ;
|
|
AddTriangle( nNewId) ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( nVertInside == 0)
|
|
RemoveTriangle( nT) ;
|
|
}
|
|
|
|
// Se avvenuta modifica, aggiorno tutto
|
|
if ( bModif)
|
|
return ( AdjustVertices() && DoCompacting()) ;
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::DecomposeLoop( CHAINVECTOR& cvOpenChain, INTVECTOR& vnDegVec, PNTMATRIX& cvBoundClosedLoopVec, BOOLVECTOR& vbInOut)
|
|
{
|
|
// Valuto se esistono loop non degeneri
|
|
int nExistNotDeg = 0 ;
|
|
for ( int nC = 0 ; nC < int( vnDegVec.size()) ; ++ nC) {
|
|
if ( vnDegVec[nC] > 0)
|
|
++ nExistNotDeg ;
|
|
}
|
|
// Divido il loop di partenza in sotto-loop
|
|
int nIterationCount = 0 ;
|
|
while ( cvOpenChain.size() > 0) {
|
|
bool bLoopSplitted = false ;
|
|
int nLastOpenLoopN = int( cvOpenChain.size()) - 1 ;
|
|
if ( vnDegVec[nLastOpenLoopN] == 1) {
|
|
for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) {
|
|
// Estremi del loop aperto
|
|
int nLastOpenLoopPoint = max( int( cvOpenChain[nLastOpenLoopN].size()) - 1, 0) ;
|
|
Point3d ptOpenLoopStP = cvOpenChain[nLastOpenLoopN][0].ptSt ;
|
|
Point3d ptOpenLoopEnP = cvOpenChain[nLastOpenLoopN][nLastOpenLoopPoint].ptEn ;
|
|
PNTVECTOR Loop1, Loop2 ;
|
|
bool bChangedStart = ChangeStart( ptOpenLoopStP, cvBoundClosedLoopVec[nLoop]) ;
|
|
bool bSplitted = SplitAtPoint( ptOpenLoopEnP, cvBoundClosedLoopVec[nLoop], Loop1, Loop2) ;
|
|
if ( ! ( bChangedStart && bSplitted) ||
|
|
( nLastOpenLoopPoint == 0 && ( Loop1.size() == 2 || Loop2.size() == 2)))
|
|
continue ;
|
|
bLoopSplitted = true ;
|
|
Chain cvCounterChain ;
|
|
for ( int nPt = int( cvOpenChain[nLastOpenLoopN].size()) - 1 ; nPt >= 0 ; -- nPt) {
|
|
IntSegment CurSeg ;
|
|
CurSeg.ptSt = cvOpenChain[nLastOpenLoopN][nPt].ptEn ;
|
|
CurSeg.ptEn = cvOpenChain[nLastOpenLoopN][nPt].ptSt ;
|
|
CurSeg.vtOuter = - cvOpenChain[nLastOpenLoopN][nPt].vtOuter ;
|
|
CurSeg.bDegenerate = cvOpenChain[nLastOpenLoopN][nPt].bDegenerate ;
|
|
cvCounterChain.emplace_back( CurSeg) ;
|
|
}
|
|
bool bAdded1 = AddChainToChain( cvCounterChain, Loop1) ;
|
|
bool bAdded2 = AddChainToChain( cvOpenChain[nLastOpenLoopN], Loop2) ;
|
|
if ( ! ( bAdded1 && bAdded2))
|
|
continue ;
|
|
// Aggiungo i nuovi loop nel vettore
|
|
int nCurSize = int( cvBoundClosedLoopVec.size()) ;
|
|
cvBoundClosedLoopVec.resize( nCurSize + 1) ;
|
|
vbInOut.resize( nCurSize + 1) ;
|
|
for ( int nCL = nCurSize - 1 ; nCL > nLoop ; -- nCL) {
|
|
cvBoundClosedLoopVec[nCL + 1] = cvBoundClosedLoopVec[nCL] ;
|
|
vbInOut[nCL + 1] = vbInOut[nCL] ;
|
|
}
|
|
cvBoundClosedLoopVec[nLoop] = Loop1 ;
|
|
cvBoundClosedLoopVec[nLoop + 1] = Loop2 ;
|
|
vbInOut[nLoop] = false ;
|
|
vbInOut[nLoop + 1] = true ;
|
|
++ nLoop ;
|
|
}
|
|
}
|
|
// Degenere
|
|
else {
|
|
Point3d ptProva = 0.5 * ( cvOpenChain[nLastOpenLoopN][0].ptSt + cvOpenChain[nLastOpenLoopN][0].ptEn) ;
|
|
Vector3d vtVecProva = cvOpenChain[nLastOpenLoopN][0].vtOuter ;
|
|
vtVecProva.Normalize( EPS_ZERO) ;
|
|
for ( int nLoop = 0 ; nLoop < int( cvBoundClosedLoopVec.size()) ; ++ nLoop) {
|
|
// Cerco se esistono dei tratti del loop chiuso corrente che sono
|
|
// toccati dagli estremi del loop aperto corrente
|
|
int nCvFirst = - 1 ;
|
|
int nCvSecond = - 1 ;
|
|
for ( int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) && nCvSecond == - 1 ; ++ nLine) {
|
|
// Estremi del segmento corrente del loop chiuso corrente
|
|
Point3d ptSegSt = cvBoundClosedLoopVec[nLoop][nLine] ;
|
|
Point3d ptSegEn = cvBoundClosedLoopVec[nLoop][( nLine + 1) % int(cvBoundClosedLoopVec[nLoop].size())] ;
|
|
// Vettore congiungente i su definiti punti
|
|
Vector3d vtClosedLoopSeg = ptSegEn - ptSegSt ;
|
|
vtClosedLoopSeg.Normalize() ;
|
|
// Vedo se gli estremi del loop aperto stanno su un segmento del chiuso
|
|
DistPointLine DistCalc( ptProva, ptSegSt, ptSegEn) ;
|
|
double dSqDist ;
|
|
DistCalc.GetSqDist( dSqDist) ;
|
|
if ( dSqDist < 2 * SQ_EPS_SMALL) {
|
|
if ( nCvFirst == - 1)
|
|
nCvFirst = nLine ;
|
|
else
|
|
nCvSecond = nLine ;
|
|
}
|
|
}
|
|
|
|
if ( nCvFirst != nCvSecond && nCvSecond != - 1) {
|
|
// li ordino in senso crescente
|
|
if ( nCvFirst > nCvSecond)
|
|
swap( nCvFirst, nCvSecond) ;
|
|
// punto medio tra primo e secondo
|
|
int nCount = 0 ;
|
|
Point3d ptM12 ;
|
|
for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) {
|
|
ptM12 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
ptM12 /= nCount ;
|
|
// Distanza quadrata media dei punti tra primo e secondo dal baricentro
|
|
double dVar12 = 0. ;
|
|
for ( int i = nCvFirst + 1 ; i <= nCvSecond ; ++ i) {
|
|
dVar12 += ( cvBoundClosedLoopVec[nLoop][i] - ptM12) * ( cvBoundClosedLoopVec[nLoop][i] - ptM12) ;
|
|
}
|
|
dVar12 /= nCount ;
|
|
// punto medio fra secondo e primo
|
|
nCount = 0 ;
|
|
Point3d ptM21 ;
|
|
for ( int i = nCvSecond + 1 ; i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) {
|
|
ptM21 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
for ( int i = 0 ; i <= nCvFirst ; ++ i) {
|
|
ptM21 += cvBoundClosedLoopVec[nLoop][i] ;
|
|
++ nCount ;
|
|
}
|
|
ptM21 /= nCount ;
|
|
// Distanza quadrata media dei punti tra secondo e primo dal baricentro
|
|
double dVar21 = 0. ;
|
|
for ( int i = nCvSecond ; i < i % int( cvBoundClosedLoopVec[nLoop].size()) ; ++ i) {
|
|
dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ;
|
|
++ nCount ;
|
|
}
|
|
for ( int i = 0 ; i <= nCvFirst ; ++ i) {
|
|
dVar21 += ( cvBoundClosedLoopVec[nLoop][i] - ptM21) * ( cvBoundClosedLoopVec[nLoop][i] - ptM21) ;
|
|
++ nCount ;
|
|
}
|
|
dVar21 /= nCount ;
|
|
// elimino i punti dalla parte non valida
|
|
if ( dVar12 > dVar21) {
|
|
// assegno i nuovi valori
|
|
cvBoundClosedLoopVec[nLoop][nCvFirst] = ptProva ;
|
|
cvBoundClosedLoopVec[nLoop][( nCvSecond + 1) % int( cvBoundClosedLoopVec[nLoop].size())] = ptProva ;
|
|
// numero totale di punti
|
|
int nPntTot = int( cvBoundClosedLoopVec[nLoop].size()) ;
|
|
// elimino i punti superflui dopo
|
|
for ( int i = nPntTot - 1 ; i > nCvSecond + 1 ; -- i)
|
|
cvBoundClosedLoopVec[nLoop].pop_back() ;
|
|
// elimino i punti superflui prima
|
|
for ( int i = 0 ; i < nCvFirst ; ++ i)
|
|
cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin()) ;
|
|
// verifico se questo punto � dalla parte valida o no
|
|
bool bC12 = ( ( ptM12 - ptProva) * vtVecProva < 0) ;
|
|
vbInOut[nLoop] = bC12 ;
|
|
}
|
|
else {
|
|
// assegno i nuovi valori
|
|
cvBoundClosedLoopVec[nLoop][nCvFirst + 1] = ptProva ;
|
|
cvBoundClosedLoopVec[nLoop][nCvSecond] = ptProva ;
|
|
// elimino i punti superflui intermedi
|
|
for ( int i = nCvFirst + 2 ; i < nCvSecond ; ++ i)
|
|
cvBoundClosedLoopVec[nLoop].erase( cvBoundClosedLoopVec[nLoop].begin() + nCvFirst + 2) ;
|
|
// verifico se questo punto � dalla parte valida o no
|
|
bool bC21 = ( ( ptM21 - ptProva) * vtVecProva < 0) ;
|
|
vbInOut[nLoop] = bC21 ;
|
|
}
|
|
bLoopSplitted = true ;
|
|
}
|
|
}
|
|
}
|
|
if ( ! bLoopSplitted && ( vnDegVec[nLastOpenLoopN] == 1 || nExistNotDeg == 0)) {
|
|
int nCurDeg = vnDegVec[nLastOpenLoopN] ;
|
|
vnDegVec.emplace( vnDegVec.begin(), nCurDeg) ;
|
|
Chain CurChain ;
|
|
for ( int nCrChSeg = 0 ; nCrChSeg < int( cvOpenChain[nLastOpenLoopN].size()) ; ++ nCrChSeg) {
|
|
IntSegment CurChainSeg ;
|
|
CurChainSeg.ptSt = cvOpenChain[nLastOpenLoopN][nCrChSeg].ptSt ;
|
|
CurChainSeg.ptEn = cvOpenChain[nLastOpenLoopN][nCrChSeg].ptEn ;
|
|
CurChainSeg.vtOuter = cvOpenChain[nLastOpenLoopN][nCrChSeg].vtOuter ;
|
|
CurChainSeg.bDegenerate = cvOpenChain[nLastOpenLoopN][nCrChSeg].bDegenerate ;
|
|
CurChain.emplace_back( CurChainSeg) ;
|
|
}
|
|
cvOpenChain.emplace( cvOpenChain.begin(), CurChain) ;
|
|
++ nLastOpenLoopN ;
|
|
++ nIterationCount ;
|
|
}
|
|
else
|
|
nIterationCount = 0 ;
|
|
vnDegVec.resize( nLastOpenLoopN) ;
|
|
cvOpenChain.resize( nLastOpenLoopN) ;
|
|
if ( nIterationCount > int( cvOpenChain.size()) + 2)
|
|
return false ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECTORMAP& Ambiguos,
|
|
SurfTriMesh& Surf, bool& bModif)
|
|
{
|
|
// La superficie deve essere valida
|
|
if ( ! Surf.IsValid())
|
|
return false ;
|
|
// Ritriangolarizzo i triangoli
|
|
for ( auto it = LoopLines.begin() ; it != LoopLines.end() ; ++ it) {
|
|
for ( int nS1 = 0 ; nS1 < int( it->second.size()) - 1 ; ++ nS1) {
|
|
for ( int nS2 = nS1 + 1 ; nS2 < int( it->second.size()) ; ++ nS2) {
|
|
if ( AreSamePointApprox( it->second[nS1].ptSt, it->second[nS2].ptEn) &&
|
|
AreSamePointApprox( it->second[nS1].ptEn, it->second[nS2].ptSt) &&
|
|
it->second[nS1].vtOuter * it->second[nS2].vtOuter < - EPS_SMALL) {
|
|
it->second.erase( it->second.begin() + nS2) ;
|
|
it->second.erase( it->second.begin() + nS1) ;
|
|
-- nS1 ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( int( it->second.size()) == 0)
|
|
continue ;
|
|
// Se il triangolo � stato sottoposto a ritriangolazione, le sue componenti sono classificabili come dentro-fuori.
|
|
// Lo tolgo dall'insieme dei triangoli ambigui (intersezione edge-edge)
|
|
else {
|
|
auto itS = Ambiguos.find( it->first) ;
|
|
if ( itS != Ambiguos.end()) {
|
|
Ambiguos.erase( itS) ;
|
|
}
|
|
}
|
|
|
|
// Creo i loop
|
|
ChainCurves LoopCreator ;
|
|
LoopCreator.Init( false, 2 * EPS_SMALL, int( it->second.size()), 10 * BOOLEAN_SCALE) ;
|
|
// Carico le curve per concatenarle
|
|
for ( int nCv = 0 ; nCv < int( it->second.size()); ++ nCv) {
|
|
Point3d ptSt = it->second[nCv].ptSt ;
|
|
Point3d ptEn = it->second[nCv].ptEn ;
|
|
Vector3d vtDir = ptEn - ptSt ;
|
|
vtDir.Normalize() ;
|
|
LoopCreator.AddCurve( nCv + 1, ptSt, vtDir, ptEn, vtDir) ;
|
|
}
|
|
// Recupero i concatenamenti
|
|
INTVECTOR vIds ;
|
|
Point3d ptNearStart = ( it->second.size() > 0 ? it->second[0].ptSt : ORIG) ;
|
|
CHAINVECTOR vChain ;
|
|
while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) {
|
|
Chain chTemp ;
|
|
for ( auto i : vIds) {
|
|
// Aggiungo la linea alla curva composta.
|
|
chTemp.emplace_back( it->second[i - 1]) ;
|
|
}
|
|
vChain.emplace_back( chTemp) ;
|
|
}
|
|
// Lavoro su loop e catene per regolarizzarle
|
|
int nChainCnt = int( vChain.size()) ;
|
|
// unisco eventuali catene estreme che sono parte di una stessa catena
|
|
if ( nChainCnt > 1) {
|
|
if ( AreSamePointApprox( vChain[0].front().ptSt, vChain[nChainCnt - 1].back().ptEn)) {
|
|
vChain[0].insert( vChain[0].begin(), vChain[nChainCnt - 1].begin(), vChain[nChainCnt - 1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
else if ( AreSamePointApprox( vChain[0].back().ptEn, vChain[nChainCnt - 1].front().ptSt)) {
|
|
vChain[0].insert( vChain[0].end(), vChain[nChainCnt - 1].begin(), vChain[nChainCnt - 1].end()) ;
|
|
vChain.pop_back() ;
|
|
-- nChainCnt ;
|
|
}
|
|
}
|
|
// semplifico catene formate da punti degeneri
|
|
for ( int nCh = 0 ; nCh < nChainCnt ; ++ nCh) {
|
|
if ( vChain[nCh].size() == 2 && ( vChain[nCh][0].bDegenerate || vChain[nCh][1].bDegenerate)) {
|
|
vChain[nCh][0].ptEn = vChain[nCh][1].ptEn ;
|
|
vChain[nCh][0].vtOuter = ( vChain[nCh][0].bDegenerate ? vChain[nCh][1].vtOuter : vChain[nCh][0].vtOuter) ;
|
|
vChain[nCh][0].bDegenerate = AreSamePointApprox( vChain[nCh][0].ptSt, vChain[nCh][0].ptEn) ;
|
|
vChain[nCh].resize( 1) ;
|
|
}
|
|
}
|
|
// Elimino la seconda copia di catene doppie
|
|
for ( int nI = 0 ; nI < nChainCnt ; ++ nI) {
|
|
for ( int nJ = nI + 1 ; nJ < nChainCnt ; ++ nJ) {
|
|
if ( vChain[nI].size() == vChain[nJ].size()) {
|
|
bool bSame = true ;
|
|
for ( int nK = 0 ; nK < int( vChain[nI].size()) ; ++ nK) {
|
|
if ( ! AreSamePointApprox( vChain[nI][nK].ptSt, vChain[nJ][nK].ptSt) ||
|
|
! AreSamePointApprox( vChain[nI][nK].ptEn, vChain[nJ][nK].ptEn)) {
|
|
bSame = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bSame) {
|
|
vChain.erase( vChain.begin() + nJ) ;
|
|
-- nChainCnt ;
|
|
-- nJ ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Se esistono loop divisi in catene, le unisco
|
|
Triangle3d trTria ;
|
|
Surf.GetTriangle( it->first, trTria) ;
|
|
for ( int nC1 = 0 ; nC1 < nChainCnt - 1 ; ++ nC1) {
|
|
int nFirstChainLastSegPos = int( vChain[nC1].size()) - 1 ;
|
|
bool bFirstChainInside = nFirstChainLastSegPos >= 0 &&
|
|
IsPointInsideTriangle( vChain[nC1][0].ptSt, trTria, TriangleType::OPEN) &&
|
|
IsPointInsideTriangle( vChain[nC1][nFirstChainLastSegPos].ptEn, trTria, TriangleType::OPEN) ;
|
|
for ( int nC2 = nC1 + 1 ; nC2 < nChainCnt && bFirstChainInside ; ++ nC2) {
|
|
int nSecondChainLastSegPos = int( vChain[nC2].size()) - 1 ;
|
|
bool bSecondChainInside = nSecondChainLastSegPos >= 0 &&
|
|
IsPointInsideTriangle( vChain[nC2][0].ptSt, trTria, TriangleType::OPEN) &&
|
|
IsPointInsideTriangle( vChain[nC2][nSecondChainLastSegPos].ptEn, trTria, TriangleType::OPEN) ;
|
|
nFirstChainLastSegPos = int( vChain[nC1].size()) - 1 ;
|
|
bool bFisrtSecond = AreSamePointEpsilon( vChain[nC1][nFirstChainLastSegPos].ptEn, vChain[nC2][0].ptSt, 10 * EPS_SMALL) ;
|
|
for ( int nSeg = 0 ; nSeg <= nSecondChainLastSegPos && bSecondChainInside && bFisrtSecond ; ++ nSeg) {
|
|
IntSegment CurSeg ;
|
|
CurSeg.ptSt = vChain[nC2][nSeg].ptSt ;
|
|
CurSeg.ptEn = vChain[nC2][nSeg].ptEn ;
|
|
CurSeg.vtOuter = vChain[nC2][nSeg].vtOuter ;
|
|
CurSeg.bDegenerate = vChain[nC2][nSeg].bDegenerate ;
|
|
vChain[nC1].emplace_back( CurSeg) ;
|
|
}
|
|
bool bSecondFirst = AreSamePointEpsilon( vChain[nC1][0].ptSt, vChain[nC2][nSecondChainLastSegPos].ptEn, 10 * EPS_SMALL) ;
|
|
for ( int nSeg = 0 ; nSeg <= nFirstChainLastSegPos && bSecondChainInside && bSecondFirst && ! bFisrtSecond ; ++ nSeg) {
|
|
IntSegment CurSeg ;
|
|
CurSeg.ptSt = vChain[nC1][nSeg].ptSt ;
|
|
CurSeg.ptEn = vChain[nC1][nSeg].ptEn ;
|
|
CurSeg.vtOuter = vChain[nC1][nSeg].vtOuter ;
|
|
CurSeg.bDegenerate = vChain[nC1][nSeg].bDegenerate ;
|
|
vChain[nC2].emplace_back( CurSeg) ;
|
|
}
|
|
if ( bSecondChainInside && bFisrtSecond && nSecondChainLastSegPos >= 0) {
|
|
nFirstChainLastSegPos = int( vChain[nC1].size()) - 1 ;
|
|
bFirstChainInside = nFirstChainLastSegPos >= 0 &&
|
|
IsPointInsideTriangle( vChain[nC1][0].ptSt, trTria, TriangleType::OPEN) &&
|
|
IsPointInsideTriangle( vChain[nC1][nFirstChainLastSegPos].ptEn, trTria, TriangleType::OPEN) ;
|
|
vChain.erase( vChain.begin() + nC2) ;
|
|
-- nChainCnt ;
|
|
-- nC2 ;
|
|
}
|
|
if ( bSecondChainInside && bSecondFirst && ! bFisrtSecond && nFirstChainLastSegPos >= 0) {
|
|
vChain.erase( vChain.begin() + nC1) ;
|
|
-- nChainCnt ;
|
|
-- nC2 ;
|
|
nC2 = nC2 == nC1 ? nC2 + 1 : nC2 ;
|
|
}
|
|
}
|
|
}
|
|
// Chiudo i loop costruiti a partire dalle catene
|
|
for ( int nC = 0 ; nC < nChainCnt ; ++ nC) {
|
|
int nChainLastSegPos = int( vChain[nC].size()) - 1 ;
|
|
if ( IsPointInsideTriangle( vChain[nC][0].ptSt, trTria, TriangleType::OPEN) &&
|
|
IsPointInsideTriangle( vChain[nC][nChainLastSegPos].ptEn, trTria, TriangleType::OPEN) &&
|
|
AreSamePointEpsilon( vChain[nC][0].ptSt, vChain[nC][nChainLastSegPos].ptEn, 10 * EPS_SMALL)) {
|
|
IntSegment CurSeg ;
|
|
CurSeg.ptSt = vChain[nC][nChainLastSegPos].ptEn ;
|
|
CurSeg.ptEn = vChain[nC][0].ptSt ;
|
|
CurSeg.vtOuter = ( CurSeg.ptEn - CurSeg.ptSt) ^ trTria.GetN() ;
|
|
CurSeg.vtOuter.Normalize() ;
|
|
CurSeg.bDegenerate = ( CurSeg.ptEn - CurSeg.ptSt).Len() > EPS_SMALL ;
|
|
vChain[nC].emplace_back( CurSeg) ;
|
|
}
|
|
}
|
|
|
|
// Fra le catene trovate separo le aperte dalle chiuse
|
|
int nDegenerateChainNum = 0 ;
|
|
INTVECTOR vnDegVec ;
|
|
CHAINVECTOR cvClosedChain ;
|
|
CHAINVECTOR cvOpenChain ;
|
|
for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) {
|
|
bool bChainDegenerate = false ;
|
|
if ( vChain[nL].size() == 1 && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][0].ptEn)) {
|
|
bChainDegenerate = true ;
|
|
}
|
|
|
|
if ( bChainDegenerate)
|
|
++ nDegenerateChainNum ;
|
|
int nCurLoopLast = max( int( vChain[nL].size()) - 1, 0) ;
|
|
if ( ( ! bChainDegenerate) && AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn))
|
|
cvClosedChain.emplace_back( vChain[nL]) ;
|
|
else {
|
|
cvOpenChain.emplace_back( vChain[nL]) ;
|
|
if ( bChainDegenerate)
|
|
vnDegVec.emplace_back( 0) ;
|
|
else
|
|
vnDegVec.emplace_back( 1) ;
|
|
}
|
|
}
|
|
|
|
for ( int nCh1 = 0 ; nCh1 < int( cvOpenChain.size()) - 1 ; ++ nCh1) {
|
|
for ( int nCh2 = nCh1 + 1 ; nCh2 < int( cvOpenChain.size()) ; ++ nCh2) {
|
|
int nChainSize1 = int( cvOpenChain[nCh1].size()) ;
|
|
int nChainSize2 = int( cvOpenChain[nCh2].size()) ;
|
|
int nSameSeg = 0 ;
|
|
for ( int nSeg1 = 0 ; nSeg1 < nChainSize1 ; ++ nSeg1) {
|
|
for ( int nSeg2 = 0 ; nSeg2 < nChainSize2 ; ++ nSeg2) {
|
|
if ( AreSamePointExact( cvOpenChain[nCh1][nSeg1].ptSt, cvOpenChain[nCh2][nSeg2].ptSt) &&
|
|
AreSamePointExact( cvOpenChain[nCh1][nSeg1].ptEn, cvOpenChain[nCh2][nSeg2].ptEn) &&
|
|
AreSameVectorExact( cvOpenChain[nCh1][nSeg1].vtOuter, cvOpenChain[nCh2][nSeg2].vtOuter)) {
|
|
++ nSameSeg ;
|
|
}
|
|
}
|
|
}
|
|
if ( nChainSize1 == nSameSeg) {
|
|
cvOpenChain.erase( cvOpenChain.begin() + nCh1) ;
|
|
vnDegVec.erase( vnDegVec.begin() + nCh1) ;
|
|
-- nCh1 ;
|
|
}
|
|
else if ( nChainSize2 == nSameSeg) {
|
|
cvOpenChain.erase( cvOpenChain.begin() + nCh2) ;
|
|
vnDegVec.erase( vnDegVec.begin() + nCh2) ;
|
|
-- nCh2 ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Creo il loop chiuso padre di tutti, il perimetro del triangolo.
|
|
// Questo viene diviso in sotto-loop chiusi mediante quelli aperti.
|
|
// I loop chiusi trovati precedentemente sono interni a uno dei sotto-loop
|
|
// chiusi di cui � formato il perimetro.
|
|
PNTVECTOR cvFirstLoop ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 0)) ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 1)) ;
|
|
cvFirstLoop.emplace_back( trTria.GetP( 2)) ;
|
|
|
|
PNTMATRIX cvBoundClosedLoopVec;
|
|
cvBoundClosedLoopVec.emplace_back( cvFirstLoop) ;
|
|
BOOLVECTOR vbInOut ;
|
|
vbInOut.push_back( true) ;
|
|
// Divido il loop usando le catene
|
|
if ( ! DecomposeLoop( cvOpenChain, vnDegVec, cvBoundClosedLoopVec, vbInOut)) {
|
|
if ( int( cvBoundClosedLoopVec.size()) == 1 && int( cvOpenChain.size()) == 2) {
|
|
Point3d ptLink0St = cvOpenChain[0][0].ptSt ;
|
|
Point3d ptLink0En = cvOpenChain[0].back().ptEn ;
|
|
Point3d ptLink1St = cvOpenChain.back()[0].ptSt ;
|
|
Point3d ptLink1En = cvOpenChain.back().back().ptEn ;
|
|
double dDist01 = sqrt( ( ptLink0En - ptLink1St) * ( ptLink0En - ptLink1St)) ;
|
|
double dDist10 = sqrt( ( ptLink1En - ptLink0St) * ( ptLink1En - ptLink0St)) ;
|
|
if ( dDist01 < 2 * EPS_SMALL) {
|
|
IntSegment LinkingSeg ;
|
|
LinkingSeg.ptSt = ptLink0En ;
|
|
LinkingSeg.ptEn = ptLink1St ;
|
|
LinkingSeg.vtOuter = cvOpenChain[0].back().vtOuter ;
|
|
LinkingSeg.bDegenerate = false ;
|
|
cvOpenChain[0].emplace_back( LinkingSeg) ;
|
|
for ( int nLinkI = 0 ; nLinkI < int( cvOpenChain.back().size()) ; ++ nLinkI) {
|
|
cvOpenChain[0].emplace_back( cvOpenChain.back()[nLinkI]) ;
|
|
}
|
|
cvOpenChain.resize( 1) ;
|
|
int nComplDeg = vnDegVec[0] * vnDegVec[1] ;
|
|
vnDegVec[0] = nComplDeg ;
|
|
vnDegVec.resize( 1) ;
|
|
}
|
|
else if ( dDist10 < 2 * EPS_SMALL) {
|
|
IntSegment LinkingSeg ;
|
|
LinkingSeg.ptSt = cvOpenChain.back().back().ptEn ;
|
|
LinkingSeg.ptEn = cvOpenChain[0].back().ptSt ;
|
|
LinkingSeg.vtOuter = cvOpenChain.back().back().vtOuter ;
|
|
LinkingSeg.bDegenerate = false ;
|
|
cvOpenChain.back().emplace_back( LinkingSeg) ;
|
|
for ( int nLinkI = 0 ; nLinkI < int( cvOpenChain[0].size()) ; ++ nLinkI) {
|
|
cvOpenChain.back().emplace_back( cvOpenChain[0][nLinkI]) ;
|
|
}
|
|
cvOpenChain.erase( cvOpenChain.begin()) ;
|
|
int nComplDeg = vnDegVec[0] * vnDegVec[1] ;
|
|
vnDegVec[0] = nComplDeg ;
|
|
vnDegVec.resize( 1) ;
|
|
}
|
|
else {
|
|
Surf.m_vTria[it->first].nTempPart = 0 ;
|
|
continue ;
|
|
}
|
|
vbInOut.resize( 1) ;
|
|
vbInOut[0] = true ;
|
|
if ( ! DecomposeLoop( cvOpenChain, vnDegVec, cvBoundClosedLoopVec, vbInOut)) {
|
|
Surf.m_vTria[it->first].nTempPart = 0 ;
|
|
continue ;
|
|
}
|
|
}
|
|
else {
|
|
Surf.m_vTria[it->first].nTempPart = 0 ;
|
|
continue ;
|
|
}
|
|
}
|
|
// Rimuovo il triangolo corrente
|
|
int nOldTriaCol = Surf.m_vTria[it->first].nTFlag ;
|
|
Surf.RemoveTriangle( it->first) ;
|
|
// Trasformo i loop compositi in loop polyline
|
|
POLYLINEVECTOR vplPolyVec ;
|
|
vplPolyVec.resize( cvBoundClosedLoopVec.size()) ;
|
|
for ( int nLoop = 0 ; nLoop < int( vplPolyVec.size()) ; ++ nLoop) {
|
|
for (int nLine = 0 ; nLine < int( cvBoundClosedLoopVec[nLoop].size()) ; ++ nLine) {
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][nLine]) ;
|
|
}
|
|
vplPolyVec[nLoop].AddUPoint( 0., cvBoundClosedLoopVec[nLoop][0]) ;
|
|
|
|
// Assegno ai loop trovati i rispettivi interni
|
|
// Assumo che i loop interni a uno dei loop creati fino ad'ora siano tutti sullo stesso livello.
|
|
// Il caso generale si risolve con una struttura ad albero in cui il nodi corrispondente a un
|
|
// loop � figlio del nodo corrispondente al loop che lo contiene.
|
|
INTVECTOR vInnerLoop ;
|
|
for ( int nCLI = 0 ; nCLI < int( cvClosedChain.size()) ; ++ nCLI) {
|
|
for ( int nPtNum = 0 ; nPtNum < int( cvClosedChain[nCLI].size()) ; ++ nPtNum) {
|
|
Point3d ptLoopStart = cvClosedChain[nCLI][nPtNum].ptSt ;
|
|
double dMinDist = DBL_MAX ;
|
|
Point3d ptMinDist ;
|
|
bool bPointOnSt = false ;
|
|
bool bPointOnEn = false ;
|
|
int nSegNum = 0 ;
|
|
int nSegMin = 0 ;
|
|
Point3d ptS, ptE ;
|
|
bool bContinueS = vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
bool bContinueE = vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
while ( bContinueS && bContinueE) {
|
|
++ nSegNum ;
|
|
DistPointLine DistCalculator( ptLoopStart, ptS, ptE) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
if ( dDist < dMinDist) {
|
|
DistCalculator.GetMinDistPoint( ptMinDist) ;
|
|
bPointOnSt = AreSamePointExact( ptMinDist, ptS) ;
|
|
bPointOnEn = AreSamePointExact( ptMinDist, ptE) ;
|
|
dMinDist = dDist ;
|
|
nSegMin = nSegNum ;
|
|
}
|
|
ptS = ptE ;
|
|
bContinueS = bContinueE ;
|
|
bContinueE = vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
if ( ! ( bPointOnSt || bPointOnEn)) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptS = ptE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtOut = vtTan ^ trTria.GetN() ;
|
|
Point3d ptMinDist2 ;
|
|
DistPointLine DistCalculator( ptLoopStart, ptS, ptE) ;
|
|
DistCalculator.GetMinDistPoint( ptMinDist2) ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist2) * vtOut ;
|
|
if ( dMinDistDot < - EPS_SMALL) {
|
|
vInnerLoop.emplace_back( nCLI) ;
|
|
break ;
|
|
}
|
|
}
|
|
else if ( bPointOnSt) {
|
|
Point3d ptPrevS, ptPrevE ;
|
|
if ( nSegMin == 1) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
vplPolyVec[nLoop].GetLastPoint( ptPrevE) ;
|
|
vplPolyVec[nLoop].GetPrevPoint( ptPrevS) ;
|
|
}
|
|
else {
|
|
-- nSegMin ;
|
|
vplPolyVec[nLoop].GetFirstPoint( ptPrevS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptPrevE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptPrevS = ptPrevE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptPrevE) ;
|
|
}
|
|
ptS = ptPrevE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtTanPrev = ptPrevE - ptPrevS ;
|
|
vtTanPrev.Normalize() ;
|
|
Vector3d vtBisector = 0.5 * ( vtTan + vtTanPrev) ^ trTria.GetN() ;
|
|
vtBisector.Normalize() ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist) * vtBisector ;
|
|
if ( dMinDistDot < - EPS_SMALL) {
|
|
vInnerLoop.emplace_back( nCLI) ;
|
|
break ;
|
|
}
|
|
}
|
|
else if ( bPointOnEn) {
|
|
Point3d ptLast ;
|
|
vplPolyVec[nLoop].GetLastPoint( ptLast) ;
|
|
vplPolyVec[nLoop].GetFirstPoint( ptS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
for ( int nSeg = 1 ; nSeg < nSegMin ; ++ nSeg) {
|
|
ptS = ptE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptE) ;
|
|
}
|
|
Point3d ptNextS, ptNextE ;
|
|
if ( AreSamePointExact( ptE, ptLast)) {
|
|
vplPolyVec[nLoop].GetFirstPoint( ptNextS) ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptNextE) ;
|
|
}
|
|
else {
|
|
ptNextS = ptE ;
|
|
vplPolyVec[nLoop].GetNextPoint( ptNextE) ;
|
|
}
|
|
Vector3d vtTan = ptE - ptS ;
|
|
vtTan.Normalize() ;
|
|
Vector3d vtTanNext = ptNextE - ptNextS ;
|
|
vtTanNext.Normalize() ;
|
|
Vector3d vtBisector = 0.5 * ( vtTan + vtTanNext) ^ trTria.GetN() ;
|
|
vtBisector.Normalize() ;
|
|
double dMinDistDot = ( ptLoopStart - ptMinDist) * vtBisector ;
|
|
if ( dMinDistDot < - EPS_SMALL) {
|
|
vInnerLoop.emplace_back( nCLI) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Elimino loop interni non validi
|
|
bool bDouble = true ;
|
|
for ( int nInnLoop = 0 ; nInnLoop < int( vInnerLoop.size()) ; ++ nInnLoop) {
|
|
if ( int( cvClosedChain[vInnerLoop[nInnLoop]].size()) > 2) {
|
|
bDouble = false ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
if ( vInnerLoop.size() == 0 || bDouble) {
|
|
// Eseguo triangolazione
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vplPolyVec[nLoop], vPt, vTr, TrgType::TRG_STANDARD)) {
|
|
// 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] = { Surf.AddVertex( vPt[nNewTriaVertId[0]]),
|
|
Surf.AddVertex( vPt[nNewTriaVertId[1]]),
|
|
Surf.AddVertex( vPt[nNewTriaVertId[2]]) } ;
|
|
int nNewTriaNum = Surf.AddTriangle( nNewId, nOldTriaCol) ;
|
|
if ( IsValidSvt( nNewTriaNum)) {
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ;
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ;
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ;
|
|
if ( vbInOut[nLoop])
|
|
Surf.m_vTria[nNewTriaNum].nTempPart = 1 ;
|
|
else
|
|
Surf.m_vTria[nNewTriaNum].nTempPart = - 1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
POLYLINEVECTOR vPolygons ;
|
|
vPolygons.emplace_back( vplPolyVec[nLoop]) ;
|
|
for ( int nL = 0 ; nL < int( vInnerLoop.size()) ; ++ nL) {
|
|
PolyLine CurLoop ;
|
|
for ( int nV = 0 ; nV < int( cvClosedChain[vInnerLoop[nL]].size()) ; ++ nV) {
|
|
CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][nV].ptSt) ;
|
|
}
|
|
CurLoop.AddUPoint( 0., cvClosedChain[vInnerLoop[nL]][0].ptSt) ;
|
|
vPolygons.emplace_back( CurLoop) ;
|
|
}
|
|
|
|
Polygon3d pgPol ;
|
|
pgPol.FromPolyLine(vPolygons[1]) ;
|
|
|
|
bool bCodirectedNormals = trTria.GetN() * pgPol.GetVersN() > 0. ;
|
|
if ( bCodirectedNormals) {
|
|
for ( int nL = 1 ; nL < int( vPolygons.size()) ; ++ nL) {
|
|
vPolygons[nL].Invert() ;
|
|
}
|
|
}
|
|
|
|
// Aggiungo al loop esterno i punti dei loop interni che si trovano su di esso
|
|
PNTULIST& ExternLoopList = vPolygons[0].GetUPointList() ;
|
|
// Ciclo sui segmenti del loop esterno
|
|
auto itSt = ExternLoopList.begin() ;
|
|
auto itEn = itSt ;
|
|
++ itEn ;
|
|
for ( ; itSt != ExternLoopList.end() && itEn != ExternLoopList.end() ; ++ itSt, ++ itEn) {
|
|
// Estremi del segmento corrente del loop esterno e scorrispondente vettore
|
|
Point3d ptSt = itSt->first ;
|
|
Point3d ptEn = itEn->first ;
|
|
Vector3d vtSeg = ptEn - ptSt ;
|
|
double dSegLen = vtSeg.Len() ;
|
|
vtSeg /= dSegLen ;
|
|
// Vettore dei punti dei loop interni che stanno sul segmento del loop esterno
|
|
PNTUVECTOR vPointWithOrder ;
|
|
// Ciclo sui loop interni
|
|
for ( int nInnPoly = 1 ; nInnPoly < int( vPolygons.size()) ; ++ nInnPoly) {
|
|
// Ciclo sui punti dei loop interni
|
|
Point3d ptInnPoint ;
|
|
bool bIsFirst = true ;
|
|
bool bContinue = vPolygons[nInnPoly].GetFirstPoint( ptInnPoint) ;
|
|
while ( bContinue) {
|
|
DistPointLine DistCalculator( ptInnPoint, ptSt, ptEn) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
double dLongPos = ( ptInnPoint - ptSt) * vtSeg ;
|
|
if ( dDist < EPS_SMALL && dLongPos > 0. && dLongPos < dSegLen) {
|
|
POINTU NewPointU ;
|
|
NewPointU.first = ptInnPoint ;
|
|
NewPointU.second = dLongPos ;
|
|
if ( ! bIsFirst)
|
|
vPointWithOrder.emplace_back( NewPointU) ;
|
|
}
|
|
bIsFirst = false ;
|
|
bContinue = vPolygons[nInnPoly].GetNextPoint( ptInnPoint) ;
|
|
}
|
|
}
|
|
// Riordino i punti interni sul segmento esterno in funzione della distanza dall'origine di esso
|
|
for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) - 1 ; ++ nPi) {
|
|
for ( int nPj = nPi + 1 ; nPj < int( vPointWithOrder.size()) ; ++ nPj) {
|
|
if ( vPointWithOrder[nPi].second > vPointWithOrder[nPj].second) {
|
|
swap( vPointWithOrder[nPi], vPointWithOrder[nPj]) ;
|
|
}
|
|
}
|
|
}
|
|
// Aggiungo i punti al loop esterno
|
|
for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) ; ++ nPi) {
|
|
itSt = ExternLoopList.emplace( itEn, vPointWithOrder[nPi]) ;
|
|
}
|
|
}
|
|
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( vPolygons, vPt, vTr, TrgType::TRG_STANDARD)) {
|
|
// 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] = { Surf.AddVertex( vPt[nNewTriaVertId[0]]),
|
|
Surf.AddVertex( vPt[nNewTriaVertId[1]]),
|
|
Surf.AddVertex( vPt[nNewTriaVertId[2]])} ;
|
|
int nNewTriaNum = Surf.AddTriangle( nNewId, nOldTriaCol) ;
|
|
if ( IsValidSvt( nNewTriaNum)) {
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ;
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ;
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ;
|
|
if ( bCodirectedNormals)
|
|
Surf.m_vTria[nNewTriaNum].nTempPart = -1 ;
|
|
else
|
|
Surf.m_vTria[nNewTriaNum].nTempPart = 1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
// Divido i loop che si autointercettano
|
|
int nInitialLoopNum = int( vPolygons.size()) ;
|
|
for ( int nL = 1 ; nL < nInitialLoopNum ; ++ nL) {
|
|
// Lista dei punti della PolyLine Loop corrente
|
|
PNTULIST& LoopPointList = vPolygons[nL].GetUPointList() ;
|
|
// Ciclo sui segmenti
|
|
auto itSt2 = LoopPointList.begin() ;
|
|
auto itEn2 = itSt2 ;
|
|
++ itEn2 ;
|
|
for ( ; itSt2 != LoopPointList.end() && itEn2 != LoopPointList.end() ; ++ itSt2, ++ itEn2) {
|
|
// Segmento corrente
|
|
Point3d ptSt = itSt2->first ;
|
|
Point3d ptEn = itEn2->first ;
|
|
Vector3d vtSeg = ptEn - ptSt ;
|
|
double dSegLen = vtSeg.Len() ;
|
|
vtSeg /= dSegLen ;
|
|
// Lista di punti da aggiungere al segmento corrente
|
|
PNTUVECTOR vAddingPointWithOrder ;
|
|
// Ciclo su tutti i punti non del segmento corrente
|
|
auto itP = LoopPointList.begin() ;
|
|
for ( ; itP != LoopPointList.end() ; ++ itP) {
|
|
if ( itP != itSt2 && itP != itEn2) {
|
|
Point3d ptP = itP->first ;
|
|
DistPointLine DistCalculator( ptP, ptSt, ptEn) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
double dLongPos = ( ptP - ptSt) * vtSeg ;
|
|
if ( dDist < EPS_SMALL && dLongPos > 0. && dLongPos < dSegLen) {
|
|
POINTU NewPointU ;
|
|
NewPointU.first = ptP ;
|
|
NewPointU.second = dLongPos ;
|
|
vAddingPointWithOrder.emplace_back( NewPointU) ;
|
|
}
|
|
}
|
|
}
|
|
// Riordino i punti interni sul segmento esterno in funzione della distanza dall'origine di esso
|
|
for ( int nPi = 0 ; nPi < int( vAddingPointWithOrder.size()) - 1 ; ++ nPi) {
|
|
for ( int nPj = nPi + 1 ; nPj < int( vAddingPointWithOrder.size()) ; ++ nPj) {
|
|
if ( vAddingPointWithOrder[nPi].second > vAddingPointWithOrder[nPj].second) {
|
|
swap( vAddingPointWithOrder[nPi], vAddingPointWithOrder[nPj]) ;
|
|
}
|
|
}
|
|
}
|
|
// Aggiungo i punti al loop esterno
|
|
for ( int nPi = 0 ; nPi < int( vAddingPointWithOrder.size()) ; ++ nPi) {
|
|
itSt2 = LoopPointList.emplace( itEn2, vAddingPointWithOrder[nPi]) ;
|
|
}
|
|
}
|
|
// Spezzo i loop autointersecantesi
|
|
|
|
POLYLINEVECTOR vAuxPolygons ;
|
|
vAuxPolygons.emplace_back( vPolygons[nL]) ;
|
|
|
|
bool bSplitted = true ;
|
|
while ( bSplitted) {
|
|
bSplitted = false ;
|
|
for ( int nl = 0 ; nl < int( vAuxPolygons.size()) ; ++ nl) {
|
|
PNTULIST& PntLst = vAuxPolygons[nl].GetUPointList() ;
|
|
PNTVECTOR vPoint ;
|
|
for ( auto it2 = PntLst.begin() ; it2 != PntLst.end() ; ++ it2) {
|
|
vPoint.emplace_back( it2->first) ;
|
|
}
|
|
int nStartPt = -1 ;
|
|
int nEndPt = int( vPoint.size()) ;
|
|
for ( int ni = 0 ; ni < int( vPoint.size()) - 1 ; ++ ni) {
|
|
for ( int nj = ni + 1 ; nj < int( vPoint.size()) ; ++ nj) {
|
|
if ( ( ni != 0 || nj != int( vPoint.size()) - 1) &&
|
|
AreSamePointApprox( vPoint[ni], vPoint[nj])) {
|
|
nStartPt = ni ;
|
|
nEndPt = nj ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
if ( nStartPt != -1 && nEndPt != int( vPoint.size())) {
|
|
PolyLine CurAuxLoop1, CurAuxLoop2 ;
|
|
for ( int ni = 0 ; ni < int( vPoint.size()) ; ++ ni) {
|
|
if ( ni < nStartPt || ni >= nEndPt)
|
|
CurAuxLoop1.AddUPoint( 0., vPoint[ni]) ;
|
|
else
|
|
CurAuxLoop2.AddUPoint( 0., vPoint[ni]) ;
|
|
}
|
|
CurAuxLoop2.AddUPoint( 0., vPoint[nStartPt]) ;
|
|
vAuxPolygons[nl].Clear() ;
|
|
Point3d ptP ;
|
|
bool bContinue = CurAuxLoop1.GetFirstPoint( ptP) ;
|
|
while ( bContinue) {
|
|
vAuxPolygons[nl].AddUPoint( 0., ptP) ;
|
|
bContinue = CurAuxLoop1.GetNextPoint( ptP) ;
|
|
}
|
|
vAuxPolygons.emplace_back( CurAuxLoop2) ;
|
|
bSplitted = true ;
|
|
}
|
|
}
|
|
}
|
|
bool bReplaced = false ;
|
|
for ( int nl = 0 ; nl < int( vAuxPolygons.size()) ; ++ nl) {
|
|
if ( true/*vAuxPolygons.GetAreaXY(double& dArea)*/) {
|
|
if ( ! bReplaced) {
|
|
vPolygons[nL].Clear() ;
|
|
Point3d ptP ;
|
|
bool bContinue = vAuxPolygons[nl].GetFirstPoint( ptP) ;
|
|
while ( bContinue) {
|
|
vPolygons[nL].AddUPoint( 0., ptP) ;
|
|
bContinue = vAuxPolygons[nl].GetNextPoint( ptP) ;
|
|
}
|
|
bReplaced = true ;
|
|
}
|
|
else {
|
|
vPolygons.emplace_back( vAuxPolygons[nl]) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for ( int nL = 1 ; nL < int( vPolygons.size()) ; ++ nL) {
|
|
vPolygons[nL].Invert() ;
|
|
if ( Triangulate().Make( vPolygons[nL], vPt, vTr, TrgType::TRG_STANDARD)) {
|
|
// 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] = { Surf.AddVertex( vPt[nNewTriaVertId[0]]),
|
|
Surf.AddVertex( vPt[nNewTriaVertId[1]]),
|
|
Surf.AddVertex( vPt[nNewTriaVertId[2]])} ;
|
|
int nNewTriaNum = Surf.AddTriangle( nNewId, nOldTriaCol) ;
|
|
if ( IsValidSvt( nNewTriaNum)) {
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ;
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ;
|
|
Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ;
|
|
if ( bCodirectedNormals)
|
|
Surf.m_vTria[nNewTriaNum].nTempPart = 1 ;
|
|
else
|
|
Surf.m_vTria[nNewTriaNum].nTempPart = -1 ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vInnerLoop.resize( 0) ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
FindTriaIncidence( const Triangle3d& trTria, const TRIA3DVECTOR& vOthTriaVec, INTMATRIX& vAdjSegToCurTria)
|
|
{
|
|
int nNumFoundContact = 0 ;
|
|
vAdjSegToCurTria.resize( 3) ;
|
|
for ( int nEdge = 0 ; nEdge < 3 ; ++ nEdge) {
|
|
for ( int nOther = 0 ; nOther < int( vOthTriaVec.size()) ; ++ nOther) {
|
|
Triangle3d trOthTria = vOthTriaVec[nOther] ;
|
|
Point3d ptSt = trTria.GetP( nEdge) ;
|
|
Point3d ptEn = trTria.GetP( ( nEdge + 1) % 3) ;
|
|
CurveLine cvEdgeLine ;
|
|
cvEdgeLine.Set( ptSt, ptEn) ;
|
|
for ( int nOthEdge = 0 ; nOthEdge < 3 ; ++ nOthEdge) {
|
|
Point3d ptOthSt = trOthTria.GetP( nOthEdge) ;
|
|
Point3d ptOthEn = trOthTria.GetP( ( nOthEdge + 1) % 3) ;
|
|
CurveLine cvOthEdgeLine ;
|
|
cvOthEdgeLine.Set( ptOthSt, ptOthEn) ;
|
|
DistPointLine DistCalculatorCurOth( 0.5 * ( ptSt + ptEn), cvOthEdgeLine, false) ;
|
|
double dSqDistCurOth ;
|
|
DistCalculatorCurOth.GetSqDist( dSqDistCurOth) ;
|
|
DistPointLine DistCalculatorOthCur( 0.5 * ( ptOthSt + ptOthEn), cvEdgeLine, false) ;
|
|
double dSqDistOthCur ;
|
|
DistCalculatorOthCur.GetSqDist( dSqDistOthCur) ;
|
|
if ( dSqDistCurOth < EPS_SMALL * EPS_SMALL && dSqDistOthCur < EPS_SMALL * EPS_SMALL) {
|
|
vAdjSegToCurTria[nEdge].emplace_back( nOther) ;
|
|
++ nNumFoundContact ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ( nNumFoundContact == int( vOthTriaVec.size())) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::AmbiguosTriangleManager( TRIA3DVECTORMAP& Ambiguos, SurfTriMesh& Surf)
|
|
{
|
|
for ( auto it = Ambiguos.begin() ; it != Ambiguos.end() ; ++ it) {
|
|
// Se il triangolo ha l'indice diverso da zero vuol dire che oltre a un
|
|
// contatto edge-edge ha avuto dei contatti che lo hanno gi� classificato.
|
|
if ( Surf.m_vTria[it->first].nTempPart != 0)
|
|
continue ;
|
|
// Recupero il triangolo corrente
|
|
Triangle3d trTria ;
|
|
Surf.GetTriangle( it->first, trTria) ;
|
|
trTria.Validate() ;
|
|
// Vettore dei triangoli i cui edge incidono su quelli del triangolo corrente
|
|
TRIA3DVECTOR& vOthTriaVec = it->second ;
|
|
// Vettore degli indici dei segmenti del triangolo adiacenti agli altri triangoli
|
|
INTMATRIX vAdjSegToCurTria ;
|
|
if ( ! FindTriaIncidence( trTria, vOthTriaVec, vAdjSegToCurTria))
|
|
return false ;
|
|
// Classifico il triangolo in base ai triangoli che incidono sui suoi edge
|
|
int nTriaClassificationByEdges[3] = { 0, 0, 0 } ;
|
|
for ( int nEdge = 0 ; nEdge < 3 ; ++ nEdge) {
|
|
if ( int( vAdjSegToCurTria[nEdge].size()) == 0)
|
|
continue ;
|
|
// Trovo due triangoli che incidono sull'edge corrente e che non sono sulla stessa faccia.
|
|
// Si assume che ci siano solo due facce dell'altra superficie per edge del triangolo
|
|
Triangle3d trOthTria1 = vOthTriaVec[vAdjSegToCurTria[nEdge][0]] ;
|
|
Triangle3d trOthTria2 ;
|
|
bool bFound = false ;
|
|
for ( int nTr = 1 ; nTr < int( vAdjSegToCurTria[nEdge].size()) ; ++ nTr) {
|
|
if ( ! AreSameVectorApprox( trOthTria1.GetN(), vOthTriaVec[vAdjSegToCurTria[nEdge][nTr]].GetN())) {
|
|
trOthTria2 = vOthTriaVec[vAdjSegToCurTria[nEdge][nTr]] ;
|
|
bFound = true ;
|
|
break ;
|
|
}
|
|
}
|
|
// Calcolo il vettore ortogonale all'edge corrente che punta al baricentro del triangolo corrente
|
|
Point3d ptBar = ( trTria.GetP( 0) + trTria.GetP( 1) + trTria.GetP( 2)) / 3. ;
|
|
Vector3d vtBarVec = ptBar - trTria.GetP( nEdge) ;
|
|
Vector3d vtEdgeDir = trTria.GetP( ( nEdge + 1) % 3) - trTria.GetP( nEdge) ;
|
|
vtEdgeDir.Normalize() ;
|
|
vtBarVec -= ( vtBarVec * vtEdgeDir) * vtEdgeDir ;
|
|
// Caso con due facce
|
|
if ( bFound) {
|
|
Point3d ptOthBar1 = ( trOthTria1.GetP( 0) + trOthTria1.GetP( 1) + trOthTria1.GetP( 2)) / 3. ;
|
|
Point3d ptOthBar2 = ( trOthTria2.GetP( 0) + trOthTria2.GetP( 1) + trOthTria2.GetP( 2)) / 3. ;
|
|
Vector3d vtBarBar12 = ptOthBar2 - ptOthBar1 ;
|
|
vtBarBar12.Normalize() ;
|
|
// Caso convesso
|
|
if ( vtBarBar12 * trOthTria1.GetN() < EPS_ZERO) {
|
|
double dDot1 = vtBarVec * trOthTria1.GetN() ;
|
|
double dDot2 = vtBarVec * trOthTria2.GetN() ;
|
|
nTriaClassificationByEdges[nEdge] = dDot1 < 0. && dDot2 < 0. ? 1 : -1 ;
|
|
}
|
|
// Caso concavo
|
|
else {
|
|
double dDot1 = vtBarVec * trOthTria1.GetN() ;
|
|
double dDot2 = vtBarVec * trOthTria2.GetN() ;
|
|
nTriaClassificationByEdges[nEdge] = dDot1 > 0. && dDot2 > 0. ? -1 : 1 ;
|
|
}
|
|
}
|
|
// Caso con una faccia
|
|
else {
|
|
double dDot1 = vtBarVec * trOthTria1.GetN() ;
|
|
nTriaClassificationByEdges[nEdge] = dDot1 < 0 ? 1 : -1 ;
|
|
}
|
|
}
|
|
// Verifico che le classificazioni siano coerenti
|
|
for ( int i = 0 ; i < 3 ; ++ i) {
|
|
if ( nTriaClassificationByEdges[i] == 0)
|
|
continue ;
|
|
Surf.m_vTria[it->first].nTempPart = nTriaClassificationByEdges[i] ;
|
|
int j ;
|
|
for ( j = i + 1 ; j < 3 ; ++ j) {
|
|
if ( nTriaClassificationByEdges[j] != 0 && nTriaClassificationByEdges[i] != nTriaClassificationByEdges[j]) {
|
|
Surf.m_vTria[it->first].nTempPart = 0 ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( j < 3)
|
|
break ;
|
|
}
|
|
// Se la classificazione � coerente segno gli edge di contatto come invalicabili
|
|
Surf.m_vTria[it->first].nETempFlag[0] = int( vAdjSegToCurTria[0].size()) > 0 ? 1 : 0 ;
|
|
Surf.m_vTria[it->first].nETempFlag[1] = int( vAdjSegToCurTria[1].size()) > 0 ? 1 : 0 ;
|
|
Surf.m_vTria[it->first].nETempFlag[2] = int( vAdjSegToCurTria[2].size()) > 0 ? 1 : 0 ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
|
|
{
|
|
bool bModif = false ;
|
|
SurfTriMesh& SurfB = Other ;
|
|
// Le superfici devono essere valide
|
|
if ( m_nStatus != OK || ! SurfB.IsValid())
|
|
return false ;
|
|
// Unordered map dei segmenti di intersezione
|
|
CHAINMAP LineMapA ;
|
|
CHAINMAP LineMapB ;
|
|
// Unordered map dei triangoli ambigui (intersezione edge-edge)
|
|
TRIA3DVECTORMAP AmbiguosA ;
|
|
TRIA3DVECTORMAP AmbiguosB ;
|
|
// Ciclo sui triangoli delle mesh
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
// Setto il triangolo come n� fuori n� dentro
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
m_vTria[nTA].nTempPart = 0 ;
|
|
m_vTria[nTA].nETempFlag[0] = 0 ;
|
|
m_vTria[nTA].nETempFlag[1] = 0 ;
|
|
m_vTria[nTA].nETempFlag[2] = 0 ;
|
|
}
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
SurfB.m_vTria[nTB].nTempPart = 0 ;
|
|
SurfB.m_vTria[nTB].nETempFlag[0] = 0 ;
|
|
SurfB.m_vTria[nTB].nETempFlag[1] = 0 ;
|
|
SurfB.m_vTria[nTB].nETempFlag[2] = 0 ;
|
|
}
|
|
// Resetto e ricalcolo la HashGrid e Pointgrid della superficie B
|
|
SurfB.ResetHashGrids3d() ;
|
|
SurfB.ResetPointGrid3d() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
// Se il triangolo A non � valido, continuo
|
|
Triangle3d trTriaA ;
|
|
if ( ! GetTriangle( nTA, trTriaA) || ! trTriaA.Validate( true))
|
|
continue ;
|
|
// Box del triangolo A
|
|
BBox3d b3dTriaA ;
|
|
trTriaA.GetLocalBBox( b3dTriaA) ;
|
|
// Recupero i triangoli di B che interferiscono col box del triangolo di A
|
|
INTVECTOR vNearTria ;
|
|
SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ;
|
|
for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) {
|
|
// Se il triangolo B non � valido, continuo
|
|
Triangle3d trTriaB ;
|
|
if ( ! SurfB.GetTriangle( vNearTria[nTB], trTriaB) || ! trTriaB.Validate( true))
|
|
continue ;
|
|
// Interseco i triangoli
|
|
Point3d ptSegSt, ptSegEn ;
|
|
TRIA3DVECTOR vTria ;
|
|
int nIntType = IntersTriaTria( trTriaA, trTriaB, ptSegSt, ptSegEn, vTria) ;
|
|
if ( nIntType == ITTT_EDGE_EDGE_SEG ||
|
|
nIntType == ITTT_EDGE_INT ||
|
|
nIntType == ITTT_INT_EDGE ||
|
|
nIntType == ITTT_INT_INT_SEG) {
|
|
// Assegno i dati di intersezione
|
|
IntSegment CurInters ;
|
|
if ( nIntType == ITTT_EDGE_EDGE_SEG || nIntType == ITTT_EDGE_INT ||
|
|
nIntType == ITTT_INT_EDGE || nIntType == ITTT_INT_INT_SEG) {
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegEn ;
|
|
CurInters.bDegenerate = false ;
|
|
}
|
|
else {
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegSt ;
|
|
CurInters.bDegenerate = true ;
|
|
}
|
|
CurInters.vtOuter = trTriaB.GetN() ;
|
|
CurInters.vtOuter -= ( ( CurInters.vtOuter * trTriaA.GetN()) * trTriaA.GetN()) ;
|
|
CurInters.vtOuter.Normalize() ;
|
|
// Salvo intersezione per superficie A
|
|
bool bIntOnEndgeA = false ;
|
|
if ( nIntType != ITTT_EDGE_EDGE_SEG && nIntType != ITTT_EDGE_INT) {
|
|
auto itA = LineMapA.find( nTA) ;
|
|
if ( itA != LineMapA.end()) {
|
|
itA->second.emplace_back( CurInters) ;
|
|
}
|
|
else {
|
|
Chain chTemp ;
|
|
chTemp.emplace_back( CurInters) ;
|
|
LineMapA.emplace( nTA, chTemp) ;
|
|
}
|
|
}
|
|
else
|
|
bIntOnEndgeA = true ;
|
|
|
|
swap( CurInters.ptSt, CurInters.ptEn) ;
|
|
CurInters.vtOuter = trTriaA.GetN() ;
|
|
CurInters.vtOuter -= ( ( CurInters.vtOuter * trTriaB.GetN()) * trTriaB.GetN()) ;
|
|
CurInters.vtOuter.Normalize() ;
|
|
|
|
// Salvo intersezione per superficie B
|
|
bool bIntOnEndgeB = false ;
|
|
if ( nIntType != ITTT_EDGE_EDGE_SEG && nIntType != ITTT_INT_EDGE) {
|
|
auto itB = LineMapB.find( vNearTria[nTB]) ;
|
|
if ( itB != LineMapB.end()) {
|
|
itB->second.emplace_back( CurInters) ;
|
|
}
|
|
else {
|
|
Chain chTemp ;
|
|
chTemp.emplace_back( CurInters) ;
|
|
LineMapB.emplace( vNearTria[nTB], chTemp) ;
|
|
}
|
|
}
|
|
else
|
|
bIntOnEndgeB = true ;
|
|
// Intersezione edge-interno
|
|
if ( bIntOnEndgeA && ! bIntOnEndgeB) {
|
|
double dMaxDist = 0. ;
|
|
int nSegMaxDist = - 1 ;
|
|
for ( int nVA = 0 ; nVA < 3 ; ++ nVA) {
|
|
double dDist = abs( ( trTriaA.GetP( nVA) - trTriaB.GetP( 0)) * trTriaB.GetN()) ;
|
|
if ( dMaxDist < dDist) {
|
|
nSegMaxDist = nVA ;
|
|
dMaxDist = dDist ;
|
|
}
|
|
}
|
|
if ( nSegMaxDist >= 0) {
|
|
// Cerco qual'� il segmento di contatto per dichiararlo come invalicabile
|
|
int nVA ;
|
|
for ( nVA = 0 ; nVA < 3 ; ++ nVA) {
|
|
if ( abs( ( trTriaA.GetP( nVA) - trTriaB.GetP( 0)) * trTriaB.GetN()) < EPS_SMALL &&
|
|
abs( ( trTriaA.GetP( ( nVA + 1) % 3) - trTriaB.GetP( 0)) * trTriaB.GetN()) < EPS_SMALL)
|
|
break ;
|
|
}
|
|
m_vTria[nTA].nTempPart = ( ( trTriaA.GetP( nSegMaxDist) - trTriaB.GetP( 0)) * trTriaB.GetN() < - EPS_SMALL ? 1 : - 1) ;
|
|
if ( nVA >= 0 && nVA <= 2)
|
|
m_vTria[nTA].nETempFlag[nVA] = m_vTria[nTA].nTempPart ;
|
|
}
|
|
}
|
|
// Intersezione interno-edge
|
|
else if ( ! bIntOnEndgeA && bIntOnEndgeB) {
|
|
double dMaxDist = 0. ;
|
|
int nSegMaxDist = - 1 ;
|
|
for ( int nVB = 0 ; nVB < 3 ; ++ nVB) {
|
|
double dDist = abs( ( trTriaB.GetP( nVB) - trTriaA.GetP( 0)) * trTriaA.GetN()) ;
|
|
if ( dMaxDist < dDist) {
|
|
nSegMaxDist = nVB ;
|
|
dMaxDist = dDist ;
|
|
}
|
|
}
|
|
if ( nSegMaxDist >= 0) {
|
|
// Cerco qual'� il segmento di contatto per dichiararlo come invalicabile
|
|
int nVB ;
|
|
for ( nVB = 0 ; nVB < 3 ; ++ nVB) {
|
|
if ( abs( ( trTriaB.GetP( nVB) - trTriaA.GetP(0)) * trTriaA.GetN()) < EPS_SMALL &&
|
|
abs( ( trTriaB.GetP( ( nVB + 1) % 3) - trTriaA.GetP( 0)) * trTriaA.GetN()) < EPS_SMALL)
|
|
break ;
|
|
}
|
|
SurfB.m_vTria[vNearTria[nTB]].nTempPart = ( ( trTriaB.GetP( nSegMaxDist) - trTriaA.GetP( 0)) * trTriaA.GetN() < - EPS_SMALL ? 1 : - 1) ;
|
|
if ( nVB >= 0 && nVB <= 2)
|
|
SurfB.m_vTria[vNearTria[nTB]].nETempFlag[nVB] = SurfB.m_vTria[vNearTria[nTB]].nTempPart ;
|
|
}
|
|
}
|
|
// Intersezione edge-edge: salvo indice e vettore triangoli
|
|
// Uso i triangoli perch�, se un triangolo fosse cancellato, non potrei accedervi poi usando l'indice.
|
|
// Salvando i triangoli risolvo il problema perch� ai fini dello studio di questi contatti, triangolo
|
|
// e sua ritriangolazione portano al medesimo risultato.
|
|
else if ( bIntOnEndgeA && bIntOnEndgeB) {
|
|
auto itA = AmbiguosA.find( nTA) ;
|
|
if ( itA == AmbiguosA.end()) {
|
|
TRIA3DVECTOR vVecTriaB ;
|
|
vVecTriaB.emplace_back( trTriaB) ;
|
|
AmbiguosA.emplace( nTA, vVecTriaB) ;
|
|
}
|
|
else {
|
|
itA->second.emplace_back( trTriaB) ;
|
|
}
|
|
auto itB = AmbiguosB.find( vNearTria[nTB]) ;
|
|
if ( itB == AmbiguosB.end()) {
|
|
TRIA3DVECTOR vVecTriaA ;
|
|
vVecTriaA.emplace_back( trTriaA) ;
|
|
AmbiguosB.emplace( vNearTria[nTB], vVecTriaA) ;
|
|
}
|
|
else {
|
|
itB->second.emplace_back( trTriaA) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ritriangolarizzo i triangoli delle superfici
|
|
RetriangulationForBooleanOperation( LineMapA, AmbiguosA, *this, bModif) ;
|
|
RetriangulationForBooleanOperation( LineMapB, AmbiguosB, SurfB, bModif) ;
|
|
|
|
// Se i triangoli delle superfici non si intersecano, una delle due � totalmente interna o esterna all'altra.
|
|
bool bRetriangulated = true ;
|
|
if ( ! bModif && ( int( AmbiguosA.size()) == 0 || int( AmbiguosB.size()) == 0)) {
|
|
bRetriangulated = false ;
|
|
int nVertNum = 0 ;
|
|
Point3d ptFirstV ;
|
|
int nCurVert = GetFirstVertex( ptFirstV) ;
|
|
int nInOutNum = 0 ;
|
|
while ( nInOutNum == 0 && nCurVert != SVT_NULL) {
|
|
int nTriaNum = - 1 ;
|
|
double dMinDist = DBL_MAX ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
// Se il triangolo B non � valido, continuo
|
|
Triangle3d trTriaB ;
|
|
if ( ! SurfB.GetTriangle( nTB, trTriaB) || ! trTriaB.Validate( true))
|
|
continue ;
|
|
double dDist ;
|
|
if ( DistPointTriangle( ptFirstV, trTriaB).GetDist( dDist) && dDist < dMinDist) {
|
|
nTriaNum = nTB ;
|
|
dMinDist = dDist ;
|
|
}
|
|
}
|
|
if ( nTriaNum >= 0) {
|
|
Triangle3d trTriaB ;
|
|
SurfB.GetTriangle( nTriaNum, trTriaB) ;
|
|
trTriaB.Validate();
|
|
if ( ( ptFirstV - trTriaB.GetP(0)) * trTriaB.GetN() < - EPS_SMALL)
|
|
nInOutNum = 1 ;
|
|
else if ( ( ptFirstV - trTriaB.GetP(0)) * trTriaB.GetN() > EPS_SMALL)
|
|
nInOutNum = - 1 ;
|
|
}
|
|
if ( nInOutNum == 0) {
|
|
nCurVert = GetNextVertex( nVertNum, ptFirstV) ;
|
|
++ nVertNum ;
|
|
}
|
|
}
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
m_vTria[nTA].nTempPart = nInOutNum ;
|
|
}
|
|
nVertNum = 0 ;
|
|
nCurVert = SurfB.GetFirstVertex( ptFirstV) ;
|
|
nInOutNum = 0 ;
|
|
while ( nInOutNum == 0 && nCurVert != SVT_NULL) {
|
|
int nTriaNum = - 1 ;
|
|
double dMinDist = DBL_MAX ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
// Se il triangolo A non � valido, continuo
|
|
Triangle3d trTriaA ;
|
|
if ( ! ( GetTriangle( nTA, trTriaA) && trTriaA.Validate( true)))
|
|
continue ;
|
|
DistPointTriangle DistCalculator( ptFirstV, trTriaA) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
if ( dDist < dMinDist) {
|
|
nTriaNum = nTA ;
|
|
dMinDist = dDist ;
|
|
}
|
|
}
|
|
if ( nTriaNum >= 0) {
|
|
Triangle3d trTriaA ;
|
|
GetTriangle( nTriaNum, trTriaA) ;
|
|
trTriaA.Validate();
|
|
if ( ( ptFirstV - trTriaA.GetP( 0)) * trTriaA.GetN() < - EPS_SMALL) {
|
|
nInOutNum = 1 ;
|
|
}
|
|
else if ( ( ptFirstV - trTriaA.GetP(0)) * trTriaA.GetN() > EPS_SMALL) {
|
|
nInOutNum = - 1 ;
|
|
}
|
|
}
|
|
if ( nInOutNum == 0) {
|
|
nCurVert = SurfB.GetNextVertex( nVertNum, ptFirstV) ;
|
|
++ nVertNum ;
|
|
}
|
|
}
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
SurfB.m_vTria[nTB].nTempPart = nInOutNum ;
|
|
}
|
|
}
|
|
|
|
// Se c'� stata una ritriangolazione di almeno un triangolo, NON siamo nel caso di tutto dentro o tutto fuori.
|
|
// Studio i triangoli ambigui.
|
|
if ( bRetriangulated) {
|
|
AmbiguosTriangleManager( AmbiguosA, *this) ;
|
|
AmbiguosTriangleManager( AmbiguosB, SurfB) ;
|
|
}
|
|
|
|
bool bContinue = true ;
|
|
// Se avvenuta modifica, aggiorno tutto
|
|
if ( bModif)
|
|
bContinue = ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ;
|
|
// Triangoli sovrapposti
|
|
if ( bContinue) {
|
|
int nTriaNum2A = GetTriangleSize() ;
|
|
// Resetto e ricalcolo la HashGrid e Pointgrid della superficie B
|
|
SurfB.ResetHashGrids3d() ;
|
|
SurfB.ResetPointGrid3d() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNum2A ; ++ nTA) {
|
|
// Se il triangolo A non � valido, continuo
|
|
Triangle3d trTriaA ;
|
|
if ( ! GetTriangle( nTA, trTriaA) || ! trTriaA.Validate( true))
|
|
continue ;
|
|
// Box del triangolo A
|
|
BBox3d b3dTriaA ;
|
|
trTriaA.GetLocalBBox( b3dTriaA) ;
|
|
// Recupero i triangoli di B che interferiscono col box del triangolo di A
|
|
INTVECTOR vNearTria ;
|
|
SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ;
|
|
for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) {
|
|
// Se il triangolo B non � valido, continuo
|
|
Triangle3d trTriaB ;
|
|
if ( ! SurfB.GetTriangle( vNearTria[nTB], trTriaB) || ! trTriaB.Validate( true))
|
|
continue ;
|
|
// Se i triangoli sono sovrapposti
|
|
TRIA3DVECTOR vTriaAB ;
|
|
Point3d ptTempA, ptTempB ;
|
|
int nIntTypeAB = IntersTriaTria( trTriaA, trTriaB, ptTempA, ptTempB, vTriaAB) ;
|
|
if ( nIntTypeAB == ITTT_OVERLAPS) {
|
|
bool bInvertB = trTriaA.GetN() * trTriaB.GetN() < 0. ;
|
|
m_vTria[nTA].nTempPart = ( bInvertB ? -2 : 2) ;
|
|
SurfB.m_vTria[vNearTria[nTB]].nTempPart = ( bInvertB ? - 2 : 2) ;
|
|
}
|
|
}
|
|
}
|
|
return ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::IdentifyParts( void) const
|
|
{
|
|
for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) {
|
|
// salto triangoli cancellati o gi� assegnati
|
|
if ( m_vTria[i].nIdVert[0] == SVT_DEL ||
|
|
abs( m_vTria[i].nTempPart) != 1)
|
|
continue ;
|
|
// set di triangoli da aggiornare
|
|
set<int> stTria ;
|
|
stTria.insert( i) ;
|
|
while ( ! stTria.empty()) {
|
|
// tolgo un triangolo dal set
|
|
const auto iIt = stTria.begin() ;
|
|
int nT = *iIt ;
|
|
stTria.erase( iIt) ;
|
|
// aggiorno i triangoli adiacenti
|
|
for ( int j = 0 ; j < 3 ; ++ j) {
|
|
if ( m_vTria[nT].nETempFlag[j] != 0)
|
|
continue ;
|
|
int nAdjT = m_vTria[nT].nIdAdjac[j] ;
|
|
if ( nAdjT != SVT_NULL && m_vTria[nAdjT].nTempPart == 0) {
|
|
m_vTria[nAdjT].nTempPart = m_vTria[nT].nTempPart ;
|
|
stTria.insert( nAdjT) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::RemoveTJunctions(void)
|
|
{
|
|
//PerformanceCounter Counter ;
|
|
|
|
if ( GetPartCount() < 0)
|
|
return false ;
|
|
// Vettore di indici dei vertici sui lati del triangolo corrente
|
|
INTMATRIX vvIndexMatrix( m_vTria.size()) ;
|
|
// Ciclo sui triangoli della superficie
|
|
for ( int nT = 0 ; nT < int( m_vTria.size()) ; ++ nT) {
|
|
// Riga di matrice per il triangolo
|
|
INTVECTOR& vIndexRow = vvIndexMatrix[nT] ;
|
|
// Se il triangolo non � valido, passo al successivo
|
|
Triangle3d trTria ;
|
|
if ( ! GetTriangle( nT, trTria) || ! trTria.Validate( true))
|
|
continue ;
|
|
// Box del triangolo
|
|
BBox3d b3Tria ;
|
|
trTria.GetLocalBBox( b3Tria) ;
|
|
INTVECTOR vNearTria ;
|
|
GetAllTriaOverlapBox( b3Tria, vNearTria) ;
|
|
// Ciclo sui lati del triangolo
|
|
for ( int nSeg = 0 ; nSeg < 3 ; ++ nSeg) {
|
|
// Aggiungo alla riga della matrice il vertice iniziale del lato
|
|
vIndexRow.emplace_back( m_vTria[nT].nIdVert[nSeg]) ;
|
|
if ( m_vTria[nT].nIdAdjac[nSeg] != SVT_NULL && m_vTria[nT].nIdAdjac[nSeg] != SVT_DEL)
|
|
continue ;
|
|
int nPrevSize = int( vIndexRow.size()) ;
|
|
// recupero la geometria del lato
|
|
Point3d ptSegSt = trTria.GetP( nSeg) ;
|
|
Point3d ptSegEn = trTria.GetP( ( nSeg + 1) % 3) ;
|
|
Vector3d vtSeg = ptSegEn - ptSegSt ;
|
|
double dSegLen = vtSeg.Len() ;
|
|
if ( dSegLen < EPS_SMALL)
|
|
continue ;
|
|
vtSeg /= dSegLen ;
|
|
// Ciclo sui triangoli vicini
|
|
for ( int nI = 0 ; nI < int( vNearTria.size()) ; ++ nI) {
|
|
// Salto il triangolo se � quello di riferimento
|
|
if ( vNearTria[nI] == nT)
|
|
continue ;
|
|
// Cerco i vertici che stanno sul lato del triangolo
|
|
for ( int nVert = 0 ; nVert < 3 ; ++ nVert) {
|
|
Point3d ptVert ;
|
|
GetVertex( m_vTria[vNearTria[nI]].nIdVert[nVert], ptVert) ;
|
|
double dProj = ( ptVert - ptSegSt) * vtSeg ;
|
|
double dOrt = ( ( ptVert - ptSegSt) - dProj * vtSeg).SqLen() ;
|
|
if ( dProj > EPS_SMALL && dProj < dSegLen - EPS_SMALL && dOrt < 10000 * SQ_EPS_TRIA_H && m_vTria[nT].nPart == m_vTria[vNearTria[nI]].nPart) {
|
|
int nCandidateId = m_vTria[vNearTria[nI]].nIdVert[nVert] ;
|
|
int nY ;
|
|
for ( nY = 0 ; nY < int( vIndexRow.size()) ; ++ nY) {
|
|
if ( vIndexRow[nY] == nCandidateId)
|
|
break ;
|
|
}
|
|
if ( nY == int( vIndexRow.size()))
|
|
vIndexRow.emplace_back( nCandidateId) ;
|
|
}
|
|
}
|
|
}
|
|
// Riordino i vertici sul segmento
|
|
auto SortVerteces = [ this, &ptSegSt, &vtSeg]( const int nV, const int nVV)
|
|
{ Point3d ptPV, ptPVV ;
|
|
GetVertex( nV, ptPV) ;
|
|
GetVertex( nVV, ptPVV) ;
|
|
return ( ( ptPV - ptSegSt) * vtSeg < ( ptPVV - ptSegSt) * vtSeg) ;
|
|
} ;
|
|
sort( vIndexRow.begin() + nPrevSize, vIndexRow.end(), SortVerteces) ;
|
|
}
|
|
}
|
|
|
|
//double dTime1 = Counter.Stop() ; Counter.Start() ;
|
|
|
|
for ( int nT = 0 ; nT < int( vvIndexMatrix.size()) ; ++ nT) {
|
|
if ( vvIndexMatrix[nT].size() > 3) {
|
|
// Vettore contenente tutti i punti di contorno sul triangolo
|
|
PNTVECTOR vP ;
|
|
for ( int nV = 0 ; nV < int( vvIndexMatrix[nT].size()) ; ++ nV) {
|
|
Point3d ptPt ;
|
|
GetVertex( vvIndexMatrix[nT][nV], ptPt) ;
|
|
vP.emplace_back( ptPt) ;
|
|
}
|
|
// Salvo il colore del triangolo, ne calcolo il baricentro e lo cancello.
|
|
Triangle3d trTria ;
|
|
if ( GetTriangle( nT, trTria) && trTria.Validate( true)) {
|
|
int nTFlag = m_vTria[nT].nTFlag ;
|
|
Point3d ptBar = ( trTria.GetP( 0) + trTria.GetP( 1) + trTria.GetP( 2)) / 3 ;
|
|
int nBarIndex = AddVertex( ptBar) ;
|
|
RemoveTriangle( nT) ;
|
|
int nContourPointNum = int( vP.size()) ;
|
|
for ( int nP = 0 ; nP < nContourPointNum ; ++ nP) {
|
|
int nNewId[3] = { nBarIndex,
|
|
AddVertex( vP[nP]),
|
|
AddVertex( vP[( nP + 1) % nContourPointNum])} ;
|
|
int nTempNewTriaId = AddTriangle( nNewId, nTFlag) ;
|
|
if ( ! IsValidSvt( nTempNewTriaId))
|
|
;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::RemoveCaps(void)
|
|
{
|
|
INTVECTOR vIndex ;
|
|
int nTriaNum = GetTriangleSize() ;
|
|
for ( int nT = 0 ; nT < nTriaNum ; ++ nT) {
|
|
Triangle3d trTria ;
|
|
GetTriangle( nT, trTria) ;
|
|
int nMinIndex = -1 ;
|
|
double dMinSqDist = DBL_MAX ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
Point3d ptVert, ptSegSt, ptSegEn ;
|
|
ptVert = trTria.GetP( nV) ;
|
|
ptSegSt = trTria.GetP( ( nV + 1) % 3) ;
|
|
ptSegEn = trTria.GetP( ( nV + 2) % 3) ;
|
|
CurveLine cvSeg ;
|
|
cvSeg.Set( ptSegSt, ptSegEn) ;
|
|
DistPointLine DistCalculator( ptVert, cvSeg, false) ;
|
|
double dSqDist ;
|
|
DistCalculator.GetSqDist( dSqDist) ;
|
|
Vector3d vtSeg = ptSegEn - ptSegSt ;
|
|
double dSegLen = vtSeg.Len() ;
|
|
vtSeg /= dSegLen ;
|
|
double dProj = ( ptVert - ptSegSt) * vtSeg ;
|
|
if ( dSqDist < dMinSqDist && dProj > EPS_SMALL && dProj < dSegLen - EPS_SMALL) {
|
|
dMinSqDist = dSqDist ;
|
|
nMinIndex = nV ;
|
|
}
|
|
}
|
|
if ( dMinSqDist < EPS_SMALL) {
|
|
vIndex.emplace_back( nT) ;
|
|
vIndex.emplace_back( nMinIndex) ;
|
|
}
|
|
}
|
|
for ( int nPos = 0 ; nPos < int( vIndex.size()) ; nPos += 2) {
|
|
int nT = vIndex[nPos] ;
|
|
int nV = vIndex[nPos + 1] ;
|
|
int nAdjT = m_vTria[nT].nIdAdjac[( nV + 1) % 3] ;
|
|
if ( nAdjT < 0)
|
|
continue ;
|
|
int nAdjV ;
|
|
for ( nAdjV = 0 ; nAdjV < 3 ; ++ nAdjV) {
|
|
if ( m_vTria[nAdjT].nIdAdjac[nAdjV] == nT)
|
|
break ;
|
|
}
|
|
Triangle3d trTriaAdj ;
|
|
GetTriangle( nAdjT, trTriaAdj) ;
|
|
Vector3d vtLen = trTriaAdj.GetP( ( nAdjV + 1) % 3) - trTriaAdj.GetP( nAdjV) ;
|
|
if ( vtLen * vtLen > 4 * EPS_SMALL * EPS_SMALL) {
|
|
FlipTriangles( nT, nAdjT) ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::RemoveTripleTriangles()
|
|
{
|
|
int nCounter = 1 ;
|
|
const int N_STOP = 100 ;
|
|
bool bContinue = true ;
|
|
while ( bContinue && nCounter <= N_STOP) {
|
|
ScanForTripleTriangles( bContinue) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::ScanForTripleTriangles( bool& bModified)
|
|
{
|
|
// Setto il flag come nessuna modifica eseguita
|
|
bModified = false ;
|
|
// Ciclo sui vertici
|
|
int nNumVert = GetVertexCount() ;
|
|
for ( int nV = 0 ; nV < nNumVert ; ++ nV) {
|
|
bool bCirc ;
|
|
INTVECTOR vTriaIndex ;
|
|
int nTriaNum = GetAllTriaAroundVertex( nV, vTriaIndex, bCirc) ;
|
|
// Se il vertice � condiviso da tre triangoli tutti adiacenti fra loro a due a due
|
|
if ( nTriaNum == 3 && bCirc) {
|
|
// Valuto parallelismo fra le normali
|
|
int nParallel = 0 ;
|
|
for ( int nT1 = 0 ; nT1 < 2 ; ++ nT1) {
|
|
for ( int nT2 = nT1 + 1 ; nT2 < 3 ; ++ nT2) {
|
|
if ( AreSameVectorExact( m_vTria[vTriaIndex[nT1]].vtN, m_vTria[vTriaIndex[nT2]].vtN)) {
|
|
++ nParallel ;
|
|
}
|
|
}
|
|
}
|
|
// Se sono tutte parallele fra loro unisco i tre triangoli in uno
|
|
if ( nParallel == 3) {
|
|
// Cerco gli altri triangoli adiacenti a quelli che sostituir� con il triangolo grande.
|
|
// Cerco anche quali lati dei tre triangoli che saranno eliminati sono adiacenti a quelli esterni
|
|
INTVECTOR vVertAndAdjTria ;
|
|
for ( int nTria = 0 ; nTria < 3 ; ++ nTria) {
|
|
for ( int nVert = 0 ; nVert < 3 ; ++ nVert) {
|
|
if ( m_vTria[vTriaIndex[nTria]].nIdVert[nVert] == nV) {
|
|
vVertAndAdjTria.emplace_back( m_vTria[vTriaIndex[nTria]].nIdVert[(nVert + 1) % 3]) ;
|
|
vVertAndAdjTria.emplace_back( m_vTria[vTriaIndex[nTria]].nIdAdjac[(nVert + 1) % 3]) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// Cerco fra questi altri triangoli esterni sono adiacenti ai triangoli che eliminer�
|
|
int nAdjTriaContactEdge[3] ;
|
|
for ( int nAdjTria = 1 ; nAdjTria < 6 ; nAdjTria += 2) {
|
|
for ( int nAdjEdge = 0 ; nAdjEdge < 3 ; ++ nAdjEdge) {
|
|
if ( vVertAndAdjTria[nAdjTria] >= 0 && m_vTria[vVertAndAdjTria[nAdjTria]].nIdAdjac[nAdjEdge] == vTriaIndex[( nAdjTria - 1) / 2])
|
|
nAdjTriaContactEdge[(nAdjTria - 1) / 2] = nAdjEdge ;
|
|
}
|
|
}
|
|
// Elimino i triangoli e salvo i loro Flag
|
|
int vnTFlag[3] ;
|
|
for ( int nTria = 0 ; nTria < 3 ; ++ nTria) {
|
|
vnTFlag[nTria] = m_vTria[vTriaIndex[nTria]].nTFlag ;
|
|
RemoveTriangle( vTriaIndex[nTria]) ;
|
|
}
|
|
// Aggiungo il nuovo triangolo con il flag
|
|
int nNewTFlag ;
|
|
if ( vnTFlag[0] == vnTFlag[1])
|
|
nNewTFlag = vnTFlag[1] ;
|
|
else if ( vnTFlag[0] == vnTFlag[2] || vnTFlag[1] == vnTFlag[2])
|
|
nNewTFlag = vnTFlag[2] ;
|
|
else
|
|
nNewTFlag = 0 ;
|
|
int nNewVert[3] = { vVertAndAdjTria[0], vVertAndAdjTria[2], vVertAndAdjTria[4] } ;
|
|
int nNewTriaId = AddTriangle( nNewVert, nNewTFlag) ;
|
|
if ( nNewTriaId != SVT_NULL) {
|
|
// Sistemo le adiacenze
|
|
m_vTria[nNewTriaId].nIdAdjac[0] = vVertAndAdjTria[1] ;
|
|
m_vTria[nNewTriaId].nIdAdjac[1] = vVertAndAdjTria[3] ;
|
|
m_vTria[nNewTriaId].nIdAdjac[2] = vVertAndAdjTria[5] ;
|
|
if ( vVertAndAdjTria[1] >= 0)
|
|
m_vTria[vVertAndAdjTria[1]].nIdAdjac[nAdjTriaContactEdge[0]] = nNewTriaId ;
|
|
if ( vVertAndAdjTria[3] >= 0)
|
|
m_vTria[vVertAndAdjTria[3]].nIdAdjac[nAdjTriaContactEdge[1]] = nNewTriaId ;
|
|
if ( vVertAndAdjTria[5] >= 0)
|
|
m_vTria[vVertAndAdjTria[5]].nIdAdjac[nAdjTriaContactEdge[2]] = nNewTriaId ;
|
|
// Setto il flag come modifica eseguita
|
|
bModified = true ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::FlipTriangles( int nTA, int nTB)
|
|
{
|
|
// Verifico esistenza triangoli
|
|
int nNumTria = GetTriangleCount() ;
|
|
if ( nTA < 0 || nTA >= nNumTria || nTB < 0 || nTB >= nNumTria)
|
|
return false ;
|
|
// Verifico adiacenza triangoli
|
|
int nEdgeA ;
|
|
for ( nEdgeA = 0 ; nEdgeA < 3 ; ++ nEdgeA) {
|
|
if ( m_vTria[nTA].nIdAdjac[nEdgeA] == nTB)
|
|
break ;
|
|
}
|
|
int nEdgeB ;
|
|
for ( nEdgeB = 0 ; nEdgeB < 3 ; ++ nEdgeB) {
|
|
if ( m_vTria[nTB].nIdAdjac[nEdgeB] == nTA)
|
|
break ;
|
|
}
|
|
// Se uno � adiacente all'altro ma non viceversa, c'� un errore
|
|
if ( ( nEdgeA == 3 && nEdgeB < 3) || ( nEdgeA < 3 && nEdgeB == 3))
|
|
return false ;
|
|
// Se non sono adiacenti, ho finito
|
|
else if ( nEdgeA == 3 && nEdgeB == 3)
|
|
return true ;
|
|
// Se non trovo i vertici del triangolo A, c'� un errorre
|
|
Point3d ptSegSt, ptSegEn, ptVertA ;
|
|
if ( ! GetVertex( m_vTria[nTA].nIdVert[nEdgeA], ptSegSt) ||
|
|
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 1) % 3], ptSegEn) ||
|
|
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3], ptVertA))
|
|
return false ;
|
|
// Se non trovo i vertici del triangolo B, c'� un errorre
|
|
Point3d ptVertB ;
|
|
if ( ! GetVertex( m_vTria[nTB].nIdVert[( nEdgeB + 2) % 3], ptVertB))
|
|
return false ;
|
|
// Calcolo le proiezioni dei Vertici fuori dal segmento su quest'ultimo
|
|
Vector3d vtVec = ptSegEn - ptSegSt ;
|
|
double dLen = vtVec.Len() ;
|
|
vtVec /= dLen ;
|
|
double dProjA = ( ptVertA - ptSegSt) * vtVec ;
|
|
double dProjB = ( ptVertB - ptSegSt) * vtVec ;
|
|
// Se le proiezioni sono interne al segmento comune eseguo il flipping
|
|
if ( dProjA > EPS_SMALL && dProjA < dLen - EPS_SMALL &&
|
|
dProjB > EPS_SMALL && dProjB < dLen - EPS_SMALL) {
|
|
m_vTria[nTA].nIdVert[nEdgeA] = m_vTria[nTB].nIdVert[( nEdgeB + 2) % 3] ;
|
|
m_vTria[nTB].nIdVert[nEdgeB] = m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3] ;
|
|
m_vTria[nTA].nIdAdjac[nEdgeA] = m_vTria[nTB].nIdAdjac[( nEdgeB + 2) % 3] ;
|
|
m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] = nTB ;
|
|
m_vTria[nTB].nIdAdjac[nEdgeB] = m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] ;
|
|
m_vTria[nTB].nIdAdjac[( nEdgeB + 2) % 3] = nTA ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::Add( const ISurfTriMesh& Other)
|
|
{
|
|
m_OGrMgr.Clear() ;
|
|
SurfTriMesh SurfB ;
|
|
SurfB.CopyFrom( &Other) ;
|
|
Frame3d frScalingRef ;
|
|
frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ;
|
|
Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
SurfB.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
IntersectTriMeshTriangle( SurfB) ;
|
|
IdentifyParts() ;
|
|
SurfB.IdentifyParts() ;
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
if ( m_vTria[nTA].nTempPart == 1 || m_vTria[nTA].nTempPart == - 2)
|
|
RemoveTriangle( nTA) ;
|
|
}
|
|
int nPrevMaxTFlag = m_nMaxTFlag ;
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
if ( SurfB.m_vTria[nTB].nTempPart == - 1) {
|
|
int nNewVert[3] ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
nNewVert[nV] = AddVertex( SurfB.m_vVert[SurfB.m_vTria[nTB].nIdVert[nV]].ptP) ;
|
|
}
|
|
if ( nPrevMaxTFlag == m_nMaxTFlag)
|
|
++ m_nMaxTFlag ;
|
|
AddTriangle( nNewVert, m_nMaxTFlag) ;
|
|
}
|
|
}
|
|
bool bOk = ( AdjustVertices() && DoCompacting()) ;
|
|
bOk && RemoveTripleTriangles() ;
|
|
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
|
|
bOk && RemoveTJunctions() ;
|
|
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
|
|
Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ;
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::Intersect( const ISurfTriMesh& Other)
|
|
{
|
|
m_OGrMgr.Clear() ;
|
|
SurfTriMesh SurfB ;
|
|
SurfB.CopyFrom( &Other) ;
|
|
//Frame3d frScalingRef ;
|
|
//frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ;
|
|
//Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
//SurfB.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
//IntersectTriMeshTriangle( SurfB) ;
|
|
IntersectTriMeshFacets( SurfB) ;
|
|
IdentifyParts() ;
|
|
SurfB.IdentifyParts() ;
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
if ( m_vTria[nTA].nTempPart == - 1 || m_vTria[nTA].nTempPart == - 2)
|
|
RemoveTriangle( nTA) ;
|
|
}
|
|
int nPrevMaxTFlag = m_nMaxTFlag ;
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
if ( SurfB.m_vTria[nTB].nTempPart == 1) {
|
|
int nNewVert[3] ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
nNewVert[nV] = AddVertex( SurfB.m_vVert[SurfB.m_vTria[nTB].nIdVert[nV]].ptP) ;
|
|
}
|
|
if ( nPrevMaxTFlag == m_nMaxTFlag)
|
|
++ m_nMaxTFlag ;
|
|
AddTriangle( nNewVert, m_nMaxTFlag) ;
|
|
}
|
|
}
|
|
bool bOk = ( AdjustVertices() && DoCompacting()) ;
|
|
////bOk && RemoveTripleTriangles() ;
|
|
////bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
|
|
bOk && RemoveTJunctions() ;
|
|
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
|
|
////Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ;
|
|
return bOk ;
|
|
//return RemoveTJunctions() ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::Subtract( const ISurfTriMesh& Other)
|
|
{
|
|
m_OGrMgr.Clear() ;
|
|
SurfTriMesh SurfB ;
|
|
SurfB.CopyFrom( &Other) ;
|
|
Frame3d frScalingRef;
|
|
frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ;
|
|
Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
SurfB.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
IntersectTriMeshTriangle( SurfB) ;
|
|
IdentifyParts() ;
|
|
SurfB.IdentifyParts() ;
|
|
int nTriaNumA = GetTriangleSize() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
if ( m_vTria[nTA].nTempPart == 1 || m_vTria[nTA].nTempPart == 2)
|
|
RemoveTriangle( nTA) ;
|
|
}
|
|
int nPrevMaxTFlag = m_nMaxTFlag ;
|
|
int nTriaNumB = SurfB.GetTriangleSize() ;
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
if ( SurfB.m_vTria[nTB].nTempPart == 1) {
|
|
int nNewVert[3] ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
nNewVert[nV] = AddVertex( SurfB.m_vVert[SurfB.m_vTria[nTB].nIdVert[nV]].ptP) ;
|
|
}
|
|
swap( nNewVert[1], nNewVert[2]) ;
|
|
if ( nPrevMaxTFlag == m_nMaxTFlag)
|
|
++ m_nMaxTFlag ;
|
|
AddTriangle( nNewVert, m_nMaxTFlag) ;
|
|
}
|
|
}
|
|
bool bOk = ( AdjustVertices() && DoCompacting()) ;
|
|
bOk && RemoveTripleTriangles() ;
|
|
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
|
|
bOk && RemoveTJunctions() ;
|
|
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
|
|
Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ;
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::GetSurfClassification( const ISurfTriMesh& ClassifierSurf,
|
|
INTVECTOR& vTriaIn, INTVECTOR& vTriaOut, INTVECTOR& vTriaOnP, INTVECTOR& vTriaOnM, INTVECTOR& vTriaIndef)
|
|
{
|
|
// Le superfici devono essere valide
|
|
if ( ! IsValid() || ! ClassifierSurf.IsValid())
|
|
return false ;
|
|
if ( ClassifierSurf.GetVertexCount() == 0 || ClassifierSurf.GetTriangleCount() == 0)
|
|
return false ;
|
|
if ( m_vVert.empty() || m_vTria.empty())
|
|
return true ;
|
|
SurfTriMesh SurfC ;
|
|
SurfC.CopyFrom( &ClassifierSurf) ;
|
|
Frame3d frScalingRef ;
|
|
frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ;
|
|
Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
SurfC.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
IntersectTriMeshTriangle( SurfC) ;
|
|
IdentifyParts() ;
|
|
Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ;
|
|
|
|
int nTriaNum = GetTriangleSize() ;
|
|
for ( int nT = 0 ; nT < nTriaNum ; ++ nT) {
|
|
if ( m_vTria[nT].nIdVert[0] == SVT_DEL)
|
|
continue ;
|
|
switch ( m_vTria[nT].nTempPart) {
|
|
case -2 :
|
|
vTriaOnM.push_back( nT) ;
|
|
break ;
|
|
case -1 :
|
|
vTriaOut.push_back( nT) ;
|
|
break ;
|
|
case 0 :
|
|
vTriaIndef.push_back( nT) ;
|
|
break ;
|
|
case 1 :
|
|
vTriaIn.push_back( nT) ;
|
|
break ;
|
|
case 2 :
|
|
vTriaOnP.push_back( nT) ;
|
|
break ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::CutWithOtherSurf( const ISurfTriMesh& CutterSurf, bool bInVsOut, bool bSaveOnEq)
|
|
{
|
|
// Le superfici devono essere valide
|
|
if ( ! IsValid() || ! CutterSurf.IsValid())
|
|
return false ;
|
|
m_OGrMgr.Clear() ;
|
|
SurfTriMesh SurfC ;
|
|
SurfC.CopyFrom( &CutterSurf) ;
|
|
Frame3d frScalingRef ;
|
|
frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ;
|
|
Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
SurfC.Scale( frScalingRef, BOOLEAN_SCALE, BOOLEAN_SCALE, BOOLEAN_SCALE) ;
|
|
IntersectTriMeshTriangle( SurfC) ;
|
|
IdentifyParts() ;
|
|
int nPartToRemove = ( bInVsOut ? -1 : 1) ;
|
|
int nCoplanarPartToRemove = ( bSaveOnEq ? ( nPartToRemove ? -2 : 2) : 5) ;
|
|
int nTriaNum = GetTriangleSize() ;
|
|
for ( int nT = 0 ; nT < nTriaNum ; ++ nT) {
|
|
if ( m_vTria[nT].nTempPart == nPartToRemove || m_vTria[nT].nTempPart == nCoplanarPartToRemove)
|
|
RemoveTriangle( nT) ;
|
|
}
|
|
bool bOk = ( AdjustVertices() && DoCompacting()) ;
|
|
Scale( frScalingRef, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE, 1. / BOOLEAN_SCALE) ;
|
|
return bOk ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int
|
|
SurfTriMesh::IntersFacetPlane( const SurfFlatRegion& Region, const PolyLine& ExtLoop, const Plane3d& plCutPlane,
|
|
LineFacetClassVector& IntersLinePart)
|
|
{
|
|
// Se la regione o il piano non sono validi, non � possibile proseguire.
|
|
if ( ! ( Region.IsValid() && plCutPlane.IsValid()))
|
|
return FPI_ERROR ;
|
|
// Determino il piano della regione.
|
|
Plane3d plFacetPlane ;
|
|
plFacetPlane.Set( Region.GetPlanePoint(), Region.GetNormVersor()) ;
|
|
// Se il piano della regione non � valido, non � possibile proseguire.
|
|
if ( ! plCutPlane.IsValid())
|
|
return FPI_ERROR ;
|
|
// Pulisco il vettore delle intersezioni risultanti.
|
|
IntersLinePart.resize( 0) ;
|
|
// Calcolo le distanze dei vertici della faccia dal piano.
|
|
int nExtLoopPointNum = int( ExtLoop.GetPointNbr()) ;
|
|
vector<double> vDist ;
|
|
vDist.reserve( nExtLoopPointNum) ;
|
|
Point3d ptP ;
|
|
bool bContinue = ExtLoop.GetFirstPoint( ptP) ;
|
|
while ( bContinue) {
|
|
vDist.emplace_back( DistPointPlane( ptP, plCutPlane)) ;
|
|
bContinue = ExtLoop.GetNextPoint( ptP) ;
|
|
}
|
|
// Verifico posizione della faccia rispetto al piano.
|
|
int nVertPos = 0 ; int nVertNeg = 0 ;
|
|
for ( const auto& dDist : vDist) {
|
|
if ( dDist > 0.5 * EPS_SMALL)
|
|
++ nVertPos ;
|
|
else if ( dDist < - 0.5 * EPS_SMALL)
|
|
++ nVertNeg ;
|
|
}
|
|
|
|
// Tutto sul piano.
|
|
if ( nVertPos == 0 && nVertNeg == 0)
|
|
return FPI_ON ;
|
|
// Tutto dentro
|
|
else if ( nVertPos == 0)
|
|
return FPI_INN ;
|
|
// Tutto fuori
|
|
else if ( nVertNeg == 0)
|
|
return FPI_OUT ;
|
|
|
|
// Intersezione tra i piani delle due facce
|
|
Point3d ptL ; Vector3d vtL ;
|
|
int nResPP = IntersPlanePlane( plFacetPlane, plCutPlane, ptL, vtL) ;
|
|
// Non essendo complanari, se non trovo la retta d'intersezione c'� un errore.
|
|
if ( nResPP == IPPT_NO || nResPP == IPPT_OVERLAPS)
|
|
return FPI_ERROR ;
|
|
|
|
// Box contenente entrambe le regioni
|
|
BBox3d b3Box ;
|
|
Region.GetLocalBBox( b3Box) ;
|
|
b3Box.Expand( 10) ;
|
|
|
|
// Limito la retta nel box contenente le regioni
|
|
INTDBLVECTOR vInters ;
|
|
if ( ! IntersLineBox( ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) < 2)
|
|
return FPI_ERROR ;
|
|
double dLen = vInters.back().second - vInters[0].second ;
|
|
Point3d ptIntLineSt = ptL + vInters[0].second * vtL ;
|
|
Point3d ptIntLineEn = ptL + vInters.back().second * vtL ;
|
|
CurveLine cvPlaneIntersLine ;
|
|
cvPlaneIntersLine.Set( ptIntLineSt, ptIntLineEn) ;
|
|
|
|
// Limito la linea di intersezione con la faccia.
|
|
CRVCVECTOR IntersectionResults ;
|
|
bool bClassificationOk = Region.GetCurveClassification( cvPlaneIntersLine, IntersectionResults) ;
|
|
// Se non trovo le intersezioni, c'� un errore.
|
|
if ( ! bClassificationOk)
|
|
return FPI_ERROR ;
|
|
|
|
// Prendo la parte interna o sul bordo.
|
|
int nPartNum = int( IntersectionResults.size()) ;
|
|
for ( int n = 0 ; n < nPartNum ; ++ n) {
|
|
int nType = IntersectionResults[n].nClass ;
|
|
if ( nType == CRVC_IN || nType == CRVC_ON_P || nType == CRVC_ON_M) {
|
|
double dParS = dLen * IntersectionResults[n].dParS ;
|
|
double dParE = dLen * IntersectionResults[n].dParE ;
|
|
IntersLinePart.emplace_back( LineFacetClass( ptIntLineSt + dParS * vtL, ptIntLineSt + dParE * vtL, nType, nType)) ;
|
|
}
|
|
}
|
|
|
|
return int( IntersLinePart.size()) > 0 ;
|
|
}
|
|
|
|
static bool
|
|
TrimLineWithExtPolygon( const CurveLine& cvLine, const POLYLINEVECTOR& vContourVec,
|
|
CRVCVECTOR& vLinePart);
|
|
int
|
|
SurfTriMesh::IntersFacetPlane( const POLYLINEVECTOR& vFacetLoopsVec, const Plane3d& plCutPlane,
|
|
LineFacetClassVector& IntersLinePart)
|
|
{
|
|
// Se i contorni non definiscono un poligono esteso o non � definito, non ha senso procedere.
|
|
double dArea ;
|
|
Plane3d plFacetPlane ;
|
|
if ( vFacetLoopsVec.empty() || ! vFacetLoopsVec[0].IsClosedAndFlat( plFacetPlane, dArea) || ! plCutPlane.IsValid())
|
|
return FPI_ERROR ;
|
|
// Pulisco il vettore delle intersezioni risultanti.
|
|
IntersLinePart.resize( 0) ;
|
|
// Calcolo le distanze dei vertici della faccia dal piano.
|
|
int nExtLoopPointNum = int( vFacetLoopsVec[0].GetPointNbr()) ;
|
|
vector<double> vDist ;
|
|
vDist.reserve( nExtLoopPointNum) ;
|
|
Point3d ptP ;
|
|
bool bContinue = vFacetLoopsVec[0].GetFirstPoint( ptP) ;
|
|
while ( bContinue) {
|
|
vDist.emplace_back( DistPointPlane( ptP, plCutPlane)) ;
|
|
bContinue = vFacetLoopsVec[0].GetNextPoint( ptP) ;
|
|
}
|
|
// Verifico posizione della faccia rispetto al piano.
|
|
int nVertPos = 0 ; int nVertNeg = 0 ;
|
|
for ( const auto& dDist : vDist) {
|
|
if ( dDist > 0.5 * EPS_SMALL)
|
|
++ nVertPos ;
|
|
else if ( dDist < - 0.5 * EPS_SMALL)
|
|
++ nVertNeg ;
|
|
}
|
|
|
|
// Tutto sul piano.
|
|
if ( nVertPos == 0 && nVertNeg == 0)
|
|
return FPI_ON ;
|
|
// Tutto dentro
|
|
else if ( nVertPos == 0)
|
|
return FPI_INN ;
|
|
// Tutto fuori
|
|
else if ( nVertNeg == 0)
|
|
return FPI_OUT ;
|
|
|
|
// Intersezione tra i piani delle due facce
|
|
Point3d ptL ; Vector3d vtL ;
|
|
int nResPP = IntersPlanePlane( plFacetPlane, plCutPlane, ptL, vtL) ;
|
|
// Non essendo complanari, se non trovo la retta d'intersezione c'� un errore.
|
|
if ( nResPP == IPPT_NO || nResPP == IPPT_OVERLAPS)
|
|
return FPI_ERROR ;
|
|
|
|
// Box contenente entrambe le regioni
|
|
BBox3d b3Box ;
|
|
vFacetLoopsVec[0].GetLocalBBox( b3Box) ;
|
|
b3Box.Expand( 10) ;
|
|
|
|
// Limito la retta nel box contenente le regioni
|
|
INTDBLVECTOR vInters ;
|
|
if ( ! IntersLineBox( ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) < 2)
|
|
return FPI_ERROR ;
|
|
double dLen = vInters.back().second - vInters[0].second ;
|
|
Point3d ptIntLineSt = ptL + vInters[0].second * vtL ;
|
|
Point3d ptIntLineEn = ptL + vInters.back().second * vtL ;
|
|
CurveLine cvPlaneIntersLine ;
|
|
cvPlaneIntersLine.Set( ptIntLineSt, ptIntLineEn) ;
|
|
|
|
// Limito la linea di intersezione con la faccia.
|
|
CRVCVECTOR IntersectionResults ;
|
|
bool bClassificationOk = TrimLineWithExtPolygon( cvPlaneIntersLine, vFacetLoopsVec, IntersectionResults) ;
|
|
// Se non trovo le intersezioni, c'� un errore.
|
|
if ( ! bClassificationOk)
|
|
return FPI_ERROR ;
|
|
|
|
// Prendo la parte interna o sul bordo.
|
|
int nPartNum = int( IntersectionResults.size()) ;
|
|
for ( int n = 0 ; n < nPartNum ; ++ n) {
|
|
int nType = IntersectionResults[n].nClass ;
|
|
if ( nType == CRVC_IN || nType == CRVC_ON_P || nType == CRVC_ON_M) {
|
|
double dParS = dLen * IntersectionResults[n].dParS ;
|
|
double dParE = dLen * IntersectionResults[n].dParE ;
|
|
IntersLinePart.emplace_back( LineFacetClass( ptIntLineSt + dParS * vtL, ptIntLineSt + dParE * vtL, nType, nType)) ;
|
|
}
|
|
}
|
|
|
|
return int( IntersLinePart.size()) > 0 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::IntersFacetFacet( const SurfFlatRegion& RegionA, const PolyLine& ExtLoopA,
|
|
const SurfFlatRegion& RegionB, const PolyLine& ExtLoopB,
|
|
LineFacetClassVector& IntersLinePart)
|
|
{
|
|
IntersLinePart.resize( 0) ;
|
|
|
|
// Determino i piani delle regioni
|
|
Plane3d plPlaneA, plPlaneB ;
|
|
plPlaneA.Set( RegionA.GetPlanePoint(), RegionA.GetNormVersor()) ;
|
|
plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ;
|
|
|
|
// Calcolo le distanze dei vertici della faccia A dal piano della faccia B.
|
|
int nExtLoopPointNumA = int( ExtLoopA.GetPointNbr()) ;
|
|
vector<double> vDistA ;
|
|
vDistA.reserve( nExtLoopPointNumA) ;
|
|
Point3d ptP ;
|
|
bool bContinue = ExtLoopA.GetFirstPoint( ptP) ;
|
|
while ( bContinue) {
|
|
vDistA.emplace_back( DistPointPlane( ptP, plPlaneB)) ;
|
|
bContinue = ExtLoopA.GetNextPoint( ptP) ;
|
|
}
|
|
// Verifico posizione della faccia A rispetto al piano della faccia B.
|
|
int nVertPosA = 0 ; int nVertNegA = 0 ;
|
|
for ( const auto& dDist : vDistA) {
|
|
if ( dDist > EPS_SMALL)
|
|
++ nVertPosA ;
|
|
else if ( dDist < - EPS_SMALL)
|
|
++ nVertNegA ;
|
|
}
|
|
// Se la faccia A giace tutta da una parte del piano, nessuna intersezione
|
|
if ( nVertPosA == nExtLoopPointNumA || nVertNegA == nExtLoopPointNumA)
|
|
return false ;
|
|
|
|
// Calcolo le distanze dei vertici della faccia B dal piano della faccia A.
|
|
int nExtLoopPointNumB = int( ExtLoopB.GetPointNbr()) ;
|
|
vector<double> vDistB ;
|
|
vDistB.reserve( nExtLoopPointNumB) ;
|
|
bContinue = ExtLoopB.GetFirstPoint( ptP) ;
|
|
while ( bContinue) {
|
|
vDistB.emplace_back( DistPointPlane( ptP, plPlaneA)) ;
|
|
bContinue = ExtLoopB.GetNextPoint( ptP) ;
|
|
}
|
|
// Verifico posizione della faccia B rispetto al piano della faccia A.
|
|
int nVertPosB = 0 ; int nVertNegB = 0 ;
|
|
for ( const auto& dDist : vDistB) {
|
|
if ( dDist > EPS_SMALL)
|
|
++ nVertPosB ;
|
|
else if ( dDist < - EPS_SMALL)
|
|
++ nVertNegB ;
|
|
}
|
|
// Se la faccia B giace tutta da una parte del piano, nessuna intersezione
|
|
if ( nVertPosB == nExtLoopPointNumB || nVertNegB == nExtLoopPointNumB)
|
|
return false ;
|
|
|
|
// Intersezione tra i piani delle due facce
|
|
Point3d ptL ; Vector3d vtL ;
|
|
int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ;
|
|
if ( nResPP == IPPT_NO)
|
|
return false ;
|
|
|
|
// Se le facce sono complanari
|
|
if ( nResPP == IPPT_OVERLAPS)
|
|
return false ;
|
|
|
|
// Box contenente entrambe le regioni
|
|
BBox3d b3Box, b3BoxB;
|
|
RegionA.GetLocalBBox( b3Box) ;
|
|
RegionB.GetLocalBBox( b3BoxB) ;
|
|
b3Box.Add(b3BoxB);
|
|
b3Box.Expand( 10);
|
|
|
|
// Limito la retta nel box contenente le regioni
|
|
INTDBLVECTOR vInters;
|
|
if ( ! IntersLineBox(ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) </*!=*/ 2)
|
|
return false ;
|
|
double dLen = vInters.back()/*[1]*/.second - vInters[0].second ;
|
|
Point3d ptIntLineSt = ptL + vInters[0].second * vtL;
|
|
Point3d ptIntLineEn = ptL + vInters.back()/*[1]*/.second * vtL;
|
|
CurveLine cvPlaneIntersLine;
|
|
cvPlaneIntersLine.Set( ptIntLineSt, ptIntLineEn);
|
|
|
|
// Limito la linea di intersezione con la faccia A
|
|
CRVCVECTOR IntersectionResultsA ;
|
|
bool bClassificationOk = RegionA.GetCurveClassification( cvPlaneIntersLine, IntersectionResultsA) ;
|
|
|
|
// Limito la linea di intersezione con la faccia B
|
|
CRVCVECTOR IntersectionResultsB ;
|
|
bClassificationOk = bClassificationOk && RegionB.GetCurveClassification( cvPlaneIntersLine, IntersectionResultsB) ;
|
|
|
|
if ( ! bClassificationOk)
|
|
return false ;
|
|
|
|
// Prendo la parte comune
|
|
int nPartNumA = int( IntersectionResultsA.size()) ;
|
|
int nPartNumB = int( IntersectionResultsB.size()) ;
|
|
for ( int nA = 0 ; nA < nPartNumA ; ++ nA) {
|
|
int nTypeA = IntersectionResultsA[nA].nClass ;
|
|
if ( nTypeA == CRVC_IN || nTypeA == CRVC_ON_P || nTypeA == CRVC_ON_M) {
|
|
for ( int nB = 0 ; nB < nPartNumB ; ++ nB) {
|
|
int nTypeB = IntersectionResultsB[nB].nClass ;
|
|
if ( nTypeB == CRVC_IN || nTypeB == CRVC_ON_P || nTypeB == CRVC_ON_M) {
|
|
double dParSA = dLen * IntersectionResultsA[nA].dParS ;
|
|
double dParEA = dLen * IntersectionResultsA[nA].dParE ;
|
|
double dParSB = dLen * IntersectionResultsB[nB].dParS ;
|
|
double dParEB = dLen * IntersectionResultsB[nB].dParE ;
|
|
if ( dParSB < dParEA - EPS_SMALL &&
|
|
dParEB > dParSA + EPS_SMALL) {
|
|
double dMinPar = max( dParSA, dParSB) ;
|
|
double dMaxPar = min( dParEA, dParEB) ;
|
|
IntersLinePart.emplace_back( LineFacetClass( ptIntLineSt + dMinPar * vtL, ptIntLineSt + dMaxPar * vtL, nTypeA, nTypeB)) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return int( IntersLinePart.size()) > 0 ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//bool
|
|
//CreateFlatRegionFromPolyLineVector( const POLYLINEVECTOR& PolyVec, SurfFlatRegion& Region)
|
|
//{
|
|
// bool bOk = true ;
|
|
// for ( int nL = 0 ; nL < int( PolyVec.size()) && bOk ; ++ nL) {
|
|
// CurveComposite Loop ;
|
|
// Point3d ptSt, ptEn ;
|
|
// bool bContinue = PolyVec[nL].GetFirstPoint( ptSt) && PolyVec[nL].GetNextPoint( ptEn) ;
|
|
// while ( bContinue) {
|
|
// CurveLine cvLine ;
|
|
// cvLine.Set( ptSt, ptEn) ;
|
|
// Loop.AddCurve( cvLine) ;
|
|
// ptSt = ptEn ;
|
|
// bContinue = PolyVec[nL].GetNextPoint( ptEn) ;
|
|
// }
|
|
// if ( nL == 0)
|
|
// bOk = bOk && Region.AddExtLoop( Loop) ;
|
|
// else
|
|
// bOk = bOk && Region.AddIntLoop( Loop) ;
|
|
// }
|
|
// return bOk ;
|
|
//}
|
|
|
|
static bool
|
|
TrimLineWithExtPolygon( const CurveLine& cvLine, const POLYLINEVECTOR& vContourVec,
|
|
CRVCVECTOR& vLinePart)
|
|
{
|
|
// Se i contorni non definiscono un poligono esteso o la retta non giace sul piano di quest'ultimo, non ha senso procedere.
|
|
double dArea ;
|
|
Plane3d plPlane ;
|
|
if ( vContourVec.empty() || ! vContourVec[0].IsClosedAndFlat( plPlane, dArea) ||
|
|
DistPointPlane( cvLine.GetStart(), plPlane) > EPS_SMALL || DistPointPlane( cvLine.GetEnd(), plPlane) > EPS_SMALL)
|
|
return false ;
|
|
|
|
// Pulisco il vettore delle parti.
|
|
vLinePart.clear() ;
|
|
|
|
// Proietto tutti i punti sul piano per eliminare eventuali deviazioni e li esprimo nel sistema di riferimento del poligono esteso.
|
|
Frame3d frPolygonFrame ;
|
|
frPolygonFrame.Set( plPlane.GetPoint(), plPlane.GetVersN()) ;
|
|
POLYLINEVECTOR vMyContourVec ;
|
|
for ( int nC = 0 ; nC < int( vContourVec.size()) ; ++ nC) {
|
|
vMyContourVec.emplace_back() ;
|
|
Point3d ptP ;
|
|
bool bContinue = vContourVec[nC].GetFirstPoint( ptP) ;
|
|
while ( bContinue) {
|
|
vMyContourVec.back().AddUPoint( 0, ProjectPointOnPlane( ptP, plPlane)) ;
|
|
bContinue = vContourVec[nC].GetNextPoint( ptP) ;
|
|
}
|
|
vMyContourVec[nC].ToLoc( frPolygonFrame) ;
|
|
}
|
|
CurveLine cvMyLine ;
|
|
cvMyLine.Set( ProjectPointOnPlane( cvLine.GetStart(), plPlane), ProjectPointOnPlane( cvLine.GetEnd(), plPlane)) ;
|
|
cvMyLine.ToLoc( frPolygonFrame) ;
|
|
|
|
// Intersezione della linea con i contoni
|
|
ICCIVECTOR vIntInfoVec ;
|
|
for ( int nC = 0 ; nC < int( vMyContourVec.size()) ; ++ nC) {
|
|
Point3d ptSegS, ptSegE ;
|
|
bool bContinue = vMyContourVec[nC].GetFirstPoint( ptSegS) && vMyContourVec[nC].GetNextPoint( ptSegE) ;
|
|
while ( bContinue) {
|
|
CurveLine cvSeg ;
|
|
cvSeg.Set( ptSegS, ptSegE) ;
|
|
IntersLineLine LineLineIntersCalc( cvMyLine, cvSeg) ;
|
|
IntCrvCrvInfo aInfo ;
|
|
if ( LineLineIntersCalc.GetIntCrvCrvInfo( aInfo))
|
|
vIntInfoVec.emplace_back( aInfo) ;
|
|
ptSegS = ptSegE ;
|
|
bContinue = vMyContourVec[nC].GetNextPoint( ptSegE) ;
|
|
}
|
|
}
|
|
|
|
// Riordino le intersezioni e unisco le parti sovrapposte.
|
|
sort( vIntInfoVec.begin(), vIntInfoVec.end(), [] ( IntCrvCrvInfo Int1, IntCrvCrvInfo Int2) { return Int1.IciA[0].dU < Int2.IciA[0].dU ; }) ;
|
|
for ( int n = 0 ; n < int( vIntInfoVec.size()) - 1 ; ++ n) {
|
|
for ( int m = n + 1 ; vIntInfoVec[n].bOverlap && m < int( vIntInfoVec.size()) ; ++ m) {
|
|
if ( vIntInfoVec[n].IciA[1].dU > vIntInfoVec[m].IciA[0].dU) {
|
|
if ( vIntInfoVec[m].bOverlap && vIntInfoVec[n].IciA[1].dU < vIntInfoVec[m].IciA[1].dU) {
|
|
vIntInfoVec[n].IciA[1] = vIntInfoVec[m].IciA[1] ;
|
|
}
|
|
vIntInfoVec.erase( vIntInfoVec.begin() + m) ;
|
|
-- m ;
|
|
}
|
|
}
|
|
|
|
for ( int m = n + 1 ; ! vIntInfoVec[n].bOverlap && m < int( vIntInfoVec.size()) ; ++ m) {
|
|
if ( vIntInfoVec[n].IciA[0].dU > vIntInfoVec[m].IciA[0].dU - EPS_SMALL) {
|
|
if ( vIntInfoVec[m].bOverlap) {
|
|
if ( vIntInfoVec[n].IciA[0].dU > vIntInfoVec[m].IciA[0].dU - EPS_SMALL) {
|
|
vIntInfoVec.erase( vIntInfoVec.begin() + n) ;
|
|
-- n ;
|
|
break ;
|
|
}
|
|
}
|
|
else if ( vIntInfoVec[n].IciA[0].dU > vIntInfoVec[m].IciA[0].dU - 100 * EPS_ZERO) {
|
|
vIntInfoVec.erase( vIntInfoVec.begin() + m) ;
|
|
-- m ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Definisco le parti di linea dentro il poligono esteso.
|
|
bool bStateInside = true ;
|
|
for ( int nC = 0 ; nC < int( vMyContourVec.size()) ; ++ nC) {
|
|
bStateInside = bStateInside && vMyContourVec[nC].IsPointInsidePolyLine( cvMyLine.GetStart()) ;
|
|
}
|
|
if ( bStateInside)
|
|
vLinePart.emplace_back( 0, -1, LCP_ERROR) ;
|
|
for ( int n = 0 ; n < int( vIntInfoVec.size()) ; ++ n) {
|
|
// La linea � dentro.
|
|
if ( bStateInside) {
|
|
// Segno che chiudiamo una parte d'intersezione.
|
|
bStateInside = false ;
|
|
// L'intersezione corrente � un segmento.
|
|
if ( vIntInfoVec[n].bOverlap) {
|
|
// Si chiude la parte precedente e si aggiunge un segmeno
|
|
if ( vIntInfoVec[n].IciA[0].dU > vLinePart.back().dParS + EPS_SMALL) {
|
|
vLinePart.back().dParE = vLinePart.back().dParS ;
|
|
vLinePart.back().nClass = LCP_OVERLAP ;
|
|
vLinePart.emplace_back( vIntInfoVec[n].IciA[0].dU, vIntInfoVec[n].IciA[1].dU, LCP_OVERLAP) ;
|
|
}
|
|
// Si promuove l'intersezione precedente a un segmento.
|
|
else {
|
|
vLinePart.back().dParE = vIntInfoVec[n].IciA[1].dU ;
|
|
vLinePart.back().nClass = LCP_OVERLAP ;
|
|
}
|
|
}
|
|
// L'intersezione corrente � un punto: chiudiamo la parte precedente.
|
|
else {
|
|
vLinePart.back().dParE = vIntInfoVec[n].IciA[0].dU ;
|
|
vLinePart.back().nClass = LCP_INN ;
|
|
}
|
|
}
|
|
// La linea � fuori
|
|
else {
|
|
// L'intersezione corrente � un segmento.
|
|
if ( vIntInfoVec[n].bOverlap) {
|
|
// Apro e chiudo una nuova parte.
|
|
vLinePart.emplace_back( vIntInfoVec[n].IciA[0].dU, vIntInfoVec[n].IciA[1].dU, CRVC_ON_P) ;
|
|
}
|
|
// L'intersezione corrente � un punto: chiudiamo la parte precedente.
|
|
else {
|
|
// Segno che apro una nuova parte.
|
|
bStateInside = true ;
|
|
// Apro una nuova parte.
|
|
vLinePart.emplace_back( vIntInfoVec[n].IciA[0].dU, - INFINITO, LCP_INN) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Controllo che non ci siano incongruenze: se tutti gli ingressi
|
|
// e le uscite sono ordinate, dovrebbe essere tutto ok.
|
|
for ( int n = 0 ; n < int( vLinePart.size()) ; ++ n) {
|
|
if ( vLinePart[n].dParS > vLinePart[n].dParE)
|
|
return false ;
|
|
if ( n + 1 < int( vLinePart.size()) && vLinePart[n].dParE > vLinePart[n + 1].dParS)
|
|
return false ;
|
|
/*for ( int m = n + 1 ; m < int( vLinePart.size()) ; ++ m) {
|
|
if ( vLinePart[n].dParE > vLinePart[m].dParS)
|
|
return false ;
|
|
}*/
|
|
}
|
|
|
|
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 ( ! vPolyVec[nLoop].IsPointInsidePolyLine( ptProjP))
|
|
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 ( vPolyVec[nLoop].DistPointPolyLine( ptP, dDist) && dDist < dPointFacetDist)
|
|
dPointFacetDist = dDist ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::SplitFacet( const INTERSCHAINMAP& IntersLineMap, PieceMap& NewFacet)
|
|
{
|
|
for ( auto it = IntersLineMap.begin() ; it != IntersLineMap.end() ; ++ it) {
|
|
// Normale alla faccia
|
|
Vector3d vtFacetNorm ;
|
|
GetFacetNormal( it->first, vtFacetNorm) ;
|
|
// Creo i loop
|
|
ChainCurves LoopCreator ;
|
|
LoopCreator.Init( false, 10 * EPS_SMALL, int( it->second.size()), 10 /** BOOLEAN_SCALE*/) ;
|
|
// Carico le curve per concatenarle
|
|
for ( int nCv = 0 ; nCv < int( it->second.size()); ++ nCv) {
|
|
Point3d ptSt = it->second[nCv].ptSt ;
|
|
Point3d ptEn = it->second[nCv].ptEn ;
|
|
Vector3d vtDir = ptEn - ptSt ;
|
|
vtDir.Normalize() ;
|
|
LoopCreator.AddCurve( nCv + 1, ptSt, vtDir, ptEn, vtDir) ;
|
|
}
|
|
// Recupero i concatenamenti e li divido fra chiusi e aperti.
|
|
INTVECTOR vIds ;
|
|
Point3d ptNearStart = ( it->second.size() > 0 ? it->second[0].ptSt : ORIG) ;
|
|
INNCHAINVECTOR cvClosedChain ;
|
|
INNCHAINVECTOR cvOpenChain ;
|
|
while ( LoopCreator.GetChainFromNear( ptNearStart, false, vIds)) {
|
|
IntersInnChain chTemp ;
|
|
for ( auto i : vIds) {
|
|
// Aggiungo la linea alla curva composta.
|
|
chTemp.emplace_back( it->second[i - 1]) ;
|
|
}
|
|
int nCurLoopLast = max( int( chTemp.size()) - 1, 0) ;
|
|
if ( AreSamePointEpsilon( chTemp[0].ptSt, chTemp[nCurLoopLast].ptEn, 10 * EPS_SMALL) && nCurLoopLast > 0)
|
|
cvClosedChain.emplace_back( chTemp) ;
|
|
else
|
|
cvOpenChain.emplace_back( chTemp) ;
|
|
}
|
|
// Elimino la seconda copia di catene aperte doppie
|
|
for ( int nI = 0 ; nI < int( cvOpenChain.size()) - 1 ; ++ nI) {
|
|
for ( int nJ = nI + 1 ; nJ < int( cvOpenChain.size()) ; ++ nJ) {
|
|
if ( cvOpenChain[nI].size() == cvOpenChain[nJ].size()) {
|
|
bool bSame = true ;
|
|
for ( int nK = 0 ; nK < int( cvOpenChain[nI].size()) ; ++ nK) {
|
|
if ( ! AreSamePointEpsilon( cvOpenChain[nI][nK].ptSt, cvOpenChain[nJ][nK].ptSt, 10 * EPS_SMALL) ||
|
|
! AreSamePointEpsilon( cvOpenChain[nI][nK].ptEn, cvOpenChain[nJ][nK].ptEn, 10 * EPS_SMALL)) {
|
|
bSame = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bSame) {
|
|
cvOpenChain.erase( cvOpenChain.begin() + nJ) ;
|
|
-- nJ ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Elimino la seconda copia di catene chiuse doppie
|
|
for ( int nI = 0 ; nI < int( cvClosedChain.size()) - 1 ; ++ nI) {
|
|
for ( int nJ = nI + 1 ; nJ < int( cvClosedChain.size()) ; ++ nJ) {
|
|
if ( cvClosedChain[nI].size() == cvClosedChain[nJ].size()) {
|
|
bool bSame = true ;
|
|
for ( int nK = 0 ; nK < int( cvClosedChain[nI].size()) ; ++ nK) {
|
|
if ( ! AreSamePointEpsilon( cvClosedChain[nI][nK].ptSt, cvClosedChain[nJ][nK].ptSt, 10 * EPS_SMALL) ||
|
|
! AreSamePointEpsilon( cvClosedChain[nI][nK].ptEn, cvClosedChain[nJ][nK].ptEn, 10 * EPS_SMALL)) {
|
|
bSame = false ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bSame) {
|
|
cvClosedChain.erase( cvClosedChain.begin() + nJ) ;
|
|
-- nJ ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Recupero i loop della faccia da dividere
|
|
vector<FacetPiece>& vNewPieces = ( NewFacet.emplace( it->first, vector<FacetPiece>()).first)->second ;
|
|
vNewPieces.emplace_back();
|
|
vNewPieces.back().nPiecePart = 1 ;
|
|
GetFacetLoops( it->first, vNewPieces.back().vPieceLoop) ;
|
|
// Divido la faccia in parti.
|
|
// Ciclo sulle catene finch� non esauriscono.
|
|
int nIterNumber = 0 ;
|
|
int nPrevLastChainNum = int( cvOpenChain.size()) ;
|
|
while ( int( cvOpenChain.size()) > 0) {
|
|
// Controllo di non essere in un loop infinito.
|
|
int nLastChainNum = int( cvOpenChain.size()) - 1 ;
|
|
if ( nPrevLastChainNum == nLastChainNum) {
|
|
cvOpenChain.insert( cvOpenChain.begin(), cvOpenChain.back()) ;
|
|
cvOpenChain.pop_back() ;
|
|
++ nIterNumber ;
|
|
}
|
|
else {
|
|
nIterNumber = 0 ;
|
|
nPrevLastChainNum = nLastChainNum;
|
|
}
|
|
if ( nIterNumber == int( cvOpenChain.size())) {
|
|
cvOpenChain.resize( int( cvOpenChain.size()) - 1) ;
|
|
-- nLastChainNum ;
|
|
}
|
|
if ( int( cvOpenChain.size()) == 0)
|
|
break ;
|
|
// Ciclo su tutte le parti della faccia.
|
|
int nPartLoopNum = int( vNewPieces.size()) ;
|
|
for ( int nPart = 0 ; nPart < nPartLoopNum ; ++ nPart) {
|
|
// Cerco i loop su cui la catena corrente inizia e finisce.
|
|
INTVECTOR vLoopIndexes ;
|
|
// Ciclo sui loop della faccia.
|
|
for ( int nLoop = 0 ; nLoop < int( vNewPieces[nPart].vPieceLoop.size()) && int( vLoopIndexes.size()) < 2 ; ++ nLoop) {
|
|
int nSegNum ;
|
|
double dParOnSeg ;
|
|
if ( vNewPieces[nPart].vPieceLoop[nLoop].PointPositionOnPolyLine( cvOpenChain[nLastChainNum][0].ptSt, nSegNum, dParOnSeg, 9 * EPS_SMALL)) {
|
|
vLoopIndexes.emplace_back( nLoop) ;
|
|
if ( vLoopIndexes.size() > 1) {
|
|
swap( vLoopIndexes[0], vLoopIndexes[1]) ;
|
|
}
|
|
}
|
|
if ( vNewPieces[nPart].vPieceLoop[nLoop].PointPositionOnPolyLine( cvOpenChain[nLastChainNum][cvOpenChain[nLastChainNum].size() - 1].ptEn,
|
|
nSegNum, dParOnSeg, 9 * EPS_SMALL)) {
|
|
vLoopIndexes.emplace_back( nLoop) ;
|
|
}
|
|
}
|
|
// Se non ho trovato almeno un taglio completo, vado al prossimo.
|
|
if ( int( vLoopIndexes.size()) < 2)
|
|
continue ;
|
|
// La catena finisce sul loop ove inizia. Divido la nuova parte.
|
|
if ( vLoopIndexes[0] == vLoopIndexes[1]) {
|
|
// Cambio inizio al loop iniziale.
|
|
vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]].ChangePolyLineStart( cvOpenChain[nLastChainNum].back().ptEn, 9 * EPS_SMALL) ;
|
|
// Divido il loop della parte
|
|
// Loop1
|
|
PolyLine NewLoop1 ;
|
|
// Inserisco i punti della catena nella PolyLine del nuovo loop.
|
|
for ( int m = 0 ; m < int( cvOpenChain[nLastChainNum].size()) ; ++ m) {
|
|
NewLoop1.AddUPoint( 0., cvOpenChain[nLastChainNum][m].ptSt) ;
|
|
if ( m == int( cvOpenChain[nLastChainNum].size()) - 1)
|
|
NewLoop1.AddUPoint( 0., cvOpenChain[nLastChainNum][m].ptEn) ;
|
|
}
|
|
// Spezzo il loop successivo alla catena nel punto in cui comincia la catena successiva.
|
|
PolyLine SplitLoop1, SplitLoop2 ;
|
|
vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]].SplitPolyLineAtPoint( cvOpenChain[nLastChainNum][0].ptSt,
|
|
SplitLoop1, SplitLoop2, 9 * EPS_SMALL) ;
|
|
// Aggiungo i punti precedenti il punto di frattura nella in NewLoop1.
|
|
NewLoop1.AddPolyLineToPolyLine( SplitLoop1, 10 * EPS_SMALL) ;
|
|
// Loop2
|
|
PolyLine NewLoop2 ;
|
|
NewLoop2.AddPolyLineToPolyLine( SplitLoop2, 10 * EPS_SMALL) ;
|
|
// Inserisco i punti della catena nella PolyLine del nuovo loop.
|
|
for ( int m = int( cvOpenChain[nLastChainNum].size()) - 1 ; m >= 0 ; -- m) {
|
|
NewLoop2.AddUPoint( 0., cvOpenChain[nLastChainNum][m].ptEn) ;
|
|
if ( m == 0)
|
|
NewLoop2.AddUPoint( 0., cvOpenChain[nLastChainNum][m].ptSt) ;
|
|
}
|
|
// Loop esterno coinvolto
|
|
if ( vLoopIndexes[0] == 0) {
|
|
// Creo i pezzi nuovi, i cui loop esterni sono quelli appena definiti.
|
|
FacetPiece PieceInn, PieceOut ;
|
|
PieceInn.vPieceLoop.emplace_back( NewLoop1) ;
|
|
PieceInn.nPiecePart = 1 ;
|
|
PieceOut.vPieceLoop.emplace_back( NewLoop2) ;
|
|
PieceOut.nPiecePart = - 1 ;
|
|
// Assegno i loop interni del vecchio pezzo non tagliati da catene ai nuovi.
|
|
for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) {
|
|
if ( nIL == vLoopIndexes[0])
|
|
continue ;
|
|
Point3d ptPointInnerLoop ;
|
|
vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ;
|
|
if ( PieceInn.vPieceLoop[0].GetPointNbr() < PieceOut.vPieceLoop[0].GetPointNbr()) {
|
|
if ( PieceInn.vPieceLoop[0].IsPointInsidePolyLine( ptPointInnerLoop)) {
|
|
PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
}
|
|
else {
|
|
PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
}
|
|
}
|
|
else {
|
|
if ( PieceOut.vPieceLoop[0].IsPointInsidePolyLine( ptPointInnerLoop)) {
|
|
PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
}
|
|
else {
|
|
PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
}
|
|
}
|
|
}
|
|
vNewPieces.erase( vNewPieces.begin() + nPart) ;
|
|
vNewPieces.emplace_back( PieceInn) ;
|
|
vNewPieces.emplace_back( PieceOut) ;
|
|
}
|
|
// Loop esterno non coinvolto
|
|
else {
|
|
Plane3d plLoopPlane1, plLoopPlane2, plContLoopPlane;
|
|
double dArea1, dArea2, dAreaCont;
|
|
NewLoop1.IsClosedAndFlat(plLoopPlane1, dArea1);
|
|
NewLoop2.IsClosedAndFlat(plLoopPlane2, dArea2);
|
|
vNewPieces[nPart].vPieceLoop[0].IsClosedAndFlat(plContLoopPlane, dAreaCont);
|
|
Vector3d vtLoopPlaneNorm1 = plLoopPlane1.GetVersN();
|
|
Vector3d vtContLoopPlaneNorm = plContLoopPlane.GetVersN();
|
|
PolyLine NewLoopCCW, NewLoopCW;
|
|
bool bFirstLoopIsCounter = vtLoopPlaneNorm1 * vtContLoopPlaneNorm > EPS_SMALL;
|
|
if (bFirstLoopIsCounter) {
|
|
NewLoopCCW = NewLoop1;
|
|
NewLoopCW = NewLoop2;
|
|
}
|
|
else {
|
|
NewLoopCCW = NewLoop2;
|
|
NewLoopCW = NewLoop1;
|
|
}
|
|
// Creo il pezzo nuovo, il cui loop esterno � stato appena definito.
|
|
FacetPiece DetachedPiece;
|
|
DetachedPiece.vPieceLoop.emplace_back(NewLoopCCW);
|
|
DetachedPiece.nPiecePart = bFirstLoopIsCounter ? 1 : -1;
|
|
// Al pezzo pezzo staccato assegno i loop interni del vecchio pezzo non tagliati da catene.
|
|
for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) {
|
|
if ( nIL == vLoopIndexes[0])
|
|
continue ;
|
|
Point3d ptPointInnerLoop ;
|
|
vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ;
|
|
if ( DetachedPiece.vPieceLoop[0].IsPointInsidePolyLine( ptPointInnerLoop)) {
|
|
DetachedPiece.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
vNewPieces[nPart].vPieceLoop.erase( vNewPieces[nPart].vPieceLoop.begin() + nIL) ;
|
|
// Cambio il numero dei loop talgiati
|
|
for ( int nIntersLoop = 0 ; nIntersLoop < int( vLoopIndexes.size()) ; ++ nIntersLoop) {
|
|
if ( vLoopIndexes[nIntersLoop] > nIL)
|
|
-- vLoopIndexes[nIntersLoop] ;
|
|
}
|
|
-- nIL ;
|
|
}
|
|
}
|
|
// Aggiungo al pezzo, da cui si stacca quello appena creato, il loop complementare a quello che appartiene al pezzo che si stacca.
|
|
/*if ( ! bFirstLoopIsCounter)*/
|
|
vNewPieces[nPart].vPieceLoop.erase(vNewPieces[nPart].vPieceLoop.begin() + vLoopIndexes[0]);
|
|
vNewPieces[nPart].vPieceLoop.emplace_back( NewLoopCW) ;
|
|
vNewPieces[nPart].nPiecePart = bFirstLoopIsCounter ? - 1 : 1 ;
|
|
vNewPieces.emplace_back( DetachedPiece) ;
|
|
}
|
|
// Elimino la catena usata.
|
|
cvOpenChain.erase( cvOpenChain.begin() + nLastChainNum) ;
|
|
// Interrompo il ciclo sulle parti.
|
|
break ;
|
|
}
|
|
// Cerco le catene per dividere la nuova parte.
|
|
else {
|
|
INTVECTOR vChainIndex ;
|
|
vChainIndex.emplace_back( nLastChainNum) ;
|
|
int nIter = 0 ;
|
|
while ( vLoopIndexes.back() != vLoopIndexes[0] && nIter == 0) {
|
|
// Cambio inizio del loop corrente in modo che il punto di inizio sia il punto finale dell'ultima catena trovata.
|
|
vNewPieces[nPart].vPieceLoop[vLoopIndexes.back()].ChangePolyLineStart( cvOpenChain[vChainIndex.back()].back().ptEn, 9 * EPS_SMALL) ;
|
|
// Cerco catene che iniziano sul loop coorente
|
|
vector<PositionOnPolyLine> vChainStartingOnLoop ;
|
|
for ( int nCh = 0 ; nCh < nLastChainNum ; ++ nCh) {
|
|
int nSegNum ;
|
|
double dParOnSeg ;
|
|
if ( vNewPieces[nPart].vPieceLoop[vLoopIndexes.back()].PointPositionOnPolyLine( cvOpenChain[nCh][0].ptSt, nSegNum, dParOnSeg, 9 * EPS_SMALL)) {
|
|
vChainStartingOnLoop.emplace_back( PositionOnPolyLine(nCh, nSegNum, dParOnSeg)) ;
|
|
}
|
|
}
|
|
// Ordino le catene secondo la vicinanza lungo il loop del loro punto d'inizio al punto d'inizio del loop stesso.
|
|
sort( vChainStartingOnLoop.begin(), vChainStartingOnLoop.end(), [] ( PositionOnPolyLine Ch1, PositionOnPolyLine Ch2) {
|
|
if ( Ch1.nSegNum < Ch2.nSegNum)
|
|
return true ;
|
|
else if ( Ch1.nSegNum == Ch2.nSegNum)
|
|
return Ch1.dParOnSeg < Ch2.dParOnSeg ;
|
|
else
|
|
return false ; } ) ;
|
|
++ nIter ;
|
|
// Cerco la prima catena che non termina sul loop corrente.
|
|
for ( int n = 0 ; n < int( vChainStartingOnLoop.size()) ; ++ n) {
|
|
bool bFound = false ;
|
|
// Indice della catena e indice del segmento finale
|
|
int nCh = vChainStartingOnLoop[n].nIndexInVec ;
|
|
int nLastLineIndex = int( cvOpenChain[nCh].size()) - 1 ;
|
|
// Ciclo sui loop
|
|
int nLoopNum = int( vNewPieces[nPart].vPieceLoop.size()) ;
|
|
int nLoop ;
|
|
for ( nLoop = 0 ; nLoop < nLoopNum ; ++ nLoop) {
|
|
// Salto il loop corrente
|
|
if ( nLoop == vLoopIndexes.back())
|
|
continue ;
|
|
int nSegNum ;
|
|
double dParOnSeg ;
|
|
// La catena termina su questo loop diverso da quello corrente.
|
|
if ( nLoop != vLoopIndexes.back() &&
|
|
vNewPieces[nPart].vPieceLoop[nLoop].PointPositionOnPolyLine( cvOpenChain[nCh][nLastLineIndex].ptEn, nSegNum, dParOnSeg, 9 * EPS_SMALL)) {
|
|
nIter = 0 ;
|
|
// Salvo l'indice della catena e quello del loop.
|
|
vChainIndex.emplace_back( nCh) ;
|
|
vLoopIndexes.emplace_back( nLoop) ;
|
|
bFound = true;
|
|
break ;
|
|
}
|
|
}
|
|
if ( nLoop == nLoopNum || bFound)
|
|
break ;
|
|
}
|
|
}
|
|
// Cambio inizio al loop iniziale.
|
|
vNewPieces[nPart].vPieceLoop[vLoopIndexes[0]].ChangePolyLineStart( cvOpenChain[vChainIndex.back()].back().ptEn, 9 * EPS_SMALL) ;
|
|
// Divido i loop della parte.
|
|
POLYLINEVECTOR vPolySecondPartVec ;
|
|
PolyLine NewLoop1 ;
|
|
for ( int n = 0 ; n < int( vChainIndex.size()) ; ++ n) {
|
|
// Inserisco i punti della catena nella PolyLine del nuovo loop.
|
|
for ( int m = 0 ; m < int( cvOpenChain[vChainIndex[n]].size()) ; ++ m) {
|
|
NewLoop1.AddUPoint( 0., cvOpenChain[vChainIndex[n]][m].ptSt) ;
|
|
if ( m == int( cvOpenChain[vChainIndex[n]].size()) - 1)
|
|
NewLoop1.AddUPoint( 0., cvOpenChain[vChainIndex[n]][m].ptEn) ;
|
|
}
|
|
// Spezzo il loop successivo alla catena nel punto in cui comincia la catena successiva.
|
|
PolyLine SplitLoop1, SplitLoop2 ;
|
|
vNewPieces[nPart].vPieceLoop[vLoopIndexes[n + 1]].SplitPolyLineAtPoint( cvOpenChain[vChainIndex[( n + 1) % int( vChainIndex.size())]][0].ptSt,
|
|
SplitLoop1, SplitLoop2, 9 * EPS_SMALL) ;
|
|
// Aggiungo i punti precedenti il punto di frattura in NewLoop1.
|
|
NewLoop1.AddPolyLineToPolyLine( SplitLoop1, 10 * EPS_SMALL) ;
|
|
// Salvo la parte dopo il punto di frattura in un apposito vettore.
|
|
vPolySecondPartVec.emplace_back( SplitLoop2) ;
|
|
}
|
|
PolyLine NewLoop2 ;
|
|
for ( int n = int( vChainIndex.size()) - 1 ; n >= 0 ; -- n) {
|
|
// Aggiungo i punti successivi il punto di frattura in NewLoop2.
|
|
NewLoop2.AddPolyLineToPolyLine( vPolySecondPartVec[n], 10 * EPS_SMALL) ;
|
|
// Inserisco i punti della catena nella PolyLine del nuovo loop.
|
|
for ( int m = int( cvOpenChain[vChainIndex[n]].size()) - 1 ; m >= 0 ; -- m) {
|
|
NewLoop2.AddUPoint( 0., cvOpenChain[vChainIndex[n]][m].ptEn) ;
|
|
if ( m == 0)
|
|
NewLoop2.AddUPoint( 0., cvOpenChain[vChainIndex[n]][m].ptSt) ;
|
|
}
|
|
}
|
|
// Controllo che il loop esterno sia interessato.
|
|
bool bExtCutted = false ;
|
|
for ( int n = 0 ; n < int( vLoopIndexes.size()) && ! bExtCutted ; ++ n) {
|
|
if ( vLoopIndexes[n] == 0)
|
|
bExtCutted = true ;
|
|
}
|
|
// Loop esterno interessato
|
|
if ( bExtCutted) {
|
|
// Creo i pezzi nuovi, i cui loop esterni sono quelli appena definiti.
|
|
FacetPiece PieceInn, PieceOut ;
|
|
PieceInn.vPieceLoop.emplace_back( NewLoop1) ;
|
|
PieceInn.nPiecePart = 1 ;
|
|
PieceOut.vPieceLoop.emplace_back( NewLoop2) ;
|
|
PieceOut.nPiecePart = - 1 ;
|
|
// Assegno i loop interni del vecchio pezzo non tagliati da catene ai nuovi.
|
|
for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) {
|
|
bool bUsed = false ;
|
|
for ( int nU = 0 ; nU < int( vLoopIndexes.size()) - 1 ; ++ nU) {
|
|
if ( nIL == vLoopIndexes[nU]) {
|
|
bUsed = true ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bUsed)
|
|
continue ;
|
|
Point3d ptPointInnerLoop ;
|
|
vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ;
|
|
if ( PieceInn.vPieceLoop[0].GetPointNbr() < PieceOut.vPieceLoop[0].GetPointNbr()) {
|
|
if ( PieceInn.vPieceLoop[0].IsPointInsidePolyLine( ptPointInnerLoop)) {
|
|
PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
}
|
|
else {
|
|
PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
}
|
|
}
|
|
else {
|
|
if ( PieceOut.vPieceLoop[0].IsPointInsidePolyLine( ptPointInnerLoop)) {
|
|
PieceOut.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
}
|
|
else {
|
|
PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
}
|
|
}
|
|
}
|
|
// Aggiungo i due nuovi pezzi ed elimino quello da cui sono nati.
|
|
vNewPieces.erase( vNewPieces.begin() + nPart) ;
|
|
vNewPieces.emplace_back( PieceInn) ;
|
|
vNewPieces.emplace_back( PieceOut) ;
|
|
}
|
|
// Loop esterno non interessato
|
|
else {
|
|
Plane3d plLoopPlane1, plLoopPlane2, plContLoopPlane ;
|
|
double dArea1, dArea2, dAreaCont ;
|
|
NewLoop1.IsClosedAndFlat( plLoopPlane1, dArea1) ;
|
|
NewLoop2.IsClosedAndFlat( plLoopPlane2, dArea2) ;
|
|
vNewPieces[nPart].vPieceLoop[0].IsClosedAndFlat( plContLoopPlane, dAreaCont) ;
|
|
Vector3d vtLoopPlaneNorm1 = plLoopPlane1.GetVersN();
|
|
Vector3d vtContLoopPlaneNorm = plContLoopPlane.GetVersN();
|
|
PolyLine NewLoopCCW, NewLoopCW;
|
|
bool bFirstLoopIsCounter = vtLoopPlaneNorm1 * vtContLoopPlaneNorm > EPS_SMALL;
|
|
if ( bFirstLoopIsCounter) {
|
|
NewLoopCCW = NewLoop1 ;
|
|
NewLoopCW = NewLoop2 ;
|
|
}
|
|
else {
|
|
NewLoopCCW = NewLoop2 ;
|
|
NewLoopCW = NewLoop1 ;
|
|
}
|
|
// // Creo il pezzo nuovo, il cui loop esterno � stato appena definito.
|
|
// FacetPiece PieceInn ;
|
|
// PieceInn.vPieceLoop.emplace_back( NewLoop1) ;
|
|
// PieceInn.nPiecePart = 1 ;
|
|
// // Assegno i loop interni del vecchio pezzo non tagliati da catene ai nuovi.
|
|
// for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) {
|
|
// bool bUsed = false ;
|
|
// for ( int nU = 1 ; nU < int( vLoopIndexes.size()) - 1 ; ++ nU) {
|
|
// if ( nIL == vLoopIndexes[nU]) {
|
|
// bUsed = true ;
|
|
// break ;
|
|
// }
|
|
// }
|
|
// if ( bUsed)
|
|
// continue ;
|
|
// Point3d ptPointInnerLoop ;
|
|
// vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ;
|
|
// if ( IsPointInsidePolyLine( ptPointInnerLoop, PieceInn.vPieceLoop[0])) {
|
|
// PieceInn.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
// vNewPieces[nPart].vPieceLoop.erase( vNewPieces[nPart].vPieceLoop.begin() + nIL) ;
|
|
// -- nIL ;
|
|
// }
|
|
// }
|
|
// // Aggiungo al pezzo, da cui si stacca quello appena creato, il loop complementare a quello che appartiene al nuovo pezzo.
|
|
// vNewPieces[nPart].vPieceLoop.emplace_back( NewLoop2) ;
|
|
// vNewPieces[nPart].nPiecePart = - 1 ;
|
|
// vNewPieces.emplace_back( PieceInn) ;
|
|
// Creo il pezzo nuovo, il cui loop esterno � stato appena definito.
|
|
FacetPiece DetachedPiece ;
|
|
DetachedPiece.vPieceLoop.emplace_back( NewLoopCCW) ;
|
|
DetachedPiece.nPiecePart = bFirstLoopIsCounter ? 1 : - 1 ;
|
|
// Al pezzo che si stacca assegno i loop interni del vecchio pezzo non tagliati da catene.
|
|
for ( int nIL = 1 ; nIL < int( vNewPieces[nPart].vPieceLoop.size()) ; ++ nIL) {
|
|
bool bUsed = false ;
|
|
for ( int nU = 1 ; nU < int( vLoopIndexes.size()) - 1 ; ++ nU) {
|
|
if ( nIL == vLoopIndexes[nU]) {
|
|
bUsed = true ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( bUsed)
|
|
continue ;
|
|
Point3d ptPointInnerLoop ;
|
|
vNewPieces[nPart].vPieceLoop[nIL].GetFirstPoint( ptPointInnerLoop) ;
|
|
if ( DetachedPiece.vPieceLoop[0].IsPointInsidePolyLine( ptPointInnerLoop)) {
|
|
DetachedPiece.vPieceLoop.emplace_back( vNewPieces[nPart].vPieceLoop[nIL]) ;
|
|
vNewPieces[nPart].vPieceLoop.erase( vNewPieces[nPart].vPieceLoop.begin() + nIL) ;
|
|
// Cambio il numero dei loop talgiati
|
|
for ( int nIntersLoop = 0 ; nIntersLoop < int( vLoopIndexes.size()) ; ++ nIntersLoop) {
|
|
if ( vLoopIndexes[nIntersLoop] > nIL)
|
|
-- vLoopIndexes[nIntersLoop] ;
|
|
}
|
|
-- nIL ;
|
|
}
|
|
}
|
|
// Aggiungo al pezzo, da cui si stacca quello appena creato, il loop complementare a quello che appartiene al pezzo che si stacca.
|
|
vLoopIndexes.resize(int(vLoopIndexes.size()) - 1);
|
|
sort( vLoopIndexes.begin(), vLoopIndexes.end(), [] ( int nIndex1, int nIndex2) { return nIndex1 > nIndex2 ; }) ;
|
|
for (int nLoopInd = 0; nLoopInd < int(vLoopIndexes.size()); ++nLoopInd) {
|
|
vNewPieces[nPart].vPieceLoop.erase(vNewPieces[nPart].vPieceLoop.begin() + vLoopIndexes[nLoopInd]);
|
|
}
|
|
vNewPieces[nPart].vPieceLoop.emplace_back( NewLoopCW) ;
|
|
vNewPieces[nPart].nPiecePart = bFirstLoopIsCounter ? - 1 : 1 ;
|
|
vNewPieces.emplace_back( DetachedPiece) ;
|
|
}
|
|
// Elimino catene usate.
|
|
sort( vChainIndex.begin(), vChainIndex.end(), [] ( int nIndex1, int nIndex2) { return nIndex1 > nIndex2 ; }) ;
|
|
for ( int nChInd = 0 ; nChInd < int( vChainIndex.size()) ; ++ nChInd) {
|
|
cvOpenChain.erase( cvOpenChain.begin() + vChainIndex[nChInd]) ;
|
|
}
|
|
// Interrompo il ciclo sulle parti.
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// Assegno i loop chiusi interni alle rispettive parti di faccia.
|
|
// Ciclo sui loop interni
|
|
for ( int nInnL = 0 ; nInnL < int( cvClosedChain.size()) ; ++ nInnL) {
|
|
// Trasformo il loop interno in PolyLine.
|
|
PolyLine CurInnerLoop ;
|
|
CurInnerLoop.AddUPoint( 0., cvClosedChain[nInnL][0].ptSt) ;
|
|
for ( int nSeg = 0 ; nSeg < int( cvClosedChain[nInnL].size()) ; ++ nSeg) {
|
|
CurInnerLoop.AddUPoint( 0., cvClosedChain[nInnL][nSeg].ptEn) ;
|
|
}
|
|
Plane3d plPlane ;
|
|
double dArea ;
|
|
if ( ! CurInnerLoop.IsClosedAndFlat( plPlane, dArea) || dArea < EPS_SMALL)
|
|
continue ;
|
|
int nIncluderPiece = - 1 ;
|
|
double dIncluderPieceArea = DBL_MAX ;
|
|
bool bNewPieceOut = false ;
|
|
// Ciclo sui pezzi di facet.
|
|
int nPieceNum = int( vNewPieces.size()) ;
|
|
for ( int nPieceN = 0 ; nPieceN < nPieceNum ; ++ nPieceN) {
|
|
// Ciclo sui punti del loop interno.
|
|
PNTULIST& LoopList = CurInnerLoop.GetUPointList() ;
|
|
for ( auto itInn = LoopList.begin() ; itInn != LoopList.end() ; ++ itInn) {
|
|
Point3d ptInnP = itInn->first ;
|
|
Point3d ptInnNextP ;
|
|
auto itInnNext = itInn ;
|
|
++ itInnNext ;
|
|
if ( itInnNext != LoopList.end())
|
|
ptInnNextP = itInnNext->first ;
|
|
if ( vNewPieces[nPieceN].vPieceLoop[0].IsPointInsidePolyLine( ptInnP) || ( itInnNext != LoopList.end() &&
|
|
vNewPieces[nPieceN].vPieceLoop[0].IsPointInsidePolyLine( 0.5 * ( ptInnP + ptInnNextP)))) {
|
|
double dPieceArea ;
|
|
Plane3d plMyFictitiousPlane ;
|
|
vNewPieces[nPieceN].vPieceLoop[0].IsClosedAndFlat( plMyFictitiousPlane, dPieceArea) ;
|
|
if ( vNewPieces[nPieceN].vPieceLoop[0].IsClosedAndFlat( plMyFictitiousPlane, dPieceArea) && dPieceArea < dIncluderPieceArea) {
|
|
nIncluderPiece = nPieceN ;
|
|
Polygon3d AuxPolygon ;
|
|
AuxPolygon.FromPolyLine( CurInnerLoop) ;
|
|
Vector3d vtInnLoopNorm = AuxPolygon.GetVersN() ;
|
|
bNewPieceOut = vtFacetNorm * vtInnLoopNorm < 0. ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( nIncluderPiece != - 1 && bNewPieceOut) {
|
|
// Aggiungo loop al pezzo.
|
|
vNewPieces[nIncluderPiece].nPiecePart = 1 ;
|
|
vNewPieces[nIncluderPiece].vPieceLoop.emplace_back( CurInnerLoop) ;
|
|
// Aggiungo nuovo pezzo.
|
|
vNewPieces.emplace_back() ;
|
|
vNewPieces.back().vPieceLoop.emplace_back( CurInnerLoop) ;
|
|
vNewPieces.back().vPieceLoop.back().Invert() ;
|
|
vNewPieces.back().nPiecePart = - 1 ;
|
|
// Cerco loop interni a quello appena aggiunto
|
|
INTVECTOR vSecondLevel ;
|
|
for ( int nSI = 1 ; nSI < int( vNewPieces[nIncluderPiece].vPieceLoop.size()) ; ++ nSI) {
|
|
PNTULIST& SecLevLoopList = vNewPieces[nIncluderPiece].vPieceLoop[nSI].GetUPointList() ;
|
|
for ( auto itSL = SecLevLoopList.begin() ; itSL != SecLevLoopList.end() ; ++ itSL) {
|
|
Point3d ptPntSL = itSL->first ;
|
|
if ( vNewPieces.back().vPieceLoop.back().IsPointInsidePolyLine( ptPntSL)) {
|
|
vSecondLevel.emplace_back( nSI) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// Aggiungo i loop al nuovo pezzo e li tolgo dal precedente.
|
|
for ( int nSI = 0 ; nSI < int( vSecondLevel.size()) ; ++ nSI)
|
|
vNewPieces.back().vPieceLoop.emplace_back( vNewPieces[nIncluderPiece].vPieceLoop[vSecondLevel[nSI]]) ;
|
|
for ( int nSI = 0 ; nSI < int( vSecondLevel.size()) ; ++ nSI)
|
|
vNewPieces[nIncluderPiece].vPieceLoop.erase( vNewPieces[nIncluderPiece].vPieceLoop.begin() + vSecondLevel[nSI]) ;
|
|
}
|
|
else {
|
|
// Aggiungo loop al pezzo.
|
|
vNewPieces[nIncluderPiece].nPiecePart = - 1 ;
|
|
vNewPieces[nIncluderPiece].vPieceLoop.emplace_back( CurInnerLoop) ;
|
|
vNewPieces[nIncluderPiece].vPieceLoop.back().Invert() ;
|
|
// Aggiungo nuovo pezzo.
|
|
vNewPieces.emplace_back() ;
|
|
vNewPieces.back().vPieceLoop.emplace_back( CurInnerLoop) ;
|
|
vNewPieces.back().nPiecePart = 1 ;
|
|
// Cerco loop interni a quello appena aggiunto
|
|
INTVECTOR vSecondLevel ;
|
|
for ( int nSI = 1 ; nSI < int( vNewPieces[nIncluderPiece].vPieceLoop.size()) ; ++ nSI) {
|
|
PNTULIST& SecLevLoopList = vNewPieces[nIncluderPiece].vPieceLoop[nSI].GetUPointList() ;
|
|
for ( auto itSL = SecLevLoopList.begin() ; itSL != SecLevLoopList.end() ; ++ itSL) {
|
|
Point3d ptPntSL = itSL->first ;
|
|
if ( vNewPieces.back().vPieceLoop.back().IsPointInsidePolyLine( ptPntSL)) {
|
|
vSecondLevel.emplace_back( nSI) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
// Aggiungo i loop al nuovo pezzo e li tolgo dal precedente.
|
|
for ( int nSI = 0 ; nSI < int( vSecondLevel.size()) ; ++ nSI)
|
|
vNewPieces.back().vPieceLoop.emplace_back( vNewPieces[nIncluderPiece].vPieceLoop[vSecondLevel[nSI]]) ;
|
|
for ( int nSI = 0 ; nSI < int( vSecondLevel.size()) ; ++ nSI)
|
|
vNewPieces[nIncluderPiece].vPieceLoop.erase( vNewPieces[nIncluderPiece].vPieceLoop.begin() + vSecondLevel[nSI]) ;
|
|
}
|
|
}
|
|
// Aggiungo al loop esterno i punti dei loop interni che lo toccano.
|
|
// Ciclo sui pezzi della faccia.
|
|
int nPieceNum = int( vNewPieces.size()) ;
|
|
for ( int nPieceN = 0 ; nPieceN < nPieceNum ; ++ nPieceN) {
|
|
// Ciclo sui segmenti del loop esterno.
|
|
PNTULIST& ExtLoopList = vNewPieces[nPieceN].vPieceLoop[0].GetUPointList() ;
|
|
auto itSt = ExtLoopList.begin() ; auto itEn = itSt ; ++ itEn ;
|
|
for ( ; itEn != ExtLoopList.end(); ++itSt, ++itEn) {
|
|
Point3d ptSt = itSt->first ;
|
|
Point3d ptEn = itEn->first ;
|
|
Vector3d vtSeg = ptEn - ptSt ;
|
|
double dSegLen = vtSeg.Len() ;
|
|
vtSeg /= dSegLen ;
|
|
// Vettore dei punti dei loop interni che stanno sul segmento del loop esterno
|
|
PNTUVECTOR vPointWithOrder ;
|
|
// Ciclo sui loop interni del pezzo
|
|
int nInnerLoopNum = int( vNewPieces[nPieceN].vPieceLoop.size()) ;
|
|
for ( int nInnLoop = 1 ; nInnLoop < nInnerLoopNum ; ++ nInnLoop) {
|
|
// Ciclo sui punti del loop interno.
|
|
Point3d ptInnPoint ;
|
|
bool bIsFirst = true ;
|
|
bool bContinue = vNewPieces[nPieceN].vPieceLoop[nInnLoop].GetFirstPoint( ptInnPoint) ;
|
|
while ( bContinue) {
|
|
DistPointLine DistCalculator( ptInnPoint, ptSt, ptEn) ;
|
|
double dDist ;
|
|
DistCalculator.GetDist( dDist) ;
|
|
double dLongPos = ( ptInnPoint - ptSt) * vtSeg ;
|
|
if ( dDist < 10 * EPS_SMALL && dLongPos > 0. && dLongPos < dSegLen) {
|
|
POINTU NewPointU ;
|
|
NewPointU.first = ptSt + ( ( ptInnPoint - ptSt) * vtSeg) * vtSeg ;
|
|
NewPointU.second = dLongPos ;
|
|
if ( ! bIsFirst)
|
|
vPointWithOrder.emplace_back( NewPointU) ;
|
|
}
|
|
bIsFirst = false ;
|
|
bContinue = vNewPieces[nPieceN].vPieceLoop[nInnLoop].GetNextPoint( ptInnPoint) ;
|
|
}
|
|
}
|
|
// Riordino i punti interni sul segmento esterno in funzione della distanza dall'origine di esso
|
|
for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) - 1 ; ++ nPi) {
|
|
for ( int nPj = nPi + 1 ; nPj < int( vPointWithOrder.size()) ; ++ nPj) {
|
|
if ( vPointWithOrder[nPi].second > vPointWithOrder[nPj].second) {
|
|
swap( vPointWithOrder[nPi], vPointWithOrder[nPj]) ;
|
|
}
|
|
}
|
|
}
|
|
// Aggiungo i punti al loop esterno
|
|
for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) ; ++ nPi) {
|
|
itSt = ExtLoopList.emplace( itEn, vPointWithOrder[nPi]) ;
|
|
}
|
|
}
|
|
}
|
|
// Se non ho diviso la faccia, la elimino
|
|
if ( int( vNewPieces.size()) == 1)
|
|
NewFacet.erase( it->first) ;
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::EdgeInteriorContactManager( const SurfTriMesh& OthSurf,
|
|
const INTERSCHAINMAP& InterInterLineMap,
|
|
const INTERSEDGEMAP& EdgeInterLineMap)
|
|
{
|
|
// Ciclo su tutte le facce.
|
|
for ( auto it = EdgeInterLineMap.begin() ; it != EdgeInterLineMap.end() ; ++ it) {
|
|
int nFacet = it->first ;
|
|
const vector<IntersEdge>& vEdgeContact = it->second ;
|
|
// Triangoli della faccia
|
|
INTVECTOR vFacetTria ;
|
|
GetAllTriaInFacet( nFacet, vFacetTria) ;
|
|
// Versore normale alla faccia.
|
|
Vector3d vtN = m_vTria[m_vFacet[nFacet]].vtN ;
|
|
// Se la faccia � stata tagliata, salto alla prossima faccia.
|
|
if ( InterInterLineMap.find( nFacet) != InterInterLineMap.end())
|
|
continue ;
|
|
int nInOutPart = 0 ;
|
|
// Ciclo sui contatti edge-interno della faccia.
|
|
for ( const IntersEdge& Edge : vEdgeContact) {
|
|
// Estremi del segmento di contatto
|
|
Point3d ptSegSt = Edge.ptSt ;
|
|
Point3d ptSegEn = Edge.ptEn ;
|
|
Vector3d vtSegDir = ptSegEn - ptSegSt ;
|
|
double dLen = vtSegDir.Len() ;
|
|
if ( dLen < EPS_SMALL)
|
|
continue ;
|
|
vtSegDir /= dLen ;
|
|
// Cerco il tratto della frontiera della faccia su cui giace il segmento di contatto.
|
|
Vector3d vtLoopSeg ;
|
|
POLYLINEVECTOR vFacetLoop ;
|
|
GetFacetLoops( nFacet, vFacetLoop) ;
|
|
for ( int nL = 0 ; nL < int( vFacetLoop.size()) && nInOutPart == 0 ; ++ nL) {
|
|
Point3d ptLs, ptLe ;
|
|
bool bContinue = vFacetLoop[nL].GetFirstPoint( ptLs) && vFacetLoop[nL].GetNextPoint( ptLe) ;
|
|
while ( bContinue) {
|
|
DistPointLine StartPointLineDistCalc( ptLs, ptSegSt, ptSegEn, false) ;
|
|
double dDistStart ;
|
|
StartPointLineDistCalc.GetDist( dDistStart) ;
|
|
DistPointLine EndPointLineDistCalc( ptLe, ptSegSt, ptSegEn, false) ;
|
|
double dDistEnd ;
|
|
EndPointLineDistCalc.GetDist( dDistEnd) ;
|
|
double dUS = ( ptLs - ptSegSt) * vtSegDir ;
|
|
double dUE = ( ptLe - ptSegSt) * vtSegDir ;
|
|
// Segmento sovrapposto
|
|
if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) {
|
|
vtLoopSeg = ptLe - ptLs ;
|
|
vtLoopSeg.Normalize() ;
|
|
bContinue = false ;
|
|
}
|
|
else {
|
|
ptLs = ptLe ;
|
|
bContinue = vFacetLoop[nL].GetNextPoint( ptLe) ;
|
|
}
|
|
}
|
|
}
|
|
// Determino il valore dell'indice interno/esterno.
|
|
Vector3d vtIn = vtN ^ vtLoopSeg ;
|
|
// Ciclo sulle facce di contatto dell'altra superficie.
|
|
for ( int nOthFacet = 0 ; nOthFacet < int( Edge.vOthFacetIndex.size()) && nInOutPart == 0 ; ++ nOthFacet) {
|
|
int nOthFacetIndex = Edge.vOthFacetIndex[nOthFacet] ;
|
|
// Versore normale all'altra faccia.
|
|
Vector3d vtOthN = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex]].vtN ;
|
|
// Valore dell'indice interno/esterno.
|
|
nInOutPart = ( vtIn * vtOthN < - EPS_SMALL ? 1 : ( vtIn * vtOthN > EPS_SMALL ? - 1 : 0)) ;
|
|
}
|
|
// Ciclo sui triangoli della faccia
|
|
for ( int& nT : vFacetTria) {
|
|
// Assegno indice interno/esterno al triangolo
|
|
m_vTria[nT].nTempPart = nInOutPart ;
|
|
Triangle3d trTria ;
|
|
GetTriangle( nT, trTria) ;
|
|
trTria.Validate() ;
|
|
// Se un segmento del triangolo si sovrappone a quello di contatto, lo marco come invalicabile.
|
|
for ( int n = 0 ; n < 3 ; ++ n) {
|
|
Point3d ptTS = trTria.GetP( n) ;
|
|
Point3d ptTE = trTria.GetP( ( n + 1) % 3) ;
|
|
DistPointLine StartPointLineDistCalc( ptTS, ptSegSt, ptSegEn, false) ;
|
|
double dDistStart ;
|
|
StartPointLineDistCalc.GetDist( dDistStart) ;
|
|
DistPointLine EndPointLineDistCalc( ptTE, ptSegSt, ptSegEn, false) ;
|
|
double dDistEnd ;
|
|
EndPointLineDistCalc.GetDist( dDistEnd) ;
|
|
double dUS = ( ptTS - ptSegSt) * vtSegDir ;
|
|
double dUE = ( ptTE - ptSegSt) * vtSegDir ;
|
|
// Segmento sovrapposto
|
|
if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) {
|
|
m_vTria[nT].nETempFlag[n] = 1 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::EdgeEdgeContactManager( const SurfTriMesh& OthSurf,
|
|
const INTERSCHAINMAP& InterInterLineMap,
|
|
const INTERSEDGEMAP& EdgeEdgeLineMap)
|
|
{
|
|
// Ciclo su tutte le facce.
|
|
for ( auto it = EdgeEdgeLineMap.begin() ; it != EdgeEdgeLineMap.end() ; ++ it) {
|
|
int nFacet = it->first ;
|
|
const vector<IntersEdge>& vEdgeContact = it->second ;
|
|
// Triangoli della faccia
|
|
INTVECTOR vFacetTria ;
|
|
GetAllTriaInFacet( nFacet, vFacetTria) ;
|
|
// Versore normale alla faccia.
|
|
Vector3d vtN = m_vTria[m_vFacet[nFacet]].vtN ;
|
|
// Se la faccia � stata tagliata, salto alla prossima faccia.
|
|
if ( InterInterLineMap.find( nFacet) != InterInterLineMap.end())
|
|
continue ;
|
|
int nInOutPart = 0 ;
|
|
// Ciclo sui contatti edge-interno della faccia.
|
|
for ( const IntersEdge& Edge : vEdgeContact) {
|
|
// Estremi del segmento di contatto
|
|
Point3d ptSegSt = Edge.ptSt ;
|
|
Point3d ptSegEn = Edge.ptEn ;
|
|
Vector3d vtSegDir = ptSegEn - ptSegSt ;
|
|
double dLen = vtSegDir.Len() ;
|
|
if ( dLen < EPS_SMALL)
|
|
continue ;
|
|
vtSegDir /= dLen ;
|
|
// Cerco il tratto della frontiera della faccia su cui giace il segmento di contatto.
|
|
Vector3d vtLoopSeg ;
|
|
POLYLINEVECTOR vFacetLoop ;
|
|
GetFacetLoops( nFacet, vFacetLoop) ;
|
|
for ( int nL = 0 ; nL < int( vFacetLoop.size()) && nInOutPart == 0 ; ++ nL) {
|
|
Point3d ptLs, ptLe ;
|
|
bool bContinue = vFacetLoop[nL].GetFirstPoint( ptLs) && vFacetLoop[nL].GetNextPoint( ptLe) ;
|
|
while ( bContinue) {
|
|
DistPointLine StartPointLineDistCalc( ptLs, ptSegSt, ptSegEn, false) ;
|
|
double dDistStart ;
|
|
StartPointLineDistCalc.GetDist( dDistStart) ;
|
|
DistPointLine EndPointLineDistCalc( ptLe, ptSegSt, ptSegEn, false) ;
|
|
double dDistEnd ;
|
|
EndPointLineDistCalc.GetDist( dDistEnd) ;
|
|
double dUS = ( ptLs - ptSegSt) * vtSegDir ;
|
|
double dUE = ( ptLe - ptSegSt) * vtSegDir ;
|
|
// Segmento sovrapposto
|
|
if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) {
|
|
vtLoopSeg = ptLe - ptLs ;
|
|
vtLoopSeg.Normalize() ;
|
|
bContinue = false ;
|
|
}
|
|
else {
|
|
ptLs = ptLe ;
|
|
bContinue = vFacetLoop[nL].GetNextPoint( ptLe) ;
|
|
}
|
|
}
|
|
}
|
|
// Determino il valore dell'indice interno/esterno.
|
|
// Vettore diretto verso l'interno della faccia.
|
|
Vector3d vtIn = vtN ^ vtLoopSeg ;
|
|
// Ciclo sulle facce di contatto dell'altra superficie.
|
|
int nOthFacet1 ;
|
|
int nOthFacet2 = - 1 ;
|
|
for ( nOthFacet1 = 0 ; nOthFacet1 < int( Edge.vOthFacetIndex.size()) - 1 && nInOutPart == 0 ; ++ nOthFacet1) {
|
|
int nOthFacetIndex1 = Edge.vOthFacetIndex[nOthFacet1] ;
|
|
Vector3d vtOthN1 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex1]].vtN ;
|
|
for ( nOthFacet2 = nOthFacet1 + 1 ; nOthFacet2 < int( Edge.vOthFacetIndex.size()) && nInOutPart == 0 ; ++ nOthFacet2) {
|
|
int nOthFacetIndex2 = Edge.vOthFacetIndex[nOthFacet2] ;
|
|
Vector3d vtOthN2 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex2]].vtN ;
|
|
if ( ! AreSameVectorApprox( vtOthN1, vtOthN2)) {
|
|
break ;
|
|
}
|
|
}
|
|
if ( nOthFacet2 != int( Edge.vOthFacetIndex.size()))
|
|
break ;
|
|
}
|
|
// Se l'indice interno/esterno non � stato assegnato
|
|
if ( nInOutPart == 0) {
|
|
// Se non ho trovato una coppia di facce, uso la prima.
|
|
if ( ( nOthFacet1 == int( Edge.vOthFacetIndex.size()) - 1 && nOthFacet2 == int( Edge.vOthFacetIndex.size())) || nOthFacet2 == - 1) {
|
|
;
|
|
int nOthFacetIndex1 = Edge.vOthFacetIndex[0] ;
|
|
Vector3d vtOthN1 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex1]].vtN ;
|
|
// Valore dell'indice interno/esterno.
|
|
nInOutPart = ( vtIn * vtOthN1 < - EPS_SMALL ? 1 : ( vtIn * vtOthN1 > EPS_SMALL ? - 1 : 0)) ;
|
|
}
|
|
// Due facce
|
|
else {
|
|
int nOthFacetIndex1 = Edge.vOthFacetIndex[nOthFacet1] ;
|
|
Vector3d vtOthN1 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex1]].vtN ;
|
|
int nOthFacetIndex2 = Edge.vOthFacetIndex[nOthFacet2] ;
|
|
Vector3d vtOthN2 = OthSurf.m_vTria[OthSurf.m_vFacet[nOthFacetIndex2]].vtN ;
|
|
POLYLINEVECTOR vOthFacetLoop2 ;
|
|
OthSurf.GetFacetLoops( nOthFacetIndex2, vOthFacetLoop2) ;
|
|
Vector3d vtContactEdgeLoop2 ;
|
|
Point3d ptLs, ptLe ;
|
|
bool bContinue = true ;
|
|
for ( int nL = 0 ; nL < int( vOthFacetLoop2.size()) && bContinue ; ++ nL) {
|
|
bContinue = vOthFacetLoop2[nL].GetFirstPoint( ptLs) && vOthFacetLoop2[nL].GetNextPoint( ptLe) ;
|
|
while ( bContinue) {
|
|
DistPointLine StartPointLineDistCalc( ptLs, ptSegSt, ptSegEn, false) ;
|
|
double dDistStart ;
|
|
StartPointLineDistCalc.GetDist( dDistStart) ;
|
|
DistPointLine EndPointLineDistCalc( ptLe, ptSegSt, ptSegEn, false) ;
|
|
double dDistEnd ;
|
|
EndPointLineDistCalc.GetDist( dDistEnd) ;
|
|
double dUS = ( ptLs - ptSegSt) * vtSegDir ;
|
|
double dUE = ( ptLe - ptSegSt) * vtSegDir ;
|
|
// Segmento sovrapposto
|
|
if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) {
|
|
vtContactEdgeLoop2 = ptLe - ptLs ;
|
|
vtContactEdgeLoop2.Normalize() ;
|
|
bContinue = false ;
|
|
}
|
|
else {
|
|
ptLs = ptLe ;
|
|
bContinue = vOthFacetLoop2[nL].GetNextPoint( ptLe) ;
|
|
}
|
|
}
|
|
}
|
|
Vector3d vtInFacet2 = vtN ^ vtContactEdgeLoop2 ;
|
|
// Convesso
|
|
if ( vtInFacet2 * vtOthN1 < 0.) {
|
|
nInOutPart = vtIn * vtOthN1 < 0 && vtIn * vtOthN2 < 0 ? 1 : - 1 ;
|
|
}
|
|
// Concavo
|
|
else {
|
|
nInOutPart = vtIn * vtOthN1 > 0 && vtIn * vtOthN2 > 0 ? - 1 : 1 ;
|
|
}
|
|
}
|
|
}
|
|
// Ciclo sui triangoli della faccia
|
|
for ( int& nT : vFacetTria) {
|
|
// Assegno indice interno/esterno al triangolo
|
|
m_vTria[nT].nTempPart = nInOutPart ;
|
|
Triangle3d trTria ;
|
|
GetTriangle( nT, trTria) ;
|
|
trTria.Validate() ;
|
|
// Se un segmento del triangolo si sovrappone a quello di contatto, lo marco come invalicabile.
|
|
for ( int n = 0 ; n < 3 ; ++ n) {
|
|
Point3d ptTS = trTria.GetP( n) ;
|
|
Point3d ptTE = trTria.GetP( ( n + 1) % 3) ;
|
|
DistPointLine StartPointLineDistCalc( ptTS, ptSegSt, ptSegEn, false) ;
|
|
double dDistStart ;
|
|
StartPointLineDistCalc.GetDist( dDistStart) ;
|
|
DistPointLine EndPointLineDistCalc( ptTE, ptSegSt, ptSegEn, false) ;
|
|
double dDistEnd ;
|
|
EndPointLineDistCalc.GetDist( dDistEnd) ;
|
|
double dUS = ( ptTS - ptSegSt) * vtSegDir ;
|
|
double dUE = ( ptTE - ptSegSt) * vtSegDir ;
|
|
// Segmento sovrapposto
|
|
if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen + EPS_SMALL && dUE > - EPS_SMALL) {
|
|
m_vTria[nT].nETempFlag[n] = 1 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
RegularizeRectangleSurf( SurfTriMesh& Surf)
|
|
{
|
|
// Se la superficie non � un quadrilatero, non procedo.
|
|
int nNumVert = Surf.GetVertexCount() ;
|
|
if ( nNumVert != 4 || Surf.GetFacetCount() != 1)
|
|
return true ;
|
|
// Recupero il contorno.
|
|
POLYLINEVECTOR ContourVec ;
|
|
Surf.GetFacetLoops( 0, ContourVec) ;
|
|
// Recupero i vertici.
|
|
Point3d ptV[4] ;
|
|
int nIndex = 0 ;
|
|
bool bContinue = ContourVec[0].GetFirstPoint( ptV[nIndex]) ;
|
|
while ( bContinue) {
|
|
++ nIndex ;
|
|
bContinue = nIndex < 4 && ContourVec[0].GetNextPoint( ptV[nIndex]) ;
|
|
}
|
|
// Se la superficie non � un rettangolo lungo, non procedo.
|
|
Vector3d vtV[2] ;
|
|
vtV[0] = ptV[1] - ptV[0] ;
|
|
vtV[1] = ptV[2] - ptV[1] ;
|
|
double dLen[2] = { vtV[0].Len(), vtV[1].Len() } ;
|
|
int nMin = dLen[0] < dLen[1] ? 0 : 1 ;
|
|
if ( abs( vtV[0] * vtV[1]) > EPS_SMALL || dLen[nMin] / dLen[( nMin + 1) % 2] > 0.25)
|
|
return true ;
|
|
// Ridefinisco il contrno del rettangolo.
|
|
Point3d ptNewV[12] ;
|
|
int nVV = 0 ;
|
|
for ( int nV = 0 ; nV < 4 ; ++ nV) {
|
|
ptNewV[nVV] = ptV[nV] ;
|
|
if ( nV != nMin && nV != ( nMin + 2) % 4) {
|
|
++ nVV ;
|
|
ptNewV[nVV] = ( 4 * ptV[nV] + ptV[( nV + 1) % 4]) / 5 ;
|
|
++ nVV ;
|
|
ptNewV[nVV] = ( 3 * ptV[nV] + 2 * ptV[( nV + 1) % 4]) / 5 ;
|
|
++ nVV ;
|
|
ptNewV[nVV] = ( 2 * ptV[nV] + 3 * ptV[( nV + 1) % 4]) / 5 ;
|
|
++ nVV ;
|
|
ptNewV[nVV] = ( ptV[nV] + 4 * ptV[( nV + 1) % 4]) / 5 ;
|
|
}
|
|
++ nVV ;
|
|
}
|
|
// Ridefinisco la superficie.
|
|
SurfTriMesh NewSurf ;
|
|
NewSurf.CopyFrom( &Surf) ;
|
|
NewSurf.Clear() ;
|
|
if ( nMin == 0) {
|
|
int nNewId[3] ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[0]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[1]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[2]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[0]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[2]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[11]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[11]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[2]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[3]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[11]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[3]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[10]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[10]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[3]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[4]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[10]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[4]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[9]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[9]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[4]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[5]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[9]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[5]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[8]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[8]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[5]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[6]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[8]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[6]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[7]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
}
|
|
else {
|
|
int nNewId[3] ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[0]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[1]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[10]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[0]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[10]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[11]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[1]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[2]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[9]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[1]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[9]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[10]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[2]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[3]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[8]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[2]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[8]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[9]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[3]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[4]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[7]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[3]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[7]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[8]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[4]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[5]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[6]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
nNewId[0] = NewSurf.AddVertex( ptNewV[4]) ;
|
|
nNewId[1] = NewSurf.AddVertex( ptNewV[6]) ;
|
|
nNewId[2] = NewSurf.AddVertex( ptNewV[7]) ;
|
|
if ( ! IsValidSvt( NewSurf.AddTriangle( nNewId)))
|
|
return false ;
|
|
}
|
|
|
|
if ( NewSurf.AdjustTopology() && NewSurf.DoCompacting()) {
|
|
Surf.CopyFrom( &NewSurf) ;
|
|
return true ;
|
|
}
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SplitPolyLineContour( const POLYLINEVECTOR& vContourVec, POLYLINEVECTOR& vContourVec1, POLYLINEVECTOR& vContourVec2)
|
|
{
|
|
// Se il contorno � vuoto, non procedo
|
|
if ( int( vContourVec.size()) == 0)
|
|
return false ;
|
|
// Se la complessit� non � eccessiva, non procedo.
|
|
int nPointsNum = vContourVec[0].GetPointNbr() ;
|
|
if ( nPointsNum < 4)
|
|
return false ;
|
|
for ( int n = 1 ; n < int( vContourVec.size()) ; ++ n)
|
|
nPointsNum += vContourVec[n].GetPointNbr() ;
|
|
if ( nPointsNum < 20)
|
|
return false ;
|
|
// Creo la regione compresa dai contorni.
|
|
PtrOwner<SurfFlatRegion> pReg( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vContourVec))) ;
|
|
if ( pReg == nullptr)
|
|
return false ;
|
|
SurfFlatRegion Region = *pReg ;
|
|
// Copio i punti in un vettore.
|
|
PNTVECTOR vPointsVec ;
|
|
vPointsVec.reserve( vContourVec[0].GetPointNbr()) ;
|
|
POLYLINEVECTOR& MyPolyVecRef = const_cast<POLYLINEVECTOR&> (vContourVec);
|
|
const PNTULIST& ContourList = MyPolyVecRef[0].GetUPointList() ;
|
|
for ( auto it = ContourList.begin() ; it != ContourList.end() ; ++ it)
|
|
vPointsVec.emplace_back( it->first) ;
|
|
// Cerco una coppia di punti che divide bene il contorno esterno.
|
|
int nSplitI = - 1 ; int nSplitJ = - 1 ;
|
|
int nNumPoints = int( vPointsVec.size()) ;
|
|
for ( int nPI = 0 ; nPI < nNumPoints ; ++ nPI) {
|
|
for ( int nPJ = nPI + 1 ; nPJ < nNumPoints - 1 ; ++ nPJ) {
|
|
CurveLine cvLineSeg ;
|
|
cvLineSeg.Set( vPointsVec[nPI], vPointsVec[nPJ]) ;
|
|
CRVCVECTOR vLinePartVec ;
|
|
if ( Region.GetCurveClassification( cvLineSeg, vLinePartVec) &&
|
|
int( vLinePartVec.size()) == 1 &&
|
|
vLinePartVec[0].nClass == CRVC_IN) {
|
|
nSplitI = nPI ;
|
|
nSplitJ = nPJ ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( nSplitI != - 1 && nSplitJ != - 1)
|
|
break ;
|
|
}
|
|
// Se non ho trovato una divisione valida, termino.
|
|
if ( nSplitI == - 1 || nSplitJ == - 1)
|
|
return false ;
|
|
// Copio il contorno esterno nella in una PolyLine ausiliaria.
|
|
PolyLine AuxPoly ;
|
|
for ( int nP = 0 ; nP < nNumPoints ; ++ nP)
|
|
AuxPoly.AddUPoint( 0, vPointsVec[nP]) ;
|
|
// Cambio origine al contorno e lo divido.
|
|
vContourVec1.emplace_back() ; vContourVec2.emplace_back() ;
|
|
if ( AuxPoly.ChangePolyLineStart( vPointsVec[nSplitI], 9 * EPS_SMALL) &&
|
|
AuxPoly.SplitPolyLineAtPoint( vPointsVec[nSplitJ], vContourVec1[0], vContourVec2[0], 9 * EPS_SMALL)) {
|
|
// Chiudo i contorni.
|
|
vContourVec1[0].AddUPoint( 0, vPointsVec[nSplitI]) ;
|
|
vContourVec2[0].AddUPoint( 0, vPointsVec[nSplitJ]) ;
|
|
// Aggiungo i contorni interni.
|
|
for ( int nC = 1 ; nC < int( vContourVec.size()) ; ++ nC) {
|
|
const PNTULIST& InnContourList = MyPolyVecRef[nC].GetUPointList() ;
|
|
for ( auto it = InnContourList.begin() ; it != InnContourList.end() ; ++ it) {
|
|
if ( vContourVec1[0].GetPointNbr() < vContourVec2[0].GetPointNbr()) {
|
|
if ( vContourVec1[0].IsPointInsidePolyLine( it->first)) {
|
|
vContourVec1.emplace_back( vContourVec[nC]) ;
|
|
break ;
|
|
}
|
|
else {
|
|
vContourVec2.emplace_back( vContourVec[nC]) ;
|
|
break ;
|
|
}
|
|
}
|
|
else {
|
|
if ( vContourVec2[0].IsPointInsidePolyLine( it->first)) {
|
|
vContourVec2.emplace_back( vContourVec[nC]) ;
|
|
break ;
|
|
}
|
|
else {
|
|
vContourVec1.emplace_back( vContourVec[nC]) ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
// Pulisco le nuove PolyLine.
|
|
vContourVec1.clear() ; vContourVec2.clear() ;
|
|
return false ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::RetriangulateFacetPieces( const PieceMap& NewFacet,
|
|
const INTERSEDGEMAP& EdgeInterLineMap,
|
|
const INTERSEDGEMAP& EdgeEdgeLineMap)
|
|
{
|
|
// Vettore degli indici delle facce
|
|
INTVECTOR vFacetIndexes ;
|
|
// Ciclo sulle facce.
|
|
for ( auto it = NewFacet.begin() ; it != NewFacet.end() ; ++ it) {
|
|
// Accedo al colore di un triangolo della faccia e cancello i triangoli della faccia.
|
|
INTVECTOR vFacetTria ;
|
|
GetAllTriaInFacet( it->first, vFacetTria) ;
|
|
for ( int& nT : vFacetTria)
|
|
RemoveTriangle( nT) ;
|
|
}
|
|
for ( auto it = NewFacet.begin() ; it != NewFacet.end() ; ++ it) {
|
|
const vector<FacetPiece>& PiecesVector = it->second ;
|
|
// Ciclo sui nuovi pezzi di faccia.
|
|
int nPartNum = int( PiecesVector.size()) ;
|
|
for ( int nPart = 0 ; nPart < nPartNum ; ++ nPart) {
|
|
PNTVECTOR vPt ;
|
|
INTVECTOR vTr ;
|
|
if ( Triangulate().Make( PiecesVector[nPart].vPieceLoop, vPt, vTr, TrgType::TRG_STANDARD)) {
|
|
// 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[it->first]].nTFlag) ;
|
|
if ( IsValidSvt( nNewTriaNum)) {
|
|
// Assegno l'indice della parte interno/esterno.
|
|
m_vTria[nNewTriaNum].nTempPart = PiecesVector[nPart].nPiecePart ;
|
|
// Indici parte interno/esterno invalicabili
|
|
m_vTria[nNewTriaNum].nETempFlag[0] = 0 ;
|
|
m_vTria[nNewTriaNum].nETempFlag[1] = 0 ;
|
|
m_vTria[nNewTriaNum].nETempFlag[2] = 0 ;
|
|
// Se la faccia ha avuto un contatto edge-interior, cerco edge invalicabili.
|
|
auto itEdgeInterEdge = EdgeInterLineMap.find( it->first) ;
|
|
auto itEdgeEdgeEdge = EdgeEdgeLineMap.find( it->first) ;
|
|
if ( itEdgeInterEdge != EdgeInterLineMap.end()) {
|
|
const vector<IntersEdge>& vEdgeContact = itEdgeInterEdge->second ;
|
|
Triangle3d trTria ;
|
|
GetTriangle( nNewTriaNum, trTria) ;
|
|
// Ciclo sui segmenti del triangolo.
|
|
for ( int n = 0 ; n < 3 ; ++ n) {
|
|
Point3d ptTS = trTria.GetP( n) ;
|
|
Point3d ptTE = trTria.GetP( ( n + 1) % 3) ;
|
|
for (int m = 0; m < int(vEdgeContact.size()) ; ++ m) {
|
|
Point3d ptEdgeSt = vEdgeContact[m].ptSt ;
|
|
Point3d ptEdgeEn = vEdgeContact[m].ptEn ;
|
|
Vector3d vtEdgeDir = ptEdgeEn - ptEdgeSt ;
|
|
double dLen = vtEdgeDir.Len() ;
|
|
if ( dLen < EPS_SMALL)
|
|
continue ;
|
|
DistPointLine StartPointLineDistCalc( ptTS, ptEdgeSt, ptEdgeEn, false) ;
|
|
double dDistStart ;
|
|
StartPointLineDistCalc.GetDist( dDistStart) ;
|
|
DistPointLine EndPointLineDistCalc( ptTE, ptEdgeSt, ptEdgeEn, false) ;
|
|
double dDistEnd ;
|
|
EndPointLineDistCalc.GetDist( dDistEnd) ;
|
|
double dUS = ( ptTS - ptEdgeSt) * vtEdgeDir ;
|
|
double dUE = ( ptTE - ptEdgeSt) * vtEdgeDir ;
|
|
// Segmento sovrapposto
|
|
if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen && dUE > 0) {
|
|
m_vTria[nNewTriaNum].nETempFlag[n] = 1 ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( itEdgeEdgeEdge != EdgeEdgeLineMap.end()) {
|
|
const vector<IntersEdge>& vEdgeContact = itEdgeEdgeEdge->second ;
|
|
Triangle3d trTria ;
|
|
GetTriangle( nNewTriaNum, trTria) ;
|
|
// Ciclo sui segmenti del triangolo.
|
|
for ( int n = 0 ; n < 3 ; ++ n) {
|
|
Point3d ptTS = trTria.GetP( n) ;
|
|
Point3d ptTE = trTria.GetP( ( n + 1) % 3) ;
|
|
for (int m = 0; m < int(vEdgeContact.size()) ; ++ m) {
|
|
Point3d ptEdgeSt = vEdgeContact[m].ptSt ;
|
|
Point3d ptEdgeEn = vEdgeContact[m].ptEn ;
|
|
Vector3d vtEdgeDir = ptEdgeEn - ptEdgeSt ;
|
|
double dLen = vtEdgeDir.Len() ;
|
|
if ( dLen < EPS_SMALL)
|
|
continue ;
|
|
DistPointLine StartPointLineDistCalc( ptTS, ptEdgeSt, ptEdgeEn, false) ;
|
|
double dDistStart ;
|
|
StartPointLineDistCalc.GetDist( dDistStart) ;
|
|
DistPointLine EndPointLineDistCalc( ptTE, ptEdgeSt, ptEdgeEn, false) ;
|
|
double dDistEnd ;
|
|
EndPointLineDistCalc.GetDist( dDistEnd) ;
|
|
double dUS = ( ptTS - ptEdgeSt) * vtEdgeDir ;
|
|
double dUE = ( ptTE - ptEdgeSt) * vtEdgeDir ;
|
|
// Segmento sovrapposto
|
|
if ( dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen && dUE > 0) {
|
|
m_vTria[nNewTriaNum].nETempFlag[n] = 1 ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
vector<POLYLINEVECTOR> vSubPieceLoop ;
|
|
vSubPieceLoop.emplace_back() ;
|
|
vSubPieceLoop.emplace_back() ;
|
|
bool bContinue = SplitPolyLineContour( PiecesVector[nPart].vPieceLoop, vSubPieceLoop[0], vSubPieceLoop[1]) ;
|
|
while ( bContinue) {
|
|
for ( int nSub = 0 ; nSub < int( vSubPieceLoop.size()) ; ++ nSub) {
|
|
if (Triangulate().Make(vSubPieceLoop[nSub], vPt, vTr, TrgType::TRG_STANDARD)) {
|
|
// 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[it->first]].nTFlag);
|
|
if (IsValidSvt(nNewTriaNum)) {
|
|
// Assegno l'indice della parte interno/esterno.
|
|
m_vTria[nNewTriaNum].nTempPart = PiecesVector[nPart].nPiecePart;
|
|
// Indici parte interno/esterno invalicabili
|
|
m_vTria[nNewTriaNum].nETempFlag[0] = 0;
|
|
m_vTria[nNewTriaNum].nETempFlag[1] = 0;
|
|
m_vTria[nNewTriaNum].nETempFlag[2] = 0;
|
|
// Se la faccia ha avuto un contatto edge-interior, cerco edge invalicabili.
|
|
auto itEdgeInterEdge = EdgeInterLineMap.find(it->first);
|
|
auto itEdgeEdgeEdge = EdgeEdgeLineMap.find(it->first);
|
|
if (itEdgeInterEdge != EdgeInterLineMap.end()) {
|
|
const vector<IntersEdge>& vEdgeContact = itEdgeInterEdge->second;
|
|
Triangle3d trTria;
|
|
GetTriangle(nNewTriaNum, trTria);
|
|
// Ciclo sui segmenti del triangolo.
|
|
for (int n = 0; n < 3; ++n) {
|
|
Point3d ptTS = trTria.GetP(n);
|
|
Point3d ptTE = trTria.GetP((n + 1) % 3);
|
|
for (int m = 0; m < int(vEdgeContact.size()); ++m) {
|
|
Point3d ptEdgeSt = vEdgeContact[m].ptSt;
|
|
Point3d ptEdgeEn = vEdgeContact[m].ptEn;
|
|
Vector3d vtEdgeDir = ptEdgeEn - ptEdgeSt;
|
|
double dLen = vtEdgeDir.Len();
|
|
if (dLen < EPS_SMALL)
|
|
continue;
|
|
DistPointLine StartPointLineDistCalc(ptTS, ptEdgeSt, ptEdgeEn, false);
|
|
double dDistStart;
|
|
StartPointLineDistCalc.GetDist(dDistStart);
|
|
DistPointLine EndPointLineDistCalc(ptTE, ptEdgeSt, ptEdgeEn, false);
|
|
double dDistEnd;
|
|
EndPointLineDistCalc.GetDist(dDistEnd);
|
|
double dUS = (ptTS - ptEdgeSt) * vtEdgeDir;
|
|
double dUE = (ptTE - ptEdgeSt) * vtEdgeDir;
|
|
// Segmento sovrapposto
|
|
if (dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen && dUE > 0) {
|
|
m_vTria[nNewTriaNum].nETempFlag[n] = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (itEdgeEdgeEdge != EdgeEdgeLineMap.end()) {
|
|
const vector<IntersEdge>& vEdgeContact = itEdgeEdgeEdge->second;
|
|
Triangle3d trTria;
|
|
GetTriangle(nNewTriaNum, trTria);
|
|
// Ciclo sui segmenti del triangolo.
|
|
for (int n = 0; n < 3; ++n) {
|
|
Point3d ptTS = trTria.GetP(n);
|
|
Point3d ptTE = trTria.GetP((n + 1) % 3);
|
|
for (int m = 0; m < int(vEdgeContact.size()); ++m) {
|
|
Point3d ptEdgeSt = vEdgeContact[m].ptSt;
|
|
Point3d ptEdgeEn = vEdgeContact[m].ptEn;
|
|
Vector3d vtEdgeDir = ptEdgeEn - ptEdgeSt;
|
|
double dLen = vtEdgeDir.Len();
|
|
if (dLen < EPS_SMALL)
|
|
continue;
|
|
DistPointLine StartPointLineDistCalc(ptTS, ptEdgeSt, ptEdgeEn, false);
|
|
double dDistStart;
|
|
StartPointLineDistCalc.GetDist(dDistStart);
|
|
DistPointLine EndPointLineDistCalc(ptTE, ptEdgeSt, ptEdgeEn, false);
|
|
double dDistEnd;
|
|
EndPointLineDistCalc.GetDist(dDistEnd);
|
|
double dUS = (ptTS - ptEdgeSt) * vtEdgeDir;
|
|
double dUE = (ptTE - ptEdgeSt) * vtEdgeDir;
|
|
// Segmento sovrapposto
|
|
if (dDistStart < EPS_SMALL && dDistEnd < EPS_SMALL && dUS < dLen && dUE > 0) {
|
|
m_vTria[nNewTriaNum].nETempFlag[n] = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vSubPieceLoop.erase(vSubPieceLoop.begin() + nSub);
|
|
--nSub;
|
|
bContinue = int(vSubPieceLoop.size()) > 0;
|
|
}
|
|
else if (int(vSubPieceLoop[nSub].size()) == 0) {
|
|
vSubPieceLoop.erase(vSubPieceLoop.begin() + nSub) ;
|
|
-- nSub ;
|
|
}
|
|
else {
|
|
vSubPieceLoop.emplace_back() ;
|
|
vSubPieceLoop.emplace_back() ;
|
|
int nPrevToLast = int( vSubPieceLoop.size()) - 2 ;
|
|
int nLast = int( vSubPieceLoop.size()) - 1 ;
|
|
SplitPolyLineContour(vSubPieceLoop[nSub], vSubPieceLoop[nPrevToLast], vSubPieceLoop[nLast]);
|
|
vSubPieceLoop.erase( vSubPieceLoop.begin() + nSub) ;
|
|
-- nSub ;
|
|
}
|
|
}
|
|
bContinue = int( vSubPieceLoop.size()) > 0 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::IntersectTriMeshFacets( SurfTriMesh& Other)
|
|
{ ////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
static int nTime = 0;
|
|
nTime++;
|
|
if (nTime == 4)
|
|
nTime = 0;
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
SurfTriMesh& SurfB = Other ;
|
|
RegularizeRectangleSurf( SurfB) ;
|
|
// Le superfici devono essere valide
|
|
if ( m_nStatus != OK || ! SurfB.IsValid())
|
|
return false ;
|
|
// Unordered map dei segmenti di intersezione (contatti interno-interno) e dei contatti con edge
|
|
INTERSCHAINMAP IntersLineMapA, IntersLineMapB ;
|
|
INTERSEDGEMAP EdgeInnLineMapA, EdgeInnLineMapB ;
|
|
INTERSEDGEMAP EdgeEdgeLineMapA, EdgeEdgeLineMapB ;
|
|
// Setto il triangolo come n� fuori n� dentro
|
|
int nTriaNumA = GetTriangleSize();
|
|
int nTriaNumB = SurfB.GetTriangleSize();
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
m_vTria[nTA].nTempPart = 0 ;
|
|
m_vTria[nTA].nETempFlag[0] = 0 ;
|
|
m_vTria[nTA].nETempFlag[1] = 0 ;
|
|
m_vTria[nTA].nETempFlag[2] = 0 ;
|
|
}
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
SurfB.m_vTria[nTB].nTempPart = 0 ;
|
|
SurfB.m_vTria[nTB].nETempFlag[0] = 0 ;
|
|
SurfB.m_vTria[nTB].nETempFlag[1] = 0 ;
|
|
SurfB.m_vTria[nTB].nETempFlag[2] = 0 ;
|
|
}
|
|
// Ciclo sulle facce delle mesh
|
|
int nFacetNumA = GetFacetCount() ;
|
|
for ( int nFA = 0 ; nFA < nFacetNumA ; ++ nFA) {
|
|
// Dati della faccia
|
|
POLYLINEVECTOR LoopVecA ;
|
|
GetFacetLoops( nFA, LoopVecA) ;
|
|
PtrOwner<SurfFlatRegion> pRegA( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( LoopVecA))) ;
|
|
if ( pRegA == nullptr)
|
|
return false ;
|
|
SurfFlatRegion RegionA = *pRegA ;
|
|
// Recupero tutti i triangoli della superficie B che cadono nel box della faccia di A.
|
|
BBox3d b3BoxA ;
|
|
RegionA.GetLocalBBox( b3BoxA) ;
|
|
INTVECTOR vNearTria ;
|
|
SurfB.GetAllTriaOverlapBox( b3BoxA, vNearTria) ;
|
|
// Determino le facce a cui appartengono i triangoli che cadono nel box
|
|
INTVECTOR vFacetIndexesB ;
|
|
for ( int& nT : vNearTria) {
|
|
int nF = SurfB.GetFacetFromTria(nT) ;
|
|
int n ;
|
|
for ( n = 0 ; n < int( vFacetIndexesB.size()) ; ++ n) {
|
|
if ( nF == vFacetIndexesB[n])
|
|
break ;
|
|
}
|
|
if ( n == int(vFacetIndexesB.size()))
|
|
vFacetIndexesB.emplace_back( nF) ;
|
|
}
|
|
for ( int& nFB : vFacetIndexesB) {
|
|
// Dati della faccia
|
|
POLYLINEVECTOR LoopVecB ;
|
|
SurfB.GetFacetLoops( nFB, LoopVecB) ;
|
|
PtrOwner<SurfFlatRegion> pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( LoopVecB))) ;
|
|
if ( pRegB == nullptr)
|
|
return false ;
|
|
SurfFlatRegion RegionB = *pRegB ;
|
|
// Interseco le due facce
|
|
LineFacetClassVector CommonIntersection ;
|
|
// Intersezione fra le facce
|
|
if ( IntersFacetFacet( RegionA, LoopVecA[0], RegionB, LoopVecB[0], CommonIntersection)) {
|
|
// Ciclo sulle parti dell'intersezione
|
|
for ( int nPart = 0 ; nPart < int( CommonIntersection.size()) ; ++ nPart) {
|
|
// Intersezione nell'interno di entrambe le facce
|
|
if ( CommonIntersection[nPart].nTypeA == CRVC_IN &&
|
|
CommonIntersection[nPart].nTypeB == CRVC_IN) {
|
|
// Salvo intersezione per la faccia A
|
|
auto itA = IntersLineMapA.find( nFA) ;
|
|
if ( itA != IntersLineMapA.end()) {
|
|
itA->second.emplace_back( IntersInnSeg( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn)) ;
|
|
}
|
|
else {
|
|
IntersLineMapA.emplace( nFA, IntersInnChain( 1, IntersInnSeg( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn))) ;
|
|
}
|
|
// Salvo intersezione per la faccia B
|
|
auto itB = IntersLineMapB.find( nFB) ;
|
|
if ( itB != IntersLineMapB.end()) {
|
|
itB->second.emplace_back( IntersInnSeg( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt)) ;
|
|
}
|
|
else {
|
|
IntersLineMapB.emplace( nFB, IntersInnChain( 1, IntersInnSeg( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt))) ;
|
|
}
|
|
}
|
|
// Intersezione all'interno della faccia A
|
|
else if ( CommonIntersection[nPart].nTypeA == CRVC_IN) {
|
|
// Salvo intersezione per la faccia A
|
|
auto itA = IntersLineMapA.find( nFA) ;
|
|
if ( itA != IntersLineMapA.end()) {
|
|
itA->second.emplace_back( IntersInnSeg( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn)) ;
|
|
}
|
|
else {
|
|
IntersLineMapA.emplace( nFA, IntersInnChain( 1, IntersInnSeg( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn))) ;
|
|
}
|
|
// Salvo intersezione per la faccia B
|
|
auto itB = EdgeInnLineMapB.find( nFB) ;
|
|
if ( itB != EdgeInnLineMapB.end()) {
|
|
int nE ;
|
|
for ( nE = 0 ; nE < int( itB->second.size()) ; ++ nE) {
|
|
if ( AreSamePointExact( itB->second[nE].ptSt, CommonIntersection[nPart].ptEn) &&
|
|
AreSamePointExact( itB->second[nE].ptEn, CommonIntersection[nPart].ptSt)) {
|
|
itB->second[nE].vOthFacetIndex.emplace_back( nFA) ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( nE == int( itB->second.size())) {
|
|
itB->second.emplace_back( IntersEdge( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt, INTVECTOR( 1, nFA))) ;
|
|
}
|
|
}
|
|
else {
|
|
EdgeInnLineMapB.emplace( nFB, IntersEdgeVec( 1, IntersEdge( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt,
|
|
INTVECTOR( 1, nFA)))) ;
|
|
}
|
|
}
|
|
// Intersezione all'interno della faccia B
|
|
else if ( CommonIntersection[nPart].nTypeB == CRVC_IN) {
|
|
// Salvo intersezione per la faccia A
|
|
auto itA = EdgeInnLineMapA.find( nFA) ;
|
|
if ( itA != EdgeInnLineMapA.end()) {
|
|
int nE ;
|
|
for ( nE = 0 ; nE < int( itA->second.size()) ; ++ nE) {
|
|
if ( AreSamePointExact( itA->second[nE].ptSt, CommonIntersection[nPart].ptSt) &&
|
|
AreSamePointExact( itA->second[nE].ptEn, CommonIntersection[nPart].ptEn)) {
|
|
itA->second[nE].vOthFacetIndex.emplace_back( nFB) ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( nE == int( itA->second.size())) {
|
|
itA->second.emplace_back( IntersEdge( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn, INTVECTOR( 1, nFB))) ;
|
|
}
|
|
}
|
|
else {
|
|
EdgeInnLineMapA.emplace( nFA, IntersEdgeVec( 1, IntersEdge( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn,
|
|
INTVECTOR( 1, nFB)))) ;
|
|
}
|
|
// Salvo intersezione per la faccia B
|
|
auto itB = IntersLineMapB.find( nFB) ;
|
|
if ( itB != IntersLineMapB.end()) {
|
|
itB->second.emplace_back( IntersInnSeg( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt)) ;
|
|
}
|
|
else {
|
|
IntersLineMapB.emplace( nFB, IntersInnChain( 1, IntersInnSeg( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt))) ;
|
|
}
|
|
}
|
|
// Intersezione sulla frontiera di entrambe le facce
|
|
else {
|
|
// Salvo intersezione per la faccia A
|
|
auto itA = EdgeEdgeLineMapA.find( nFA) ;
|
|
if ( itA != EdgeEdgeLineMapA.end()) {
|
|
int nE ;
|
|
for ( nE = 0 ; nE < int( itA->second.size()) ; ++ nE) {
|
|
if ( ( AreSamePointExact( itA->second[nE].ptSt, CommonIntersection[nPart].ptSt) &&
|
|
AreSamePointExact( itA->second[nE].ptEn, CommonIntersection[nPart].ptEn)) ||
|
|
( AreSamePointExact( itA->second[nE].ptSt, CommonIntersection[nPart].ptEn) &&
|
|
AreSamePointExact( itA->second[nE].ptEn, CommonIntersection[nPart].ptSt))) {
|
|
itA->second[nE].vOthFacetIndex.emplace_back( nFB) ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( nE == int( itA->second.size())) {
|
|
itA->second.emplace_back( IntersEdge( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn, INTVECTOR( 1, nFB)));
|
|
}
|
|
}
|
|
else {
|
|
EdgeEdgeLineMapA.emplace( nFA, IntersEdgeVec( 1, IntersEdge( CommonIntersection[nPart].ptSt, CommonIntersection[nPart].ptEn,
|
|
INTVECTOR( 1, nFB)))) ;
|
|
}
|
|
// Salvo intersezione per la faccia B
|
|
auto itB = EdgeEdgeLineMapB.find( nFB) ;
|
|
if ( itB != EdgeEdgeLineMapB.end()) {
|
|
int nE ;
|
|
for ( nE = 0 ; nE < int( itB->second.size()) ; ++ nE) {
|
|
if ( ( AreSamePointExact( itB->second[nE].ptSt, CommonIntersection[nPart].ptEn) &&
|
|
AreSamePointExact( itB->second[nE].ptEn, CommonIntersection[nPart].ptSt)) ||
|
|
( AreSamePointExact( itB->second[nE].ptSt, CommonIntersection[nPart].ptSt) &&
|
|
AreSamePointExact( itB->second[nE].ptEn, CommonIntersection[nPart].ptEn))) {
|
|
itB->second[nE].vOthFacetIndex.emplace_back( nFA) ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( nE == int( itB->second.size())) {
|
|
itB->second.emplace_back( IntersEdge( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt, INTVECTOR( 1, nFA))) ;
|
|
}
|
|
}
|
|
else {
|
|
EdgeEdgeLineMapB.emplace( nFB, IntersEdgeVec( 1, IntersEdge( CommonIntersection[nPart].ptEn, CommonIntersection[nPart].ptSt,
|
|
INTVECTOR( 1, nFA)))) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Divido le facce
|
|
PieceMap NewFacetA, NewFacetB ;
|
|
SplitFacet( IntersLineMapA, NewFacetA) ;
|
|
SurfB.SplitFacet( IntersLineMapB, NewFacetB) ;
|
|
|
|
// Facce EdgeInn
|
|
EdgeInteriorContactManager( SurfB, IntersLineMapA, EdgeInnLineMapA) ;
|
|
SurfB.EdgeInteriorContactManager( *this, IntersLineMapB, EdgeInnLineMapB) ;
|
|
|
|
// Facce Edge Edge
|
|
EdgeEdgeContactManager( SurfB, IntersLineMapA, EdgeEdgeLineMapA) ;
|
|
SurfB.EdgeEdgeContactManager( *this, IntersLineMapB, EdgeEdgeLineMapB) ;
|
|
|
|
// Se non ci sono stati tagli, valuto se una � tutta interna all'altra.
|
|
if ( int( NewFacetA.size() + NewFacetB.size()) == 0) {
|
|
int nVertNum = 0 ;
|
|
Point3d ptVert ;
|
|
int nCurVert = GetFirstVertex( ptVert) ;
|
|
int nInOutNumA = 0 ;
|
|
while ( nInOutNumA == 0 && nCurVert != SVT_NULL) {
|
|
int nFacetNum = - 1 ;
|
|
double dMinDist = DBL_MAX ;
|
|
for ( int nFB = 0 ; nFB < SurfB.GetFacetCount() ; ++ nFB) {
|
|
// Loop della faccia della superficie B
|
|
POLYLINEVECTOR vFacetLoopVec ;
|
|
SurfB.GetFacetLoops( nFB, vFacetLoopVec) ;
|
|
double dDist ;
|
|
if ( DistPointFacet( ptVert, vFacetLoopVec, dDist) && dDist < dMinDist) {
|
|
dMinDist = dDist ;
|
|
nFacetNum = nFB ;
|
|
}
|
|
}
|
|
if ( nFacetNum >= 0) {
|
|
Triangle3d trTriaB ;
|
|
SurfB.GetTriangle( SurfB.m_vFacet[nFacetNum], trTriaB) ;
|
|
trTriaB.Validate() ;
|
|
if ( ( ptVert - trTriaB.GetP( 0)) * trTriaB.GetN() < - EPS_SMALL)
|
|
nInOutNumA = 1 ;
|
|
else if ( ( ptVert - trTriaB.GetP( 0)) * trTriaB.GetN() > EPS_SMALL)
|
|
nInOutNumA = - 1 ;
|
|
}
|
|
if ( nInOutNumA == 0) {
|
|
nCurVert = GetNextVertex( nVertNum, ptVert) ;
|
|
++ nVertNum ;
|
|
}
|
|
}
|
|
// Se la superficie A non � interna valuto la posizione della superficie B.
|
|
int nInOutNumB = nInOutNumA == 1 ? - 1 : 0 ;
|
|
if ( nInOutNumB == 0) {
|
|
nVertNum = 0 ;
|
|
nCurVert = SurfB.GetFirstVertex( ptVert) ;
|
|
while ( nInOutNumB == 0 && nCurVert != SVT_NULL) {
|
|
int nFacetNum = - 1 ;
|
|
double dMinDist = DBL_MAX ;
|
|
for ( int nFA = 0 ; nFA < GetFacetCount() ; ++ nFA) {
|
|
// Loop della faccia della superficie A
|
|
POLYLINEVECTOR vFacetLoopVec ;
|
|
GetFacetLoops( nFA, vFacetLoopVec) ;
|
|
double dDist ;
|
|
if ( DistPointFacet( ptVert, vFacetLoopVec, dDist) && dDist < dMinDist) {
|
|
dMinDist = dDist ;
|
|
nFacetNum = nFA ;
|
|
}
|
|
}
|
|
if ( nFacetNum >= 0) {
|
|
Triangle3d trTriaA ;
|
|
GetTriangle( m_vFacet[nFacetNum], trTriaA) ;
|
|
trTriaA.Validate() ;
|
|
if ( ( ptVert - trTriaA.GetP( 0)) * trTriaA.GetN() < - EPS_SMALL)
|
|
nInOutNumB = 1 ;
|
|
else if ( ( ptVert - trTriaA.GetP( 0)) * trTriaA.GetN() > EPS_SMALL)
|
|
nInOutNumB = - 1 ;
|
|
|
|
}
|
|
if ( nInOutNumB == 0) {
|
|
nCurVert = SurfB.GetNextVertex( nVertNum, ptVert) ;
|
|
++ nVertNum ;
|
|
}
|
|
}
|
|
}
|
|
// Se la posizione della superficie A rispetto alla B non � definita e
|
|
// B � esterna ad A, allora assumiamo che siano reciprocamente esterne.
|
|
if ( nInOutNumA == 0 && nInOutNumA == - 1)
|
|
nInOutNumA = - 1 ;
|
|
// Assegno gli indici interni/esterni.
|
|
for ( int nTA = 0 ; nTA < nTriaNumA ; ++ nTA) {
|
|
m_vTria[nTA].nTempPart = nInOutNumA ;
|
|
}
|
|
for ( int nTB = 0 ; nTB < nTriaNumB ; ++ nTB) {
|
|
SurfB.m_vTria[nTB].nTempPart = nInOutNumB ;
|
|
}
|
|
}
|
|
|
|
#define UseTria 0
|
|
#if ! UseTria
|
|
// Gestisco facce sovrapposte.
|
|
// Ciclo sulle facce di A.
|
|
for ( int nFA = 0 ; nFA < nFacetNumA ; ++ nFA) {
|
|
auto itFacetA = NewFacetA.find( nFA) ;
|
|
// Faccia A divisa in pezzi.
|
|
if ( itFacetA != NewFacetA.end()) {
|
|
// Ciclo sui pezzi della faccia A.
|
|
for ( int nPieceNumA = 0 ; nPieceNumA < int( itFacetA->second.size()) ; ++ nPieceNumA) {
|
|
// Dati del pezzo di faccia di A
|
|
POLYLINEVECTOR& vPieceLoopsVecA = itFacetA->second[nPieceNumA].vPieceLoop ;
|
|
PtrOwner<SurfFlatRegion> pRegA( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vPieceLoopsVecA))) ;
|
|
if ( pRegA == nullptr)
|
|
return false ;
|
|
SurfFlatRegion RegionA = *pRegA ;
|
|
Plane3d plPlaneA ;
|
|
plPlaneA.Set( RegionA.GetPlanePoint(), RegionA.GetNormVersor()) ;
|
|
// Recupero tutti i triangoli della superficie B che cadono nel box del pezzo di faccia di A.
|
|
BBox3d b3BoxA ;
|
|
RegionA.GetLocalBBox( b3BoxA) ;
|
|
INTVECTOR vNearTria ;
|
|
SurfB.GetAllTriaOverlapBox( b3BoxA, vNearTria) ;
|
|
// Determino le facce a cui appartengono i tirangoli che cadono nel box
|
|
INTVECTOR vFacetIndexesB ;
|
|
for ( int& nT : vNearTria) {
|
|
int nF = SurfB.GetFacetFromTria( nT) ;
|
|
int n ;
|
|
for ( n = 0 ; n < int( vFacetIndexesB.size()) ; ++ n) {
|
|
if ( nF == vFacetIndexesB[n])
|
|
break ;
|
|
}
|
|
if ( n == int( vFacetIndexesB.size()))
|
|
vFacetIndexesB.emplace_back( nF) ;
|
|
}
|
|
// Ciclo sulle facce di B
|
|
for ( int& nFB : vFacetIndexesB) {
|
|
auto itFacetB = NewFacetB.find( nFB) ;
|
|
// Faccia B divisa in pezzi
|
|
if ( itFacetB != NewFacetB.end()) {
|
|
// Ciclo sui pezzi della faccia B.
|
|
for ( int nPieceNumB = 0 ; nPieceNumB < int( itFacetB->second.size()) ; ++ nPieceNumB) {
|
|
// Dati del pezzo di faccia di B
|
|
POLYLINEVECTOR& vPieceLoopsVecB = itFacetB->second[nPieceNumB].vPieceLoop ;
|
|
PtrOwner<SurfFlatRegion> pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vPieceLoopsVecB))) ;
|
|
if ( pRegB == nullptr)
|
|
return false ;
|
|
SurfFlatRegion RegionB = *pRegB ;
|
|
Plane3d plPlaneB ;
|
|
plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ;
|
|
// Intersezione tra i piani delle due facce: se non esiste esse sono complanari.
|
|
Point3d ptL ; Vector3d vtL ;
|
|
int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ;
|
|
if ( /*nResPP == IPPT_NO ||*/ nResPP == IPPT_OVERLAPS) {
|
|
// Se necessario inverto la regione B per eseguire l'intersezione.
|
|
if ( plPlaneA.GetVersN() * plPlaneB.GetVersN() < - EPS_SMALL)
|
|
RegionB.Invert() ;
|
|
SurfFlatRegion frIntersRegion = RegionA ;
|
|
frIntersRegion.Intersect( RegionB) ;
|
|
double dIntersRegArea ;
|
|
frIntersRegion.GetArea( dIntersRegArea) ;
|
|
// Assegno indice di parte ai pezzi.
|
|
if ( dIntersRegArea > EPS_SMALL) {
|
|
bool bCodirectedNorm = plPlaneA.GetVersN() * plPlaneB.GetVersN() > 0 ;
|
|
int nPartIndex = bCodirectedNorm ? 2 : - 2 ;
|
|
itFacetA->second[nPieceNumA].nPiecePart = nPartIndex ;
|
|
itFacetB->second[nPieceNumB].nPiecePart = nPartIndex ;
|
|
}
|
|
}
|
|
else if ( nResPP == IPPT_YES) {
|
|
Point3d ptCentroidA, ptCentroidB ;
|
|
RegionA.GetCentroid( ptCentroidA) ;
|
|
RegionB.GetCentroid( ptCentroidB) ;
|
|
if ( AreSameOrOppositeVectorApprox( plPlaneA.GetVersN(), plPlaneB.GetVersN()) &&
|
|
abs( ( ptCentroidB - ptCentroidA) * plPlaneA.GetVersN()) < EPS_SMALL) {
|
|
BBox3d b3Box, b3BoxB ;
|
|
RegionA.GetLocalBBox( b3Box) ;
|
|
RegionB.GetLocalBBox( b3BoxB) ;
|
|
b3Box.Add( b3BoxB) ;
|
|
b3Box.Expand( 10) ;
|
|
INTDBLVECTOR vInters ;
|
|
if ( ! IntersLineBox( ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) < 2) {
|
|
// Se necessario inverto la regione B per eseguire l'intersezione.
|
|
if ( plPlaneA.GetVersN() * plPlaneB.GetVersN() < - EPS_SMALL)
|
|
RegionB.Invert() ;
|
|
SurfFlatRegion frIntersRegion = RegionA ;
|
|
frIntersRegion.Intersect( RegionB) ;
|
|
double dIntersRegArea ;
|
|
frIntersRegion.GetArea( dIntersRegArea) ;
|
|
// Assegno indice di parte ai pezzi.
|
|
if ( dIntersRegArea > EPS_SMALL) {
|
|
bool bCodirectedNorm = plPlaneA.GetVersN() * plPlaneB.GetVersN() > 0 ;
|
|
int nPartIndex = bCodirectedNorm ? 2 : - 2 ;
|
|
itFacetA->second[nPieceNumA].nPiecePart = nPartIndex ;
|
|
itFacetB->second[nPieceNumB].nPiecePart = nPartIndex ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Faccia B non divisa in pezzi
|
|
else {
|
|
// Dati della faccia
|
|
POLYLINEVECTOR vFacetLoopVecB ;
|
|
SurfB.GetFacetLoops( nFB, vFacetLoopVecB) ;
|
|
PtrOwner<SurfFlatRegion> pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vFacetLoopVecB))) ;
|
|
if ( pRegB == nullptr)
|
|
return false ;
|
|
SurfFlatRegion RegionB = *pRegB ;
|
|
Plane3d plPlaneB ;
|
|
plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ;
|
|
// Intersezione tra i piani delle due facce: se non esiste esse sono complanari.
|
|
Point3d ptL ; Vector3d vtL ;
|
|
int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ;
|
|
if ( /*nResPP == IPPT_NO ||*/ nResPP == IPPT_OVERLAPS) {
|
|
// Se necessario inverto la regione B per eseguire l'intersezione.
|
|
if ( plPlaneA.GetVersN() * plPlaneB.GetVersN() < - EPS_SMALL)
|
|
RegionB.Invert() ;
|
|
SurfFlatRegion frIntersRegion = RegionA ;
|
|
frIntersRegion.Intersect( RegionB) ;
|
|
double dIntersRegArea ;
|
|
frIntersRegion.GetArea( dIntersRegArea) ;
|
|
// Assegno indice di parte al pezzo di faccia A e ai triangoli della faccia B.
|
|
if ( dIntersRegArea > EPS_SMALL) {
|
|
bool bCodirectedNorm = plPlaneA.GetVersN() * plPlaneB.GetVersN() > 0 ;
|
|
int nPartIndex = bCodirectedNorm ? 2 : - 2 ;
|
|
itFacetA->second[nPieceNumA].nPiecePart = nPartIndex ;
|
|
INTVECTOR vTB ;
|
|
SurfB.GetAllTriaInFacet( nFB, vTB) ;
|
|
for ( int& nTB : vTB)
|
|
SurfB.m_vTria[nTB].nTempPart = nPartIndex ;
|
|
}
|
|
}
|
|
else if ( nResPP == IPPT_YES) {
|
|
Point3d ptCentroidA, ptCentroidB ;
|
|
RegionA.GetCentroid( ptCentroidA) ;
|
|
RegionB.GetCentroid( ptCentroidB) ;
|
|
if ( AreSameOrOppositeVectorApprox(plPlaneA.GetVersN(), plPlaneB.GetVersN()) &&
|
|
abs( ( ptCentroidB - ptCentroidA) * plPlaneA.GetVersN()) < EPS_SMALL) {
|
|
BBox3d b3Box, b3BoxB ;
|
|
RegionA.GetLocalBBox( b3Box) ;
|
|
RegionB.GetLocalBBox( b3BoxB) ;
|
|
b3Box.Add( b3BoxB) ;
|
|
b3Box.Expand( 10) ;
|
|
INTDBLVECTOR vInters ;
|
|
if ( ! IntersLineBox( ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) < 2) {
|
|
// Se necessario inverto la regione B per eseguire l'intersezione.
|
|
if ( plPlaneA.GetVersN() * plPlaneB.GetVersN() < - EPS_SMALL)
|
|
RegionB.Invert() ;
|
|
SurfFlatRegion frIntersRegion = RegionA ;
|
|
frIntersRegion.Intersect( RegionB) ;
|
|
double dIntersRegArea ;
|
|
frIntersRegion.GetArea( dIntersRegArea) ;
|
|
// Assegno indice di parte al pezzo di faccia A e ai triangoli della faccia B.
|
|
if ( dIntersRegArea > EPS_SMALL) {
|
|
bool bCodirectedNorm = plPlaneA.GetVersN() * plPlaneB.GetVersN() > 0 ;
|
|
int nPartIndex = bCodirectedNorm ? 2 : - 2 ;
|
|
itFacetA->second[nPieceNumA].nPiecePart = nPartIndex ;
|
|
INTVECTOR vTB ;
|
|
SurfB.GetAllTriaInFacet( nFB, vTB) ;
|
|
for ( int& nTB : vTB)
|
|
SurfB.m_vTria[nTB].nTempPart = nPartIndex ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Faccia A non divisa in pezzi
|
|
else {
|
|
// Dati della faccia
|
|
POLYLINEVECTOR vFacetLoopsVecA ;
|
|
GetFacetLoops( nFA, vFacetLoopsVecA) ;
|
|
PtrOwner<SurfFlatRegion> pRegA( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vFacetLoopsVecA))) ;
|
|
if ( pRegA == nullptr)
|
|
return false ;
|
|
SurfFlatRegion RegionA = *pRegA ;
|
|
Plane3d plPlaneA ;
|
|
plPlaneA.Set( RegionA.GetPlanePoint(), RegionA.GetNormVersor()) ;
|
|
// Recupero tutti i triangoli della superficie B che cadono nel box del pezzo di faccia di A.
|
|
BBox3d b3BoxA ;
|
|
RegionA.GetLocalBBox( b3BoxA) ;
|
|
INTVECTOR vNearTria ;
|
|
SurfB.GetAllTriaOverlapBox( b3BoxA, vNearTria) ;
|
|
// Determino le facce a cui appartengono i tirangoli che cadono nel box
|
|
INTVECTOR vFacetIndexesB ;
|
|
for ( int& nT : vNearTria) {
|
|
int nF = SurfB.GetFacetFromTria( nT) ;
|
|
int n ;
|
|
for ( n = 0 ; n < int( vFacetIndexesB.size()) ; ++ n) {
|
|
if ( nF == vFacetIndexesB[n])
|
|
break ;
|
|
}
|
|
if ( n == int( vFacetIndexesB.size()))
|
|
vFacetIndexesB.emplace_back( nF) ;
|
|
}
|
|
// Ciclo sulle facce di B
|
|
for ( int& nFB : vFacetIndexesB) {
|
|
auto itFacetB = NewFacetB.find( nFB) ;
|
|
// Faccia B divisa in pezzi
|
|
if ( itFacetB != NewFacetB.end()) {
|
|
for ( int nPieceNumB = 0 ; nPieceNumB < int( itFacetB->second.size()) ; ++ nPieceNumB) {
|
|
POLYLINEVECTOR& vPieceLoopsVecB = itFacetB->second[nPieceNumB].vPieceLoop ;
|
|
PtrOwner<SurfFlatRegion> pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vPieceLoopsVecB))) ;
|
|
if ( pRegB == nullptr)
|
|
return false ;
|
|
SurfFlatRegion RegionB = *pRegB ;
|
|
Plane3d plPlaneB ;
|
|
plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ;
|
|
// Intersezione tra i piani delle due facce: se non esiste esse sono complanari.
|
|
Point3d ptL ; Vector3d vtL ;
|
|
int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ;
|
|
if ( /*nResPP == IPPT_NO ||*/ nResPP == IPPT_OVERLAPS) {
|
|
// Se necessario inverto la regione B per eseguire l'intersezione.
|
|
if ( plPlaneA.GetVersN() * plPlaneB.GetVersN() < - EPS_SMALL)
|
|
RegionB.Invert() ;
|
|
SurfFlatRegion frIntersRegion = RegionA ;
|
|
frIntersRegion.Intersect( RegionB) ;
|
|
double dIntersRegArea ;
|
|
frIntersRegion.GetArea( dIntersRegArea) ;
|
|
// Assegno indice di parte ai triangoli di A e ai pezzi di B.
|
|
if ( dIntersRegArea > EPS_SMALL) {
|
|
bool bCodirectedNorm = plPlaneA.GetVersN() * plPlaneB.GetVersN() > 0 ;
|
|
int nPartIndex = bCodirectedNorm ? 2 : - 2 ;
|
|
INTVECTOR vTA ;
|
|
GetAllTriaInFacet( nFA, vTA) ;
|
|
for ( int& nTA : vTA)
|
|
m_vTria[nTA].nTempPart = nPartIndex ;
|
|
itFacetB->second[nPieceNumB].nPiecePart = nPartIndex ;
|
|
}
|
|
}
|
|
else if ( nResPP == IPPT_YES) {
|
|
Point3d ptCentroidA, ptCentroidB ;
|
|
RegionA.GetCentroid( ptCentroidA) ;
|
|
RegionB.GetCentroid( ptCentroidB) ;
|
|
if ( AreSameOrOppositeVectorApprox( plPlaneA.GetVersN(), plPlaneB.GetVersN()) &&
|
|
abs( ( ptCentroidB - ptCentroidA) * plPlaneA.GetVersN()) < EPS_SMALL) {
|
|
BBox3d b3Box, b3BoxB ;
|
|
RegionA.GetLocalBBox( b3Box) ;
|
|
RegionB.GetLocalBBox( b3BoxB) ;
|
|
b3Box.Add( b3BoxB) ;
|
|
b3Box.Expand( 10) ;
|
|
INTDBLVECTOR vInters;
|
|
if ( ! IntersLineBox( ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) < 2) {
|
|
// Se necessario inverto la regione B per eseguire l'intersezione.
|
|
if ( plPlaneA.GetVersN() * plPlaneB.GetVersN() < - EPS_SMALL)
|
|
RegionB.Invert() ;
|
|
SurfFlatRegion frIntersRegion = RegionA ;
|
|
frIntersRegion.Intersect( RegionB) ;
|
|
double dIntersRegArea ;
|
|
frIntersRegion.GetArea( dIntersRegArea) ;
|
|
// Assegno indice di parte ai triangoli di A e ai pezzi di B.
|
|
if ( dIntersRegArea > EPS_SMALL) {
|
|
bool bCodirectedNorm = plPlaneA.GetVersN() * plPlaneB.GetVersN() > 0 ;
|
|
int nPartIndex = bCodirectedNorm ? 2 : - 2 ;
|
|
INTVECTOR vTA ;
|
|
GetAllTriaInFacet( nFA, vTA) ;
|
|
for ( int& nTA : vTA)
|
|
m_vTria[nTA].nTempPart = nPartIndex ;
|
|
itFacetB->second[nPieceNumB].nPiecePart = nPartIndex ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Faccia B non divisa in pezzi
|
|
else {
|
|
// Dati della faccia
|
|
POLYLINEVECTOR vFacetLoopVecB ;
|
|
SurfB.GetFacetLoops( nFB, vFacetLoopVecB) ;
|
|
PtrOwner<SurfFlatRegion> pRegB( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vFacetLoopVecB))) ;
|
|
if ( pRegB == nullptr)
|
|
return false ;
|
|
SurfFlatRegion RegionB = *pRegB ;
|
|
Plane3d plPlaneB ;
|
|
plPlaneB.Set( RegionB.GetPlanePoint(), RegionB.GetNormVersor()) ;
|
|
// Intersezione tra i piani delle due facce: se non esiste esse sono complanari.
|
|
Point3d ptL ; Vector3d vtL ;
|
|
int nResPP = IntersPlanePlane( plPlaneA, plPlaneB, ptL, vtL) ;
|
|
if ( /*nResPP == IPPT_NO ||*/ nResPP == IPPT_OVERLAPS) {
|
|
// Se necessario inverto la regione B per eseguire l'intersezione.
|
|
if ( plPlaneA.GetVersN() * plPlaneB.GetVersN() < - EPS_SMALL)
|
|
RegionB.Invert() ;
|
|
SurfFlatRegion frIntersRegion = RegionA ;
|
|
frIntersRegion.Intersect( RegionB) ;
|
|
double dIntersRegArea ;
|
|
frIntersRegion.GetArea( dIntersRegArea) ;
|
|
// Assegno indice di parte al pezzo di faccia A e ai triangoli della faccia B.
|
|
if ( dIntersRegArea > EPS_SMALL) {
|
|
bool bCodirectedNorm = plPlaneA.GetVersN() * plPlaneB.GetVersN() > 0 ;
|
|
int nPartIndex = bCodirectedNorm ? 2 : - 2 ;
|
|
INTVECTOR vTA ;
|
|
GetAllTriaInFacet( nFA, vTA) ;
|
|
for ( int& nTA : vTA)
|
|
m_vTria[nTA].nTempPart = nPartIndex ;
|
|
INTVECTOR vTB ;
|
|
SurfB.GetAllTriaInFacet( nFB, vTB) ;
|
|
for ( int& nTB : vTB)
|
|
SurfB.m_vTria[nTB].nTempPart = nPartIndex ;
|
|
}
|
|
}
|
|
else if ( nResPP == IPPT_YES) {
|
|
Point3d ptCentroidA, ptCentroidB ;
|
|
RegionA.GetCentroid( ptCentroidA) ;
|
|
RegionB.GetCentroid( ptCentroidB) ;
|
|
if ( AreSameOrOppositeVectorApprox( plPlaneA.GetVersN(), plPlaneB.GetVersN()) &&
|
|
abs( ( ptCentroidB - ptCentroidA) * plPlaneA.GetVersN()) < EPS_SMALL) {
|
|
BBox3d b3Box, b3BoxB ;
|
|
RegionA.GetLocalBBox( b3Box) ;
|
|
RegionB.GetLocalBBox( b3BoxB) ;
|
|
b3Box.Add( b3BoxB) ;
|
|
b3Box.Expand( 10) ;
|
|
INTDBLVECTOR vInters ;
|
|
if ( ! IntersLineBox( ptL, vtL, 100., b3Box, vInters, false) || int( vInters.size()) < 2) {
|
|
// Se necessario inverto la regione B per eseguire l'intersezione.
|
|
if ( plPlaneA.GetVersN() * plPlaneB.GetVersN() < - EPS_SMALL)
|
|
RegionB.Invert() ;
|
|
SurfFlatRegion frIntersRegion = RegionA ;
|
|
frIntersRegion.Intersect( RegionB) ;
|
|
double dIntersRegArea ;
|
|
frIntersRegion.GetArea( dIntersRegArea) ;
|
|
// Assegno indice di parte al pezzo di faccia A e ai triangoli della faccia B.
|
|
if ( dIntersRegArea > EPS_SMALL) {
|
|
bool bCodirectedNorm = plPlaneA.GetVersN() * plPlaneB.GetVersN() > 0 ;
|
|
int nPartIndex = bCodirectedNorm ? 2 : - 2 ;
|
|
INTVECTOR vTA ;
|
|
GetAllTriaInFacet( nFA, vTA) ;
|
|
for ( int& nTA : vTA)
|
|
m_vTria[nTA].nTempPart = nPartIndex ;
|
|
INTVECTOR vTB ;
|
|
SurfB.GetAllTriaInFacet( nFB, vTB) ;
|
|
for ( int& nTB : vTB)
|
|
SurfB.m_vTria[nTB].nTempPart = nPartIndex ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Elimino i triangoli delle facce e li sostituisco con i nuovi con i loro indici
|
|
RetriangulateFacetPieces( NewFacetA, EdgeInnLineMapA, EdgeEdgeLineMapB) ;
|
|
SurfB.RetriangulateFacetPieces( NewFacetB, EdgeInnLineMapB, EdgeEdgeLineMapB) ;
|
|
|
|
bool bOk = ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ;
|
|
|
|
#if UseTria
|
|
// Gestione triangoli sovrapposti
|
|
if ( bOk) {
|
|
int nTriaNum2A = GetTriangleSize() ;
|
|
// Resetto e ricalcolo la HashGrid e PointGrid della superficie B
|
|
SurfB.ResetHashGrids3d() ;
|
|
SurfB.ResetPointGrid3d() ;
|
|
for ( int nTA = 0 ; nTA < nTriaNum2A ; ++ nTA) {
|
|
// Se il triangolo A non � valido, continuo
|
|
Triangle3d trTriaA ;
|
|
if ( ! GetTriangle( nTA, trTriaA) || ! trTriaA.Validate( true))
|
|
continue ;
|
|
// Box del triangolo A
|
|
BBox3d b3dTriaA ;
|
|
trTriaA.GetLocalBBox( b3dTriaA) ;
|
|
// Recupero i triangoli di B che interferiscono col box del triangolo di A
|
|
INTVECTOR vNearTria ;
|
|
SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ;
|
|
for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) {
|
|
// Se il triangolo B non � valido, continuo
|
|
Triangle3d trTriaB ;
|
|
if ( ! SurfB.GetTriangle( vNearTria[nTB], trTriaB) || ! trTriaB.Validate( true))
|
|
continue ;
|
|
// Se i triangoli sono sovrapposti
|
|
TRIA3DVECTOR vTriaAB ;
|
|
Point3d ptTempA, ptTempB ;
|
|
int nIntTypeAB = IntersTriaTria( trTriaA, trTriaB, ptTempA, ptTempB, vTriaAB) ;
|
|
// Verifica della correttezza del'intersezione
|
|
bool bSuccesfullInters = true ;
|
|
if ( int( vTriaAB.size()) == 1) {
|
|
Point3d ptIntTriaCentroid = vTriaAB[0].GetCentroid() ;
|
|
bSuccesfullInters = IsPointInsideTriangle( ptIntTriaCentroid, trTriaA, TriangleType::EXACT) &&
|
|
IsPointInsideTriangle( ptIntTriaCentroid, trTriaB, TriangleType::EXACT) ;
|
|
}
|
|
// Se l'intersezeione � corretta e i triangoli sono sovrapposti aggiorno gli indici.
|
|
if ( nIntTypeAB == ITTT_OVERLAPS && bSuccesfullInters) {
|
|
bool bInvertB = trTriaA.GetN() * trTriaB.GetN() < 0. ;
|
|
m_vTria[nTA].nTempPart = ( bInvertB ? -2 : 2) ;
|
|
SurfB.m_vTria[vNearTria[nTB]].nTempPart = ( bInvertB ? - 2 : 2) ;
|
|
}
|
|
}
|
|
}
|
|
return ( AdjustVertices() && DoCompacting() && SurfB.AdjustVertices() && SurfB.DoCompacting()) ;
|
|
}
|
|
#endif
|
|
return bOk ;
|
|
} |