9b11212d07
- in TriMesh eliminata ResetFaceting e UpdateFaceting ora cerca di ricostruire facce con indice come le eventuali precedenti - in Trimesh SimplifyFacets cerca di conservare l'identificativo di faccia nei nuovi triangoli - in Trimesh aggiunta funzione Repair e migliorata SimplifyFacets - in Trimesh al termine di CutWithOtherSurf si cerca di regolarizzare il risultato.
875 lines
35 KiB
C++
875 lines
35 KiB
C++
//----------------------------------------------------------------------------
|
|
// EgalTech 2019-2021
|
|
//----------------------------------------------------------------------------
|
|
// File : SurfTriMeshCuts.cpp Data : 06.11.21 Versione : 2.3k3
|
|
// Contenuto : Implementazione delle funzioni di taglio per SurfFTrimesh.
|
|
//
|
|
//
|
|
//
|
|
// Modifiche : 06.11.21 DS Creazione modulo.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "stdafx.h"
|
|
#include "CurveComposite.h"
|
|
#include "SurfTriMesh.h"
|
|
#include "SurfFlatRegion.h"
|
|
#include "DistPointLine.h"
|
|
#include "Triangulate.h"
|
|
#include "GeoConst.h"
|
|
#include "/EgtDev/Include/EgkSfrCreate.h"
|
|
#include "/EgtDev/Include/EGkDistPointCurve.h"
|
|
#include "/EgtDev/Include/EGkIntersLinePlane.h"
|
|
#include "/EgtDev/Include/EGkIntersPlaneTria.h"
|
|
|
|
using namespace std ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
const double CUT_SCALE = 1024 ;
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// recupero il numero originale di triangoli e di facce
|
|
int nTriaOriCnt = GetTriangleCount() ;
|
|
int nFacetOriCnt = GetFacetCount() ;
|
|
|
|
// eseguo il taglio con il metodo delle faccette o dei triangoli (per ora solo coi triangoli)
|
|
bool bModif = false ;
|
|
if ( true || ! CutByFacets( plPlane, bSaveOnEq, bModif)) {
|
|
bModif = false ;
|
|
if ( ! CutByTriangles( plPlane, bSaveOnEq, bModif))
|
|
return false ;
|
|
}
|
|
|
|
// se effettuate modifiche
|
|
if ( bModif) {
|
|
// aggiorno tutto
|
|
if ( ! AdjustVertices() || ! DoCompacting())
|
|
return false ;
|
|
}
|
|
|
|
// se superficie originale a facce, cerco di semplificarle in ogni caso
|
|
if ( nFacetOriCnt < 200 || double( nTriaOriCnt) / nFacetOriCnt > 4) {
|
|
if ( ! SimplifyFacets())
|
|
LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::Cut")
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::CutByTriangles( const Plane3d& plPlane, bool bSaveOnEq, bool& bModif)
|
|
{
|
|
// la superficie deve essere validata
|
|
if ( m_nStatus != OK)
|
|
return false ;
|
|
|
|
// classifico i vertici rispetto al piano
|
|
double dTol = max( min( 0.5 * m_dLinTol, 10 * EPS_SMALL), EPS_SMALL) ;
|
|
for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
|
|
double dDist = DistPointPlane( m_vVert[i].ptP, plPlane) ;
|
|
if ( abs( dDist) < dTol) {
|
|
m_vVert[i].nTemp = 0 ;
|
|
if ( abs( dDist) > EPS_SMALL)
|
|
m_vVert[i].ptP -= plPlane.GetVersN() * dDist ;
|
|
}
|
|
else if ( dDist > 0)
|
|
m_vVert[i].nTemp = +1 ;
|
|
else
|
|
m_vVert[i].nTemp = -1 ;
|
|
}
|
|
|
|
// aggiorno timestamp dei triangoli
|
|
for ( auto& Tria : m_vTria)
|
|
Tria.nTemp = m_nTimeStamp ;
|
|
++ m_nTimeStamp ;
|
|
|
|
// sistemo i triangoli (eventualmente li elimino)
|
|
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
|
|
// salto i triangoli cancellati e quelli aggiunti
|
|
if ( m_vTria[i].nIdVert[0] == SVT_DEL || m_vTria[i].nTemp == m_nTimeStamp)
|
|
continue ;
|
|
CutTriangleByPlane( i, plPlane, bSaveOnEq, bModif) ;
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::CutTriangleByPlane( int nT, const Plane3d& plPlane, bool bSaveOnEq, bool& bModif)
|
|
{
|
|
// se flag abilita e giace sul piano ed equiverso, lo salvo
|
|
if ( bSaveOnEq &&
|
|
m_vVert[ m_vTria[nT].nIdVert[0]].nTemp == 0 &&
|
|
m_vVert[ m_vTria[nT].nIdVert[1]].nTemp == 0 &&
|
|
m_vVert[ m_vTria[nT].nIdVert[2]].nTemp == 0 &&
|
|
AreSameVectorApprox( m_vTria[nT].vtN, plPlane.GetVersN()))
|
|
;
|
|
// se giace sul piano o dalla parte esterna del piano, lo cancello
|
|
else if ( m_vVert[ m_vTria[nT].nIdVert[0]].nTemp != -1 &&
|
|
m_vVert[ m_vTria[nT].nIdVert[1]].nTemp != -1 &&
|
|
m_vVert[ m_vTria[nT].nIdVert[2]].nTemp != -1) {
|
|
bModif = true ;
|
|
RemoveTriangle( nT) ;
|
|
}
|
|
// se giace dalla parte interna con al massimo un lato sul piano, lo conservo
|
|
else if ( m_vVert[ m_vTria[nT].nIdVert[0]].nTemp != 1 &&
|
|
m_vVert[ m_vTria[nT].nIdVert[1]].nTemp != 1 &&
|
|
m_vVert[ m_vTria[nT].nIdVert[2]].nTemp != 1)
|
|
;
|
|
// altrimenti attraversa il piano, devo modificarlo
|
|
else {
|
|
bModif = true ;
|
|
int nDisc = m_vVert[ m_vTria[nT].nIdVert[0]].nTemp +
|
|
m_vVert[ m_vTria[nT].nIdVert[1]].nTemp +
|
|
m_vVert[ m_vTria[nT].nIdVert[2]].nTemp ;
|
|
// se ha un vertice all'interno e uno sul piano -> 1 nuovo vertice e 1 nuovo triangolo
|
|
if ( nDisc == 0) {
|
|
// classifico i vertici
|
|
int nVertOn, nVertIn, nVertOut ;
|
|
if ( m_vVert[ m_vTria[nT].nIdVert[0]].nTemp == 0) {
|
|
nVertOn = 0 ;
|
|
nVertIn = 1 ;
|
|
nVertOut = 2 ;
|
|
if ( m_vVert[ m_vTria[nT].nIdVert[1]].nTemp > 0)
|
|
swap( nVertIn, nVertOut) ;
|
|
}
|
|
else if ( m_vVert[ m_vTria[nT].nIdVert[1]].nTemp == 0) {
|
|
nVertOn = 1 ;
|
|
nVertIn = 2 ;
|
|
nVertOut = 0 ;
|
|
if ( m_vVert[ m_vTria[nT].nIdVert[2]].nTemp > 0)
|
|
swap( nVertIn, nVertOut) ;
|
|
}
|
|
else {
|
|
nVertOn = 2 ;
|
|
nVertIn = 0 ;
|
|
nVertOut = 1 ;
|
|
if ( m_vVert[ m_vTria[nT].nIdVert[0]].nTemp > 0)
|
|
swap( nVertIn, nVertOut) ;
|
|
}
|
|
// calcolo il punto di intersezione del lato che attraversa il piano
|
|
double dDistIn = - DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nVertIn]].ptP, plPlane) ;
|
|
double dDistOut = DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nVertOut]].ptP, plPlane) ;
|
|
Point3d ptInt = Media( m_vVert[m_vTria[nT].nIdVert[nVertIn]].ptP,
|
|
m_vVert[m_vTria[nT].nIdVert[nVertOut]].ptP,
|
|
dDistIn / ( dDistIn + dDistOut)) ;
|
|
// inserisco il nuovo vertice
|
|
int nNewV = AddVertex( ptInt) ;
|
|
// inserisco il nuovo triangolo
|
|
int nIdVert[3] = { m_vTria[nT].nIdVert[0], m_vTria[nT].nIdVert[1], m_vTria[nT].nIdVert[2]} ;
|
|
nIdVert[nVertOut] = nNewV ;
|
|
int nIdTria = AddTriangle( nIdVert) ;
|
|
if ( nIdTria == SVT_NULL)
|
|
return false ;
|
|
if ( nIdTria != SVT_DEL)
|
|
m_vTria[nIdTria].nTemp = m_nTimeStamp ;
|
|
// cancello il vecchio triangolo
|
|
RemoveTriangle( nT) ;
|
|
}
|
|
// se ha un vertice all'interno e due all'esterno -> 2 nuovi vertici e 1 nuovo triangolo
|
|
else if ( nDisc == 1) {
|
|
// classifico i vertici
|
|
int nVertIn, nVertOut1, nVertOut2 ;
|
|
if ( m_vVert[ m_vTria[nT].nIdVert[0]].nTemp == -1) {
|
|
nVertIn = 0 ;
|
|
nVertOut1 = 1 ;
|
|
nVertOut2 = 2 ;
|
|
}
|
|
else if ( m_vVert[ m_vTria[nT].nIdVert[1]].nTemp == -1) {
|
|
nVertIn = 1 ;
|
|
nVertOut1 = 2 ;
|
|
nVertOut2 = 0 ;
|
|
}
|
|
else {
|
|
nVertIn = 2 ;
|
|
nVertOut1 = 0 ;
|
|
nVertOut2 = 1 ;
|
|
}
|
|
// calcolo i punti di intersezione dei lati che attraversano il piano
|
|
double dDistIn = - DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nVertIn]].ptP, plPlane) ;
|
|
double dDistOut1 = DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nVertOut1]].ptP, plPlane) ;
|
|
double dDistOut2 = DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nVertOut2]].ptP, plPlane) ;
|
|
Point3d ptInt1 = Media( m_vVert[m_vTria[nT].nIdVert[nVertIn]].ptP,
|
|
m_vVert[m_vTria[nT].nIdVert[nVertOut1]].ptP,
|
|
dDistIn / ( dDistIn + dDistOut1)) ;
|
|
Point3d ptInt2 = Media( m_vVert[m_vTria[nT].nIdVert[nVertIn]].ptP,
|
|
m_vVert[m_vTria[nT].nIdVert[nVertOut2]].ptP,
|
|
dDistIn / ( dDistIn + dDistOut2)) ;
|
|
// inserisco i nuovi vertici
|
|
int nNewV1 = AddVertex( ptInt1) ;
|
|
int nNewV2 = AddVertex( ptInt2) ;
|
|
// inserisco il nuovo triangolo
|
|
int nIdVert[3] = { m_vTria[nT].nIdVert[0], m_vTria[nT].nIdVert[1], m_vTria[nT].nIdVert[2]} ;
|
|
nIdVert[nVertOut1] = nNewV1 ;
|
|
nIdVert[nVertOut2] = nNewV2 ;
|
|
int nIdTria = AddTriangle( nIdVert) ;
|
|
if ( nIdTria == SVT_NULL)
|
|
return false ;
|
|
if ( nIdTria != SVT_DEL)
|
|
m_vTria[nIdTria].nTemp = m_nTimeStamp ;
|
|
// cancello il vecchio triangolo
|
|
RemoveTriangle( nT) ;
|
|
}
|
|
// altrimenti ha due vertici all'interno e uno all'esterno -> 2 nuovi vertici e 2 nuovi triangoli
|
|
else {
|
|
// classifico i vertici
|
|
int nVertIn1, nVertIn2, nVertOut ;
|
|
if ( m_vVert[ m_vTria[nT].nIdVert[0]].nTemp == 1) {
|
|
nVertOut = 0 ;
|
|
nVertIn1 = 1 ;
|
|
nVertIn2 = 2 ;
|
|
}
|
|
else if ( m_vVert[ m_vTria[nT].nIdVert[1]].nTemp == 1) {
|
|
nVertOut = 1 ;
|
|
nVertIn1 = 2 ;
|
|
nVertIn2 = 0 ;
|
|
}
|
|
else {
|
|
nVertOut = 2 ;
|
|
nVertIn1 = 0 ;
|
|
nVertIn2 = 1 ;
|
|
}
|
|
// calcolo i punti di intersezione dei lati che attraversano il piano
|
|
double dDistIn1 = - DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nVertIn1]].ptP, plPlane) ;
|
|
double dDistIn2 = - DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nVertIn2]].ptP, plPlane) ;
|
|
double dDistOut = DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nVertOut]].ptP, plPlane) ;
|
|
Point3d ptInt1 = Media( m_vVert[m_vTria[nT].nIdVert[nVertIn1]].ptP,
|
|
m_vVert[m_vTria[nT].nIdVert[nVertOut]].ptP,
|
|
dDistIn1 / ( dDistIn1 + dDistOut)) ;
|
|
Point3d ptInt2 = Media( m_vVert[m_vTria[nT].nIdVert[nVertIn2]].ptP,
|
|
m_vVert[m_vTria[nT].nIdVert[nVertOut]].ptP,
|
|
dDistIn2 / ( dDistIn2 + dDistOut)) ;
|
|
// inserisco i nuovi vertici
|
|
int nNewV1 = AddVertex( ptInt1) ;
|
|
int nNewV2 = AddVertex( ptInt2) ;
|
|
// inserisco i nuovi triangoli
|
|
int nIdVert1[3] = { m_vTria[nT].nIdVert[0], m_vTria[nT].nIdVert[1], m_vTria[nT].nIdVert[2]} ;
|
|
int nIdVert2[3] = { m_vTria[nT].nIdVert[0], m_vTria[nT].nIdVert[1], m_vTria[nT].nIdVert[2]} ;
|
|
double dSqDist1 = SqDist( m_vVert[m_vTria[nT].nIdVert[nVertIn1]].ptP, ptInt2) ;
|
|
double dSqDist2 = SqDist( m_vVert[m_vTria[nT].nIdVert[nVertIn2]].ptP, ptInt1) ;
|
|
if ( dSqDist1 <= dSqDist2) {
|
|
nIdVert1[nVertOut] = nNewV1 ;
|
|
nIdVert1[nVertIn2] = nNewV2 ;
|
|
nIdVert2[nVertOut] = nNewV2 ;
|
|
}
|
|
else {
|
|
nIdVert1[nVertOut] = nNewV1 ;
|
|
nIdVert2[nVertOut] = nNewV2 ;
|
|
nIdVert2[nVertIn1] = nNewV1 ;
|
|
}
|
|
int nIdTria1 = AddTriangle( nIdVert1) ;
|
|
int nIdTria2 = AddTriangle( nIdVert2) ;
|
|
if ( nIdTria1 == SVT_NULL || nIdTria2 == SVT_NULL)
|
|
return false ;
|
|
if ( nIdTria1 != SVT_DEL)
|
|
m_vTria[nIdTria1].nTemp = m_nTimeStamp ;
|
|
if ( nIdTria2 != SVT_DEL)
|
|
m_vTria[nIdTria2].nTemp = m_nTimeStamp ;
|
|
// cancello il vecchio triangolo
|
|
RemoveTriangle( nT) ;
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
bool
|
|
SurfTriMesh::CutByFacets( const Plane3d& plPlane, bool bSaveOnEq, bool& bModif)
|
|
{
|
|
// Setto posizione triangoli non definita
|
|
for ( int nT = 0 ; nT < GetTriangleSize() ; ++ nT)
|
|
m_vTria[nT].nTempPart = 0 ;
|
|
|
|
INTERSCHAINMAP IntersLineMap ;
|
|
|
|
// Ciclo su tutte le facce.
|
|
for ( int nF = 0 ; nF < GetFacetCount() ; ++ nF) {
|
|
// Dati della faccia
|
|
POLYLINEVECTOR vLoopVec ;
|
|
GetFacetLoops( nF, vLoopVec) ;
|
|
if ( vLoopVec.empty())
|
|
continue ;
|
|
// Verifico la posizione del loop esterno
|
|
int nIntType = VerifyLoopPlane( vLoopVec[0], plPlane) ;
|
|
// Se interseca il piano di taglio, calcolo la divisione della faccia
|
|
LineFacetClassVector IntersLinePart ;
|
|
if ( nIntType == FPI_CUT) {
|
|
PtrOwner<SurfFlatRegion> pReg( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLineVector( vLoopVec))) ;
|
|
if ( IsNull( pReg) || ! pReg->IsValid())
|
|
return false ;
|
|
nIntType = IntersFacetPlane( *pReg, plPlane, IntersLinePart) ;
|
|
}
|
|
// Gestione dei risultati
|
|
if ( nIntType == FPI_CUT) {
|
|
for ( int nPart = 0 ; nPart < int( IntersLinePart.size()) ; ++ nPart) {
|
|
// Salvo intersezione per la faccia.
|
|
auto it = IntersLineMap.find( nF) ;
|
|
if ( it != IntersLineMap.end()) {
|
|
it->second.emplace_back( IntersInnSeg( IntersLinePart[nPart].ptSt, IntersLinePart[nPart].ptEn)) ;
|
|
}
|
|
else {
|
|
IntersLineMap.emplace( nF, IntersInnChain( 1, IntersInnSeg( IntersLinePart[nPart].ptSt, IntersLinePart[nPart].ptEn))) ;
|
|
}
|
|
}
|
|
}
|
|
else if ( nIntType == FPI_ON) {
|
|
INTVECTOR vT ;
|
|
GetAllTriaInFacet( nF, vT) ;
|
|
Vector3d vtNf ;
|
|
GetFacetNormal( nF, vtNf) ;
|
|
for ( auto& nT : vT)
|
|
m_vTria[nT].nTempPart = ( vtNf * plPlane.GetVersN() > 0 ? 2 : -2) ;
|
|
}
|
|
else if ( nIntType == FPI_IN) {
|
|
INTVECTOR vT ;
|
|
GetAllTriaInFacet( nF, vT) ;
|
|
for ( auto& nT : vT)
|
|
m_vTria[nT].nTempPart = 1 ;
|
|
}
|
|
else if ( nIntType == FPI_OUT) {
|
|
INTVECTOR vT ;
|
|
GetAllTriaInFacet( nF, vT) ;
|
|
for ( auto& nT : vT)
|
|
m_vTria[nT].nTempPart = -1 ;
|
|
}
|
|
else
|
|
return false ;
|
|
}
|
|
|
|
// Divido le facce.
|
|
PieceMap NewFacet ;
|
|
SplitFacet( IntersLineMap, NewFacet) ;
|
|
INTERSEDGEMAP EdgeInterLineMap, EdgeEdgeLineMap ;
|
|
RetriangulateFacetPieces( NewFacet, EdgeInterLineMap, EdgeEdgeLineMap) ;
|
|
|
|
// Elimino i triangoli superflui
|
|
for ( int nT = 0 ; nT < GetTriangleSize() ; ++ nT) {
|
|
if ( m_vTria[nT].nTempPart == 0 ||
|
|
m_vTria[nT].nTempPart == -1 ||
|
|
m_vTria[nT].nTempPart == -2 ||
|
|
( ! bSaveOnEq && m_vTria[nT].nTempPart == 2)) {
|
|
RemoveTriangle( nT) ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
|
|
return true ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Risultato : 0=nessuna intersezione, 1=intersezione è un punto, 2=intersezione è un segmento
|
|
static int
|
|
IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3d& vtL2,
|
|
const Triangle3d& trTria, Point3d& ptStSeg, Point3d& ptEnSeg)
|
|
{
|
|
// Assegno tolleranza lineare
|
|
double dTol = EPS_SMALL ;
|
|
// Definisco il piano del rettangolo
|
|
Plane3d plRectanglePlane ;
|
|
if ( ! plRectanglePlane.Set( ptP, vtL1 ^ vtL2))
|
|
return -1 ;
|
|
// Interseco il piano con il triangolo (recupero estremi in ordine inverso per mantenere l'esterno a destra nei loop)
|
|
int nPlTrIntRes = IntersPlaneTria( plRectanglePlane, trTria, ptEnSeg, ptStSeg) ;
|
|
if ( nPlTrIntRes != IntPlaneTriaType::IPTT_YES)
|
|
return 0 ;
|
|
// Limito il segmento col rettangolo
|
|
Vector3d vtSegDir = ptEnSeg - ptStSeg ;
|
|
double dSegLen = vtSegDir.Len() ;
|
|
vtSegDir /= dSegLen ;
|
|
// utilizzo piani ortogonali al rettangolo passanti per i suoi estremi
|
|
Plane3d plTrim1 ; plTrim1.Set( ptP, -vtL1) ;
|
|
Plane3d plTrim2 ; plTrim2.Set( ptP + vtL1, vtL1) ;
|
|
if ( vtSegDir * vtL1 < 0.)
|
|
swap( plTrim1, plTrim2) ;
|
|
Point3d ptInt1 ;
|
|
int nLnPl1IntRes = IntersLinePlane( ptStSeg, vtSegDir, dSegLen, plTrim1, ptInt1, false) ;
|
|
Point3d ptInt2 ;
|
|
int nLnPl2IntRes = IntersLinePlane( ptStSeg, vtSegDir, dSegLen, plTrim2, ptInt2, false) ;
|
|
// Se il segmento giace in uno dei due piani
|
|
if ( ( nLnPl1IntRes == ILPT_NO && nLnPl2IntRes == ILPT_INPLANE) ||
|
|
( nLnPl2IntRes == ILPT_NO && nLnPl1IntRes == ILPT_INPLANE))
|
|
return ( AreSamePointEpsilon( ptStSeg, ptEnSeg, dTol) ? 1 : 2) ;
|
|
// Se non ci sono intersezioni
|
|
if ( nLnPl1IntRes == ILPT_NO && nLnPl2IntRes == ILPT_NO) {
|
|
// se è tra i due piani
|
|
if (( ptStSeg - plTrim1.GetPoint()) * plTrim1.GetVersN() < 0. &&
|
|
( ptStSeg - plTrim2.GetPoint()) * plTrim2.GetVersN() < 0.)
|
|
return ( AreSamePointEpsilon( ptStSeg, ptEnSeg, dTol) ? 1 : 2) ;
|
|
// altrimenti è esterno
|
|
else
|
|
return 0 ;
|
|
}
|
|
// Posizioni parametriche delle intersezioni sul segmento
|
|
double dLen1 = ( ptInt1 - ptStSeg) * vtSegDir ;
|
|
double dLen2 = ( ptInt2 - ptStSeg) * vtSegDir ;
|
|
// Se la prima intersezione supera la fine o la seconda viene prima dell'inizio, non ci sono intersezioni
|
|
if ( dLen1 > dSegLen + EPS_ZERO || dLen2 < -EPS_ZERO)
|
|
return 0 ;
|
|
// Eventuale aggiustamento inizio
|
|
if ( dLen1 > 0.) {
|
|
ptStSeg = ptInt1 ;
|
|
dSegLen -= dLen1 ;
|
|
dLen2 -= dLen1 ;
|
|
}
|
|
// Eventuale aggiustamento fine
|
|
if ( dLen2 < dSegLen) {
|
|
ptEnSeg = ptInt2 ;
|
|
dSegLen = dLen2 ;
|
|
}
|
|
// Assegno il tipo di intersezione
|
|
return ( dSegLen > dTol ? 2 : 1) ;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
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 ;
|
|
|
|
// Recupero il numero originale di triangoli e di facce
|
|
int nTriaOriCnt = GetTriangleCount() ;
|
|
int nFacetOriCnt = GetFacetCount() ;
|
|
|
|
// Approssimo la curva con segmenti
|
|
CurveComposite cvCompo ;
|
|
{
|
|
PolyLine PL ;
|
|
if ( ! cvCurve.ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_STD, PL) || ! cvCompo.FromPolyLine( PL))
|
|
return false ;
|
|
}
|
|
|
|
// Eseguo scalature
|
|
Frame3d frScalingRef;
|
|
frScalingRef.Set( m_vVert[0].ptP, X_AX, Y_AX, Z_AX) ;
|
|
Scale( frScalingRef, CUT_SCALE, CUT_SCALE, CUT_SCALE) ;
|
|
cvCompo.Scale( frScalingRef, CUT_SCALE, CUT_SCALE, CUT_SCALE) ;
|
|
|
|
// 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)) {
|
|
Scale( frScalingRef, 1. / CUT_SCALE, 1. / CUT_SCALE, 1. / CUT_SCALE) ;
|
|
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 se il centro del triangolo cade all'interno della curva
|
|
bool bTriaCenIn = false ;
|
|
{
|
|
// centro proiettato sul piano della curva
|
|
Point3d ptCen = trTria.GetCentroid() ;
|
|
ptCen = ptCen - ( ptCen - ptStart) * vtExtr * vtExtr ;
|
|
// calcolo distanza
|
|
DistPointCurve dstPC( ptCen, cvCompo) ;
|
|
double dDist ; dstPC.GetDist( dDist) ;
|
|
// se maggiore oltre il limite originale
|
|
if ( dDist > CUT_SCALE * EPS_SMALL) {
|
|
int nSide ;
|
|
if ( dstPC.GetSideAtMinDistPoint( 0, vtExtr, nSide))
|
|
bTriaCenIn = ( nSide == MDS_LEFT) ;
|
|
}
|
|
// altrimenti ricalcolo con centro del triangolo spostato all'interno sulla normale
|
|
else {
|
|
Point3d ptCen2 = trTria.GetCentroid() - CUT_SCALE * EPS_SMALL * trTria.GetN() ;
|
|
DistPointCurve dstP2C( ptCen2, cvCompo) ;
|
|
int nSide2 ;
|
|
if ( dstP2C.GetSideAtMinDistPoint( 0, vtExtr, nSide2))
|
|
bTriaCenIn = ( nSide2 == MDS_LEFT && bSaveOnEq) ;
|
|
}
|
|
}
|
|
|
|
// Vettore di catene di punti e flag sulla complanarità del triangolo con uno dei rettangoli
|
|
CHAINVECTOR vChain ;
|
|
bool bTriaOn = false ;
|
|
// Segnalatore di taglio piccolo, punto e vettore per costruire il piano per eseguirlo
|
|
int nSmallCutState = 0 ;
|
|
Point3d ptSmallCutPnt ;
|
|
Vector3d vtSmallCutVec ;
|
|
// 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) ;
|
|
// Se il segmento giace sul piano del triangolo, lo segnalo.
|
|
if ( abs( ( ptSt - trTria.GetCentroid()) * trTria.GetN()) < CUT_SCALE * EPS_SMALL &&
|
|
abs( ( ptEn - trTria.GetCentroid()) * trTria.GetN()) < CUT_SCALE * EPS_SMALL &&
|
|
abs( trTria.GetN() * vtExtr) < EPS_SMALL)
|
|
bTriaOn = true ;
|
|
// 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 == 2) {
|
|
// 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 ;
|
|
CurInters.ptSt = ptSegSt ;
|
|
CurInters.ptEn = ptSegEn ;
|
|
// 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 {
|
|
// Taglio piccolo
|
|
if ( nInt == 1) {
|
|
if ( nSmallCutState == 0)
|
|
nSmallCutState = 1 ;
|
|
else
|
|
nSmallCutState = 2 ;
|
|
ptSmallCutPnt = ptSt ;
|
|
vtSmallCutVec = ptEn - ptSt ;
|
|
}
|
|
bChain = false ;
|
|
}
|
|
pCrv = cvCompo.GetNextCurve() ;
|
|
}
|
|
// Gestisco il taglio piccolo.
|
|
if ( nSmallCutState == 1 && int( vChain.size()) == 0) {
|
|
Plane3d plPlane ;
|
|
plPlane.Set( ptSmallCutPnt, vtSmallCutVec ^ ( vtMax - vtMin)) ;
|
|
for ( int nV = 0 ; nV < 3 ; ++ nV) {
|
|
double dDist = DistPointPlane( m_vVert[m_vTria[nT].nIdVert[nV]].ptP, plPlane) ;
|
|
if ( abs( dDist) < EPS_SMALL) {
|
|
m_vVert[m_vTria[nT].nIdVert[nV]].nTemp = 0 ;
|
|
if ( abs( dDist) > EPS_SMALL)
|
|
m_vVert[m_vTria[nT].nIdVert[nV]].ptP -= plPlane.GetVersN() * dDist ;
|
|
}
|
|
else if ( dDist > 0)
|
|
m_vVert[m_vTria[nT].nIdVert[nV]].nTemp = +1 ;
|
|
else
|
|
m_vVert[m_vTria[nT].nIdVert[nV]].nTemp = -1 ;
|
|
}
|
|
CutTriangleByPlane( nT, plPlane, bSaveOnEq, bModif) ;
|
|
continue ;
|
|
}
|
|
for ( auto itI = vChain.begin() ; itI != vChain.end() ; ) {
|
|
bool bErased = false ;
|
|
auto itJ = itI ;
|
|
++ itJ ;
|
|
for ( ; itJ != vChain.end() && ! bErased ; ) {
|
|
if ( int( itI->size()) == 1 && int( itJ->size()) == 1 &&
|
|
AreSamePointEpsilon( itI->back().ptSt, itJ->back().ptEn, 2 * EPS_SMALL) &&
|
|
AreSamePointEpsilon( itI->back().ptEn, itJ->back().ptSt, 2 * EPS_SMALL)) {
|
|
itJ = vChain.erase( itJ) ;
|
|
bErased = true ;
|
|
}
|
|
else
|
|
++ itJ ;
|
|
}
|
|
if ( bErased) {
|
|
itI = vChain.erase( itI) ;
|
|
bErased = false ;
|
|
}
|
|
else
|
|
++ itI ;
|
|
}
|
|
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 ;
|
|
}
|
|
}
|
|
|
|
// 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
|
|
CHAINVECTOR cvClosedChain ;
|
|
CHAINVECTOR cvOpenChain ;
|
|
for ( int nL = 0 ; nL < int( vChain.size()) ; ++ nL) {
|
|
int nCurLoopLast = max( int(vChain[nL].size()) - 1, 0) ;
|
|
if ( AreSamePointApprox( vChain[nL][0].ptSt, vChain[nL][nCurLoopLast].ptEn) && nCurLoopLast > 0)
|
|
cvClosedChain.emplace_back( vChain[nL]) ;
|
|
else {
|
|
cvOpenChain.emplace_back( vChain[nL]) ;
|
|
}
|
|
}
|
|
for ( auto it = cvClosedChain.begin() ; it != cvClosedChain.end() ; ) {
|
|
if ( int( it->size()) < 3)
|
|
it = cvClosedChain.erase( it) ;
|
|
else
|
|
++ it ;
|
|
}
|
|
// Se più di una catena chiusa oppure catene chiuse e aperte, errore
|
|
if ( cvClosedChain.size() > 1 || ( cvClosedChain.size() > 0 && int( cvOpenChain.size()) > 0)) {
|
|
Scale( frScalingRef, 1. / CUT_SCALE, 1. / CUT_SCALE, 1. / CUT_SCALE) ;
|
|
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)) {
|
|
// 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 ;
|
|
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 ;
|
|
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 ;
|
|
}
|
|
cvOpenChain.resize( nLastOpenLoopN) ;
|
|
}
|
|
// Rimuovo il triangolo corrente
|
|
RemoveTriangle( nT) ;
|
|
// Se il triangolo originale aveva il centro interno alla curva oppure devo tenere le parti
|
|
// di superficie che hanno una parte giacente sul rettangolo della superficie di taglio,
|
|
// aggiungo i nuovi triangoli.
|
|
if ( ! bTriaOn || bSaveOnEq) {
|
|
// 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)) {
|
|
// 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 ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// da eliminare
|
|
else if ( ! bTriaCenIn) {
|
|
RemoveTriangle( nT) ;
|
|
bModif = true ;
|
|
}
|
|
}
|
|
|
|
// Se avvenuta modifica, aggiorno tutto
|
|
if ( bModif) {
|
|
// aggiorno tutto
|
|
if ( ! AdjustVertices() || ! DoCompacting()) {
|
|
Scale( frScalingRef, 1. / CUT_SCALE, 1. / CUT_SCALE, 1. / CUT_SCALE) ;
|
|
return false ;
|
|
}
|
|
}
|
|
|
|
// Ripristino scala originale
|
|
Scale( frScalingRef, 1. / CUT_SCALE, 1. / CUT_SCALE, 1. / CUT_SCALE) ;
|
|
|
|
// se superficie originale a facce, cerco di semplificarle in ogni caso
|
|
if ( nFacetOriCnt < 200 || double( nTriaOriCnt) / nFacetOriCnt > 4) {
|
|
if ( ! SimplifyFacets())
|
|
LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::GeneralizedCut")
|
|
}
|
|
|
|
return true ;
|
|
}
|