Merge remote-tracking branch 'origin/HEAD' into MoreBezier

This commit is contained in:
Daniele Bariletti
2024-08-30 15:04:46 +02:00
3 changed files with 106 additions and 210 deletions
BIN
View File
Binary file not shown.
+101 -205
View File
@@ -594,18 +594,12 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType)
if ( ! IsValid())
return false ;
// verifico se curve sono coerenti per calcolo dell'offset
if ( ! VerifyCurvesValidityForOffset())
return false ;
// se offset nullo restituisco direttamente le curve
if ( abs( dOffs) < EPS_SMALL) {
for ( auto pCrv : m_vpCrvs)
vOffs.emplace_back( pCrv->Clone()) ;
}
bool bClosed = m_vpCrvs[0]->IsClosed() ;
// calcolo offset
ICRVCOMPOPLIST OffsList ;
if ( ! CalcVroniOffset( OffsList, abs( dOffs)))
@@ -614,39 +608,34 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType)
// sistemo le curve di offset calcolate con vroni
for ( auto pCrv : OffsList) {
// seleziono le curve di offset corrette in base al segno dell'offset
if ( bClosed)
AdjustClosedOffsetCurve( *pCrv, dOffs) ;
else
AdjustOpenOffsetCurve( *pCrv, dOffs) ;
if ( pCrv->IsValid()) {
// eventuale inversione
if ( dOffs > EPS_SMALL)
pCrv->Invert() ;
// sistemo i raccordi
if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0) {
IdentifyFillets( pCrv, dOffs) ;
AdjustCurveFillets( pCrv, dOffs, nType) ;
}
// seleziono le porzioni dell'offset che si trovano dal lato richiesto
ICRVCOMPOPOVECTOR vResult = AdjustOffsetCurves( pCrv, dOffs) ;
for ( int i = 0 ; i < int( vResult.size()) ; ++ i) {
if ( bClosed) {
// forzo chiusura della curva per evitare piccole imprecisioni
pCrv->Close() ;
// sistemo il punto di inizio
AdjustOffsetStart( *pCrv) ;
}
// porto nel frame globale
pCrv->ToGlob( m_Frame) ;
// unisco le parti allineate
pCrv->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ;
// aggiungo al vettore finale
vOffs.emplace_back( pCrv) ;
// eventuale inversione
if ( dOffs > EPS_SMALL)
vResult[i]->Invert() ;
// sistemo il punto di inizio
if ( vResult[i]->IsClosed())
AdjustOffsetStart( vResult[i]) ;
// sistemo i raccordi
if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0) {
IdentifyFillets( vResult[i], dOffs) ;
AdjustCurveFillets( vResult[i], dOffs, nType) ;
}
// porto nel frame globale
vResult[i]->ToGlob( m_Frame) ;
// unisco le parti allineate
vResult[i]->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ;
// aggiungo al vettore finale
vOffs.emplace_back( Release( vResult[i])) ;
}
else
delete pCrv ;
// dealloco curva
delete( pCrv) ;
}
return true ;
@@ -717,14 +706,6 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
if ( ! IsValid())
return false ;
int nOrigCrvCnt = 1 ;
if ( m_vpCrvs[0]->GetType() == CRV_COMPO) {
const CurveComposite * pOrigCompo = GetBasicCurveComposite( m_vpCrvs[0]) ;
if ( pOrigCompo == nullptr)
return false ;
nOrigCrvCnt = pOrigCompo->GetCurveCount() ;
}
try {
// reset di eventuali offset precedenti
m_vroni->apiResetOffsetData() ;
@@ -772,9 +753,17 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
int nCurrCrvId = pCrvOffs->GetCurveCount() - 1 ;
pCrvOffs->SetCurveTempProp( nCurrCrvId, nOrigCrv + 1, 0) ;
pCrvOffs->SetCurveTempProp( nCurrCrvId, nOrigLoop, 1) ;
// verifico se è raccordo relativo agli estremi della curva
if ( nOrigCrv == -1 && ( nOrigPnt == 0 || nOrigPnt == nOrigCrvCnt))
pCrvOffs->SetCurveTempParam( nCurrCrvId, 1.0, 0) ;
// verifico se è una giunzione, ovvero un raccordo relativo agli estremi di una curva ( con distinzione fra curva
// aperta e chiusa)
if ( nOrigCrv == -1) {
int nOrigCrvCnt = 1 ;
if ( m_vpCrvs[nOrigLoop]->GetType() == CRV_COMPO)
nOrigCrvCnt = GetBasicCurveComposite( m_vpCrvs[nOrigLoop])->GetCurveCount() ;
if ( nOrigPnt == 0 || nOrigPnt == nOrigCrvCnt) {
double dParam = m_vpCrvs[nOrigLoop]->IsClosed() ? VRONI_JUNCTION_CLOSED : VRONI_JUNCTION_OPEN ;
pCrvOffs->SetCurveTempParam( nCurrCrvId, dParam, 0) ;
}
}
}
}
@@ -814,169 +803,76 @@ Voronoi::UpdateVoronoi( double dOffs)
}
//----------------------------------------------------------------------------
bool
Voronoi::VerifyCurvesValidityForOffset()
{
if ( m_vpCrvs.size() == 1)
return true ;
// se ho più curve, devono essere tutte chiuse
for ( auto pCrv : m_vpCrvs) {
if ( ! pCrv->IsClosed())
return false ;
}
// verifico se gli orientamenti delle curve sono coerenti
DBLVECTOR vArea( m_vpCrvs.size()) ;
double dRefArea = 0.0 ;
for ( int i = 0 ; i < ( int)m_vpCrvs.size() ; i ++) {
m_vpCrvs[i]->GetAreaXY( vArea[i]) ;
if ( abs( vArea[i]) > abs( dRefArea))
dRefArea = vArea[i] ;
}
bool bRefCCW = ( dRefArea > EPS_SMALL) ;
for ( int i = 0 ; i < ( int)vArea.size() ; i++) {
// se curva con orientamento principale verifico sia esterna a tutte le altre curve con orientamento principale
if ( vArea[i] * dRefArea > EPS_SMALL) {
for ( int j = 0 ; j < ( int)vArea.size() ; j++) {
if ( j != i && vArea[i] * vArea[j] > EPS_SMALL) {
IntersCurveCurve ccInt( *m_vpCrvs[i], *m_vpCrvs[j]) ;
int nRes = ccInt.GetRegionCurveClassification() ;
if ( nRes == CCREGC_NULL || nRes == CCREGC_SAME || nRes == CCREGC_INTERS)
return false ;
if ( ( bRefCCW && nRes == CCREGC_IN1) || ( ! bRefCCW && nRes == CCREGC_IN2)) {
// se è interna ad una curva con orientamento principale, verifico sia esterna ad almeno una curva con orientamento
// diverso dal principale
bool bFound = false ;
for ( int k = 0 ; k < ( int)vArea.size() ; k++) {
if ( k != i && vArea[i] * vArea[k] < EPS_SMALL) {
IntersCurveCurve ccInt( *m_vpCrvs[i], *m_vpCrvs[k]) ;
int nRes = ccInt.GetRegionCurveClassification() ;
if ( ( bRefCCW && nRes == CCREGC_OUT) || ( ! bRefCCW && nRes == CCREGC_IN1)) {
bFound = true ;
break ;
}
}
}
if ( ! bFound)
return false ;
}
}
}
}
// se curva con orientamento diverso dal principale verifico sia contenuta in una curva con orientamento principale
else if ( vArea[i] * dRefArea < - EPS_SMALL) {
bool bInside = false ;
for ( int j = 0 ; j < ( int)vArea.size() ; j++) {
if ( j != i && vArea[j] * dRefArea > EPS_SMALL) {
IntersCurveCurve ccInt( *m_vpCrvs[i], *m_vpCrvs[j]) ;
int nRes = ccInt.GetRegionCurveClassification() ;
if ( ( bRefCCW && nRes == CCREGC_IN1) || ( ! bRefCCW && nRes == CCREGC_OUT)) {
bInside = true ;
break ;
}
}
}
if ( ! bInside)
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
Voronoi::AdjustClosedOffsetCurve( ICurveComposite& pCompo, double dOffs)
{
int nSideRef = dOffs < EPS_SMALL ? MDS_LEFT : MDS_RIGHT ;
int nSide = GetOffsetCurveSide( pCompo, 0) ;
if ( nSide != nSideRef)
// se lato errato, tutta la curva va cancellata
pCompo.Clear() ;
return true ;
}
//----------------------------------------------------------------------------
bool
Voronoi::AdjustOpenOffsetCurve( ICurveComposite& pCompo, double dOffs)
ICRVCOMPOPOVECTOR
Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const
{
ICRVCOMPOPOVECTOR vResult ;
int nSideRef = dOffs < EPS_SMALL ? MDS_LEFT : MDS_RIGHT ;
// recupero i raccordi relativi agli estremi della curva aperta
INTVECTOR vJunctions ;
for ( int i = 0 ; i < pCompo.GetCurveCount() ; i++) {
double dParTmp ;
pCompo.GetCurveTempParam( i, dParTmp) ;
if ( dParTmp > EPS_SMALL)
vJunctions.push_back( i) ;
// verifico se presenti giunzioni
bool bJunctions = false ;
for ( int i = 0 ; i < pCompo->GetCurveCount() ; i ++) {
double dParam ; pCompo->GetCurveTempParam( i, dParam) ;
if ( abs( dParam - VRONI_JUNCTION_OPEN) < EPS_SMALL) {
bJunctions = true ;
break ;
}
}
if ( vJunctions.size() == 0) {
// verifico se si trova dal lato corretto
if ( ! bJunctions) {
// controllo la curva complessiva
int nSide = GetOffsetCurveSide( pCompo, 0) ;
if ( nSide != nSideRef)
// se lato errato, tutta la curva va cancellata
pCompo.Clear() ;
if ( nSide == nSideRef)
vResult.emplace_back( pCompo->Clone()) ;
}
else if ( vJunctions.size() == 2) {
// recupero i due tratti di curva
PtrOwner<CurveComposite> pCompo1( ConvertCurveToBasicComposite( pCompo.CopyParamRange( vJunctions[0] + 1, vJunctions[1]))) ;
PtrOwner<CurveComposite> pCompo2( ConvertCurveToBasicComposite( pCompo.CopyParamRange( vJunctions[1] + 1, vJunctions[0]))) ;
pCompo.Clear() ;
if ( ! IsNull( pCompo1) && pCompo1->IsValid()) {
int nSide = GetOffsetCurveSide( *pCompo1, 0) ;
if ( nSide == nSideRef)
pCompo.CopyFrom( pCompo1) ;
else if ( ! IsNull( pCompo2) && pCompo2->IsValid())
pCompo.CopyFrom( pCompo2) ;
}
else if ( ! IsNull( pCompo2) && pCompo2->IsValid()) {
int nSide = GetOffsetCurveSide( *pCompo2, 0) ;
if ( nSide == nSideRef)
pCompo.CopyFrom( pCompo2) ;
}
}
else {
// mi posiziono dopo la junction
pCompo.ChangeStartPoint( vJunctions[0] + 1) ;
delete( pCompo.RemoveFirstOrLastCurve()) ;
// verifico validità della curva
int nSide = GetOffsetCurveSide( pCompo, 0) ;
if ( nSide == nSideRef) {
// scorro fino alla prima curva non valida ed elimino la curva da quel punto fino alla fine
for ( int i = 1 ; i < pCompo.GetCurveCount() ; i++) {
else {
// scorro la curva eliminando le giunzioni relative a curve aperte e le sottocurve che si trovano dal lato sbagliato
PtrOwner<CurveComposite> pCompoCurr( CreateBasicCurveComposite()) ;
for ( int i = 0 ; i < pCompo->GetCurveCount() ; i ++) {
bool bKeep = true ;
double dParTmp ; pCompo->GetCurveTempParam( i, dParTmp) ;
if ( abs( dParTmp - VRONI_JUNCTION_OPEN) < EPS_SMALL)
bKeep = false ;
else {
int nSide = GetOffsetCurveSide( pCompo, i) ;
if ( nSide != nSideRef)
pCompo.TrimEndAtParam( i) ;
}
}
else {
// elimino finchè non trovo una curva valida
while( nSide != nSideRef && pCompo.IsValid()) {
delete( pCompo.RemoveFirstOrLastCurve( false)) ;
if ( pCompo.IsValid())
nSide = GetOffsetCurveSide( pCompo, 0) ;
}
}
}
bKeep = ( nSide == nSideRef) ;
}
return true ;
if ( bKeep)
pCompoCurr->AddCurve( pCompo->GetCurve( i)->Clone()) ;
else {
// salvo la curva ottenuta fino ad ora e resetto per i prossimi tratti validi
if ( pCompoCurr->IsValid()) {
vResult.emplace_back( Release( pCompoCurr)) ;
pCompoCurr.Set( CreateBasicCurveComposite()) ;
}
}
}
// salvo eventuale ultima curva
if ( pCompoCurr->IsValid())
vResult.emplace_back( Release( pCompoCurr)) ;
// verifico se posso concatenare prima e ultima curva
if ( vResult.size() > 1) {
Point3d ptStart ; vResult.front()->GetStartPoint( ptStart) ;
Point3d ptEnd ; vResult.back()->GetEndPoint( ptEnd) ;
if ( AreSamePointApprox( ptStart, ptEnd) && vResult.front()->AddCurve( vResult.back()->Clone(), false))
vResult.pop_back() ;
}
}
return vResult ;
}
//---------------------------------------------------------------------------
int
Voronoi::GetOffsetCurveSide( const ICurveComposite& pOffs, int nCrv)
Voronoi::GetOffsetCurveSide( const ICurveComposite* pOffs, int nCrv) const
{
Point3d ptM ; pOffs.GetCurve( nCrv)->GetMidPoint( ptM) ;
Point3d ptM ; pOffs->GetCurve( nCrv)->GetMidPoint( ptM) ;
// recupero curva e sottocurva di riferimento
int nOrigSubCrv ; pOffs.GetCurveTempProp( nCrv, nOrigSubCrv) ;
int nOrigCrv ; pOffs.GetCurveTempProp( nCrv, nOrigCrv, 1) ;
int nOrigSubCrv ; pOffs->GetCurveTempProp( nCrv, nOrigSubCrv) ;
int nOrigCrv ; pOffs->GetCurveTempProp( nCrv, nOrigCrv, 1) ;
const ICurve* pCrvRef = m_vpCrvs[nOrigCrv] ;
if ( nOrigSubCrv != 0 && m_vpCrvs[nOrigCrv]->GetType() == CRV_COMPO) {
const CurveComposite* pCompoOrig = GetBasicCurveComposite( m_vpCrvs[nOrigCrv]) ;
@@ -992,19 +888,19 @@ Voronoi::GetOffsetCurveSide( const ICurveComposite& pOffs, int nCrv)
//---------------------------------------------------------------------------
bool
Voronoi::AdjustOffsetStart( ICurveComposite& pCrv)
Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const
{
for ( int i = 0 ; i < pCrv.GetCurveCount() ; i++) {
// cerco il tratto associato alla prima curva originale
int nProp ; pCrv.GetCurveTempProp( i, nProp) ;
if ( nProp == 1) {
pCrv.ChangeStartPoint( i) ;
for ( int i = 0 ; i < pCrv->GetCurveCount() ; i++) {
// cerco il tratto associato alla prima sottocurva originale
int nOrigCrv ; pCrv->GetCurveTempProp( i, nOrigCrv) ;
if ( nOrigCrv == 1) {
pCrv->ChangeStartPoint( i) ;
break ;
}
// oppure un raccordo di junction
double dParam ; pCrv.GetCurveTempParam( i, dParam) ;
if ( abs( dParam - 1) < EPS_SMALL) {
pCrv.ChangeStartPoint( i + 1) ;
// oppure associato ad una giunzione
double dParam ; pCrv->GetCurveTempParam( i, dParam) ;
if ( abs( dParam - VRONI_JUNCTION_CLOSED) < EPS_SMALL) {
pCrv->ChangeStartPoint( i + 1) ;
break ;
}
}
+5 -5
View File
@@ -25,6 +25,8 @@
static const bool USE_VORONOI = true ;
static const int VORONOI_STD_BOUND = 3 ;
static const double VRONI_OFFS_TOL = 1e-9 ;
static const double VRONI_JUNCTION_OPEN = 1.0 ;
static const double VRONI_JUNCTION_CLOSED = 2.0 ;
//-------------------------- Forward Definitions -------------------------------
class ISurfFlatRegion ;
@@ -77,11 +79,9 @@ class Voronoi
bool CalcVoronoi( int nBound = VORONOI_STD_BOUND) ;
bool CalcVroniOffset( ICRVCOMPOPLIST& vOffs, double dOffs) ;
bool UpdateVoronoi( double dOffs) ;
bool VerifyCurvesValidityForOffset( void) ;
bool AdjustOpenOffsetCurve( ICurveComposite& pCompo, double dOffs) ;
bool AdjustClosedOffsetCurve( ICurveComposite& pCompo, double dOffs) ;
bool AdjustOffsetStart( ICurveComposite& pCompo) ;
int GetOffsetCurveSide( const ICurveComposite& pOffs, int nCrv) ;
ICRVCOMPOPOVECTOR AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const ;
bool AdjustOffsetStart( ICurveComposite* pCompo) const ;
int GetOffsetCurveSide( const ICurveComposite* pOffs, int nCrv) const ;
ICurve* GetBisectorCurve( int i) ;
private :