Aggiunta funzione FimplifyFacets in TriMesh
This commit is contained in:
+2
-2
@@ -13,8 +13,8 @@
|
||||
|
||||
//--------------------------- Include ----------------------------------------
|
||||
#include "stdafx.h"
|
||||
#include "\EgtDev\Include\EGkBBox3d.h"
|
||||
#include "\EgtDev\Include\EGkFrame3d.h"
|
||||
#include "/EgtDev/Include/EGkBBox3d.h"
|
||||
#include "/EgtDev/Include/EGkFrame3d.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace std ;
|
||||
|
||||
@@ -392,6 +392,7 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
|
||||
<ClCompile Include="SurfFlatRegionBooleans.cpp" />
|
||||
<ClCompile Include="SurfFlatRegionOffset.cpp" />
|
||||
<ClCompile Include="SurfTriMeshBooleans.cpp" />
|
||||
<ClCompile Include="SurfTriMeshUtilities.cpp" />
|
||||
<ClCompile Include="TextureData.cpp" />
|
||||
<ClCompile Include="Tool.cpp" />
|
||||
<ClCompile Include="UserObjDefault.cpp" />
|
||||
|
||||
@@ -453,6 +453,9 @@
|
||||
<ClCompile Include="CDeRectPrismoidTria.cpp">
|
||||
<Filter>File di origine\GeoCollision</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SurfTriMeshUtilities.cpp">
|
||||
<Filter>File di origine\Geo</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
|
||||
+477
@@ -21,6 +21,7 @@
|
||||
#include "GeoConst.h"
|
||||
#include "/EgtDev/Include/EGkPolyLine.h"
|
||||
#include "/EgtDev/Include/EGkPlane3d.h"
|
||||
#include "/EgtDev/Include/EGkPolygon3d.h"
|
||||
#include "/EgtDev/Include/EGnStringUtils.h"
|
||||
|
||||
using namespace std ;
|
||||
@@ -1296,3 +1297,479 @@ PolyLine::Trim( const Plane3d& plPlane, bool bInVsOut)
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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 ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
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 ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
ChangePolyLineStart( const Point3d& ptNewStart, PolyLine& Loop)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
auto itMinDist = LoopList.end() ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDist = itSt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, errore
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Se il punto non sta su un vertice del segmento, lo aggiungo. Altrimenti non devo fare nulla.
|
||||
auto itNewPointSt = LoopList.begin() ;
|
||||
auto itNext = itMinDist ;
|
||||
++ itNext ;
|
||||
bool bOnStart = AreSamePointApprox( ptNewStart, itMinDist->first) ;
|
||||
bool bOnEnd = AreSamePointApprox( ptNewStart, itNext->first) ;
|
||||
itNewPointSt = LoopList.emplace( itNext, ptNewStart, 0) ;
|
||||
// Sposto i punti precedenti in coda.
|
||||
bool bStartRemoved = false ;
|
||||
auto it = LoopList.begin() ;
|
||||
while ( it != itNewPointSt) {
|
||||
if ( bStartRemoved) {
|
||||
LoopList.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
bStartRemoved = true ;
|
||||
it = LoopList.erase( it) ;
|
||||
}
|
||||
// Se il punto inserito non coincide con l'inizio del segmento chiudo il loop.
|
||||
if ( ! bOnStart) {
|
||||
LoopList.emplace_back( ptNewStart, 0) ;
|
||||
// Se coincide con la fine tolgo il punto di fine che diviene inutile.
|
||||
if ( bOnEnd) {
|
||||
//LoopList.erase( itNext) ;
|
||||
auto itNewStart = LoopList.begin() ;
|
||||
++ itNewStart ;
|
||||
LoopList.erase( itNewStart) ;
|
||||
}
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nSegNum 0-based
|
||||
bool
|
||||
PointPositionOnPolyLine( const Point3d& ptPoint, /*const*/ PolyLine& Loop, int& nSegNum, double& dParOnSeg)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
/*const*/ PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
nSegNum = - 1 ;
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
int nS = 0 ;
|
||||
auto itMinDistSt = LoopList.end() ;
|
||||
auto itMinDistEn = itMinDistSt ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn, ++ nS) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
nSegNum = nS ;
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDistSt = itSt ;
|
||||
itMinDistEn = itEn ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, lo segnalo.
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Calcolo il parametro lungo il segmento.
|
||||
Vector3d vtSeg = itMinDistEn->first - itMinDistSt->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
if ( dSegLen < EPS_SMALL)
|
||||
return false ;
|
||||
vtSeg /= dSegLen ;
|
||||
dParOnSeg = Clamp( ( ptPoint - itMinDistSt->first) * vtSeg, 0., dSegLen) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
IsPointInsidePolyLine( const Point3d& ptP, /*const*/ PolyLine& plPoly)
|
||||
{
|
||||
// Se la PolyLine non è chiusa, il punto non può essere interno.
|
||||
if ( ! plPoly.IsClosed())
|
||||
return false ;
|
||||
// Lista dei punti
|
||||
/*const*/ PNTULIST& List = plPoly.GetUPointList() ;
|
||||
// Ciclo sui segmenti della PolyLine per cercarne il tratto più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
Point3d ptMinDist ;
|
||||
auto itMinDistSt = List.end() ;
|
||||
auto itSt = List.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != List.end() && itEn != List.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptP, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
dDistCalc.GetMinDistPoint( ptMinDist) ;
|
||||
itMinDistSt = itSt ;
|
||||
}
|
||||
}
|
||||
// Termine del segmento di minima distanza.
|
||||
auto itMinDistEn = itMinDistSt ;
|
||||
++ itMinDistEn ;
|
||||
// Punto di minima distanza nell'estremo iniziale del segento
|
||||
if ( AreSamePointApprox( ptMinDist, itMinDistSt->first)) {
|
||||
auto itPrevSt = List.begin() ;
|
||||
if ( itMinDistSt == List.begin()) {
|
||||
auto itAuxNext = itPrevSt ;
|
||||
++ ( ++ itAuxNext) ;
|
||||
for ( ; itAuxNext != List.end() ; ++ itPrevSt, ++ itAuxNext)
|
||||
;
|
||||
}
|
||||
else {
|
||||
auto itAuxNext = itPrevSt ;
|
||||
++ itAuxNext ;
|
||||
for (; itAuxNext != itMinDistSt; ++itPrevSt, ++itAuxNext)
|
||||
;
|
||||
}
|
||||
Vector3d vtPrevTan = itMinDistSt->first - itPrevSt->first ;
|
||||
vtPrevTan.Normalize() ;
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtPrevOut = vtPrevTan ^ vtPolyNorm ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
// Caso concavo
|
||||
if ( vtTan * vtPrevOut > 0) {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtPrevOut < 0 || vtTest * vtOut < 0)
|
||||
return true ;
|
||||
}
|
||||
// Caso convesso
|
||||
else {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtPrevOut < 0 && vtTest * vtOut < 0)
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
// Punto di minima distanza nell'estremo finale del segento
|
||||
else if ( AreSamePointApprox( ptMinDist, itMinDistEn->first)) {
|
||||
auto itNextEn = itMinDistEn ;
|
||||
++ itNextEn ;
|
||||
if ( itNextEn == List.end()) {
|
||||
itNextEn = List.begin() ;
|
||||
++ itNextEn ;
|
||||
}
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Vector3d vtNextTan = itNextEn->first - itMinDistEn->first ;
|
||||
vtNextTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
Vector3d vtNextOut = vtNextTan ^ vtPolyNorm ;
|
||||
// Caso concavo
|
||||
if ( vtNextTan * vtOut > 0) {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtOut < 0 || vtTest * vtNextOut < 0)
|
||||
return true ;
|
||||
}
|
||||
// Caso convesso
|
||||
else {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtOut < 0 && vtTest * vtNextOut < 0)
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
// Punto di minima distanza interno al segmeno
|
||||
else {
|
||||
Vector3d vtP = ptP - itMinDistSt->first ;
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
vtP -= ( vtP * vtTan) * vtTan ;
|
||||
if ( vtP * vtOut < - EPS_SMALL)
|
||||
return true ;
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dPointPolyLineDist)
|
||||
{
|
||||
if ( plPoly.GetPointNbr() == 0)
|
||||
return false ;
|
||||
dPointPolyLineDist = DBL_MAX ;
|
||||
Point3d ptSt, ptEn ;
|
||||
bool bContinue = plPoly.GetFirstPoint( ptSt) && plPoly.GetNextPoint( ptEn) ;
|
||||
while ( bContinue) {
|
||||
double dPoinLineDist ;
|
||||
DistPointLine PointLineDistCalc( ptP, ptSt, ptEn) ;
|
||||
PointLineDistCalc.GetDist( dPoinLineDist) ;
|
||||
if ( dPoinLineDist < dPointPolyLineDist)
|
||||
dPointPolyLineDist = dPoinLineDist ;
|
||||
ptSt = ptEn ;
|
||||
bContinue = plPoly.GetNextPoint( ptEn) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Una faccia di una trimesh ha una sola componente connessa.
|
||||
// Si assume che i loop siano corretti e rispettino tale proprietà.
|
||||
bool
|
||||
DistPointFacet( const Point3d& ptP, /*const*/ POLYLINEVECTOR& vPolyVec, double& dPointFacetDist)
|
||||
{
|
||||
// Vedo se la proiezione del punto sul piano della faccia è interno ad essa.
|
||||
Point3d ptPlaneP ;
|
||||
Vector3d vtPlaneN ;
|
||||
double dPointPlaneSignedDist ;
|
||||
Point3d ptProjP ;
|
||||
bool bPointIsInside = true ;
|
||||
for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) && bPointIsInside ; ++ nLoop) {
|
||||
Plane3d plPlane ;
|
||||
double dArea ;
|
||||
if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea))
|
||||
return false ;
|
||||
if ( nLoop == 0) {
|
||||
ptPlaneP = plPlane.GetPoint() ;
|
||||
vtPlaneN = plPlane.GetVersN() ;
|
||||
dPointPlaneSignedDist = ( ptP - ptPlaneP) * vtPlaneN ;
|
||||
ptProjP = ptP + dPointPlaneSignedDist * vtPlaneN ;
|
||||
}
|
||||
if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop]))
|
||||
bPointIsInside = false ;
|
||||
}
|
||||
// Se la proiezione del punto sul piano della faccia è interno, ho finito.
|
||||
// La distanza del punto dalla faccia è pari alla distanza dello stesso dal piano
|
||||
// in cui giace quest'ultima.
|
||||
if ( bPointIsInside) {
|
||||
dPointFacetDist = abs( dPointPlaneSignedDist) ;
|
||||
return bPointIsInside ;
|
||||
}
|
||||
// Calcolo la minima distanza del punto dalle polilinee del contorno.
|
||||
dPointFacetDist = DBL_MAX ;
|
||||
for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) ; ++ nLoop) {
|
||||
double dDist ;
|
||||
if ( DistPointPolyLine( ptP, vPolyVec[nLoop], dDist) && dDist < dPointFacetDist)
|
||||
dPointFacetDist = dDist ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SplitPolyLineAtPoint( const Point3d& ptPoint, /*const*/ PolyLine& Loop, PolyLine& Loop1, PolyLine& Loop2)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
/*const*/ PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
auto itMinDistSt = LoopList.end() ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDistSt = itSt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, lo segnalo.
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Se il punto di stop sta su un vertice non devo aggiungerlo e il
|
||||
// punto di stop sarà uno degli estremi del segmento su cui giace.
|
||||
auto itStop = itMinDistSt ;
|
||||
auto itNext = itMinDistSt ;
|
||||
++ itNext ;
|
||||
if ( AreSamePointApprox( ptPoint, itStop->first))
|
||||
;
|
||||
else if ( AreSamePointApprox( ptPoint, itNext->first))
|
||||
itStop = itNext ;
|
||||
else {
|
||||
itStop = LoopList.emplace( itNext, ptPoint, 0.) ;
|
||||
}
|
||||
// Creo i due loop
|
||||
PNTULIST& LoopList1 = Loop1.GetUPointList() ;
|
||||
PNTULIST& LoopList2 = Loop2.GetUPointList() ;
|
||||
for ( auto it = LoopList.begin() ; it != itStop ; ++ it) {
|
||||
LoopList1.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
LoopList1.emplace_back( itStop->first, itStop->second) ;
|
||||
for ( auto it = itStop ; it != LoopList.end() ; ++ it) {
|
||||
LoopList2.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
AddPolyLineToPolyLine( PolyLine& Poly, PolyLine& PolyToAdd)
|
||||
{
|
||||
// Se la PolyLine a cui devo aggiungere l'altra è chiusa, non posso aggiungere nulla.
|
||||
if ( Poly.IsClosed())
|
||||
return false ;
|
||||
// Se la PolyLina che devo aggiungere è vuota, ho finito.
|
||||
PNTULIST& PolyToAddList = PolyToAdd.GetUPointList() ;
|
||||
if ( int( PolyToAddList.size()) == 0)
|
||||
return true ;
|
||||
// Se Poly non è vuota e la sua fine non coincide con l'inizio di PolyToAdd, non è possibile aggiungere nulla.
|
||||
Point3d ptLast ;
|
||||
Poly.GetLastPoint( ptLast) ;
|
||||
auto it = PolyToAddList.begin() ;
|
||||
if ( Poly.GetPointNbr() != 0 && ! AreSamePointEpsilon( it->first, ptLast, 10 * EPS_SMALL))
|
||||
return false ;
|
||||
/*if ( Poly.GetPointNbr() == 0)
|
||||
Poly.AddUPoint( 0., it->first) ;
|
||||
++ it ;*/
|
||||
// Aggiungo i punti.
|
||||
for ( ; it != PolyToAddList.end() ; ++ it) {
|
||||
Poly.AddUPoint( 0., it->first) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
@@ -3716,6 +3716,8 @@ SurfTriMesh::Cut( const Plane3d& plPlane, bool bSaveOnEq)
|
||||
return false ;
|
||||
}
|
||||
|
||||
SimplifyFacets( 500) ;
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
|
||||
@@ -397,6 +397,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
|
||||
bool RetriangulateFacetPieces( const PieceMap& NewFacet,
|
||||
const INTERSEDGEMAP& EdgeInterLineMap,
|
||||
const INTERSEDGEMAP& EdgeEdgeLineMap) ;
|
||||
bool SimplifyFacets( double dMaxEdgeLen) ;
|
||||
bool EdgeInteriorContactManager( const SurfTriMesh& OthSurf,
|
||||
const INTERSCHAINMAP& InterInterLineMap,
|
||||
const INTERSEDGEMAP& EdgeInterLineMap) ;
|
||||
|
||||
@@ -124,118 +124,6 @@ IntersRectangleTriangle( const Point3d& ptP, const Vector3d& vtL1, const Vector3
|
||||
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)
|
||||
@@ -2826,370 +2714,6 @@ SurfTriMesh::IntersFacetFacet( const SurfFlatRegion& RegionA, const PolyLine& Ex
|
||||
// return bOk ;
|
||||
//}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
ChangePolyLineStart( const Point3d& ptNewStart, PolyLine& Loop)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
auto itMinDist = LoopList.end() ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDist = itSt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, errore
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Se il punto non sta su un vertice del segmento, lo aggiungo. Altrimenti non devo fare nulla.
|
||||
auto itNewPointSt = LoopList.begin() ;
|
||||
auto itNext = itMinDist ;
|
||||
++ itNext ;
|
||||
bool bOnStart = AreSamePointApprox( ptNewStart, itMinDist->first) ;
|
||||
bool bOnEnd = AreSamePointApprox( ptNewStart, itNext->first) ;
|
||||
itNewPointSt = LoopList.emplace( itNext, ptNewStart, 0) ;
|
||||
// Sposto i punti precedenti in coda.
|
||||
bool bStartRemoved = false ;
|
||||
auto it = LoopList.begin() ;
|
||||
while ( it != itNewPointSt) {
|
||||
if ( bStartRemoved) {
|
||||
LoopList.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
bStartRemoved = true ;
|
||||
it = LoopList.erase( it) ;
|
||||
}
|
||||
// Se il punto inserito non coincide con l'inizio del segmento chiudo il loop.
|
||||
if ( ! bOnStart) {
|
||||
LoopList.emplace_back( ptNewStart, 0) ;
|
||||
// Se coincide con la fine tolgo il punto di fine che diviene inutile.
|
||||
if ( bOnEnd) {
|
||||
//LoopList.erase( itNext) ;
|
||||
auto itNewStart = LoopList.begin() ;
|
||||
++ itNewStart ;
|
||||
LoopList.erase( itNewStart) ;
|
||||
}
|
||||
}
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// nSegNum 0-based
|
||||
static bool
|
||||
PointPositionOnPolyLine( const Point3d& ptPoint, /*const*/ PolyLine& Loop, int& nSegNum, double& dParOnSeg)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
/*const*/ PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
nSegNum = - 1 ;
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
int nS = 0 ;
|
||||
auto itMinDistSt = LoopList.end() ;
|
||||
auto itMinDistEn = itMinDistSt ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn, ++ nS) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
nSegNum = nS ;
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDistSt = itSt ;
|
||||
itMinDistEn = itEn ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, lo segnalo.
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Calcolo il parametro lungo il segmento.
|
||||
Vector3d vtSeg = itMinDistEn->first - itMinDistSt->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
if ( dSegLen < EPS_SMALL)
|
||||
return false ;
|
||||
vtSeg /= dSegLen ;
|
||||
dParOnSeg = Clamp( ( ptPoint - itMinDistSt->first) * vtSeg, 0., dSegLen) ;
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
IsPointInsidePolyLine( const Point3d& ptP, /*const*/ PolyLine& plPoly)
|
||||
{
|
||||
// Se la PolyLine non è chiusa, il punto non può essere interno.
|
||||
if ( ! plPoly.IsClosed())
|
||||
return false ;
|
||||
// Lista dei punti
|
||||
/*const*/ PNTULIST& List = plPoly.GetUPointList() ;
|
||||
// Ciclo sui segmenti della PolyLine per cercarne il tratto più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
Point3d ptMinDist ;
|
||||
auto itMinDistSt = List.end() ;
|
||||
auto itSt = List.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != List.end() && itEn != List.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptP, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
dDistCalc.GetMinDistPoint( ptMinDist) ;
|
||||
itMinDistSt = itSt ;
|
||||
}
|
||||
}
|
||||
// Termine del segmento di minima distanza.
|
||||
auto itMinDistEn = itMinDistSt ;
|
||||
++ itMinDistEn ;
|
||||
// Punto di minima distanza nell'estremo iniziale del segento
|
||||
if ( AreSamePointApprox( ptMinDist, itMinDistSt->first)) {
|
||||
auto itPrevSt = List.begin() ;
|
||||
if ( itMinDistSt == List.begin()) {
|
||||
auto itAuxNext = itPrevSt ;
|
||||
++ ( ++ itAuxNext) ;
|
||||
for ( ; itAuxNext != List.end() ; ++ itPrevSt, ++ itAuxNext)
|
||||
;
|
||||
}
|
||||
else {
|
||||
auto itAuxNext = itPrevSt ;
|
||||
++ itAuxNext ;
|
||||
for (; itAuxNext != itMinDistSt; ++itPrevSt, ++itAuxNext)
|
||||
;
|
||||
}
|
||||
Vector3d vtPrevTan = itMinDistSt->first - itPrevSt->first ;
|
||||
vtPrevTan.Normalize() ;
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtPrevOut = vtPrevTan ^ vtPolyNorm ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
// Caso concavo
|
||||
if ( vtTan * vtPrevOut > 0) {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtPrevOut < 0 || vtTest * vtOut < 0)
|
||||
return true ;
|
||||
}
|
||||
// Caso convesso
|
||||
else {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtPrevOut < 0 && vtTest * vtOut < 0)
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
// Punto di minima distanza nell'estremo finale del segento
|
||||
else if ( AreSamePointApprox( ptMinDist, itMinDistEn->first)) {
|
||||
auto itNextEn = itMinDistEn ;
|
||||
++ itNextEn ;
|
||||
if ( itNextEn == List.end()) {
|
||||
itNextEn = List.begin() ;
|
||||
++ itNextEn ;
|
||||
}
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Vector3d vtNextTan = itNextEn->first - itMinDistEn->first ;
|
||||
vtNextTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
Vector3d vtNextOut = vtNextTan ^ vtPolyNorm ;
|
||||
// Caso concavo
|
||||
if ( vtNextTan * vtOut > 0) {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtOut < 0 || vtTest * vtNextOut < 0)
|
||||
return true ;
|
||||
}
|
||||
// Caso convesso
|
||||
else {
|
||||
Vector3d vtTest = ptP - ptMinDist ;
|
||||
if ( vtTest * vtOut < 0 && vtTest * vtNextOut < 0)
|
||||
return true ;
|
||||
}
|
||||
}
|
||||
// Punto di minima distanza interno al segmeno
|
||||
else {
|
||||
Vector3d vtP = ptP - itMinDistSt->first ;
|
||||
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
|
||||
vtTan.Normalize() ;
|
||||
Polygon3d AuxPolygon ;
|
||||
AuxPolygon.FromPolyLine( plPoly) ;
|
||||
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
|
||||
Vector3d vtOut = vtTan ^ vtPolyNorm ;
|
||||
vtP -= ( vtP * vtTan) * vtTan ;
|
||||
if ( vtP * vtOut < - EPS_SMALL)
|
||||
return true ;
|
||||
}
|
||||
return false ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dPointPolyLineDist)
|
||||
{
|
||||
if ( plPoly.GetPointNbr() == 0)
|
||||
return false ;
|
||||
dPointPolyLineDist = DBL_MAX ;
|
||||
Point3d ptSt, ptEn ;
|
||||
bool bContinue = plPoly.GetFirstPoint( ptSt) && plPoly.GetNextPoint( ptEn) ;
|
||||
while ( bContinue) {
|
||||
double dPoinLineDist ;
|
||||
DistPointLine PointLineDistCalc( ptP, ptSt, ptEn) ;
|
||||
PointLineDistCalc.GetDist( dPoinLineDist) ;
|
||||
if ( dPoinLineDist < dPointPolyLineDist)
|
||||
dPointPolyLineDist = dPoinLineDist ;
|
||||
ptSt = ptEn ;
|
||||
bContinue = plPoly.GetNextPoint( ptEn) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Una faccia di una trimesh ha una sola componente connessa.
|
||||
// Si assume che i loop siano corretti e rispettino tale proprietà.
|
||||
bool
|
||||
DistPointFacet( const Point3d& ptP, /*const*/ POLYLINEVECTOR& vPolyVec, double& dPointFacetDist)
|
||||
{
|
||||
// Vedo se la proiezione del punto sul piano della faccia è interno ad essa.
|
||||
Point3d ptPlaneP ;
|
||||
Vector3d vtPlaneN ;
|
||||
double dPointPlaneSignedDist ;
|
||||
Point3d ptProjP ;
|
||||
bool bPointIsInside = true ;
|
||||
for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) && bPointIsInside ; ++ nLoop) {
|
||||
Plane3d plPlane ;
|
||||
double dArea ;
|
||||
if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea))
|
||||
return false ;
|
||||
if ( nLoop == 0) {
|
||||
ptPlaneP = plPlane.GetPoint() ;
|
||||
vtPlaneN = plPlane.GetVersN() ;
|
||||
dPointPlaneSignedDist = ( ptP - ptPlaneP) * vtPlaneN ;
|
||||
ptProjP = ptP + dPointPlaneSignedDist * vtPlaneN ;
|
||||
}
|
||||
if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop]))
|
||||
bPointIsInside = false ;
|
||||
}
|
||||
// Se la proiezione del punto sul piano della faccia è interno, ho finito.
|
||||
// La distanza del punto dalla faccia è pari alla distanza dello stesso dal piano
|
||||
// in cui giace quest'ultima.
|
||||
if ( bPointIsInside) {
|
||||
dPointFacetDist = abs( dPointPlaneSignedDist) ;
|
||||
return bPointIsInside ;
|
||||
}
|
||||
// Calcolo la minima distanza del punto dalle polilinee del contorno.
|
||||
dPointFacetDist = DBL_MAX ;
|
||||
for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) ; ++ nLoop) {
|
||||
double dDist ;
|
||||
if ( DistPointPolyLine( ptP, vPolyVec[nLoop], dDist) && dDist < dPointFacetDist)
|
||||
dPointFacetDist = dDist ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
SplitPolyLineAtPoint( const Point3d& ptPoint, /*const*/ PolyLine& Loop, PolyLine& Loop1, PolyLine& Loop2)
|
||||
{
|
||||
// Rinomino la lista di punti della PolyLine.
|
||||
/*const*/ PNTULIST& LoopList = Loop.GetUPointList() ;
|
||||
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
|
||||
double dMinSqDist = DBL_MAX ;
|
||||
auto itMinDistSt = LoopList.end() ;
|
||||
auto itSt = LoopList.begin() ;
|
||||
auto itEn = itSt ;
|
||||
++ itEn ;
|
||||
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) {
|
||||
// Estremi del segmento corrente del loop
|
||||
Point3d ptSegSt = itSt->first ;
|
||||
Point3d ptSegEn = itEn->first ;
|
||||
// Distanza del punto dal segmento del loop
|
||||
DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ;
|
||||
double dSqDist ;
|
||||
dDistCalc.GetSqDist( dSqDist) ;
|
||||
if ( dSqDist < dMinSqDist) {
|
||||
dMinSqDist = dSqDist ;
|
||||
itMinDistSt = itSt ;
|
||||
}
|
||||
}
|
||||
// Se il punto non sta sul loop, lo segnalo.
|
||||
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
|
||||
return false ;
|
||||
// Se il punto di stop sta su un vertice non devo aggiungerlo e il
|
||||
// punto di stop sarà uno degli estremi del segmento su cui giace.
|
||||
auto itStop = itMinDistSt ;
|
||||
auto itNext = itMinDistSt ;
|
||||
++ itNext ;
|
||||
if ( AreSamePointApprox( ptPoint, itStop->first))
|
||||
;
|
||||
else if ( AreSamePointApprox( ptPoint, itNext->first))
|
||||
itStop = itNext ;
|
||||
else {
|
||||
itStop = LoopList.emplace( itNext, ptPoint, 0.) ;
|
||||
}
|
||||
// Creo i due loop
|
||||
PNTULIST& LoopList1 = Loop1.GetUPointList() ;
|
||||
PNTULIST& LoopList2 = Loop2.GetUPointList() ;
|
||||
for ( auto it = LoopList.begin() ; it != itStop ; ++ it) {
|
||||
LoopList1.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
LoopList1.emplace_back( itStop->first, itStop->second) ;
|
||||
for ( auto it = itStop ; it != LoopList.end() ; ++ it) {
|
||||
LoopList2.emplace_back( it->first, it->second) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
static bool
|
||||
AddPolyLineToPolyLine( PolyLine& Poly, PolyLine& PolyToAdd)
|
||||
{
|
||||
// Se la PolyLine a cui devo aggiungere l'altra è chiusa, non posso aggiungere nulla.
|
||||
if ( Poly.IsClosed())
|
||||
return false ;
|
||||
// Se la PolyLina che devo aggiungere è vuota, ho finito.
|
||||
PNTULIST& PolyToAddList = PolyToAdd.GetUPointList() ;
|
||||
if ( int( PolyToAddList.size()) == 0)
|
||||
return true ;
|
||||
// Se Poly non è vuota e la sua fine non coincide con l'inizio di PolyToAdd, non è possibile aggiungere nulla.
|
||||
Point3d ptLast ;
|
||||
Poly.GetLastPoint( ptLast) ;
|
||||
auto it = PolyToAddList.begin() ;
|
||||
if ( Poly.GetPointNbr() != 0 && ! AreSamePointEpsilon( it->first, ptLast, 10 * EPS_SMALL))
|
||||
return false ;
|
||||
/*if ( Poly.GetPointNbr() == 0)
|
||||
Poly.AddUPoint( 0., it->first) ;
|
||||
++ it ;*/
|
||||
// Aggiungo i punti.
|
||||
for ( ; it != PolyToAddList.end() ; ++ it) {
|
||||
Poly.AddUPoint( 0., it->first) ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
struct PositionOnPolyLine {
|
||||
int nIndexInVec ;
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// EgalTech 2015-2015
|
||||
//----------------------------------------------------------------------------
|
||||
// File : SurfTriMeshUtilities.cpp Data : 25.10.21 Versione :
|
||||
// Contenuto : Implementazione della classe Superfici TriMesh.
|
||||
//
|
||||
//
|
||||
//
|
||||
// Modifiche : 25.10.21 LM Creazione modulo.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//--------------------------- Include ----------------------------------------
|
||||
#include "stdafx.h"
|
||||
#include "Triangulate.h"
|
||||
#include "SurfTriMesh.h"
|
||||
#include "DistPointLine.h"
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
SurfTriMesh::SimplifyFacets( double dMaxEdgeLen)
|
||||
{
|
||||
// Se la lunghezza massima del lato del triangolo sul bordo della faccia è nulla, ho finito.
|
||||
if ( dMaxEdgeLen < EPS_SMALL)
|
||||
return true ;
|
||||
|
||||
// Le superfici devono essere valide.
|
||||
if ( ! IsValid())
|
||||
return false ;
|
||||
|
||||
// Verifico la definizione delle facce.
|
||||
VerifyFaceting() ;
|
||||
|
||||
// Ciclo sulle facce delle mesh.
|
||||
unordered_map<int, POLYLINEVECTOR> FacetMap ;
|
||||
int nFacetNum = GetFacetCount() ;
|
||||
for ( int nF = 0 ; nF < nFacetNum ; ++ nF) {
|
||||
bool bFacetToRetriangulate = false ;
|
||||
// Recupero i loop della faccia.
|
||||
POLYLINEVECTOR LoopVec ;
|
||||
GetFacetLoops( nF, LoopVec) ;
|
||||
// Recupero le adiacenze della faccia.
|
||||
INTMATRIX vAdj ;
|
||||
GetFacetAdjacencies( nF, vAdj) ;
|
||||
// Ciclo sui loop della faccia.
|
||||
for ( int nL = 0 ; nL < int( LoopVec.size()) ; ++ nL) {
|
||||
// Lista dei punti del loop.
|
||||
PNTULIST& PointList = LoopVec[nL].GetUPointList() ;
|
||||
|
||||
// Mi assicuro che il punto finale non sia all'interno di un segmento.
|
||||
auto itFirst = PointList.begin() ;
|
||||
int nNewStartPos = 0 ;
|
||||
for ( auto it = itFirst ; it != PointList.end() ; ++ it, ++ nNewStartPos) {
|
||||
if ( itFirst->second != it->second) {
|
||||
//ChangePolyLineStart( it->first, LoopVec[nL]) ;
|
||||
{
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
PointList.pop_back() ;
|
||||
// sposto la metà iniziale dei punti alla fine
|
||||
for ( int i = 0 ; i < nNewStartPos ; ++ i)
|
||||
PointList.splice( PointList.end(), PointList, PointList.begin()) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
PointList.push_back( PointList.front()) ;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
else if ( itFirst->second == - 1 && it != itFirst) {
|
||||
// Valuto se i punti compresi fra gli estremi sono allinati.
|
||||
bool bAreAlligned = true ;
|
||||
auto itNextToLast = itFirst ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itFirst->first, it->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
// I punti sono allineati.
|
||||
if ( bAreAlligned) {
|
||||
// Valuto se includendo anche il punto successivo non ci sarebbe più allineamento,
|
||||
// ovvero avrei trovato un insieme massimale di punti allineati.
|
||||
auto itNextToCurr = it ;
|
||||
++ itNextToCurr ;
|
||||
// Se il punto corrente è l'ultimo, ho trovato un insieme massimale di punti allineati.
|
||||
if ( itNextToCurr != PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itFirst->first, itNextToCurr->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
}
|
||||
// Se ho trovato un insieme massimale di punti allineati li ridistribuisco,
|
||||
// altrimenti procedo per includere il punto successivo nell'insieme.
|
||||
if ( ! bAreAlligned || itNextToCurr == PointList.end()) {
|
||||
//ChangePolyLineStart( it->first, LoopVec[nL]) ;
|
||||
{
|
||||
// cancello ultimo punto ( coincide con primo)
|
||||
PointList.pop_back() ;
|
||||
// sposto la metà iniziale dei punti alla fine
|
||||
for ( int i = 0 ; i < nNewStartPos ; ++ i)
|
||||
PointList.splice( PointList.end(), PointList, PointList.begin()) ;
|
||||
// aggiungo punto finale come copia dell'iniziale
|
||||
PointList.push_back( PointList.front()) ;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ciclo sui punti del loop.
|
||||
auto itLast = PointList.begin() ;
|
||||
for ( auto it = itLast ; it != PointList.end() ; ++ it) {
|
||||
// Dal punto corrente spicca un segmento adiacente a una nuova faccia.
|
||||
if ( itLast->second != it->second) {
|
||||
// Elimino punti interni.
|
||||
auto itNextToLast = itLast ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
// Versore direzione del segmento e sua lunghezza.
|
||||
Vector3d vtSeg = it->first - itLast->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
vtSeg /= dSegLen ;
|
||||
// Calcolo numero dei punti da inserire.
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepNum = ( dRatio < 1 + EPS_SMALL ? int( dRatio) : int( dRatio) + 1) ;
|
||||
// Aggiungo i nuovi punti.
|
||||
double dMyLen = dSegLen / nStepNum ;
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepNum ; ++ nP) {
|
||||
itAdd = PointList.insert( itAdd, POINTU( it->first - nP * dMyLen * vtSeg, itLast->second)) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
itLast = it ;
|
||||
}
|
||||
// Possono essere due segmenti liberi non allineati.
|
||||
else if ( itLast->second == - 1 && it != itLast) {
|
||||
// Valuto se i punti compresi fra gli estremi sono allinati.
|
||||
bool bAreAlligned = true ;
|
||||
auto itNextToLast = itLast ;
|
||||
++ itNextToLast ;
|
||||
for ( auto itInn = itNextToLast ; itInn != it && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, it->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
// I punti sono allineati.
|
||||
if ( bAreAlligned) {
|
||||
// Valuto se includendo anche il punto successivo non ci sarebbe più allineamento,
|
||||
// ovvero avrei trovato un insieme massimale di punti allineati.
|
||||
auto itNextToCurr = it ;
|
||||
++ itNextToCurr ;
|
||||
// Se il punto corrente è l'ultimo, ho trovato un insieme massimale di punti allineati.
|
||||
if ( itNextToCurr != PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != itNextToCurr && bAreAlligned ; ++ itInn) {
|
||||
DistPointLine PointLineDistCalc( itInn->first, itLast->first, itNextToCurr->first, false) ;
|
||||
double dDist ;
|
||||
PointLineDistCalc.GetDist( dDist) ;
|
||||
bAreAlligned = bAreAlligned && dDist < EPS_SMALL ;
|
||||
}
|
||||
}
|
||||
// Se ho trovato un insieme massimale di punti allineati li ridistribuisco,
|
||||
// altrimenti procedo per includere il punto successivo nell'insieme.
|
||||
if ( ! bAreAlligned || itNextToCurr == PointList.end()) {
|
||||
for ( auto itInn = itNextToLast ; itInn != it ; ) {
|
||||
itInn = PointList.erase( itInn) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
// Versore direzione del segmento e sua lunghezza.
|
||||
Vector3d vtSeg = it->first - itLast->first ;
|
||||
double dSegLen = vtSeg.Len() ;
|
||||
vtSeg /= dSegLen ;
|
||||
// Calcolo numero dei punti da inserire.
|
||||
double dRatio = dSegLen / dMaxEdgeLen ;
|
||||
int nStepNum = ( dRatio < 1 + EPS_SMALL ? int( dRatio) : int( dRatio) + 1) ;
|
||||
// Aggiungo i nuovi punti.
|
||||
double dMyLen = dSegLen / nStepNum ;
|
||||
auto itAdd = it ;
|
||||
for ( int nP = 1 ; nP < nStepNum ; ++ nP) {
|
||||
itAdd = PointList.insert( itAdd, POINTU( it->first - nP * dMyLen * vtSeg, itLast->second)) ;
|
||||
bFacetToRetriangulate = true ;
|
||||
}
|
||||
itLast = it ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( bFacetToRetriangulate) {
|
||||
FacetMap.emplace( nF, LoopVec) ;
|
||||
}
|
||||
}
|
||||
|
||||
// Ciclo sulle facce da ritriangolare per eliminare i triangoli.
|
||||
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
|
||||
// Cancello i triangoli della faccia.
|
||||
INTVECTOR vFacetTria ;
|
||||
GetAllTriaInFacet( itF->first, vFacetTria) ;
|
||||
for ( int& nT : vFacetTria)
|
||||
RemoveTriangle( nT) ;
|
||||
}
|
||||
// Ritriangolo le facce.
|
||||
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
|
||||
// Ritriangolo la faccia.
|
||||
PNTVECTOR vPt ;
|
||||
INTVECTOR vTr ;
|
||||
if ( Triangulate().Make( itF->second, vPt, vTr)) {
|
||||
// Inserisco i nuovi triangoli.
|
||||
for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) {
|
||||
int nNewTriaVertId[3] = { vTr[n], vTr[n + 1], vTr[n + 2] } ;
|
||||
int nNewId[3] = { AddVertex(vPt[nNewTriaVertId[0]]),
|
||||
AddVertex(vPt[nNewTriaVertId[1]]),
|
||||
AddVertex(vPt[nNewTriaVertId[2]]) } ;
|
||||
// Il colore passato nel secondo parametro è definito perché il vettore delle facce ha ancora salvato l'indice di un suo triangolo e
|
||||
// il triangolo è cancellato semplicente assegnadno la costante apposita VT_DEL (-2) a nIdVert[0]; ma il suo colore resta definito.
|
||||
int nNewTriaNum = AddTriangle( nNewId, m_vTria[m_vFacet[itF->first]].nTFlag) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AdjustVertices() && DoCompacting() ;
|
||||
}
|
||||
Reference in New Issue
Block a user