From da4cd4c4827707ca581a502e3e7c2750c31ed539 Mon Sep 17 00:00:00 2001 From: Riccardo Elitropi Date: Fri, 27 Mar 2026 18:39:41 +0100 Subject: [PATCH] EgtGeomKernel (Nst_SurfFr) : - primo commit per CAv tra Regioni Piane con loop interni e Interferenza tra Regioni Piane. --- CAvSurfFrMove.cpp | 710 ++++++++++++++++++++++++++++++++++ CAvSurfFrMove.h | 46 +++ EGkCAvSurfFrMove.h | 69 ++++ EgtGeomKernel.vcxproj | 2 + EgtGeomKernel.vcxproj.filters | 6 + SurfFlatRegion.cpp | 138 ++++++- SurfFlatRegion.h | 2 + 7 files changed, 971 insertions(+), 2 deletions(-) create mode 100644 CAvSurfFrMove.cpp create mode 100644 CAvSurfFrMove.h create mode 100644 EGkCAvSurfFrMove.h diff --git a/CAvSurfFrMove.cpp b/CAvSurfFrMove.cpp new file mode 100644 index 0000000..31fee0d --- /dev/null +++ b/CAvSurfFrMove.cpp @@ -0,0 +1,710 @@ +//---------------------------------------------------------------------------- +// EgalTech 2026-2026 +//---------------------------------------------------------------------------- +// File : CASurfFrMove.cpp Data : 26.03.2026 Versione : 3.1c6 +// Contenuto : Implementazione delle funzioni di movimento per SurfFlatRegion +// senza collisione con altri oggetti dello stesso tipo e nello +// stesso piano o in piani paralleli. +// +// +// Modifiche : 26.03.2026 RE Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +//--------------------------- Include ---------------------------------------- +#include "stdafx.h" +#include "CAvSurfFrMove.h" +#include "SurfFlatRegion.h" +#include "CurveLine.h" +#include "CurveArc.h" +#include "CurveComposite.h" +#include "IntersLineArc.h" +#include "GeoConst.h" +#include "/EgtDev/Include/EGkCAvSurfFrMove.h" +#include "/EgtDev/Include/EgtPointerOwner.h" + +using namespace std ; + +//---------------------------------------------------------------------------- +// CASurfFrMove +//---------------------------------------------------------------------------- +CAvSurfFrMove::CAvSurfFrMove( const ISurfFlatRegion& SfrM, const ISurfFlatRegion& SfrF) +{ + // salvo puntatori alle regioni + m_pRegM = &SfrM ; + m_pRegF = &SfrF ; +} + +//---------------------------------------------------------------------------- +bool +CAvSurfFrMove::Translate( const Vector3d& vtDir, double& dLen) +{ + MyCAvSurfFrMove ScdMove( *m_pRegM, *m_pRegF) ; + m_CollInfo.nType = CI_NONE ; + if ( ! ScdMove.Translate( vtDir, dLen)) + return false ; + m_CollInfo = ScdMove.GetCollInfo() ; + return true ; +} + +//---------------------------------------------------------------------------- +bool +CAvSurfFrMove::Rotate( const Point3d& ptCen, double& dAng) +{ + MyCAvSurfFrMove ScdMove( *m_pRegM, *m_pRegF) ; + m_CollInfo.nType = CI_NONE ; + return ScdMove.Rotate( ptCen, dAng) ; +} + + +//---------------------------------------------------------------------------- +// MyCAvSurfFrMove +//---------------------------------------------------------------------------- +MyCAvSurfFrMove::MyCAvSurfFrMove( const ISurfFlatRegion& SfrM, const ISurfFlatRegion& SfrF) +{ + // recupero rappresentazione base della regione mobile + m_pRegM = GetBasicSurfFlatRegion( &SfrM) ; + // ne verifico lo stato + if ( m_pRegM == nullptr || ! m_pRegM->IsValid()) + m_pRegM = nullptr ; + // recupero rappresentazione base della regione fissa + m_pRegF = GetBasicSurfFlatRegion( &SfrF) ; + // ne verifico lo stato + if ( m_pRegF == nullptr || ! m_pRegF->IsValid()) + m_pRegF = nullptr ; +} + +//---------------------------------------------------------------------------- +bool +MyCAvSurfFrMove::Translate( const Vector3d& vtDir, double& dLen) +{ + // verifico validità regioni + if ( m_pRegM == nullptr || m_pRegF == nullptr) + return false ; + + // verifico che le due regioni giacciano in piani paralleli + if ( ! AreSameVectorApprox( m_pRegM->m_frF.VersZ(), m_pRegF->m_frF.VersZ())) + return false ; + + // reset info di collisione + m_CollInfo.nType = CI_NONE ; + + // porto il vettore di movimento nel riferimento intrinseco e ne annullo la componente Z + Vector3d vtDirL = vtDir ; + vtDirL.ToLoc( m_pRegM->m_frF) ; + vtDirL.z = 0 ; + double dLenXY = vtDirL.Len() ; + if ( dLenXY < EPS_SMALL) + return true ; + vtDirL /= dLenXY ; + dLenXY *= dLen ; + double dNewLenXY = dLenXY ; + + // ciclo sui chunk della seconda superficie + for ( int nCF = 0 ; nCF < m_pRegF->GetChunkCount() ; ++ nCF) { + // ciclo sui bordi dei chunk + for ( int nLF = 0 ; nLF < m_pRegF->GetLoopCount( nCF) ; ++ nLF) { + + // curva corrente del chunk della seconda regione in locale nel riferimento intrinseco della prima + const ICurve* pCrv2Loc = nullptr ; + PtrOwner pCopyCrv ; + if ( AreSameFrame( m_pRegM->m_frF, m_pRegF->m_frF)) + pCrv2Loc = m_pRegF->GetMyLoop( nCF, nLF) ; + else { + pCopyCrv.Set( m_pRegF->GetMyLoop( nCF, nLF)->Clone()) ; + if ( IsNull( pCopyCrv)) + return false ; + pCopyCrv->LocToLoc( m_pRegF->m_frF, m_pRegM->m_frF) ; + pCrv2Loc = pCopyCrv ; + } + const CurveComposite* pCompo2 = GetBasicCurveComposite( pCrv2Loc) ; + + // ciclo sui chunk della prima superficie + for ( int nCM = 0 ; nCM < m_pRegM->GetChunkCount() ; ++ nCM) { + // ciclo sui bordi del chunk + for ( int nLM = 0 ; nLM < m_pRegM->GetLoopCount( nCM) ; ++ nLM) { + + // per CAv non ha senso confrontare due loop interni tra di loro. + // posso confrontatare - due loop esterni (come per la CAvSimpleSurfFrMove) + // - un loop esterno con uno interno (nel caso in cui un Chunk sia contenuto dentro un isola) + if ( nLF > 0 && nLM > 0) + continue ; + + // curva corrente del chunk della prima regione (ovviamente già in locale al riferimento intrinseco) + const ICurve* pCrv1Loc = m_pRegM->GetMyLoop( nCM, nLM) ; + const CurveComposite* pCompo1 = GetBasicCurveComposite( pCrv1Loc) ; + + // verifico la collisione tra le entità dei loop esterni dei due chunk + int k = 0 ; + const ICurve* pCrv1 = ( pCompo1 != nullptr ? pCompo1->GetFirstCurve() : pCrv1Loc) ; + while ( pCrv1 != nullptr) { + int l = 0 ; + const ICurve* pCrv2 = ( pCompo2 != nullptr ? pCompo2->GetFirstCurve() : pCrv2Loc) ; + while ( pCrv2 != nullptr) { + CollInfo cInfoCurr ; + double dPrevLenXY = dNewLenXY ; + if ( ! TranslateCurveNoCollisionCurve( pCrv1, pCrv2, vtDirL, dNewLenXY, cInfoCurr)) + return false ; + if ( abs( dNewLenXY - dPrevLenXY) < EPS_SMALL) { + if ( cInfoCurr.nType == CI_LINE_LINE || cInfoCurr.nType == CI_PNT_LINE) { + m_CollInfo = cInfoCurr ; + m_CollInfo.nChunkM = nCM ; + m_CollInfo.nLoopM = nLM ; + m_CollInfo.nCrvM = k ; + m_CollInfo.nChunkF = nCF ; + m_CollInfo.nLoopF = nLF ; + m_CollInfo.nCrvF = l ; + } + } + else if ( dNewLenXY < dPrevLenXY) { + m_CollInfo = cInfoCurr ; + m_CollInfo.nChunkM = nCM ; + m_CollInfo.nLoopM = nLM ; + m_CollInfo.nCrvM = k ; + m_CollInfo.nChunkF = nCF ; + m_CollInfo.nLoopF = nLF ; + m_CollInfo.nCrvF = l ; + } + pCrv2 = ( pCompo2 != nullptr ? pCompo2->GetNextCurve() : nullptr) ; + ++ l ; + } + pCrv1 = ( pCompo1 != nullptr ? pCompo1->GetNextCurve() : nullptr) ; + ++ k ; + } + } + } + } + } + + // se da limitare il movimento + if ( dNewLenXY < dLenXY - EPS_SMALL) + dLen *= dNewLenXY / dLenXY ; + + // porto i punti e le direzioni di SCollInfo da intrinseco a locale della prima regione + if ( m_CollInfo.nType != CI_NONE) { + m_CollInfo.ptP1.ToGlob( m_pRegM->m_frF) ; + m_CollInfo.vtDirM.ToGlob( m_pRegM->m_frF) ; + m_CollInfo.vtDirF.ToGlob( m_pRegM->m_frF) ; + } + if ( m_CollInfo.nType == CI_LINE_LINE) + m_CollInfo.ptP2.ToGlob( m_pRegM->m_frF) ; + + return true ; +} + +//---------------------------------------------------------------------------- +bool +MyCAvSurfFrMove::Rotate( const Point3d& ptCen, double& dAng) +{ + // verifico validità regioni + if ( m_pRegM == nullptr || m_pRegF == nullptr) + return false ; + + // verifico che le due regioni giacciano in piani paralleli + if ( ! AreSameVectorApprox( m_pRegM->m_frF.VersZ(), m_pRegF->m_frF.VersZ())) + return false ; + + // reset info di collisione + m_CollInfo.nType = CI_NONE ; + + // porto il centro di rotazione nel riferimento intrinseco e ne annullo la componente Z + Point3d ptCenL = ptCen ; + ptCenL.ToLoc( m_pRegM->m_frF) ; + ptCenL.z = 0 ; + if ( abs( dAng) < EPS_ANG_SMALL) + return true ; + double dNewAng = dAng ; + + // ciclo sui chunk della seconda superficie + for ( int nCF = 0 ; nCF < m_pRegF->GetChunkCount() ; ++ nCF) { + // ciclo sui bordi del Chunk + for ( int nLF = 0 ; nLF < m_pRegF->GetLoopCount( nCF) ; ++ nLF) { + + // curva corrente del chunk della seconda regione in locale nel riferimento intrinseco della prima + const ICurve* pCrv2Loc = nullptr ; + PtrOwner pCopyCrv ; + if ( AreSameFrame( m_pRegM->m_frF, m_pRegF->m_frF)) + pCrv2Loc = m_pRegF->GetMyLoop( nCF, nLF) ; + else { + pCopyCrv.Set( m_pRegF->GetMyLoop( nCF, nLF)->Clone()) ; + if ( IsNull( pCopyCrv)) + return false ; + pCopyCrv->LocToLoc( m_pRegF->m_frF, m_pRegM->m_frF) ; + pCrv2Loc = pCopyCrv ; + } + const CurveComposite* pCompo2 = GetBasicCurveComposite( pCrv2Loc) ; + + // ciclo sui chunk della prima superficie + for ( int nCM = 0 ; nCM < m_pRegM->GetChunkCount() ; ++ nCM) { + // ciclo sui bordi del chunk + for ( int nLM = 0 ; nLM < m_pRegM->GetLoopCount( nCM) ; ++ nLM) { + + // per CAv non ha senso confrontare due loop interni tra di loro. + // posso confrontatare - due loop esterni (come per la CAvSimpleSurfFrMove) + // - un loop esterno con uno interno (nel caso in cui un Chunk sia contenuto dentro un isola) + if ( nLF > 0 && nLM > 0) + continue ; + + // curva esterna del chunk della prima regione (ovviamente già in locale al riferimento intrinseco) + const ICurve* pCrv1Loc = m_pRegM->GetMyLoop( nCM, nLM) ; + const CurveComposite* pCompo1 = GetBasicCurveComposite( pCrv1Loc) ; + + // verifico la collisione tra le entità dei loop esterni dei due chunk + const ICurve* pCrv1 = ( pCompo1 != nullptr ? pCompo1->GetFirstCurve() : pCrv1Loc) ; + while ( pCrv1 != nullptr) { + const ICurve* pCrv2 = ( pCompo2 != nullptr ? pCompo2->GetFirstCurve() : pCrv2Loc) ; + while ( pCrv2 != nullptr) { + if ( ! RotateCurveNoCollisionCurve( pCrv1, pCrv2, ptCenL, dNewAng)) + return false ; + pCrv2 = ( pCompo2 != nullptr ? pCompo2->GetNextCurve() : nullptr) ; + } + pCrv1 = ( pCompo1 != nullptr ? pCompo1->GetNextCurve() : nullptr) ; + } + } + } + } + } + + // se da limitare il movimento + if ( ( dAng > 0 && dNewAng < dAng - EPS_ANG_SMALL) || + ( dAng < 0 && dNewAng > dAng + EPS_ANG_SMALL)) + dAng = dNewAng ; + + return true ; +} + +//---------------------------------------------------------------------------- +// Massima traslazione da posizione sicura in direzione e con limite dati +//---------------------------------------------------------------------------- +bool +MyCAvSurfFrMove::TranslateCurveNoCollisionCurve( const ICurve* pCrv1, const ICurve* pCrv2, + const Vector3d& vtDir, double& dLen, CollInfo& cInfo) +{ + // se entrambe linee, procedo direttamente + if ( pCrv1->GetType() == CRV_LINE && pCrv2->GetType() == CRV_LINE) { + const CurveLine* pLine1 = GetBasicCurveLine( pCrv1) ; + const CurveLine* pLine2 = GetBasicCurveLine( pCrv2) ; + if ( ! TranslateLineNoCollisionLine( pLine1, pLine2, vtDir, dLen, cInfo)) + return false ; + cInfo.vtDirM = pLine1->GetEnd() - pLine1->GetStart() ; + cInfo.vtDirF = pLine2->GetEnd() - pLine2->GetStart() ; + return true ; + } + + // altrimenti confronto le approssimazioni con linee delle curve + // determino le due polilinee + PolyLine PL1 ; + if ( ! pCrv1->ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL1)) + return false ; + PolyLine PL2 ; + if ( ! pCrv2->ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL2)) + return false ; + // ciclo sulle linee della prima polilinea + Point3d ptStart1, ptEnd1 ; + bool bPL1 = PL1.GetFirstLine( ptStart1, ptEnd1) ; + while ( bPL1) { + // definisco la prima linea della coppia + CurveLine Line1 ; + Line1.Set( ptStart1, ptEnd1) ; + // ciclo sulle linee della seconda polilinea + Point3d ptStart2, ptEnd2 ; + bool bPL2 = PL2.GetFirstLine( ptStart2, ptEnd2) ; + while ( bPL2) { + // definisco la seconda linea della coppia + CurveLine Line2 ; + Line2.Set( ptStart2, ptEnd2) ; + // confronto le linee + CollInfo scInfoCurr ; + double dPrevLen = dLen ; + if ( ! TranslateLineNoCollisionLine( &Line1, &Line2, vtDir, dLen, scInfoCurr)) + return false ; + if ( dLen < dPrevLen) { + cInfo = scInfoCurr ; + cInfo.nType = CI_PNT_PNT ; + cInfo.vtDirM = ptEnd1 - ptStart1 ; + cInfo.vtDirF = ptEnd2 - ptStart2 ; + } + bPL2 = PL2.GetNextLine( ptStart2, ptEnd2) ; + } + bPL1 = PL1.GetNextLine( ptStart1, ptEnd1) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +// Massima traslazione da posizione sicura in direzione e con limite dati +//---------------------------------------------------------------------------- +bool +MyCAvSurfFrMove::TranslateLineNoCollisionLine( const CurveLine* pLine1, const CurveLine* pLine2, + const Vector3d& vtDir, double& dLen, CollInfo& cInfo) +{ + // versore ortogonale al movimento + Vector3d vtNorm( vtDir.y, - vtDir.x, 0) ; + // coordinate degli estremi dei segmenti nel riferimento formato da O=L1Start X=vtNorm Y=vtDir + Point3d ptS1( 0, 0, 0) ; + Point3d ptE1( ( pLine1->GetEnd() - pLine1->GetStart()) * vtNorm, + ( pLine1->GetEnd() - pLine1->GetStart()) * vtDir, 0) ; + Point3d ptS2( ( pLine2->GetStart() - pLine1->GetStart()) * vtNorm, + ( pLine2->GetStart() - pLine1->GetStart()) * vtDir, 0) ; + Point3d ptE2( ( pLine2->GetEnd() - pLine1->GetStart()) * vtNorm, + ( pLine2->GetEnd() - pLine1->GetStart()) * vtDir, 0) ; + // perpendicolari esterne alle due linee (nel riferimento sopra definito) + Vector3d vtN1( ( ptE1.y - ptS1.y), - ( ptE1.x - ptS1.x), 0) ; + Vector3d vtN2( ( ptE2.y - ptS2.y), - ( ptE2.x - ptS2.x), 0) ; + // reset info di collisione + cInfo.nType = CI_NONE ; + // eseguo culling (le linee sono il contorno di una area chiusa) + if ( vtN1.y <= 0 || vtN2.y >= 0) + return true ; + // ordino l'intervallo della prima linea secondo X crescenti + if ( ptS1.x > ptE1.x) + swap( ptS1, ptE1) ; + // ordino l'intervallo della seconda linea secondo X crescenti + if ( ptS2.x > ptE2.x) + swap( ptS2, ptE2) ; + // se gli intervalli non si sovrappongono, non ci sono limiti + if ( ptS1.x > ptE2.x - EPS_SMALL || ptS2.x > ptE1.x - EPS_SMALL) + return true ; + // calcolo il minimo movimento degli estremi interni all'intervallo comune + double dNewLen ; + // estremo inferiore + if ( ptS1.x >= ptS2.x) { + double dY2 ; + if ( abs( ptE2.x - ptS2.x) < EPS_SMALL) + dY2 = min( ptE2.y, ptS2.y) ; + else + dY2 = ptS2.y + ( ptE2.y - ptS2.y) / ( ptE2.x - ptS2.x) * ( ptS1.x - ptS2.x) ; + dNewLen = dY2 - ptS1.y ; + if ( abs( ptS1.x - ptS2.x) < EPS_SMALL || abs( ptS1.x - ptE2.x) < EPS_SMALL) + cInfo.nType = CI_PNT_PNT ; + else + cInfo.nType = CI_PNT_LINE ; + cInfo.ptP1 = pLine1->GetStart() + ptS1.x * vtNorm + dY2 * vtDir ; + } + else { + double dY1 ; + if ( abs( ptE1.x - ptS1.x) < EPS_SMALL) + dY1 = max( ptE1.y, ptS1.y) ; + else + dY1 = ptS1.y + ( ptE1.y - ptS1.y) / ( ptE1.x - ptS1.x) * ( ptS2.x - ptS1.x) ; + dNewLen = ptS2.y - dY1 ; + if ( abs( ptS2.x - ptS1.x) < EPS_SMALL || abs( ptS2.x - ptE1.x) < EPS_SMALL) + cInfo.nType = CI_PNT_PNT ; + else + cInfo.nType = CI_LINE_PNT ; + cInfo.ptP1 = pLine1->GetStart() + ptS2.x * vtNorm + ptS2.y * vtDir ; + } + // estremo superiore + if ( ptE1.x <= ptE2.x) { + double dY2 ; + if ( abs( ptE2.x - ptS2.x) < EPS_SMALL) + dY2 = min( ptE2.y, ptS2.y) ; + else + dY2 = ptS2.y + ( ptE2.y - ptS2.y) / ( ptE2.x - ptS2.x) * ( ptE1.x - ptS2.x) ; + double dCurLen = dY2 - ptE1.y ; + if ( abs( dCurLen - dNewLen) < EPS_SMALL) { + cInfo.nType = CI_LINE_LINE ; + cInfo.ptP2 = pLine1->GetStart() + ptE1.x * vtNorm + dY2 * vtDir ; + } + else if ( dCurLen < dNewLen) { + dNewLen = dCurLen ; + if ( abs( ptE1.x - ptS2.x) < EPS_SMALL || abs( ptE1.x - ptE2.x) < EPS_SMALL) + cInfo.nType = CI_PNT_PNT ; + else + cInfo.nType = CI_PNT_LINE ; + cInfo.ptP1 = pLine1->GetStart() + ptE1.x * vtNorm + dY2 * vtDir ; + } + } + else { + double dY1 ; + if ( abs( ptE1.x - ptS1.x) < EPS_SMALL) + dY1 = max( ptE1.y, ptS1.y) ; + else + dY1 = ptS1.y + ( ptE1.y - ptS1.y) / ( ptE1.x - ptS1.x) * ( ptE2.x - ptS1.x) ; + double dCurLen = ptE2.y - dY1 ; + if ( abs( dCurLen - dNewLen) < EPS_SMALL) { + cInfo.nType = CI_LINE_LINE ; + cInfo.ptP2 = pLine1->GetStart() + ptE2.x * vtNorm + ptE2.y * vtDir ; + } + else if ( dCurLen < dNewLen) { + dNewLen = dCurLen ; + if ( abs( ptE2.x - ptS1.x) < EPS_SMALL || abs( ptE2.x - ptE1.x) < EPS_SMALL) + cInfo.nType = CI_PNT_PNT ; + else + cInfo.nType = CI_LINE_PNT ; + cInfo.ptP1 = pLine1->GetStart() + ptE2.x * vtNorm + ptE2.y * vtDir ; + } + } + // confronto con movimento corrente + if ( dNewLen > - 5 * EPS_SMALL && dNewLen < EPS_SMALL) + dLen = 0 ; + else if ( dNewLen > 0 && dNewLen < dLen) + dLen = dNewLen ; + else // non c'è collisione, reset Info + cInfo.nType = CI_NONE ; + return true ; +} + +//---------------------------------------------------------------------------- +// Massima rotazione da posizione sicura in direzione e con limite dati +//---------------------------------------------------------------------------- +bool +MyCAvSurfFrMove::RotateCurveNoCollisionCurve( const ICurve* pCrv1, const ICurve* pCrv2, const Point3d& ptCen, double& dAng) +{ + // se entrambe linee, procedo direttamente + if ( pCrv1->GetType() == CRV_LINE && pCrv2->GetType() == CRV_LINE) { + const CurveLine* pLine1 = GetBasicCurveLine( pCrv1) ; + const CurveLine* pLine2 = GetBasicCurveLine( pCrv2) ; + if ( ! RotateLineNoCollisionLine( pLine1, pLine2, ptCen, dAng)) + return false ; + return true ; + } + + // altrimenti confronto le approssimazioni con linee delle curve + // determino le due polilinee + PolyLine PL1 ; + if ( ! pCrv1->ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL1)) + return false ; + PolyLine PL2 ; + if ( ! pCrv2->ApproxWithLines( LIN_TOL_FINE, ANG_TOL_STD_DEG, ICurve::APL_RIGHT, PL2)) + return false ; + // ciclo sulle linee della prima polilinea + Point3d ptStart1, ptEnd1 ; + bool bPL1 = PL1.GetFirstLine( ptStart1, ptEnd1) ; + while ( bPL1) { + // definisco la prima linea della coppia + CurveLine Line1 ; + Line1.Set( ptStart1, ptEnd1) ; + // ciclo sulle linee della seconda polilinea + Point3d ptStart2, ptEnd2 ; + bool bPL2 = PL2.GetFirstLine( ptStart2, ptEnd2) ; + while ( bPL2) { + // definisco la seconda linea della coppia + CurveLine Line2 ; + Line2.Set( ptStart2, ptEnd2) ; + // confronto le linee + if ( ! RotateLineNoCollisionLine( &Line1, &Line2, ptCen, dAng)) + return false ; + bPL2 = PL2.GetNextLine( ptStart2, ptEnd2) ; + } + bPL1 = PL1.GetNextLine( ptStart1, ptEnd1) ; + } + return true ; +} + +//---------------------------------------------------------------------------- +// Massima rotazione da posizione sicura in direzione e con limite dati +//---------------------------------------------------------------------------- +bool +MyCAvSurfFrMove::RotateLineNoCollisionLine( const CurveLine* pLine1, const CurveLine* pLine2, const Point3d& ptCen, double& dAng) +{ + // senso di rotazione + bool bCCW = ( dAng > 0) ; + + // analisi della prima linea + Point3d ptS1 = pLine1->GetStart() ; + Point3d ptE1 = pLine1->GetEnd() ; + Vector3d vtDir1 = ptE1 - ptS1 ; + vtDir1.z = 0 ; + double dLen1 = vtDir1.LenXY() ; + if ( dLen1 < EPS_SMALL) + return false ; + vtDir1 /= dLen1 ; + Vector3d vtN1( vtDir1.y, - vtDir1.x, 0) ; + // linea per successivi controlli + CurveLine NewLine1 ; + // se punto a minima distanza da C non interno al segmento, eseguo direttamente culling su intera linea + double dUMin1 = ( ptCen - ptS1) * vtDir1 ; + if ( dUMin1 < EPS_SMALL || dUMin1 > dLen1 - EPS_SMALL) { + Vector3d vtRad = 0.5 * ( ptE1 + ptS1) - ptCen ; + Vector3d vtMove = ( bCCW ? Vector3d( - vtRad.y, vtRad.x, 0) : Vector3d( vtRad.y, - vtRad.x, 0)) ; + if ( vtN1 * vtMove <= 0) + return true ; + } + // altrimenti tengo parte con culling superato + else { + // verifico primo estremo + Vector3d vtRad = ptS1 - ptCen ; + Vector3d vtMove = ( bCCW ? Vector3d( - vtRad.y, vtRad.x, 0) : Vector3d( vtRad.y, - vtRad.x, 0)) ; + // se va bene il primo estremo + if ( vtN1 * vtMove > 0) { + ptE1 = ptS1 + vtDir1 * dUMin1 ; + dLen1 = dUMin1 ; + } + // altrimenti deve andare bene il secondo + else { + ptS1 += vtDir1 * dUMin1 ; + dLen1 -= dUMin1 ; + } + NewLine1.Set( ptE1, ptS1) ; + pLine1 = &NewLine1 ; + } + + // analisi della seconda linea + Point3d ptS2 = pLine2->GetStart() ; + Point3d ptE2 = pLine2->GetEnd() ; + Vector3d vtDir2 = ptE2 - ptS2 ; + vtDir2.z = 0 ; + double dLen2 = vtDir2.LenXY() ; + if ( dLen2 < EPS_SMALL) + return false ; + vtDir2 /= dLen2 ; + Vector3d vtN2( vtDir2.y, - vtDir2.x, 0) ; + // linea per successivi controlli + CurveLine NewLine2 ; + // se punto a minima distanza da C non interno al segmento, eseguo direttamente culling su intera linea + double dUMin2 = ( ptCen - ptS2) * vtDir2 ; + if ( dUMin2 < EPS_SMALL || dUMin2 > dLen2 - EPS_SMALL) { + Vector3d vtRad = 0.5 * ( ptE2 + ptS2) - ptCen ; + Vector3d vtMove = ( bCCW ? Vector3d( - vtRad.y, vtRad.x, 0) : Vector3d( vtRad.y, - vtRad.x, 0)) ; + if ( vtN2 * vtMove >= 0) + return true ; + } + // altrimenti tengo parte con culling superato + else { + // verifico primo estremo + Vector3d vtRad = ptS2 - ptCen ; + Vector3d vtMove = ( bCCW ? Vector3d( - vtRad.y, vtRad.x, 0) : Vector3d( vtRad.y, - vtRad.x, 0)) ; + // se va bene il primo estremo + if ( vtN2 * vtMove < 0) { + ptE2 = ptS2 + vtDir2 * dUMin2 ; + dLen2 = dUMin2 ; + } + // altrimenti deve andare bene il secondo + else { + ptS2 += vtDir2 * dUMin2 ; + dLen2 -= dUMin2 ; + } + NewLine2.Set( ptE2, ptS2) ; + pLine2 = &NewLine2 ; + } + + // verifico se gli intervalli radiali si sovrappongono + Vector3d vtDirS1 = ptS1 - ptCen ; + vtDirS1.z = 0 ; + double dRadS1 = vtDirS1.LenXY() ; + Vector3d vtDirE1 = ptE1 - ptCen ; + vtDirE1.z = 0 ; + double dRadE1 = vtDirE1.LenXY() ; + Vector3d vtDirS2 = ptS2 - ptCen ; + vtDirS2.z = 0 ; + double dRadS2 = vtDirS2.LenXY() ; + Vector3d vtDirE2 = ptE2 - ptCen ; + vtDirE2.z = 0 ; + double dRadE2 = vtDirE2.LenXY() ; + + // ordino l'intervallo della prima linea secondo raggi crescenti + if ( dRadS1 > dRadE1) { + swap( ptS1, ptE1) ; + swap( vtDirS1, vtDirE1) ; + swap( dRadS1, dRadE1) ; + } + // ordino l'intervallo della seconda linea secondo raggi crescenti + if ( dRadS2 > dRadE2) { + swap( ptS2, ptE2) ; + swap( vtDirS2, vtDirE2) ; + swap( dRadS2, dRadE2) ; + } + // se gli intervalli non si sovrappongono, non ci sono limiti + if ( dRadS1 > dRadE2 - EPS_SMALL || dRadS2 > dRadE1 - EPS_SMALL) + return true ; + + // calcolo la minima rotazione degli estremi interni all'intervallo comune + double dNewAng = dAng ; + if ( ! AreSamePointXYEpsilon( ptS1, ptS2, 10 * EPS_SMALL)) { + if ( dRadS1 >= dRadS2) { + vtDirS1 /= dRadS1 ; + CurveArc ArcS1 ; + ArcS1.Set( ptCen, Z_AX, dRadS1, vtDirS1, dAng, 0) ; + IntersLineArc intLA( *pLine2, ArcS1) ; + if ( intLA.GetNumInters() == 2) { + IntCrvCrvInfo iccInfo1, iccInfo2 ; + intLA.GetIntCrvCrvInfo( 0, iccInfo1) ; + intLA.GetIntCrvCrvInfo( 1, iccInfo2) ; + dNewAng = dAng * min( iccInfo1.IciB[0].dU, iccInfo2.IciB[0].dU) ; + } + else if ( intLA.GetNumInters() == 1) { + IntCrvCrvInfo iccInfo ; + intLA.GetIntCrvCrvInfo( 0, iccInfo) ; + dNewAng = dAng * iccInfo.IciB[0].dU ; + } + } + else { + vtDirS2 /= dRadS2 ; + CurveArc ArcS2 ; + ArcS2.Set( ptCen, Z_AX, dRadS2, vtDirS2, - dAng, 0) ; + IntersLineArc intLA( *pLine1, ArcS2) ; + if ( intLA.GetNumInters() == 2) { + IntCrvCrvInfo iccInfo1, iccInfo2 ; + intLA.GetIntCrvCrvInfo( 0, iccInfo1) ; + intLA.GetIntCrvCrvInfo( 1, iccInfo2) ; + dNewAng = dAng * min( iccInfo1.IciB[0].dU, iccInfo2.IciB[0].dU) ; + } + else if ( intLA.GetNumInters() == 1) { + IntCrvCrvInfo iccInfo ; + intLA.GetIntCrvCrvInfo( 0, iccInfo) ; + dNewAng = dAng * iccInfo.IciB[0].dU ; + } + } + } + if ( ! AreSamePointXYEpsilon( ptE1, ptE2, 10 * EPS_SMALL)) { + if ( dRadE1 <= dRadE2) { + vtDirE1 /= dRadE1 ; + CurveArc ArcE1 ; + ArcE1.Set( ptCen, Z_AX, dRadE1, vtDirE1, dAng, 0) ; + IntersLineArc intLA( *pLine2, ArcE1) ; + if ( intLA.GetNumInters() == 2) { + IntCrvCrvInfo iccInfo1, iccInfo2 ; + intLA.GetIntCrvCrvInfo( 0, iccInfo1) ; + intLA.GetIntCrvCrvInfo( 1, iccInfo2) ; + if ( bCCW) + dNewAng = min( dNewAng, dAng * min( iccInfo1.IciB[0].dU, iccInfo2.IciB[0].dU)) ; + else + dNewAng = max( dNewAng, dAng * min( iccInfo1.IciB[0].dU, iccInfo2.IciB[0].dU)) ; + } + else if ( intLA.GetNumInters() == 1) { + IntCrvCrvInfo iccInfo ; + intLA.GetIntCrvCrvInfo( 0, iccInfo) ; + if ( bCCW) + dNewAng = min( dNewAng, dAng * iccInfo.IciB[0].dU) ; + else + dNewAng = max( dNewAng, dAng * iccInfo.IciB[0].dU) ; + } + } + else { + vtDirE2 /= dRadE2 ; + CurveArc ArcE2 ; + ArcE2.Set( ptCen, Z_AX, dRadE2, vtDirE2, - dAng, 0) ; + IntersLineArc intLA( *pLine1, ArcE2) ; + if ( intLA.GetNumInters() == 2) { + IntCrvCrvInfo iccInfo1, iccInfo2 ; + intLA.GetIntCrvCrvInfo( 0, iccInfo1) ; + intLA.GetIntCrvCrvInfo( 1, iccInfo2) ; + if ( bCCW) + dNewAng = min( dNewAng, dAng * min( iccInfo1.IciB[0].dU, iccInfo2.IciB[0].dU)) ; + else + dNewAng = max( dNewAng, dAng * min( iccInfo1.IciB[0].dU, iccInfo2.IciB[0].dU)) ; + } + else if ( intLA.GetNumInters() == 1) { + IntCrvCrvInfo iccInfo ; + intLA.GetIntCrvCrvInfo( 0, iccInfo) ; + if ( bCCW) + dNewAng = min( dNewAng, dAng * iccInfo.IciB[0].dU) ; + else + dNewAng = max( dNewAng, dAng * iccInfo.IciB[0].dU) ; + } + } + } + if ( AreSamePointXYEpsilon( ptS1, ptS2, 10 * EPS_SMALL) && + AreSamePointXYEpsilon( ptE1, ptE2, 10 * EPS_SMALL)) + dNewAng = 0 ; + // confronto con rotazione corrente + if ( abs( dNewAng) < EPS_ANG_SMALL) + dAng = 0 ; + else if ( bCCW && dNewAng > 0) + dAng = min( dAng, dNewAng) ; + else if ( ! bCCW && dNewAng < 0) + dAng = max( dAng, dNewAng) ; + return true ; +} diff --git a/CAvSurfFrMove.h b/CAvSurfFrMove.h new file mode 100644 index 0000000..b504958 --- /dev/null +++ b/CAvSurfFrMove.h @@ -0,0 +1,46 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2018 +//---------------------------------------------------------------------------- +// File : CAvSurfFrMove.h Data : 27.04.18 Versione : 3.1c6 +// Contenuto : Dich.ne classe privata per movimento di superfici flat region +// nel loro piano evitando collisioni +// +// Modifiche : 26.03.2026 RE Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkCAvSurfFrMove.h" + +class CurveLine ; +class SurfFlatRegion ; + +//---------------------------------------------------------------------------- +class MyCAvSurfFrMove +{ + public : + MyCAvSurfFrMove( const ISurfFlatRegion& SfrM, const ISurfFlatRegion& SfrF) ; + + public : + bool Translate( const Vector3d& vtDir, double& dLen) ; + bool Rotate( const Point3d& ptCen, double& dAng) ; + const CollInfo& GetCollInfo() + { return m_CollInfo ; } + + private : + bool TranslateCurveNoCollisionCurve( const ICurve* pCrv1, const ICurve* pCrv2, + const Vector3d& vtDir, double& dLen, CollInfo& cInfo) ; + bool TranslateLineNoCollisionLine( const CurveLine* pLine1, const CurveLine* pLine2, + const Vector3d& vtDir, double& dLen, CollInfo& cInfo) ; + bool RotateCurveNoCollisionCurve( const ICurve* pCrv1, const ICurve* pCrv2, + const Point3d& ptCen, double& dAng) ; + bool RotateLineNoCollisionLine( const CurveLine* pLine1, const CurveLine* pLine2, + const Point3d& ptCen, double& dAng) ; + + private : + const SurfFlatRegion* m_pRegM ; + const SurfFlatRegion* m_pRegF ; + CollInfo m_CollInfo ; +} ; diff --git a/EGkCAvSurfFrMove.h b/EGkCAvSurfFrMove.h new file mode 100644 index 0000000..b05a723 --- /dev/null +++ b/EGkCAvSurfFrMove.h @@ -0,0 +1,69 @@ +//---------------------------------------------------------------------------- +// EgalTech 2015-2018 +//---------------------------------------------------------------------------- +// File : EGkCAvSurfFrMove.h Data : 26.03.2026 Versione : 3.1c6 +// Contenuto : Dichiarazione classe per movimento di superfici flat region +// nel loro piano evitando collisioni +// +// Modifiche : 26.03.26 RE Creazione modulo. +// +// +//---------------------------------------------------------------------------- + +#pragma once + +#include "/EgtDev/Include/EGkSurfFlatRegion.h" + +//----------------------- Macro per import/export ---------------------------- +#undef EGK_EXPORT +#if defined( I_AM_EGK) // da definirsi solo nella DLL + #define EGK_EXPORT __declspec( dllexport) +#else + #define EGK_EXPORT __declspec( dllimport) +#endif + +//---------------------------------------------------------------------------- +// Costanti per info su tipo di Collisione tra regioni piane +const int CI_NONE = 0 ; // non definito +const int CI_PNT_PNT = 1 ; // tra punto di mobile e punto di fissa +const int CI_PNT_LINE = 2 ; // tra punto di mobile e linea di fissa +const int CI_LINE_PNT = 3 ; // tra linea di mobile e punto di fissa +const int CI_LINE_LINE = 4 ; // tra linea di mobile e linea di fissa + +//---------------------------------------------------------------------------- +struct CollInfo +{ + int nType ; // tipo di collisione + int nChunkM ; // indice del chunk della regione mobile + int nCrvM ; // indice della curva nel loop esterno del chunk + int nChunkF ; // indice del chunk della regione fissa + int nCrvF ; // indice della curva nel loop esterno del chunk + Point3d ptP1 ; // punto di contatto + Point3d ptP2 ; // se contatto linea-linea, secondo punto di contatto + Vector3d vtDirM ; // se contatto del mobile con linea, sua direzione + Vector3d vtDirF ; // se contatto del fisso con linea, sua direzione + // costruttori + CollInfo() : nType( CI_NONE), nChunkM( -1), nCrvM( -1), nChunkF( -1), nCrvF( -1), + ptP1(), ptP2(), vtDirM(), vtDirF() {} + CollInfo( const CollInfo& Sou) : nType( Sou.nType), nChunkM( Sou.nChunkM), nCrvM( Sou.nCrvM), + nChunkF( Sou.nChunkF), nCrvF( Sou.nCrvF), ptP1( Sou.ptP1), + ptP2( Sou.ptP2), vtDirM( Sou.vtDirM), vtDirF( Sou.vtDirF) {} +} ; + +//---------------------------------------------------------------------------- +class CAvSurfFrMove +{ + public : + EGK_EXPORT CAvSurfFrMove( const ISurfFlatRegion& SfrM, const ISurfFlatRegion& SfrF) ; + + public : + EGK_EXPORT bool Translate( const Vector3d& vtDir, double& dLen) ; + EGK_EXPORT bool Rotate( const Point3d& ptCen, double& dAng) ; + EGK_EXPORT const CollInfo& GetCollInfo() + { return m_CollInfo ; } + + private : + const ISurfFlatRegion* m_pRegM ; + const ISurfFlatRegion* m_pRegF ; + CollInfo m_CollInfo ; +} ; \ No newline at end of file diff --git a/EgtGeomKernel.vcxproj b/EgtGeomKernel.vcxproj index 202867f..d1aee7b 100644 --- a/EgtGeomKernel.vcxproj +++ b/EgtGeomKernel.vcxproj @@ -284,6 +284,7 @@ copy $(TargetPath) \EgtProg\Dll64 + @@ -353,6 +354,7 @@ copy $(TargetPath) \EgtProg\Dll64 + diff --git a/EgtGeomKernel.vcxproj.filters b/EgtGeomKernel.vcxproj.filters index 0c644f1..e5df427 100644 --- a/EgtGeomKernel.vcxproj.filters +++ b/EgtGeomKernel.vcxproj.filters @@ -570,6 +570,9 @@ File di origine\Geo + + File di origine\GeoCollisionAvoid + @@ -1256,6 +1259,9 @@ File di intestazione\Include + + File di intestazione + diff --git a/SurfFlatRegion.cpp b/SurfFlatRegion.cpp index 550f687..21b09ca 100644 --- a/SurfFlatRegion.cpp +++ b/SurfFlatRegion.cpp @@ -1549,7 +1549,7 @@ SurfFlatRegion::GetChunkSimpleClassification( int nChunk, const ISurfFlatRegion& // classifico il loop esterno del chunk della prima regione rispetto a quello del chunk della seconda IntersCurveCurve ccInt( *pCrv1Loc, *pCrv2Loc) ; int nClass = ccInt.GetRegionCurveClassification() ; - switch ( nClass){ + switch ( nClass) { default : // CCREGC_NULL return REGC_NULL ; case CCREGC_IN1 : @@ -1562,7 +1562,141 @@ SurfFlatRegion::GetChunkSimpleClassification( int nChunk, const ISurfFlatRegion& return REGC_OUT ; case CCREGC_INTERS : return REGC_INTERS ; - } + } +} + +//---------------------------------------------------------------------------- +bool +SurfFlatRegion::CheckChunkInterference( int nChunk, const ISurfFlatRegion& Other, int nOthChunk, bool& bInterference) const +{ + bInterference = false ; + // verifico lo stato e il numero di chunk + if ( m_nStatus != OK || m_vpLoop.empty() || nChunk >= GetChunkCount()) + return false ; + // recupero rappresentazione base dell'altra regione + const SurfFlatRegion& Reg2 = *GetBasicSurfFlatRegion( &Other) ; + // verifico lo stato e il numero di chunk dell'altra regione + if ( Reg2.m_nStatus != OK || Reg2.m_vpLoop.empty() || nOthChunk >= Reg2.GetChunkCount()) + return false ; + + // verifico che le due regioni giacciano in piani paralleli + if ( ! AreSameVectorApprox( m_frF.VersZ(), Reg2.m_frF.VersZ())) + return false ; + + // classifico il loop esterno del chunk della prima regione rispetto a quello del chunk della seconda + int nClass = GetChunkSimpleClassification( nChunk, Other, nOthChunk) ; + if ( nClass == REGC_NULL) + return false ; + // se le regioni non hanno isole, allora ho già identificato se i Chunks fanno interferenza + int nLoopCnt = GetLoopCount( nChunk) ; + int nOtherLoopCnt = Other.GetLoopCount( nOthChunk) ; + if ( nLoopCnt == 1 && nOtherLoopCnt == 1) { + bInterference = ( nClass != REGC_OUT) ; + return true ; + } + + // --- a prescindere dalle isole presenti nei 2 Chunks in esame : + // se i due loop esterni si intersecano tra loro o sono gli stessi, allora fanno per forza interferenza + if ( nClass == REGC_INTERS || nClass == CCREGC_SAME) { + bInterference = true ; + return true ; + } + // se invece sono esterni tra loro, allora non c'è interferenza + else if ( nClass == REGC_OUT) + return true ; + // --- Analisi del loop interni : + // se la curva esterna corrente è interna alla curva esterna dell'altro chunk + else if ( nClass == REGC_IN1) { + // se l'altro chunk non ha isole, c'è interferenza (a prescinere da numero di loop interni del primo chunk) + if ( nOtherLoopCnt == 1) { + bInterference = true ; + return true ; + } + // curva esterna del chunk della prima regione (ovviamente già in locale al riferimento intrinseco) + const ICurve* pCrv1Loc = GetMyLoop( nChunk, 0) ; + // per ogni loop interno (isole) + for ( int i = 1 ; i < nOtherLoopCnt ; ++ i) { + const ICurve* pCrv2Loc = nullptr ; + PtrOwner pCopyCrv ; + if ( AreSameFrame( m_frF, Reg2.m_frF)) + pCrv2Loc = Reg2.GetMyLoop( nOthChunk, i) ; + else { + pCopyCrv.Set( Reg2.GetMyLoop( nOthChunk, i)->Clone()) ; + if ( IsNull( pCopyCrv)) + return false ; + pCopyCrv->LocToLoc( Reg2.m_frF, m_frF) ; + pCrv2Loc = pCopyCrv ; + } + // classifico il loop esterno del chunk della prima regione rispetto all'interno corrente del chunk della seconda + IntersCurveCurve ccInt( *pCrv1Loc, *pCrv2Loc) ; + int nInternalClass = ccInt.GetRegionCurveClassification() ; + // se le curve non sono classificabili, errore + if ( nInternalClass == REGC_NULL) + return false ; + // se la curva di bordo corrente è interna (le isole girano al contrario) all'isola corrente + else if ( nInternalClass == REGC_IN1) + ; // non faccio nulla, potrebbe non essere l'isola adatta per la classificazione + // se la curva di bordo corrente è esterna (le isole girano al contrario) all'isola corrente, allora non ho interferenza + else if ( nInternalClass == REGC_OUT) + return true ; + // se la curva di bordo corrente interseca l'isola o coincide con essa allora c'è interferenza + else if ( nInternalClass == REGC_INTERS || nInternalClass == REGC_SAME) { + bInterference = true ; + return true ; + } + // negli altri casi ho un orientamento errato dei loop o delle regioni + else + return false ; + } + } + // se la curva esterna dell'altro chunk è interna alla curva esterna corrente + else if ( nClass == REGC_IN2) { + // se l'altro chunk non ha isole, c'è interferenza + if ( nLoopCnt == 1) { + bInterference = true ; + return true ; + } + // curva esterna del chunk della prima regione (ovviamente già in locale al riferimento intrinseco) + const ICurve* pCrv2Loc = Reg2.GetMyLoop( nChunk, 0) ; + // per ogni loop interno (isole) + for ( int i = 1 ; i < nLoopCnt ; ++ i) { + const ICurve* pCrv1Loc = nullptr ; + PtrOwner pCopyCrv ; + if ( AreSameFrame( Reg2.m_frF, m_frF)) + pCrv1Loc = GetMyLoop( nOthChunk, i) ; + else { + pCopyCrv.Set( GetMyLoop( nOthChunk, i)->Clone()) ; + if ( IsNull( pCopyCrv)) + return false ; + pCopyCrv->LocToLoc( m_frF, Reg2.m_frF) ; + pCrv1Loc = pCopyCrv ; + } + // classifico il loop esterno del chunk della prima regione rispetto a quello del chunk della seconda + IntersCurveCurve ccInt( *pCrv2Loc, *pCrv1Loc) ; + int nInternalClass = ccInt.GetRegionCurveClassification() ; + // se le curve non sono classificabili, errore + if ( nInternalClass == REGC_NULL) + return false ; + // se la curva di bordo corrente è interna (le isole girano al contrario) all'isola corrente + else if ( nInternalClass == REGC_IN1) + ; // non faccio nulla, potrebbe non essere l'isola adatta per la classificazione + // se la curva di bordo corrente è esterna (le isole girano al contrario) all'isola corrente, allora non ho interferenza + else if ( nInternalClass == REGC_OUT) + return true ; + // se la curva di bordo corrente interseca l'isola o coincide con essa allora c'è interferenza + else if ( nInternalClass == REGC_INTERS || nInternalClass == REGC_SAME) { + bInterference = true ; + return true ; + } + // negli altri casi ho un orientamento errato dei loop o delle regioni + else + return false ; + } + } + + // in questo la curva di bordo è interna ad ogni isola ma interna anche al loop esterno, quindi esiste interferenza + bInterference = true ; + return true ; } //---------------------------------------------------------------------------- diff --git a/SurfFlatRegion.h b/SurfFlatRegion.h index 70b865e..e4e2526 100644 --- a/SurfFlatRegion.h +++ b/SurfFlatRegion.h @@ -107,6 +107,7 @@ class SurfFlatRegion : public ISurfFlatRegion, public IGeoObjRW bool GetChunkArea( int nChunk, double& dArea) const override ; bool GetChunkPerimeter( int nChunk, double& dLen) const override ; int GetChunkSimpleClassification( int nChunk, const ISurfFlatRegion& Other, int nOthChunk) const override ; // compare only outsides + bool CheckChunkInterference( int nChunk, const ISurfFlatRegion& Other, int nOthChunk, bool& bInterference) const override ; // compare alls bool GetChunkMaxOffset( int nChunk, double& dOffs) const override ; int GetLoopCount( int nChunk) const override ; int GetLoopCurveCount( int nChunk, int nLoop) const override ; @@ -139,6 +140,7 @@ class SurfFlatRegion : public ISurfFlatRegion, public IGeoObjRW SurfTriMesh* CalcAuxSurf( double dLinTol, double dAngTolDeg) const ; friend class MyCAvSimpleSurfFrMove ; + friend class MyCAvSurfFrMove ; private : enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ;