EgtGeomKernel 2.3k1 :

- corretto offset di segmenti di retta singoli con estrusione
- modifiche per calcolo taglio superfici TriMesh
- modifiche a funzione SimplifyFacets di superfici TriMesh.
This commit is contained in:
DarioS
2021-11-02 08:19:11 +01:00
parent 6deff01b6e
commit 76d009ddbe
7 changed files with 680 additions and 1236 deletions
+178 -437
View File
@@ -21,8 +21,8 @@
#include "GeoConst.h"
#include "/EgtDev/Include/EGkPolyLine.h"
#include "/EgtDev/Include/EGkPlane3d.h"
#include "/EgtDev/Include/EGkPolygon3d.h"
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/EgtNumUtils.h"
using namespace std ;
@@ -830,12 +830,11 @@ PolyLine::MyChangeStart( int nPos)
// solo per polilinee chiuse
if ( ! IsClosed())
return false ;
// cancello ultimo punto ( coincide con primo)
// cancello l'ultimo punto ( coincide con il primo)
m_lUPoints.pop_back() ;
// sposto la metà iniziale dei punti alla fine
for ( int i = 0 ; i < nPos ; ++ i)
m_lUPoints.splice( m_lUPoints.end(), m_lUPoints, m_lUPoints.begin()) ;
// aggiungo punto finale come copia dell'iniziale
// sposto la parte iniziale dei punti alla fine
m_lUPoints.splice( m_lUPoints.end(), m_lUPoints, m_lUPoints.begin(), next( m_lUPoints.begin(), nPos)) ;
// aggiungo il punto finale come copia dell'iniziale
m_lUPoints.push_back( m_lUPoints.front()) ;
return true ;
@@ -1298,478 +1297,220 @@ PolyLine::Trim( const Plane3d& plPlane, bool bInVsOut)
return true ;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
bool
ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop)
DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dDist)
{
// Cerco il tratto del loop chiuso più vicino al punto
int nMinSeg = - 1 ;
double dMinSqDinst = DBL_MAX ;
for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) {
// Estremi del segmento corrente del loop
Point3d ptSegSt = Loop[nPt] ;
Point3d ptSegEn = Loop[( nPt + 1) % int( Loop.size())] ;
// Distanza del punto dal segmento del loop
DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ;
double dSqDist ;
dDistCalc.GetSqDist( dSqDist) ;
if ( dSqDist < dMinSqDinst) {
dMinSqDinst = dSqDist ;
nMinSeg = nPt ;
}
}
// Se il punto non sta sul loop, errore
if ( dMinSqDinst > SQ_EPS_SMALL)
// La polilinea deve contenere almeno due punti
if ( plPoly.GetPointNbr() < 2)
return false ;
// Verifico che il punto stia su un vertice, in tal caso non devo fare nulla
bool bOnStart = AreSamePointApprox( Loop[nMinSeg], ptNewStart) ;
bool bOnEnd = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptNewStart) ;
if ( bOnStart || bOnEnd) {
if ( bOnEnd) {
++ nMinSeg ;
if ( nMinSeg % int( Loop.size()) == 0)
return true ;
}
PNTVECTOR vTempVec ;
for ( int nPt = 0 ; nPt < nMinSeg ; ++ nPt)
vTempVec.emplace_back( Loop[nPt]) ;
int nSize = int( Loop.size()) ;
for ( int nPt = 0 ; nPt < nSize - nMinSeg ; ++ nPt) {
Loop[nPt] = Loop[nPt + nMinSeg] ;
}
for ( int nPt = 0 ; nPt < int( vTempVec.size()) ; ++ nPt) {
Loop[nPt + nSize - nMinSeg] = vTempVec[nPt] ;
}
return true ;
}
// Ridimensiono il loop
Loop.resize( Loop.size() + 1) ;
// Copio i primi punti
PNTVECTOR LoopTemp ;
for ( int nPt = 0 ; nPt <= nMinSeg ; ++ nPt)
LoopTemp.emplace_back( Loop[nPt]) ;
// Aggiungo il nuovo punto all'inizio
Loop[0] = ptNewStart ;
// Sposto gli ultimi in testa
int nLastPointNum = int( Loop.size()) - 1 - nMinSeg ;
for ( int nPt = 1 ; nPt <= nLastPointNum ; ++ nPt) {
Loop[nPt] = Loop[nPt + nMinSeg] ;
}
// Porto i primi in fondo
for ( int nPt = 0 ; nPt < int( LoopTemp.size()) ; ++ nPt) {
Loop[nPt + nLastPointNum] = LoopTemp[nPt] ;
// Ciclo sui punti della polilinea
dDist = INFINITO ;
Point3d ptStart, ptEnd ;
plPoly.GetFirstPoint( ptStart) ;
while ( plPoly.GetNextPoint( ptEnd)) {
// distanza del punto dal segmento della polilinea
DistPointLine PointLineDistCalc( ptP, ptStart, ptEnd) ;
double dPlDist ;
PointLineDistCalc.GetDist( dPlDist) ;
if ( dPlDist < dDist)
dDist = dPlDist ;
// assegno nuovo inizio
ptStart = ptEnd ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2)
IsPointInsidePolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler)
{
// Cerco il tratto del loop chiuso più vicino al punto
int nMinSeg = -1 ;
double dMinSqDinst = DBL_MAX ;
for ( int nPt = 0 ; nPt < int( Loop.size()) ; ++ nPt) {
// Estremi del segmento corrente del loop
Point3d ptSegSt = Loop[nPt] ;
Point3d ptSegEn = Loop[( nPt + 1) % int(Loop.size())] ;
// Distanza del punto dal segmento del loop
DistPointLine dDistCalc( ptStop, ptSegSt, ptSegEn) ;
double dSqDist ;
dDistCalc.GetSqDist( dSqDist) ;
if ( dSqDist < dMinSqDinst) {
dMinSqDinst = dSqDist ;
nMinSeg = nPt ;
}
}
// Se il punto non sta sul loop, errore
if ( dMinSqDinst > SQ_EPS_SMALL)
// La polilinea deve essere chiusa e piatta, altrimenti non ha senso parlare di interno
Plane3d plPlane ;
double dArea ;
if ( ! plPoly.IsClosedAndFlat( plPlane, dArea, 10 * EPS_SMALL))
return false ;
// Verifico che il punto stia su un vertice, in tal caso non devo aggiungerlo
bool bFirst = AreSamePointApprox( Loop[nMinSeg], ptStop) ;
bool bLast = AreSamePointApprox( Loop[( nMinSeg + 1) % int( Loop.size())], ptStop) ;
// Se il punto è sul vertice finale del segmento, aggiungo il vertice alla lista da inglobare al primo loop
if ( bLast)
++ nMinSeg ;
// Inglobo fino a nSeg nel primo loop
for ( int nPt = 0 ; nPt <= nMinSeg ; ++ nPt)
Loop1.emplace_back( Loop[nPt]) ;
// Se il punto è interno al segmento, lo inglobo in entrambi i loop
if ( ! ( bFirst || bLast)) {
Loop1.emplace_back( ptStop) ;
Loop2.emplace_back( ptStop) ;
}
else {
Loop2.emplace_back( Loop[nMinSeg]) ;
}
// Inglobo gli ultimi vertici in Loop2
for ( int nPt = nMinSeg + 1 ; nPt < int( Loop.size()) ; ++ nPt)
Loop2.emplace_back( Loop[nPt]) ;
Loop2.emplace_back( Loop[0]) ;
return true ;
}
//----------------------------------------------------------------------------
bool
ChangePolyLineStart( const Point3d& ptNewStart, PolyLine& Loop)
{
// Rinomino la lista di punti della PolyLine.
PNTULIST& LoopList = Loop.GetUPointList() ;
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
double dMinSqDist = DBL_MAX ;
auto itMinDist = LoopList.end() ;
auto itSt = LoopList.begin() ;
auto itEn = itSt ;
++ itEn ;
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) {
// Estremi del segmento corrente del loop
Point3d ptSegSt = itSt->first ;
Point3d ptSegEn = itEn->first ;
// Distanza del punto dal segmento del loop
DistPointLine dDistCalc( ptNewStart, ptSegSt, ptSegEn) ;
double dSqDist ;
dDistCalc.GetSqDist( dSqDist) ;
if ( dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
itMinDist = itSt ;
}
}
// Se il punto non sta sul loop, errore
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
// Impongo l'orientamento CCW
if ( dArea < 0)
plPlane.Invert() ;
// Il punto deve giacere nel piano della polilinea
if ( ! PointInPlaneEpsilon( ptP, plPlane, 10 * EPS_SMALL))
return false ;
// Se il punto non sta su un vertice del segmento, lo aggiungo. Altrimenti non devo fare nulla.
auto itNewPointSt = LoopList.begin() ;
auto itNext = itMinDist ;
++ itNext ;
bool bOnStart = AreSamePointApprox( ptNewStart, itMinDist->first) ;
bool bOnEnd = AreSamePointApprox( ptNewStart, itNext->first) ;
itNewPointSt = LoopList.emplace( itNext, ptNewStart, 0) ;
// Sposto i punti precedenti in coda.
bool bStartRemoved = false ;
auto it = LoopList.begin() ;
while ( it != itNewPointSt) {
if ( bStartRemoved) {
LoopList.emplace_back( it->first, it->second) ;
}
bStartRemoved = true ;
it = LoopList.erase( it) ;
}
// Se il punto inserito non coincide con l'inizio del segmento chiudo il loop.
if ( ! bOnStart) {
LoopList.emplace_back( ptNewStart, 0) ;
// Se coincide con la fine tolgo il punto di fine che diviene inutile.
if ( bOnEnd) {
//LoopList.erase( itNext) ;
auto itNewStart = LoopList.begin() ;
++ itNewStart ;
LoopList.erase( itNewStart) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
// nSegNum 0-based
bool
PointPositionOnPolyLine( const Point3d& ptPoint, /*const*/ PolyLine& Loop, int& nSegNum, double& dParOnSeg)
{
// Rinomino la lista di punti della PolyLine.
/*const*/ PNTULIST& LoopList = Loop.GetUPointList() ;
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
nSegNum = - 1 ;
double dMinSqDist = DBL_MAX ;
int nS = 0 ;
auto itMinDistSt = LoopList.end() ;
auto itMinDistEn = itMinDistSt ;
auto itSt = LoopList.begin() ;
auto itEn = itSt ;
++ itEn ;
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn, ++ nS) {
// Estremi del segmento corrente del loop
Point3d ptSegSt = itSt->first ;
Point3d ptSegEn = itEn->first ;
// Distanza del punto dal segmento del loop
DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ;
double dSqDist ;
dDistCalc.GetSqDist( dSqDist) ;
if ( dSqDist < dMinSqDist) {
nSegNum = nS ;
dMinSqDist = dSqDist ;
itMinDistSt = itSt ;
itMinDistEn = itEn ;
}
}
// Se il punto non sta sul loop, lo segnalo.
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
return false ;
// Calcolo il parametro lungo il segmento.
Vector3d vtSeg = itMinDistEn->first - itMinDistSt->first ;
double dSegLen = vtSeg.Len() ;
if ( dSegLen < EPS_SMALL)
return false ;
vtSeg /= dSegLen ;
dParOnSeg = Clamp( ( ptPoint - itMinDistSt->first) * vtSeg, 0., dSegLen) ;
return true ;
}
//----------------------------------------------------------------------------
bool
IsPointInsidePolyLine( const Point3d& ptP, /*const*/ PolyLine& plPoly)
{
// Se la PolyLine non è chiusa, il punto non può essere interno.
if ( ! plPoly.IsClosed())
return false ;
// Lista dei punti
/*const*/ PNTULIST& List = plPoly.GetUPointList() ;
// Ciclo sui segmenti della PolyLine per cercarne il tratto più vicino al punto.
double dMinSqDist = DBL_MAX ;
// Riferimento alla lista dei punti
PNTULIST& List = const_cast<PolyLine&>( plPoly).GetUPointList() ;
// Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto
double dMinSqDist = SQ_INFINITO ;
Point3d ptMinDist ;
auto itMinDistSt = List.end() ;
auto itSt = List.begin() ;
auto itEn = itSt ;
++ itEn ;
for ( ; itSt != List.end() && itEn != List.end() ; ++ itSt, ++ itEn) {
// Estremi del segmento corrente del loop
Point3d ptSegSt = itSt->first ;
Point3d ptSegEn = itEn->first ;
// Distanza del punto dal segmento del loop
DistPointLine dDistCalc( ptP, ptSegSt, ptSegEn) ;
auto itMinDistEnd = List.end() ;
auto itStart = List.begin() ;
auto itEnd = next( itStart) ;
for ( ; itEnd != List.end() ; ++ itStart, ++ itEnd) {
// Distanza del punto dal segmento corrente
DistPointLine dDistCalc( ptP, itStart->first, itEnd->first) ;
double dSqDist ;
dDistCalc.GetSqDist( dSqDist) ;
if ( dSqDist < dMinSqDist) {
if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
dDistCalc.GetMinDistPoint( ptMinDist) ;
itMinDistSt = itSt ;
itMinDistEnd = itEnd ;
}
}
// Termine del segmento di minima distanza.
auto itMinDistEn = itMinDistSt ;
++ itMinDistEn ;
// Punto di minima distanza nell'estremo iniziale del segento
if ( AreSamePointApprox( ptMinDist, itMinDistSt->first)) {
auto itPrevSt = List.begin() ;
if ( itMinDistSt == List.begin()) {
auto itAuxNext = itPrevSt ;
++ ( ++ itAuxNext) ;
for ( ; itAuxNext != List.end() ; ++ itPrevSt, ++ itAuxNext)
;
}
else {
auto itAuxNext = itPrevSt ;
++ itAuxNext ;
for (; itAuxNext != itMinDistSt; ++itPrevSt, ++itAuxNext)
;
}
Vector3d vtPrevTan = itMinDistSt->first - itPrevSt->first ;
vtPrevTan.Normalize() ;
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
vtTan.Normalize() ;
Polygon3d AuxPolygon ;
AuxPolygon.FromPolyLine( plPoly) ;
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
Vector3d vtPrevOut = vtPrevTan ^ vtPolyNorm ;
Vector3d vtOut = vtTan ^ vtPolyNorm ;
// Caso concavo
if ( vtTan * vtPrevOut > 0) {
Vector3d vtTest = ptP - ptMinDist ;
if ( vtTest * vtPrevOut < 0 || vtTest * vtOut < 0)
return true ;
}
// Caso convesso
else {
Vector3d vtTest = ptP - ptMinDist ;
if ( vtTest * vtPrevOut < 0 && vtTest * vtOut < 0)
return true ;
}
// Determino tangente di riferimento
Vector3d vtTang ;
// se minima distanza nell'estremo iniziale del segmento
if ( AreSamePointApprox( ptMinDist, prev( itMinDistEnd)->first)) {
// direzione del segmento
Vector3d vtCurrTg = itMinDistEnd->first - prev( itMinDistEnd)->first ;
vtCurrTg.Normalize() ;
// direzione del segmento precedente
Vector3d vtPrevTg ;
if ( prev( itMinDistEnd) != List.begin())
vtPrevTg = prev( itMinDistEnd)->first - prev( itMinDistEnd, 2)->first ;
else
vtPrevTg = prev( itMinDistEnd)->first - prev( List.rbegin())->first ;
vtPrevTg.Normalize() ;
// tangente media
vtTang = vtPrevTg + vtCurrTg ;
vtTang.Normalize() ;
}
// Punto di minima distanza nell'estremo finale del segento
else if ( AreSamePointApprox( ptMinDist, itMinDistEn->first)) {
auto itNextEn = itMinDistEn ;
++ itNextEn ;
if ( itNextEn == List.end()) {
itNextEn = List.begin() ;
++ itNextEn ;
}
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
vtTan.Normalize() ;
Vector3d vtNextTan = itNextEn->first - itMinDistEn->first ;
vtNextTan.Normalize() ;
Polygon3d AuxPolygon ;
AuxPolygon.FromPolyLine( plPoly) ;
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
Vector3d vtOut = vtTan ^ vtPolyNorm ;
Vector3d vtNextOut = vtNextTan ^ vtPolyNorm ;
// Caso concavo
if ( vtNextTan * vtOut > 0) {
Vector3d vtTest = ptP - ptMinDist ;
if ( vtTest * vtOut < 0 || vtTest * vtNextOut < 0)
return true ;
}
// Caso convesso
else {
Vector3d vtTest = ptP - ptMinDist ;
if ( vtTest * vtOut < 0 && vtTest * vtNextOut < 0)
return true ;
}
// se altrimenti minima distanza nell'estremo finale del segmento
else if ( AreSamePointApprox( ptMinDist, itMinDistEnd->first)) {
// direzione del segmento
Vector3d vtCurrTg = itMinDistEnd->first - prev( itMinDistEnd)->first ;
vtCurrTg.Normalize() ;
// direzione del segmento successivo
Vector3d vtNextTg ;
if ( next( itMinDistEnd) != List.end())
vtNextTg = next( itMinDistEnd)->first - itMinDistEnd->first ;
else
vtNextTg = next( List.begin())->first - itMinDistEnd->first ;
vtNextTg.Normalize() ;
// tangente media
vtTang = vtCurrTg + vtNextTg ;
vtTang.Normalize() ;
}
// Punto di minima distanza interno al segmeno
// altrimenti minima distanza con l'interno
else {
Vector3d vtP = ptP - itMinDistSt->first ;
Vector3d vtTan = itMinDistEn->first - itMinDistSt->first ;
vtTan.Normalize() ;
Polygon3d AuxPolygon ;
AuxPolygon.FromPolyLine( plPoly) ;
Vector3d vtPolyNorm = AuxPolygon.GetVersN() ;
Vector3d vtOut = vtTan ^ vtPolyNorm ;
vtP -= ( vtP * vtTan) * vtTan ;
if ( vtP * vtOut < - EPS_SMALL)
return true ;
vtTang = itMinDistEnd->first - prev( itMinDistEnd)->first ;
}
return false ;
// Determino la posizione del punto
Vector3d vtDiff = ptP - ptMinDist ;
Vector3d vtOut = vtTang ^ plPlane.GetVersN() ;
vtOut.Normalize() ;
return ( vtDiff * vtOut < -dToler) ;
}
//----------------------------------------------------------------------------
bool
DistPointPolyLine( const Point3d& ptP, const PolyLine& plPoly, double& dPointPolyLineDist)
GetPointParamOnPolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler, double& dPar)
{
if ( plPoly.GetPointNbr() == 0)
// La polilinea deve contenere almeno due punti
if ( plPoly.GetPointNbr() < 2)
return false ;
dPointPolyLineDist = DBL_MAX ;
Point3d ptSt, ptEn ;
bool bContinue = plPoly.GetFirstPoint( ptSt) && plPoly.GetNextPoint( ptEn) ;
while ( bContinue) {
double dPoinLineDist ;
DistPointLine PointLineDistCalc( ptP, ptSt, ptEn) ;
PointLineDistCalc.GetDist( dPoinLineDist) ;
if ( dPoinLineDist < dPointPolyLineDist)
dPointPolyLineDist = dPoinLineDist ;
ptSt = ptEn ;
bContinue = plPoly.GetNextPoint( ptEn) ;
}
return true ;
}
//----------------------------------------------------------------------------
// Una faccia di una trimesh ha una sola componente connessa.
// Si assume che i loop siano corretti e rispettino tale proprietà.
bool
DistPointFacet( const Point3d& ptP, /*const*/ POLYLINEVECTOR& vPolyVec, double& dPointFacetDist)
{
// Vedo se la proiezione del punto sul piano della faccia è interno ad essa.
Point3d ptPlaneP ;
Vector3d vtPlaneN ;
double dPointPlaneSignedDist ;
Point3d ptProjP ;
bool bPointIsInside = true ;
for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) && bPointIsInside ; ++ nLoop) {
Plane3d plPlane ;
double dArea ;
if ( ! vPolyVec[nLoop].IsClosedAndFlat( plPlane, dArea))
return false ;
if ( nLoop == 0) {
ptPlaneP = plPlane.GetPoint() ;
vtPlaneN = plPlane.GetVersN() ;
dPointPlaneSignedDist = ( ptP - ptPlaneP) * vtPlaneN ;
ptProjP = ptP + dPointPlaneSignedDist * vtPlaneN ;
}
if ( ! IsPointInsidePolyLine( ptProjP, vPolyVec[nLoop]))
bPointIsInside = false ;
}
// Se la proiezione del punto sul piano della faccia è interno, ho finito.
// La distanza del punto dalla faccia è pari alla distanza dello stesso dal piano
// in cui giace quest'ultima.
if ( bPointIsInside) {
dPointFacetDist = abs( dPointPlaneSignedDist) ;
return bPointIsInside ;
}
// Calcolo la minima distanza del punto dalle polilinee del contorno.
dPointFacetDist = DBL_MAX ;
for ( int nLoop = 0 ; nLoop < int( vPolyVec.size()) ; ++ nLoop) {
double dDist ;
if ( DistPointPolyLine( ptP, vPolyVec[nLoop], dDist) && dDist < dPointFacetDist)
dPointFacetDist = dDist ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SplitPolyLineAtPoint( const Point3d& ptPoint, /*const*/ PolyLine& Loop, PolyLine& Loop1, PolyLine& Loop2)
{
// Rinomino la lista di punti della PolyLine.
/*const*/ PNTULIST& LoopList = Loop.GetUPointList() ;
// Ciclo sui segmenti del loop per cercare il tratto del loop chiuso più vicino al punto.
double dMinSqDist = DBL_MAX ;
auto itMinDistSt = LoopList.end() ;
auto itSt = LoopList.begin() ;
auto itEn = itSt ;
++ itEn ;
for ( ; itSt != LoopList.end() && itEn != LoopList.end() ; ++ itSt, ++ itEn) {
// Estremi del segmento corrente del loop
Point3d ptSegSt = itSt->first ;
Point3d ptSegEn = itEn->first ;
// Distanza del punto dal segmento del loop
DistPointLine dDistCalc( ptPoint, ptSegSt, ptSegEn) ;
// Ciclo sui punti della polilinea
int nSeg = -1 ;
double dMinSqDist = SQ_INFINITO ;
double dMinPar = -1 ;
Point3d ptStart, ptEnd ;
plPoly.GetFirstPoint( ptStart) ;
while ( plPoly.GetNextPoint( ptEnd)) {
// aggiorno l'indice
++ nSeg ;
// distanza del punto dal segmento della polilinea
DistPointLine dDistCalc( ptP, ptStart, ptEnd) ;
double dSqDist ;
dDistCalc.GetSqDist( dSqDist) ;
if ( dSqDist < dMinSqDist) {
if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
itMinDistSt = itSt ;
double dSegPar ;
dDistCalc.GetParamAtMinDistPoint( dSegPar) ;
dMinPar = nSeg + dSegPar ;
}
// assegno nuovo inizio
ptStart = ptEnd ;
}
// Il punto è sulla linea se la sua distanza rispetta la tolleranza
return ( dMinSqDist < dToler * dToler) ;
}
//----------------------------------------------------------------------------
bool
ChangePolyLineStart( PolyLine& plPoly, const Point3d& ptNewStart, double dToler)
{
// La polilinea deve essere chiusa
if ( ! plPoly.IsClosed())
return false ;
// Riferimento alla lista dei punti
PNTULIST& LoopList = const_cast<PolyLine&>( plPoly).GetUPointList() ;
// Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto
double dMinSqDist = SQ_INFINITO ;
auto itMinDistEnd = LoopList.end() ;
auto itStart = LoopList.begin() ;
auto itEnd = next( itStart) ;
for ( ; itEnd != LoopList.end() ; ++ itStart, ++ itEnd) {
// Distanza del punto dal segmento corrente
DistPointLine dDistCalc( ptNewStart, itStart->first, itEnd->first) ;
double dSqDist ;
if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
itMinDistEnd = itEnd ;
}
}
// Se il punto non sta sul loop, lo segnalo.
if ( dMinSqDist > 4 * SQ_EPS_SMALL)
// Se il punto non sta sulla polilinea, non ha senso cambiare l'inizio
if ( dMinSqDist > dToler * dToler)
return false ;
// Se il punto di stop sta su un vertice non devo aggiungerlo e il
// punto di stop sarà uno degli estremi del segmento su cui giace.
auto itStop = itMinDistSt ;
auto itNext = itMinDistSt ;
++ itNext ;
if ( AreSamePointApprox( ptPoint, itStop->first))
;
else if ( AreSamePointApprox( ptPoint, itNext->first))
itStop = itNext ;
else {
itStop = LoopList.emplace( itNext, ptPoint, 0.) ;
}
// Creo i due loop
PNTULIST& LoopList1 = Loop1.GetUPointList() ;
PNTULIST& LoopList2 = Loop2.GetUPointList() ;
for ( auto it = LoopList.begin() ; it != itStop ; ++ it) {
LoopList1.emplace_back( it->first, it->second) ;
}
LoopList1.emplace_back( itStop->first, itStop->second) ;
for ( auto it = itStop ; it != LoopList.end() ; ++ it) {
LoopList2.emplace_back( it->first, it->second) ;
}
// Se il punto non coincide con un vertice, lo aggiungo
auto itNewStart = LoopList.end() ;
if ( AreSamePointApprox( ptNewStart, prev( itMinDistEnd)->first))
itNewStart = prev( itMinDistEnd) ;
else if ( AreSamePointApprox( ptNewStart, itMinDistEnd->first))
itNewStart = itMinDistEnd ;
else
itNewStart = LoopList.emplace( itMinDistEnd, ptNewStart, 0) ;
// Cancello l'ultimo punto ( coincide con il primo)
LoopList.pop_back() ;
// Sposto la parte iniziale dei punti alla fine
LoopList.splice( LoopList.end(), LoopList, LoopList.begin(), itNewStart) ;
// Aggiungo il punto finale come copia dell'iniziale
LoopList.push_back( LoopList.front()) ;
return true ;
}
//----------------------------------------------------------------------------
bool
AddPolyLineToPolyLine( PolyLine& Poly, PolyLine& PolyToAdd)
SplitPolyLineAtPoint( const PolyLine& plPoly, const Point3d& ptP, double dToler, PolyLine& plPoly1, PolyLine& plPoly2)
{
// Se la PolyLine a cui devo aggiungere l'altra è chiusa, non posso aggiungere nulla.
if ( Poly.IsClosed())
// La polilinea deve contenere almeno due punti
if ( plPoly.GetPointNbr() < 2)
return false ;
// Se la PolyLina che devo aggiungere è vuota, ho finito.
PNTULIST& PolyToAddList = PolyToAdd.GetUPointList() ;
if ( int( PolyToAddList.size()) == 0)
return true ;
// Se Poly non è vuota e la sua fine non coincide con l'inizio di PolyToAdd, non è possibile aggiungere nulla.
Point3d ptLast ;
Poly.GetLastPoint( ptLast) ;
auto it = PolyToAddList.begin() ;
if ( Poly.GetPointNbr() != 0 && ! AreSamePointEpsilon( it->first, ptLast, 10 * EPS_SMALL))
return false ;
/*if ( Poly.GetPointNbr() == 0)
Poly.AddUPoint( 0., it->first) ;
++ it ;*/
// Aggiungo i punti.
for ( ; it != PolyToAddList.end() ; ++ it) {
Poly.AddUPoint( 0., it->first) ;
// Riferimento alla lista dei punti
const PNTULIST& LoopList = const_cast<PolyLine&>( plPoly).GetUPointList() ;
// Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto
double dMinSqDist = SQ_INFINITO ;
auto itMinDistEnd = LoopList.end() ;
auto itStart = LoopList.begin() ;
auto itEnd = next( itStart) ;
for ( ; itEnd != LoopList.end() ; ++ itStart, ++ itEnd) {
// Distanza del punto dal segmento corrente
DistPointLine dDistCalc( ptP, itStart->first, itEnd->first) ;
double dSqDist ;
if ( dDistCalc.GetSqDist( dSqDist) && dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
itMinDistEnd = itEnd ;
}
}
// Se il punto non sta sulla polilinea, non ha senso spezzare
if ( dMinSqDist > dToler * dToler)
return false ;
// Copio i punti opportuni nella prima parte
PNTULIST& LoopList1 = plPoly1.GetUPointList() ;
for ( auto it = LoopList.begin() ; it != itMinDistEnd ; ++ it)
LoopList1.emplace_back( it->first, it->second) ;
plPoly1.AddUPoint( 0, ptP) ;
// Copio i punti opportuni nella seconda parte
PNTULIST& LoopList2 = plPoly2.GetUPointList() ;
for ( auto it = itMinDistEnd ; it != LoopList.end() ; ++ it)
LoopList2.emplace_back( it->first, it->second) ;
plPoly2.AddUPoint( 0, ptP, false) ;
return true ;
}