From 119bbe0bcbd91945075deb9187cdff06914efada Mon Sep 17 00:00:00 2001 From: SaraP Date: Thu, 28 May 2026 15:30:41 +0200 Subject: [PATCH] EgtGeomKernel : - prime migliorie nella creazione di solidi swept con sezione rettangolare e bevel ( prima versione, da sistemare caps flat e none) - correzione in Voronoi. --- StmFromCurves.cpp | 1655 ++++++++++++++++++++++++++++++--------------- Voronoi.cpp | 13 +- 2 files changed, 1128 insertions(+), 540 deletions(-) diff --git a/StmFromCurves.cpp b/StmFromCurves.cpp index 3ffa6ee..e96af3a 100644 --- a/StmFromCurves.cpp +++ b/StmFromCurves.cpp @@ -19,6 +19,7 @@ #include "CurveComposite.h" #include "SurfTriMesh.h" #include "Voronoi.h" +#include "IntersLineLine.h" #include "/EgtDev/Include/EGkSfrCreate.h" #include "/EgtDev/Include/EGkOffsetCurve.h" #include "/EgtDev/Include/EGkStmFromCurves.h" @@ -26,11 +27,21 @@ #include "/EgtDev/Include/EGkRotationMinimizingFrame.h" #include "/EgtDev/Include/EGkRotationXplaneFrame.h" #include "/EgtDev/Include/EGkIntersCurves.h" +#include "/EgtDev/Include/EGkDistPointCurve.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include using namespace std ; + +//------------------------------------------------------------------------------- +// costanti per SurfTmRectSwept +static const int STM_RECTSWEPT_FLATCAP_START = -1 ; +static const int STM_RECTSWEPT_FLATCAP_END = -2 ; +static const int STM_RECTSWEPT_LINK = -3 ; +static const int STM_RECTSWEPT_FLATCAP_EXTRA = -4 ; + + //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshByFlatContour( const ICurve* pCurve, double dLinTol) @@ -345,6 +356,426 @@ GetSurfTriMeshByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vecto return Release( pSTM) ; } +//------------------------------------------------------------------------------- +static bool +RemoveFatCurveJunctions( ICURVEPOVECTOR& vCrvs) +{ + ICURVEPOVECTOR vResCurves ; + for ( int i = 0 ; i < ssize( vCrvs) ; i ++) { + int nStart = ssize( vResCurves) ; + CurveComposite* pFatCrv = GetBasicCurveComposite( vCrvs[i]) ; + if ( pFatCrv == nullptr) + return false ; + PtrOwner pCrv( CreateBasicCurveComposite()) ; + if ( IsNull( pCrv)) + return false ; + PtrOwner pCurrCrv( pFatCrv->RemoveFirstOrLastCurve( false)) ; + while ( ! IsNull( pCurrCrv)) { + if ( abs( pCurrCrv->GetTempParam() - VRONI_JUNCTION_OPEN) < EPS_SMALL) { + if ( pCrv->IsValid()) { + // salvo la catena trovata fino ad ora e la resetto + vResCurves.emplace_back( Release( pCrv)) ; + pCrv.Set( CreateBasicCurveComposite()) ; + if ( IsNull( pCrv)) + return false ; + } + } + else { + // aggiungo la curva alla catena corrente + pCrv->AddCurve( Release( pCurrCrv)) ; + } + pCurrCrv.Set( pFatCrv->RemoveFirstOrLastCurve( false)) ; + } + if ( pCrv->IsValid()) { + if ( ssize( vResCurves) != nStart) { + // verifico se da concatenare alla prima + Point3d ptEnd ; pCrv->GetEndPoint( ptEnd) ; + Point3d ptStart ; vResCurves[nStart]->GetStartPoint( ptStart) ; + if ( AreSamePointApprox( ptStart, ptEnd)) { + ICurveComposite* pCompo = GetBasicCurveComposite( vResCurves[nStart]) ; + if ( pCompo == nullptr) + return false ; + pCompo->AddCurve( Release( pCrv), false) ; + } + else + vResCurves.emplace_back( Release( pCrv)) ; + } + else + vResCurves.emplace_back( Release( pCrv)) ; + } + } + swap( vResCurves, vCrvs) ; + + return true ; +} + +//------------------------------------------------------------------------------- +static ISurfFlatRegion* +CalcSweptSurface( ICurveComposite* pGuide, const Vector3d& vtNorm, double dOffs) +{ + PtrOwner pSrf( CreateSurfFlatRegion()) ; + if ( IsNull( pSrf)) + return nullptr ; + + // per ogni sottotratto della guida calcolo la regione spazzata dalla sezione su quel tratto + for ( int i = 0 ; i < pGuide->GetCurveCount() ; i ++) { + PtrOwner pCrv( pGuide->GetCurve( i)->Clone()) ; + pCrv->SetExtrusion( vtNorm) ; + if ( pCrv->SimpleOffset( - dOffs)) { + PtrOwner pBorder( CreateCurveComposite()) ; + if ( IsNull( pBorder)) + return nullptr ; + pBorder->AddCurve( pGuide->GetCurve( i)->Clone()) ; + pCrv->Invert() ; + Point3d ptS ; pCrv->GetStartPoint( ptS) ; + pBorder->AddLine( ptS) ; + pBorder->AddCurve( Release( pCrv)) ; + pBorder->Close() ; + + if ( ! pSrf->IsValid()) { + pSrf->AddExtLoop( Release( pBorder)) ; + } + else { + PtrOwner pSrfTmp( CreateSurfFlatRegion()) ; + if ( IsNull( pSrfTmp)) + return nullptr ; + pSrfTmp->AddExtLoop( Release( pBorder)) ; + pSrf->Add( *pSrfTmp) ; + } + } + else { + // se arco che collassa devo costruire separatamente i due spicchi + ICurveArc* pArc = GetCurveArc( pCrv) ; + if ( pArc == nullptr) + return nullptr ; + + Point3d ptC = pArc->GetCenter() ; + Point3d ptS ; pArc->GetStartPoint( ptS) ; + Vector3d vtS = ptC - ptS ; + vtS.Normalize() ; + Point3d ptS2 = ptS + vtS * dOffs ; + + Point3d ptE ; pArc->GetEndPoint( ptE) ; + Vector3d vtE = ptC - ptE ; + vtE.Normalize() ; + Point3d ptE2 = ptE + vtE * dOffs ; + + PtrOwner pArc2( CreateCurveArc()) ; + if ( IsNull( pArc2) || ! pArc2->SetC2PN( ptC, ptS2, ptE2, vtNorm)) + return nullptr ; + + PtrOwner pBorder1( CreateCurveComposite()) ; + if ( IsNull( pBorder1)) + return nullptr ; + pBorder1->AddPoint( ptC) ; + pBorder1->AddLine( ptS) ; + pBorder1->AddCurve( Release( pCrv)) ; + pBorder1->Close() ; + + PtrOwner pBorder2( CreateCurveComposite()) ; + if ( IsNull( pBorder2)) + return nullptr ; + pBorder2->AddPoint( ptC) ; + pBorder2->AddLine( ptS2) ; + pBorder2->AddCurve( Release( pArc2)) ; + pBorder2->Close() ; + + PtrOwner pSrfTmp2( CreateSurfFlatRegion()) ; + if ( IsNull( pSrfTmp2)) + return nullptr ; + pSrfTmp2->AddExtLoop( Release( pBorder2)) ; + + if ( ! pSrf->IsValid()) { + pSrf->AddExtLoop( Release( pBorder1)) ; + pSrf->Add( *pSrfTmp2) ; + } + else { + PtrOwner pSrfTmp1( CreateSurfFlatRegion()) ; + if ( IsNull( pSrfTmp1)) + return nullptr ; + pSrfTmp1->AddExtLoop( Release( pBorder1)) ; + pSrf->Add( *pSrfTmp1) ; + pSrf->Add( *pSrfTmp2) ; + } + } + } + + return Release( pSrf) ; +} + +//------------------------------------------------------------------------------- +static bool +AdjustSurfTriMeshRectSweptCaps( int nCapType, ICURVEPOVECTOR& vCrvs, const Vector3d& vtNorm, const ICurve* pOrigGuide, double dOffs) +{ + // se RSCAP_FLAT trasformo tutte le giunzioni relative agli estremi in linee controllando se necessario chiudere le curve + // con opportuni tratti di offset. + // RSCAP_NONE viene gestito allo stesso modo perchè per la superficie top e bottom servono curve chiuse, le curve + // di giunzione saranno rimosse successivamente per il calcolo della superficie laterale + if ( nCapType == RSCAP_FLAT || nCapType == RSCAP_NONE) { + + // spezzo le curve in corrispondenza delle junctions + RemoveFatCurveJunctions( vCrvs) ; + + // creo le linee di junction sugli estremi della giuda ( j = 0 start, j = 1 end) + for ( int j = 0 ; j < 2 ; j ++) { + Point3d ptP ; + Vector3d vtDir ; + if ( j == 0) { + pOrigGuide->GetStartPoint( ptP) ; + pOrigGuide->GetStartDir( vtDir) ; + } + else { + pOrigGuide->GetEndPoint( ptP) ; + pOrigGuide->GetEndDir( vtDir) ; + } + vtDir.Rotate( vtNorm, ANG_RIGHT) ; + Point3d pt1 = ptP + dOffs * vtDir ; + Point3d pt2 = ptP - dOffs * vtDir ; + + // cerco su quali curve poggia la linea di junction + int nCrv1 = -1 ; bool bStart1 = true ; + int nCrv2 = -1 ; bool bStart2 = true ; + for ( int i = 0 ; i < ssize( vCrvs) ; i ++) { + Point3d ptS ; vCrvs[i]->GetStartPoint( ptS) ; + Point3d ptE ; vCrvs[i]->GetEndPoint( ptE) ; + if ( AreSamePointEpsilon( ptS, pt1, 10 * EPS_SMALL)) { + nCrv1 = i ; + bStart1 = true ; + } + else if ( AreSamePointEpsilon( ptS, pt2, 10 * EPS_SMALL)) { + nCrv2 = i ; + bStart2 = true ; + } + if ( AreSamePointEpsilon( ptE, pt1, 10 * EPS_SMALL)) { + nCrv1 = i ; + bStart1 = false ; + } + else if ( AreSamePointEpsilon( ptE, pt2, 10 * EPS_SMALL)) { + nCrv2 = i ; + bStart2 = false ; + } + } + int nFlatCapProp = ( j == 0 ? STM_RECTSWEPT_FLATCAP_START : STM_RECTSWEPT_FLATCAP_END) ; + + // se congiunge due curve le unisco + if ( nCrv1 != -1 && nCrv2 != -1) { + if ( nCrv1 == nCrv2) { + // se è la stessa curva la chiudo semplicemente con una linea + ICurveComposite* pCompo = GetCurveComposite( vCrvs[nCrv1]) ; + if ( pCompo == nullptr) + return false ; + pCompo->Close() ; + pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, nFlatCapProp) ; + } + else { + int nFirst = ( bStart1 ? nCrv2 : nCrv1) ; + int nSecond = ( bStart1 ? nCrv1 : nCrv2) ; + ICurveComposite* pCompo = GetCurveComposite( vCrvs[nFirst]) ; + if ( pCompo == nullptr) + return false ; + Point3d ptRef ; vCrvs[nSecond]->GetStartPoint( ptRef) ; + pCompo->AddLine( ptRef) ; + pCompo->SetCurveTempProp( pCompo->GetCurveCount() - 1, nFlatCapProp) ; + pCompo->AddCurve( Release( vCrvs[nSecond])) ; + // elimino la curva mergiata dal vettore + swap( vCrvs[nSecond], vCrvs.back()) ; + vCrvs.pop_back() ; + } + } + + // se non congiunge due curve aggiungo il tratto lineare libero sull'estremo + else { + if ( nCrv1 != -1) { + ICurveComposite* pCompo = GetCurveComposite( vCrvs[nCrv1]) ; + if ( pCompo == nullptr) + return false ; + pCompo->AddLine( pt2, ! bStart1) ; + int nSubCrv = ( bStart1 ? 0 : pCompo->GetCurveCount() - 1) ; + pCompo->SetCurveTempProp( nSubCrv, nFlatCapProp) ; + } + else if ( nCrv2 != -1) { + ICurveComposite* pCompo = GetCurveComposite( vCrvs[nCrv2]) ; + if ( pCompo == nullptr) + return false ; + pCompo->AddLine( pt1, ! bStart2) ; + int nSubCrv = ( bStart2 ? 0 : pCompo->GetCurveCount() - 1) ; + pCompo->SetCurveTempProp( nSubCrv, nFlatCapProp) ; + } + } + } + + // controllo chiusura di tutte le curve + for ( int i = 0 ; i < ssize( vCrvs) ; i++) { + if ( ! vCrvs[i]->IsClosed()) { + + ICurveComposite* pCompo = GetCurveComposite( vCrvs[i]) ; + if ( pCompo == nullptr) + return false ; + double dTempProp1 = pCompo->GetFirstCurve()->GetTempProp() ; + double dTempProp2 = pCompo->GetLastCurve()->GetTempProp() ; + + // verifico se necessaria inversione della guida per renderla coerente con la fat curve + bool bInvert = false ; + if ( dTempProp1 < 0 || dTempProp2 < 0) { + bInvert = ( dTempProp1 == STM_RECTSWEPT_FLATCAP_END || dTempProp2 == STM_RECTSWEPT_FLATCAP_START) ; + } + else { + Point3d ptS ; pCompo->GetStartPoint( ptS) ; + DistPointCurve distPC( ptS, *pOrigGuide) ; + int nSide = 0 ; + distPC.GetSideAtMinDistPoint( 0, vtNorm, nSide) ; + bInvert = ( nSide == MDS_RIGHT) ; + } + + // ricavo la superficie spazzata dalla guida + PtrOwner pGuide( ConvertCurveToComposite( pOrigGuide->Clone())) ; + if ( bInvert) + pGuide->Invert() ; + PtrOwner pSurf( CalcSweptSurface( pGuide, vtNorm, dOffs)) ; + + // verifico come trimmare + bool bTrimStart = false ; + bool bTrimEnd = false ; + if ( dTempProp1 < 0 && dTempProp2 >= 0) + bTrimStart = true ; + else if ( dTempProp1 >= 0 && dTempProp2 < 0) + bTrimEnd = true ; + else if ( dTempProp1 < 0 && dTempProp2 < 0) { + bTrimStart = true ; + bTrimEnd = true ; + } + + // recupero il loop opportuno + PtrOwner pBorder( ConvertCurveToComposite( pSurf->GetLoop( 0, 0))) ; + if ( pSurf->GetChunkCount() > 1) { + Point3d ptRef ; pCompo->GetStartPoint( ptRef) ; + if ( bTrimStart) + pCompo->GetEndPoint( ptRef) ; + for ( int j = 0 ; j < pSurf->GetChunkCount() ; j ++) { + pBorder.Set( ConvertCurveToComposite( pSurf->GetLoop( j, 0))) ; + if ( pBorder->IsPointOn( ptRef)) + break ; + } + } + + double dPar1, dPar2 ; + if ( ! bTrimStart && ! bTrimEnd) { + Point3d ptS ; pCompo->GetStartPoint( ptS) ; + Point3d ptE ; pCompo->GetEndPoint( ptE) ; + pBorder->GetParamAtPoint( ptE, dPar1) ; + pBorder->GetParamAtPoint( ptS, dPar2) ; + } + else if ( bTrimStart && bTrimEnd) { + + const CurveLine* pLineS = GetBasicCurveLine( pCompo->GetFirstCurve()) ; + const CurveLine* pLineE = GetBasicCurveLine( pCompo->GetLastCurve()) ; + + if ( pLineS == nullptr || pLineE == nullptr) + return false ; + + IntersLineLine intLL( *pLineS, *pLineE) ; + if ( intLL.GetNumInters() > 0) { + IntCrvCrvInfo aInfo ; + intLL.GetIntCrvCrvInfo( aInfo) ; + pCompo->TrimStartEndAtParam( aInfo.IciA[0].dU, pCompo->GetCurveCount() - 1 + aInfo.IciB[0].dU) ; + continue ; + } + else { + // da fare in frame locale + IntersCurveCurve intCC( *pLineS, *pBorder) ; + IntCrvCrvInfo aInfo ; + intCC.GetIntCrvCrvInfo( intCC.GetIntersCount() - 1, aInfo) ; + dPar2 = aInfo.IciB[0].dU ; + pCompo->TrimStartAtParam( aInfo.IciA[0].dU) ; + + IntersCurveCurve intCC2( *pLineE, *pBorder) ; + intCC2.GetIntCrvCrvInfo( 0, aInfo) ; + dPar1 = aInfo.IciB[0].dU ; + + pCompo->TrimEndAtParam( pCompo->GetCurveCount() - 1 + aInfo.IciA[0].dU) ; + } + } + else if ( bTrimStart) { + Point3d ptE ; pCompo->GetEndPoint( ptE) ; + pBorder->GetParamAtPoint( ptE, dPar1) ; + + // intersezione con lo start + const ICurve* pLine = pCompo->GetFirstCurve() ; + IntersCurveCurve intCC( *pLine, *pBorder) ; + IntCrvCrvInfo aInfo ; + intCC.GetIntCrvCrvInfo( intCC.GetIntersCount() - 1, aInfo) ; + dPar2 = aInfo.IciB[0].dU ; + + pCompo->TrimStartAtParam( aInfo.IciA[0].dU) ; + } + else { + Point3d ptS ; pCompo->GetStartPoint( ptS) ; + pBorder->GetParamAtPoint( ptS, dPar2) ; + + // intersezione con end + const ICurve* pLine = pCompo->GetLastCurve() ; + IntersCurveCurve intCC( *pLine, *pBorder) ; + IntCrvCrvInfo aInfo ; + intCC.GetIntCrvCrvInfo( 0, aInfo) ; + dPar1 = aInfo.IciB[0].dU ; + + pCompo->TrimEndAtParam( pCompo->GetCurveCount() - 1 + aInfo.IciA[0].dU) ; + } + + pBorder->TrimStartEndAtParam( dPar1, dPar2) ; + // setto temp param per identificarli + for ( int j = 0 ; j < pBorder->GetCurveCount() ; j++) { + pBorder->SetCurveTempProp( j, STM_RECTSWEPT_FLATCAP_EXTRA) ; + } + + pCompo->AddCurve( Release( pBorder)) ; + } + + } + } + + // se RSCAP_BEVEL approssimo tutte le junction relative agli estremi + else if ( nCapType == RSCAP_BEVEL) { + double dStepRotDeg = ANG_STRAIGHT / 4 ; // tolleranza + for ( int i = 0 ; i < ssize( vCrvs) ; i ++) { + CurveComposite* pFatCrv = GetBasicCurveComposite( vCrvs[i]) ; + if ( pFatCrv == nullptr) + return false ; + PtrOwner pNewCrv( CreateBasicCurveComposite()) ; + if ( IsNull( pNewCrv)) + return false ; + PtrOwner pCurrCrv( pFatCrv->RemoveFirstOrLastCurve( false)) ; + while ( ! IsNull( pCurrCrv)) { + if ( pCurrCrv->GetTempParam() > EPS_SMALL) { + // sostituisco con la sua approssimazione + CurveComposite* ccTemp = CreateBasicCurveComposite() ; + CurveArc* pArc = GetBasicCurveArc( pCurrCrv) ; + if ( pArc == nullptr || ccTemp == nullptr) + return false ; + int nStep = max( 1, static_cast( ceil( pArc->GetAngCenter() / dStepRotDeg))) ; + for ( int j = 0 ; j <= nStep ; ++ j) { + Point3d ptArc ; + pArc->GetPointD1D2( (double)j / nStep, ICurve::FROM_MINUS, ptArc) ; + if ( j == 0) + ccTemp->AddPoint( ptArc) ; + else + ccTemp->AddLine( ptArc) ; + } + pNewCrv->AddCurve( ccTemp) ; + } + else { + // aggiungo la curva + pNewCrv->AddCurve( Release( pCurrCrv)) ; + } + // passo alla curva successiva + pCurrCrv.Set( pFatCrv->RemoveFirstOrLastCurve( false)) ; + } + vCrvs[i].Set( pNewCrv) ; + } + } + return true ; +} + //------------------------------------------------------------------------------- static ISurfTriMesh* GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, int nCapType, double dLinTol) @@ -358,215 +789,64 @@ GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, vtNorm = Z_AX ; // determino se la guida è chiusa bool bGuideClosed = pGuide->IsClosed() ; - // curve di offset - OffsetCurve OffsCrvR ; - if ( ! OffsCrvR.Make( pGuide, dDimH / 2, ICurve::OFF_FILLET) || OffsCrvR.GetCurveCount() == 0) + + // calcolo fat curve + ICURVEPOVECTOR vFatCrvs ; + if ( ! CalcCurveFatCurve( *pGuide, vFatCrvs, dDimH / 2, false, false)) return nullptr ; - PtrOwner pCrvR( OffsCrvR.GetLongerCurve()) ; - if ( IsNull( pCrvR)) - return nullptr ; - OffsetCurve OffsCrvL ; - if ( ! OffsCrvL.Make( pGuide, -dDimH / 2, ICurve::OFF_FILLET) || OffsCrvL.GetCurveCount() == 0) - return nullptr ; - PtrOwner pCrvL( OffsCrvL.GetLongerCurve()) ; - if ( IsNull( pCrvL)) - return nullptr ; - // costruisco le parti di superficie - PtrOwner pSrfTop( GetSurfTriMeshRuled( pCrvR, pCrvL, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; - if ( IsNull( pSrfTop)) - return nullptr ; - PtrOwner pSrfBot( pSrfTop->Clone()) ; - if ( IsNull( pSrfBot)) - return nullptr ; - pSrfBot->Translate( - dDimV * vtNorm) ; - pSrfBot->Invert() ; - PtrOwner pSrfRgt( GetSurfTriMeshByExtrusion( pCrvR, -dDimV * vtNorm, false, dLinTol)) ; - if ( IsNull( pSrfRgt)) - return nullptr ; - pSrfRgt->Invert() ; - PtrOwner pSrfLft( GetSurfTriMeshByExtrusion( pCrvL, -dDimV * vtNorm, false, dLinTol)) ; - if ( IsNull( pSrfLft)) - return nullptr ; - // unisco le parti - int nBuckets = max( 2 * ( pSrfRgt->GetVertexSize() + pSrfLft->GetVertexSize()), 1000) ; - StmFromTriangleSoup stmSoup ; - if ( ! stmSoup.Start( nBuckets)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pSrfTop) ; - stmSoup.AddSurfTriMesh( *pSrfRgt) ; - stmSoup.AddSurfTriMesh( *pSrfLft) ; - stmSoup.AddSurfTriMesh( *pSrfBot) ; + + // se necessario modifico i caps sugli estremi + if ( ! bGuideClosed) { + if ( ! AdjustSurfTriMeshRectSweptCaps( nCapType, vFatCrvs, vtNorm, pGuide, dDimH / 2)) + return nullptr ; + } + PtrOwner pSTM ; - // se guida aperta e tappi piatti - if ( ! bGuideClosed && nCapType == RSCAP_FLAT) { - // completo unione e recupero la superficie risultante - if ( ! stmSoup.End()) + if ( nCapType == RSCAP_NONE && ! bGuideClosed) { + // se nessun cap devo costruire separatamente le superfici top/bottom e quelle laterali + CICURVEPVECTOR vTopCurves ; vTopCurves.reserve( vFatCrvs.size()) ; + for ( int i = 0 ; i < ssize( vFatCrvs) ; i ++) + vTopCurves.emplace_back( vFatCrvs[i]) ; + PtrOwner pSrfTop( GetSurfTriMeshByRegion( vTopCurves, dLinTol)) ; + if ( IsNull( pSrfTop)) return nullptr ; - pSTM.Set( stmSoup.GetSurf()) ; - // verifico che le due estremità siano chiuse e piatte - POLYLINEVECTOR vPL ; - if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2) + PtrOwner pSrfBot( pSrfTop->Clone()) ; + if ( IsNull( pSrfBot)) return nullptr ; - Plane3d plEnds ; double dArea ; - if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 50 * EPS_SMALL)) + pSrfBot->Translate( -dDimV * vtNorm) ; + pSrfBot->Invert() ; + + int nBuckets = max( 4 * ( pSrfTop->GetVertexSize()), 1000) ; + StmFromTriangleSoup stmSoup ; + if ( ! stmSoup.Start( nBuckets)) return nullptr ; - if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 50 * EPS_SMALL)) + stmSoup.AddSurfTriMesh( *pSrfTop) ; + stmSoup.AddSurfTriMesh( *pSrfBot) ; + + // rimuovo le giunzioni per costruire le superfici laterali + if ( ! RemoveFatCurveJunctions( vFatCrvs)) return nullptr ; - // calcolo il cap sull'inizio - PtrOwner pSci( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSci) || ! pSci->CreateByFlatContour( vPL[0])) - return nullptr ; - pSci->Invert() ; - // calcolo il cap sulla fine - PtrOwner pSce( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSce) || ! pSce->CreateByFlatContour( vPL[1])) - return nullptr ; - pSce->Invert() ; - // cucio i tappi all'estrusione - if ( ! pSTM->DoSewing( *pSci) || ! pSTM->DoSewing( *pSce)) - return nullptr ; - } - // se altrimenti guida aperta e tappi arrotondati - if ( ! bGuideClosed && ( nCapType == RSCAP_ROUND || nCapType == RSCAP_BEVEL)) { - // step di rotazione per rispettare la tolleranza - double dStepRotDeg = ( nCapType == RSCAP_BEVEL ? ANG_STRAIGHT / 4 : sqrt( 8 * dLinTol / dDimH) * RADTODEG) ; - // se l'offset interno alla guida è chiuso - if ( pCrvL->IsClosed()) { - // calcolo l'angolo di rotazione per screwing faccia Top e Bottom - Point3d ptRight ; pCrvR->GetEndPoint( ptRight) ; - Point3d ptLeft ; pCrvR->GetStartPoint( ptLeft) ; - Point3d ptJunction ; pCrvL->GetStartPoint( ptJunction) ; - Point3d ptCenter = Media( ptRight, ptLeft) ; - Vector3d vtRight = ptRight - ptCenter ; - Vector3d vtLeft = ptLeft - ptCenter ; - double dAng = ANG_STRAIGHT ; - vtRight.GetAngle( vtLeft, dAng) ; - vtRight.Normalize() ; - PolyLine plLoop ; - // creo il loop defininendo i punti - plLoop.AddUPoint( 0, ptRight) ; // primo punto - double dAngStep = ceil( dAng / dStepRotDeg) ; // aggiusto lo step - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptRight ; - ptRot.Rotate( ptCenter, vtNorm, i * ( dAng / dAngStep)) ; - plLoop.AddUPoint( i, ptRot) ; // punto intermedio sulla circonferenza - } - plLoop.AddUPoint( dAngStep ++, ptLeft) ; // ultimo punto - plLoop.AddUPoint( dAngStep ++, ptJunction) ; // punto centrale sull'offset chiuso - plLoop.AddUPoint( dAngStep, ptRight) ; // polyLine chiusa - // superificie Top - PtrOwner pStmTop( CreateSurfTriMesh()) ; - if ( IsNull( pStmTop) || ! pStmTop->CreateByFlatContour( plLoop)) + for ( int i = 0 ; i < ssize( vFatCrvs) ; i ++) { + PtrOwner pSrfLat( GetSurfTriMeshByExtrusion( vFatCrvs[i], -dDimV * vtNorm, false, dLinTol)) ; + if ( IsNull( pSrfLat)) return nullptr ; - stmSoup.AddSurfTriMesh( *pStmTop) ; - // superificie Bottom - PtrOwner pStmBottom( CloneSurfTriMesh( pStmTop)) ; - pStmBottom->Translate( - dDimV * vtNorm) ; - pStmBottom->Invert() ; - stmSoup.AddSurfTriMesh( *pStmBottom) ; - // superificie perpendicolare - // la PolyLine che utilizzo la posso ricavare da quella calcolata sopra - plLoop.EraseLastUPoint() ; // apro il loop - plLoop.EraseLastUPoint() ; // tolgo il punto di contatto sull'offset - PtrOwner pStmPerp( CreateSurfTriMesh()) ; - if ( IsNull( pStmPerp) || ! pStmPerp->CreateByExtrusion( plLoop, - vtNorm * dDimV) || - ! pStmPerp->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmPerp) ; + pSrfLat->Invert() ; + stmSoup.AddSurfTriMesh( *pSrfLat) ; } - // se l'offset interno della guida è aperto... - else { - // aggiungo il cap sull'inizio - Point3d ptStart ; - pGuide->GetStartPoint( ptStart) ; - // calcolo l'angolo di rotazione per screwing faccia Top e Bottom - Point3d ptSLeft ; pCrvL->GetStartPoint( ptSLeft) ; - Point3d ptSRight ; pCrvR->GetStartPoint( ptSRight) ; - Vector3d vtLeft = ptSLeft - ptStart ; - Vector3d vtRight = ptSRight - ptStart ; - double dAng = ANG_STRAIGHT ; - vtLeft.GetAngle( vtRight, dAng) ; - vtLeft.Normalize() ; - PolyLine plLoop ; - // creo il loop defininendo i punti - plLoop.AddUPoint( 0, ptSLeft) ; // primo punto - double dAngStep = ceil( dAng / dStepRotDeg) ; - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptSLeft ; - ptRot.Rotate( ptStart, vtNorm, i * ( dAng / dAngStep)) ; - plLoop.AddUPoint( i, ptRot) ; - } - plLoop.AddUPoint( dAngStep, ptSRight) ; // ultimo punto - plLoop.AddUPoint( dAngStep + 1, ptSLeft) ; // polyline chiusa - // creo la superficie Top - PtrOwner pStmTop_start( CreateSurfTriMesh()) ; - if ( IsNull( pStmTop_start) || ! pStmTop_start->CreateByFlatContour( plLoop)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmTop_start) ; - // superificie Bottom - PtrOwner pStmBottom_start( CloneSurfTriMesh( pStmTop_start)) ; - pStmBottom_start->Translate( - dDimV * vtNorm) ; - pStmBottom_start->Invert() ; - stmSoup.AddSurfTriMesh( *pStmBottom_start) ; - // superificie perpendicolare - // la PolyLine che utilizzo la posso ricavare da quella calcolata sopra - plLoop.EraseLastUPoint() ; // apro il loop - PtrOwner pStmPerp_start( CreateSurfTriMesh()) ; - if ( IsNull( pStmPerp_start) || ! pStmPerp_start->CreateByExtrusion( plLoop, - vtNorm * dDimV) || - ! pStmPerp_start->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmPerp_start) ; - // aggiungo il cap sulla fine - Point3d ptEnd ; - pGuide->GetEndPoint( ptEnd) ; - // calcolo l'angolo di rotazione per screwing faccia Top e Bottom - pCrvL->GetEndPoint( ptSLeft) ; - pCrvR->GetEndPoint( ptSRight) ; - vtLeft = ptSLeft - ptEnd ; - vtRight = ptSRight - ptEnd ; - dAng = ANG_STRAIGHT ; - vtRight.GetAngle( vtLeft, dAng) ; - vtRight.Normalize() ; - plLoop.Clear() ; - // creo il loop defininendo i punti - plLoop.AddUPoint( 0, ptSRight) ; - dAngStep = ceil( dAng / dStepRotDeg) ; // primo punto - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptSRight ; - ptRot.Rotate( ptEnd, vtNorm, i * ( dAng / dAngStep)) ; - plLoop.AddUPoint( i, ptRot) ; - } - plLoop.AddUPoint( dAngStep, ptSLeft) ; // ultimo punto - plLoop.AddUPoint( dAngStep + 1, ptSRight) ; // polyline chiusa - // creo la superficie Top - PtrOwner pStmTop_end( CreateSurfTriMesh()) ; - if ( IsNull( pStmTop_end) || ! pStmTop_end->CreateByFlatContour( plLoop)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmTop_end) ; - // creo la superificie Bottom - PtrOwner pStmBottom_end( CloneSurfTriMesh( pStmTop_end)) ; - pStmBottom_end->Translate( - dDimV * vtNorm) ; - pStmBottom_end->Invert() ; - stmSoup.AddSurfTriMesh( *pStmBottom_end) ; - // creo la superificie perpendicolare alla guida - plLoop.EraseLastUPoint() ; // apro il loop - PtrOwner pStmPerp_end( CreateSurfTriMesh()) ; - if ( IsNull( pStmPerp_end) || ! pStmPerp_end->CreateByExtrusion( plLoop, - vtNorm * dDimV) || - ! pStmPerp_end->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmPerp_end) ; - } - // completo unione e recupero la superficie risultante if ( ! stmSoup.End()) return nullptr ; pSTM.Set( stmSoup.GetSurf()) ; } - else { - // completo unione e recupero la superficie risultante - if ( ! stmSoup.End()) - return nullptr ; - pSTM.Set( stmSoup.GetSurf()) ; + else { + // costruisco la superficie per estrusione dalle fat curve + CICURVEPVECTOR vCurves ; vCurves.reserve( vFatCrvs.size()) ; + for ( int i = 0 ; i < ssize( vFatCrvs) ; i ++) + vCurves.emplace_back( vFatCrvs[i]) ; + pSTM.Set( GetSurfTriMeshByRegionExtrusion( vCurves, - dDimV * vtNorm, dLinTol)) ; } + + if ( IsNull( pSTM)) + return nullptr ; // salvo tolleranza lineare usata e imposto angolo per smooth pSTM->SetLinearTolerance( dLinTol) ; pSTM->SetSmoothAngle( 20) ; @@ -574,12 +854,413 @@ GetSurfTriMeshSharpRectSwept( double dDimH, double dDimV, const ICurve* pGuide, return Release( pSTM) ; } +//------------------------------------------------------------------------------- +static ICurveComposite* +Connect( const ICurve* pGuide, ICURVEPOVECTOR& vCrvs, const INTVECTOR& vIdx, double dRadius, double dBevelH, double dBevelV, + const Vector3d& vtNorm, int nCapType) +{ + double dChainTol = 50 * EPS_SMALL ; + double dOffsMin = 0.5 * dRadius - dBevelH ; + double dOffsMax = 0.5 * dRadius ; + + // calcolo il medial axis e conservo solo le porzioni interne alla regione tra i due offset + ICURVEPOVECTOR vMedialAxis ; + CalcCurveMedialAxis( *pGuide, vMedialAxis, 0) ; + ICRVCOMPOPOVECTOR vMedialCrvs ; + for ( int i = 0 ; i < ssize( vMedialAxis) ; i ++) { + double dPar1 = vMedialAxis[i]->GetTempParam( 0) ; + double dPar2 = vMedialAxis[i]->GetTempParam( 1) ; + + // se non comprende l'offset non va considerato + if ( dPar1 > dOffsMax - EPS_SMALL || dPar2 < dOffsMin + EPS_SMALL) + continue ; + + if ( dOffsMin - EPS_SMALL < dPar1 && dPar2 < dOffsMax + EPS_SMALL) { + // tratto va conservato completamente + vMedialCrvs.emplace_back( ConvertCurveToComposite( Release( vMedialAxis[i]))) ; + } + else { + // determino la parte compresa tra gli offset massimo e minimo + if ( vMedialAxis[i]->GetType() == CRV_LINE) { + double dTrimParS = ( dOffsMin - dPar1) / ( dPar2 - dPar1) ; + double dTrimParE = ( dOffsMax - dPar1) / ( dPar2 - dPar1) ; + dTrimParS = clamp( dTrimParS, 0.0, 1.0) ; + dTrimParE = clamp( dTrimParE, 0.0, 1.0) ; + vMedialAxis[i]->TrimStartEndAtParam( dTrimParS, dTrimParE) ; + if ( dTrimParS > EPS_SMALL) + vMedialAxis[i]->SetTempParam( dOffsMin, 0) ; + if ( dTrimParE < 1 - EPS_SMALL) + vMedialAxis[i]->SetTempParam( dOffsMax, 1) ; + vMedialCrvs.emplace_back( ConvertCurveToComposite( Release( vMedialAxis[i]))) ; + } + else { + ICurveComposite* pCompo = GetCurveComposite( vMedialAxis[i]) ; + if ( pCompo == nullptr) + return nullptr ; + double dS, dE ; pCompo->GetDomain( dS, dE) ; + double dTrimParS = dS ; + double dTrimParE = dE ; + for ( int j = 0 ; j < pCompo->GetCurveCount() ; j ++) { + double dPar1 = pCompo->GetCurve( j)->GetTempParam( 0) ; + double dPar2 = pCompo->GetCurve( j)->GetTempParam( 1) ; + if ( dPar1 - EPS_SMALL < dOffsMin && dOffsMin < dPar2 + EPS_SMALL) + dTrimParS = j + ( dOffsMin - dPar1) / ( dPar2 - dPar1) ; + if ( dPar1 - EPS_SMALL < dOffsMax && dOffsMax < dPar2 + EPS_SMALL) { + dTrimParE = j + ( dOffsMax - dPar1) / ( dPar2 - dPar1) ; + break ; + } + } + dTrimParS = clamp( dTrimParS, 0.0, dE) ; + dTrimParE = clamp( dTrimParE, 0.0, dE) ; + pCompo->TrimStartEndAtParam( dTrimParS, dTrimParE) ; + if ( dTrimParS > EPS_SMALL) + pCompo->SetCurveTempParam( 0, dOffsMin, 0) ; + if ( dTrimParE < dE - EPS_SMALL) + pCompo->SetCurveTempParam( pCompo->GetCurveCount() - 1, dOffsMax, 1) ; + vMedialCrvs.emplace_back( ConvertCurveToComposite( Release( vMedialAxis[i]))) ; + } + } + + // aggiusto la quota + if ( vMedialCrvs.back()->GetCurveCount() == 1) { + double dPar1 = vMedialCrvs.back()->GetTempParam( 0) ; + double dPar2 = vMedialCrvs.back()->GetTempParam( 1) ; + Point3d ptS, ptE ; + vMedialCrvs.back()->GetStartPoint( ptS) ; + vMedialCrvs.back()->GetEndPoint( ptE) ; + double dDeltaS = - dBevelV / dBevelH * ( dPar1 - dOffsMin) ; + double dDeltaE = - dBevelV / dBevelH * ( dPar2 - dOffsMin) ; + vMedialCrvs.back()->ModifyStart( ptS + vtNorm * dDeltaS) ; + vMedialCrvs.back()->ModifyEnd( ptE + vtNorm * dDeltaE) ; + } + else { + for ( int j = 0 ; j < vMedialCrvs.back()->GetCurveCount() ; j ++) { + double dPar = vMedialCrvs.back()->GetCurve( j)->GetTempParam( 0) ; + Point3d ptJ ; + vMedialCrvs.back()->GetPointD1D2( j, ICurve::FROM_MINUS, ptJ) ; + double dDelta = - dBevelV / dBevelH * ( dPar - dOffsMin) ; + vMedialCrvs.back()->ModifyJoint( j, ptJ + vtNorm * dDelta) ; + } + Point3d ptE ; vMedialCrvs.back()->GetEndPoint( ptE) ; + double dPar = vMedialCrvs.back()->GetLastCurve()->GetTempParam( 1) ; + double dDelta = - dBevelV / dBevelH * ( dPar - dOffsMin) ; + vMedialCrvs.back()->ModifyEnd( ptE + vtNorm * dDelta) ; + } + } + + // chain dei medialaxis + GetChainedCurves( vMedialCrvs, 5 * EPS_SMALL, true) ; + + // se cap flat aggiungo tratti sugli estremi + if ( nCapType == RSCAP_FLAT) { + + Frame3d frLoc ; frLoc.Set( ORIG, vtNorm) ; + + for ( int i = 0 ; i < 2 ; i ++) { + // recupero il tratto start/end + int nRefProp = ( i == 0 ? STM_RECTSWEPT_FLATCAP_START : STM_RECTSWEPT_FLATCAP_END) ; + bool bFound = false ; + for ( int j = 0 ; j < ssize( vCrvs) && ! bFound ; j ++) { + ICurveComposite* pCompo = GetCurveComposite( vCrvs[j]) ; + if ( pCompo == nullptr) + return nullptr ; + for ( int k = 0 ; k < pCompo->GetCurveCount() ; k++) { + int nProp = pCompo->GetCurve( k)->GetTempProp() ; + if ( nProp == nRefProp) { + double dLen ; pCompo->GetCurve( k)->GetLength( dLen) ; + if ( abs( dLen - 2 * dOffsMax) > EPS_SMALL) { + Point3d ptP ; pCompo->GetCurve( k)->GetStartPoint( ptP) ; + Vector3d vtDir ; pCompo->GetCurve( k)->GetStartDir( vtDir) ; + if ( i == 0) + vtDir.Invert() ; + PtrOwner pLine( CreateCurveLine()) ; + if ( IsNull( pLine)) + return nullptr ; + pLine->SetPVL( ptP, vtDir, 2 * dOffsMax - dLen) ; + pLine->ToLoc( frLoc) ; + + // verifico se interseca una curva dei medialaxis + for ( int l = 0 ; l < ssize( vMedialCrvs) ; l++) { + vMedialCrvs[l]->ToLoc( frLoc) ; + IntersCurveCurve intCC( *pLine, *vMedialCrvs[l]) ; + vMedialCrvs[l]->ToGlob( frLoc) ; + if ( intCC.GetIntersCount() == 1) { + IntCrvCrvInfo aInfo ; + intCC.GetIntCrvCrvInfo( 0, aInfo) ; + double dTempParam1 = vMedialCrvs[l]->GetFirstCurve()->GetTempParam() ; + double dTempParam2 = vMedialCrvs[l]->GetLastCurve()->GetTempParam() ; + if ( dTempParam1 < dTempParam2) { + vMedialCrvs[l]->TrimStartAtParam( aInfo.IciB[0].dU) ; + vMedialCrvs[l]->AddLine( ptP, false) ; + vMedialCrvs[l]->SetCurveTempParam( 0, dOffsMax, 0) ; + } + else { + vMedialCrvs[l]->TrimEndAtParam( aInfo.IciB[0].dU) ; + vMedialCrvs[l]->AddLine( ptP) ; + vMedialCrvs[l]->SetCurveTempParam( vMedialCrvs[l]->GetCurveCount() - 1, dOffsMax, 1) ; + } + break ; + } + } + } + bFound = true ; + break ; + } + } + + } + } + } + + // creo catena + ICurveComposite* pResult = nullptr ; + BOOLVECTOR vUsed1( vIdx.size(), false) ; + + for ( int i = 0 ; i < ssize( vMedialCrvs) ; i++) { + // verifico se è una curva sensata per il collegamento ( ovvero se i parametri ai suoi estremi sono il valore di max offset) + bool bValid = false ; + if ( vMedialCrvs[i]->GetCurveCount() == 1) { + double dPar1 = vMedialCrvs[i]->GetFirstCurve()->GetTempParam() ; + double dPar2 = vMedialCrvs[i]->GetFirstCurve()->GetTempParam( 1) ; + bValid = ( abs( dPar1 - dOffsMax) < EPS_SMALL && abs( dPar2 - dOffsMax) < EPS_SMALL) ; + } + else { + // controllo sia parametro start ed end perchè il chain permette inversione + double dParS1 = vMedialCrvs[i]->GetFirstCurve()->GetTempParam() ; + double dParS2 = vMedialCrvs[i]->GetFirstCurve()->GetTempParam( 1) ; + double dParE1 = vMedialCrvs[i]->GetLastCurve()->GetTempParam( ) ; + double dParE2 = vMedialCrvs[i]->GetLastCurve()->GetTempParam( 1) ; + bValid = ( ( abs( dParS1 - dOffsMax) < EPS_SMALL || abs( dParS2 - dOffsMax) < EPS_SMALL) && + ( abs( dParE1 - dOffsMax) < EPS_SMALL || abs( dParE2 - dOffsMax) < EPS_SMALL)) ; + } + + if ( ! bValid) + continue ; + + // setto tutte le temp prop ad un valore fissato per identificarla in seguito + for ( int nC = 0 ; nC < vMedialCrvs[i]->GetCurveCount() ; nC ++) + vMedialCrvs[i]->SetCurveTempProp( nC, STM_RECTSWEPT_LINK) ; + + // trovo le curve che collega + Point3d ptS ; vMedialCrvs[i]->GetStartPoint( ptS) ; + Point3d ptE ; vMedialCrvs[i]->GetEndPoint( ptE) ; + double dParS = -1, dParE = -1 ; + int nS = -1, nE = -1 ; + for ( int j = 0 ; j < ssize( vIdx) ; j ++) { + if ( vCrvs[vIdx[j]] == nullptr) + continue ; + if ( nS == -1 && vCrvs[vIdx[j]]->GetParamAtPoint( ptS, dParS, dChainTol)) + nS = vIdx[j] ; + else if ( nE == -1 && vCrvs[vIdx[j]]->GetParamAtPoint( ptE, dParE, dChainTol)) + nE = vIdx[j] ; + if ( nS != -1 && nE != -1) + break ; + } + + if ( nS == -1 || nE == -1) + return nullptr ; + + // i parametri devono essere su un joint per costruzione + dParS = round( dParS) ; + dParE = round( dParE) ; + + pResult = GetCurveComposite( vCrvs[nS]) ; + + ICurve* pResultEnd = nullptr ; + if ( dParS > EPS_SMALL) { + pResultEnd = pResult->CopyParamRange( dParS, pResult->GetCurveCount()) ; + pResult->TrimEndAtParam( dParS) ; + } + pResult->AddCurve( vMedialCrvs[i]->Clone(), true, dChainTol) ; + GetBasicCurveComposite( vCrvs[nE])->ChangeStartPoint( dParE) ; + pResult->AddCurve( Release( vCrvs[nE]), true, dChainTol) ; + vMedialCrvs[i]->Invert() ; + pResult->AddCurve( Release( vMedialCrvs[i]), true, dChainTol) ; + if ( pResultEnd != nullptr) + pResult->AddCurve( pResultEnd, true, dChainTol) ; + // forzo chiusura + pResult->Close() ; + } + return pResult ; +} + +//------------------------------------------------------------------------------- +static bool +GetTrimParams( const ICurveComposite* pCrv1, const ICurveComposite* pCrv2, int nOrigCrv, int nCurrCrv2, const Vector3d& vtNorm, + DBLVECTOR& vPar1, DBLVECTOR& vPar2) +{ + int nFlag ; + + Point3d ptP ; pCrv2->GetCurve( nCurrCrv2)->GetStartPoint( ptP) ; + int nStart = int( floor( vPar1.back() + 0.5)) ; + + // se deriva da una curva ben definita della giuda cerco la corrispondente dal lato corretto sull'altra curva + if ( nOrigCrv != 0) { + for ( int j = nStart ; j < pCrv1->GetCurveCount() ; j ++) { + int nOrigCrv1 = pCrv1->GetCurve( j)->GetTempProp() ; + if ( nOrigCrv1 == nOrigCrv) { + // se estremo di flat cap spezzo il bisettore appena trovato nel punto a minima distanza + // e sulla curva 1 avrò corrispondenza con un punto + if ( nOrigCrv == STM_RECTSWEPT_FLATCAP_START || nOrigCrv == STM_RECTSWEPT_FLATCAP_END) { + Point3d ptRef ; pCrv1->GetCurve( j)->GetStartPoint( ptRef) ; + PtrOwner pCurrBisector( pCrv2->CopyParamRange( vPar2.back(), nCurrCrv2)) ; + DistPointCurve distPC( ptRef, *pCurrBisector) ; + double dParTrim ; distPC.GetParamAtMinDistPoint( 0, dParTrim, nFlag) ; + vPar1.emplace_back( j) ; + vPar2.emplace_back( vPar2.back() + dParTrim) ; + vPar1.emplace_back( j) ; + vPar2.emplace_back( nCurrCrv2) ; + } + else { + DistPointCurve distPC( ptP, *pCrv1->GetCurve( j)) ; + int nSide = 0 ; + double dParMinDist ; + distPC.GetSideAtMinDistPoint( 0, vtNorm, nSide) ; + if ( nSide == MDS_RIGHT) { + distPC.GetParamAtMinDistPoint( 0, dParMinDist, nFlag) ; + dParMinDist += j ; + vPar1.emplace_back( dParMinDist) ; + vPar2.emplace_back( nCurrCrv2) ; + break ; + } + } + } + } + } + + // se deriva da raccordo devo controllare il più vicino + else { + double dMinDist = INFINITO ; + double dParMinDist ; + for ( int j = nStart ; j < pCrv1->GetCurveCount() ; j ++) { + int nOrigCrv1 = pCrv1->GetCurve( j)->GetTempProp() ; + if ( nOrigCrv1 == nOrigCrv) { + DistPointCurve distPC( ptP, *pCrv1->GetCurve( j)) ; + int nSide = 0 ; + distPC.GetSideAtMinDistPoint( 0, vtNorm, nSide) ; + if ( nSide == MDS_RIGHT) { + double dCurrDist ; distPC.GetDist( dCurrDist) ; + if ( dCurrDist < dMinDist) { + distPC.GetParamAtMinDistPoint( 0, dParMinDist, nFlag) ; + dParMinDist += j ; + dMinDist = dCurrDist ; + } + } + } + } + vPar1.emplace_back( dParMinDist) ; + vPar2.emplace_back( nCurrCrv2) ; + } + + return true ; +} + +//------------------------------------------------------------------------------- +static bool +Associate( const ICurveComposite* pCrv1, ICurveComposite* pCrv2, const Vector3d& vtNorm, DBLVECTOR& vPar1, DBLVECTOR& vPar2) +{ + + vPar1.emplace_back( 0) ; + vPar2.emplace_back( 0) ; + + // assegno il punto di inizio della curva 2 il più vicino possibile a quello della curva 1 preferendo curve non problematiche + int nStartCrvId = pCrv1->GetFirstCurve()->GetTempProp() ; + if ( nStartCrvId == STM_RECTSWEPT_FLATCAP_START) { + for ( int i = 0 ; i < pCrv2->GetCurveCount() ; i ++) { + int nOrigCrv = pCrv2->GetCurve( i)->GetTempProp() ; + if ( nOrigCrv == nStartCrvId) { + pCrv2->ChangeStartPoint( i) ; + break ; + } + } + } + else { + Point3d ptStart ; pCrv1->GetStartPoint( ptStart) ; + double dPar ; int nFlag ; + DistPointCurve( ptStart, *pCrv2).GetParamAtMinDistPoint(0, dPar, nFlag) ; + pCrv2->ChangeStartPoint( dPar) ; + } + + // segnalo parametro di split per le curve quando trovo l'inizio o la fine di un tratto che deriva da un bisettore + // o da un tratto aggiunto per la chiusura dei flat caps + bool bBisector = false ; + for ( int i = 0 ; i < pCrv2->GetCurveCount() ; i++) { + int nTmpProp = pCrv2->GetCurve( i)->GetTempProp() ; + if ( nTmpProp == STM_RECTSWEPT_LINK || nTmpProp == STM_RECTSWEPT_FLATCAP_EXTRA) { + if ( ! bBisector) { + // inizio bisettore + bBisector = true ; + if ( i > 0) { + int nOrigCrv = pCrv2->GetCurve( i-1)->GetTempProp() ; + GetTrimParams( pCrv1, pCrv2, nOrigCrv, i, vtNorm, vPar1, vPar2) ; + } + } + } + else { + if ( bBisector) { + // fine del bisettore + bBisector = false ; + int nOrigCrv = pCrv2->GetCurve(i)->GetTempProp() ; + GetTrimParams( pCrv1, pCrv2, nOrigCrv, i, vtNorm, vPar1, vPar2) ; + } + } + } + + // aggiungo parametro finale + double dTmp, dE1, dE2 ; + pCrv1->GetDomain( dTmp, dE1) ; + pCrv2->GetDomain( dTmp, dE2) ; + + vPar1.emplace_back( dE1) ; + vPar2.emplace_back( dE2) ; + + return true ; +} + +//------------------------------------------------------------------------------- +static POLYLINEVECTOR +TrimPolyLine( const PolyLine& PLOrig, const DBLVECTOR& vPar) +{ + POLYLINEVECTOR vPL ; vPL.reserve( vPar.size()) ; + + double dPar1, dPar2 ; + Point3d pt1, pt2 ; + + bool bFound = PLOrig.GetFirstUPoint( &dPar1, &pt1) ; + PolyLine PLCurr ; PLCurr.AddUPoint( 0, pt1) ; + bFound = PLOrig.GetNextUPoint( &dPar2, &pt2) ; + for ( int i = 0 ; i < ssize( vPar) && bFound ; i ++) { + while( dPar2 < vPar[i] - EPS_SMALL && bFound) { + // se non si è ancora arrivati al parametro richiesto devo aggiungere il punto e passare al successivo + PLCurr.AddUPoint( dPar2, pt2) ; + dPar1 = dPar2 ; + pt1 = pt2 ; + bFound = PLOrig.GetNextUPoint( &dPar2, &pt2) ; + } + + if ( bFound) { + // ricavo il punto di interruzione + double dCoeff = ( vPar[i] - dPar1) / ( dPar2 - dPar1) ; + Point3d ptSplit = Media( pt1, pt2, dCoeff) ; + PLCurr.AddUPoint( vPar[i], ptSplit) ; + // ho concluso una polyline e pareparo la prossima + vPL.emplace_back( PLCurr) ; + PLCurr.Clear() ; + PLCurr.AddUPoint( vPar[i], ptSplit) ; + } + } + + // ultima curva + if ( PLCurr.GetPointNbr() > 1) + vPL.emplace_back( PLCurr) ; + + return vPL ; +} + //------------------------------------------------------------------------------- static ISurfTriMesh* GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, double dBevelV, const ICurve* pGuide, int nCapType, double dLinTol) { - // metodo di calcolo impostato da USE_VORONOI - // verifico che la linea guida sia piana Plane3d plGuide ; if ( ! pGuide->IsFlat( plGuide, true, 10 * EPS_SMALL)) @@ -592,367 +1273,266 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub ptCen -= dDimV / 2 * vtNorm ; // determino se la guida è chiusa bool bGuideClosed = pGuide->IsClosed() ; - // curve di offset - const int NUM_OFFS = 4 ; - OffsetCurve vOffsCrv[NUM_OFFS] ; - double vDist[NUM_OFFS] = { dDimH / 2 - dBevelH, -dDimH / 2 + dBevelH, dDimH / 2, -dDimH / 2} ; - bool bOk = true ; - if ( ! USE_VORONOI) { - future vRes[NUM_OFFS] ; - for ( int i = 0 ; i < NUM_OFFS ; ++ i) - vRes[i] = async( launch::async, &OffsetCurve::Make, &vOffsCrv[i], pGuide, vDist[i], ICurve::OFF_FILLET) ; - bool bOk = true ; - int nFin = 0 ; - while ( nFin < NUM_OFFS) { - for ( int i = 0 ; i < NUM_OFFS ; ++ i) { - if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) { - bOk = vRes[i].get() && bOk ; - ++ nFin ; - } + + // calcolo le fat curve + ICURVEPOVECTOR vFatCrvs1 ; + if ( ! CalcCurveFatCurve( *pGuide, vFatCrvs1, dDimH / 2 - dBevelH, false, false)) + return nullptr ; + ICURVEPOVECTOR vFatCrvs2 ; + if ( ! CalcCurveFatCurve( *pGuide, vFatCrvs2, dDimH / 2, false, false)) + return nullptr ; + + // aggiusto per eventuali caps + if ( ! bGuideClosed) { + if ( ! AdjustSurfTriMeshRectSweptCaps( nCapType, vFatCrvs1, vtNorm, pGuide, dDimH / 2 - dBevelH) || + ! AdjustSurfTriMeshRectSweptCaps( nCapType, vFatCrvs2, vtNorm, pGuide, dDimH / 2)) + return nullptr ; + } + + // setto estrusione + for ( int i = 0 ; i < ssize( vFatCrvs1) ; i++) + vFatCrvs1[i]->SetExtrusion( vtNorm) ; + for ( int i = 0 ; i < ssize( vFatCrvs2) ; i++) + vFatCrvs2[i]->SetExtrusion( vtNorm) ; + + // ordino i vettori per avere il loop esterno per primo + for ( int i = 0 ; i < ssize( vFatCrvs1) ; i ++) { + Plane3d plPlane ; double dTmp ; + vFatCrvs1[i]->GetArea( plPlane, dTmp) ; + if ( AreSameVectorApprox( plPlane.GetVersN(), vtNorm)) { + swap( vFatCrvs1[i], vFatCrvs1[0]) ; + break ; + } + } + for ( int i = 0 ; i < ssize( vFatCrvs2) ; i ++) { + Plane3d plPlane ; double dTmp ; + vFatCrvs2[i]->GetArea( plPlane, dTmp) ; + if ( AreSameVectorApprox( plPlane.GetVersN(), vtNorm)) { + swap( vFatCrvs2[i], vFatCrvs2[0]) ; + break ; + } + } + + // sposto il punto di start del loop esterno della FatCrv1 in modo sensato + ICurveComposite* pCompo = GetCurveComposite( vFatCrvs1[0]) ; + if ( pCompo == nullptr) + return nullptr ; + for ( int j = 0 ; j < pCompo->GetCurveCount() ; j ++) { + int nOrigCrv = pCompo->GetCurve( j)->GetTempProp() ; + if ( nOrigCrv > 0) { + Point3d ptP ; pCompo->GetCurve( j)->GetStartPoint( ptP) ; + DistPointCurve distPC( ptP, *vFatCrvs2[0]) ; + double dDist = 0 ; + distPC.GetDist( dDist) ; + if ( abs( dDist - dBevelH) < 100 * EPS_SMALL) { + pCompo->ChangeStartPoint( j + 0.5) ; + break ; } - } + } } - else { - // se Voronoi non è possibile calcolare gli offset di una stessa curva in parallelo - for ( int i = 0 ; i < NUM_OFFS && bOk ; ++ i) - bOk = vOffsCrv[i].Make( pGuide, vDist[i], ICurve::OFF_FILLET) ; - } - if ( ! bOk || - vOffsCrv[0].GetCurveCount() == 0 || vOffsCrv[1].GetCurveCount() == 0 || - vOffsCrv[2].GetCurveCount() == 0 || vOffsCrv[3].GetCurveCount() == 0) - return nullptr ; - PtrOwner pCrvR( vOffsCrv[0].GetLongerCurve()) ; - if ( IsNull( pCrvR)) - return nullptr ; - PtrOwner pCrvL( vOffsCrv[1].GetLongerCurve()) ; - if ( IsNull( pCrvL)) - return nullptr ; - PtrOwner pCrvRb( vOffsCrv[2].GetLongerCurve()) ; - if ( IsNull( pCrvRb)) - return nullptr ; - pCrvRb->Translate( - dBevelV * vtNorm) ; - PtrOwner pCrvLb( vOffsCrv[3].GetLongerCurve()) ; - if ( IsNull( pCrvLb)) - return nullptr ; - pCrvLb->Translate( - dBevelV * vtNorm) ; + + for ( int i = 0 ; i < ssize( vFatCrvs2) ; i++) + vFatCrvs2[i]->Translate( - dBevelV * vtNorm) ; + + // trasformo in polylines + POLYLINEVECTOR vPL1( vFatCrvs1.size()) ; + for ( int i = 0 ; i < ssize( vFatCrvs1) ; i++) + vFatCrvs1[i]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, vPL1[i]) ; + // costruisco le parti di superficie - PtrOwner pSrfTop( GetSurfTriMeshRuled( pCrvR, pCrvL, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; - if ( IsNull( pSrfTop)) + PtrOwner pSrfTop( CreateSurfTriMesh()) ; + if ( IsNull( pSrfTop) || ! pSrfTop->CreateByPolygonWithHoles( vPL1)) return nullptr ; PtrOwner pSrfBot( pSrfTop->Clone()) ; if ( IsNull( pSrfBot)) return nullptr ; pSrfBot->Translate( -dDimV * vtNorm) ; pSrfBot->Invert() ; - PtrOwner pSrfTopR( GetSurfTriMeshRuled( pCrvRb, pCrvR, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; - if ( IsNull( pSrfTopR)) - return nullptr ; - PtrOwner pSrfBotR( pSrfTopR->Clone()) ; - if ( IsNull( pSrfBotR)) - return nullptr ; - pSrfBotR->Mirror( ptCen, vtNorm) ; - PtrOwner pSrfTopL( GetSurfTriMeshRuled( pCrvL, pCrvLb, ISurfTriMesh::RLT_MINDIST, dLinTol)) ; - if ( IsNull( pSrfTopL)) - return nullptr ; - PtrOwner pSrfBotL( pSrfTopL->Clone()) ; - if ( IsNull( pSrfBotL)) - return nullptr ; - pSrfBotL->Mirror( ptCen, vtNorm) ; - PtrOwner pSrfRgt( GetSurfTriMeshByExtrusion( pCrvRb, ( -dDimV + 2 * dBevelV) * vtNorm, false, dLinTol)) ; - if ( IsNull( pSrfRgt)) - return nullptr ; - pSrfRgt->Invert() ; - PtrOwner pSrfLft( GetSurfTriMeshByExtrusion( pCrvLb, ( -dDimV + 2 * dBevelV) * vtNorm, false, dLinTol)) ; - if ( IsNull( pSrfLft)) - return nullptr ; - // unisco le parti - int nBuckets = max( 4 * ( pSrfRgt->GetVertexSize() + pSrfLft->GetVertexSize()), 1000) ; + + int nBuckets = max( 4 * ( pSrfTop->GetVertexSize()), 1000) ; StmFromTriangleSoup stmSoup ; if ( ! stmSoup.Start( nBuckets)) return nullptr ; stmSoup.AddSurfTriMesh( *pSrfTop) ; - stmSoup.AddSurfTriMesh( *pSrfTopR) ; - stmSoup.AddSurfTriMesh( *pSrfTopL) ; - stmSoup.AddSurfTriMesh( *pSrfRgt) ; - stmSoup.AddSurfTriMesh( *pSrfLft) ; - stmSoup.AddSurfTriMesh( *pSrfBotR) ; - stmSoup.AddSurfTriMesh( *pSrfBotL) ; stmSoup.AddSurfTriMesh( *pSrfBot) ; - PtrOwner pSTM ; - // se guida aperta e tappi piatti - if ( ! bGuideClosed && nCapType == RSCAP_FLAT) { - // completo unione e recupero la superficie risultante - if ( ! stmSoup.End()) - return nullptr ; - pSTM.Set( stmSoup.GetSurf()) ; - // verifico che le due estremità siano chiuse e piatte - POLYLINEVECTOR vPL ; - if ( ! pSTM->GetLoops( vPL) || vPL.size() != 2) - return nullptr ; - Plane3d plEnds ; double dArea ; - if ( ! vPL[0].IsClosedAndFlat( plEnds, dArea, 50 * EPS_SMALL)) - return nullptr ; - if ( ! vPL[1].IsClosedAndFlat( plEnds, dArea, 50 * EPS_SMALL)) - return nullptr ; - // calcolo il cap sull'inizio - PtrOwner pSci( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSci) || ! pSci->CreateByFlatContour( vPL[0])) - return nullptr ; - pSci->Invert() ; - // calcolo il cap sulla fine - PtrOwner pSce( CreateBasicSurfTriMesh()) ; - if ( IsNull( pSce) || ! pSce->CreateByFlatContour( vPL[1])) - return nullptr ; - pSce->Invert() ; - // cucio i tappi all'estrusione - if ( ! pSTM->DoSewing( *pSci) || ! pSTM->DoSewing( *pSce)) - return nullptr ; - } - // se altrimenti guida aperta e tappi arrotondati - else if ( ! bGuideClosed && ( nCapType == RSCAP_ROUND || nCapType == RSCAP_BEVEL)) { - // step di rotazione per rispettare il tipo o la tolleranza - double dStepRotDeg = ( nCapType == RSCAP_BEVEL ? ANG_STRAIGHT / 4 : sqrt( 8 * dLinTol / dDimH) * RADTODEG) ; - // se l'offset interno della guida è chiuso... - if ( pCrvL->IsClosed()) { - // calcolo l'angolo di rotazione per screwing faccia Top e Bottom - Point3d ptRight ; pCrvR->GetEndPoint( ptRight) ; - Point3d ptLeft ; pCrvR->GetStartPoint( ptLeft) ; - Point3d ptJunction ; pCrvL->GetStartPoint( ptJunction) ; - Point3d ptCenter = Media( ptRight, ptLeft) ; - Vector3d vtRight = ptRight - ptCenter ; - Vector3d vtLeft = ptLeft - ptCenter ; - double dAng = ANG_STRAIGHT ; - vtRight.GetAngle( vtLeft, dAng) ; - vtRight.Normalize() ; - PolyLine plLoop ; - // creo il loop defininendo i punti - plLoop.AddUPoint( 0, ptRight) ; // primo punto - double dAngStep = ceil( dAng / dStepRotDeg) ; // aggiusto lo step - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptRight ; - ptRot.Rotate( ptCenter, vtNorm, i * ( dAng / dAngStep)) ; - plLoop.AddUPoint( i, ptRot) ; // punto intermedio sulla circonferenza + + BOOLVECTOR bUsed( vFatCrvs2.size(), false) ; + bool bRepair = false ; + + for ( int i = 0 ; i < ssize( vFatCrvs1) ; i ++) { + // cerco le FatCurve2 che contengono la FatCurve1 corrente + INTVECTOR vAssociatedIdx ; + for ( int j = 0 ; j < ssize( vFatCrvs2) ; j ++) { + if ( ! bUsed[j]) { + double dS, dE ; vFatCrvs2[j]->GetDomain( dS, dE) ; + double dU = 0.5 ; + int nSide = MDS_ON ; + while ( nSide == MDS_ON && dU < dE) { + Point3d ptTest ; vFatCrvs2[j]->GetPointD1D2( dU, ICurve::FROM_MINUS, ptTest) ; + DistPointCurve distPC( ptTest, *vFatCrvs1[i]) ; + distPC.GetSideAtMinDistPoint( 0, vtNorm, nSide) ; + if ( nSide == MDS_RIGHT) { + bUsed[j] = true ; + vAssociatedIdx.emplace_back( j) ; + } + dU += 1 ; + } } - plLoop.AddUPoint( dAngStep ++, ptLeft) ; // ultimo punto - plLoop.AddUPoint( dAngStep ++, ptJunction) ; // punto centrale sull'offset chiuso - plLoop.AddUPoint( dAngStep, ptRight) ; // polyLine chiusa - // superificie Top - PtrOwner pStmTop( CreateSurfTriMesh()) ; - if ( IsNull( pStmTop) || ! pStmTop->CreateByFlatContour( plLoop)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmTop) ; - // superificie Bottom - PtrOwner pStmBottom( CloneSurfTriMesh( pStmTop)) ; - if ( IsNull( pStmBottom) || ! pStmBottom->Mirror( ptCen, vtNorm)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmBottom) ; - // calcolo l'angolo di rotazione per la faccia Top del bevel - // NB. Questo angolo va ricalcolato, il bevel è inclinato rispetto alla normale della guida - ptCenter.Translate( - dBevelV * vtNorm) ; - Point3d ptbRight ; pCrvRb->GetEndPoint( ptbRight) ; - Point3d ptbLeft ; pCrvRb->GetStartPoint( ptbLeft) ; - Vector3d vtbLeft = ptbLeft - ptCenter ; - Vector3d vtbRight = ptbRight - ptCenter ; - dAng = ANG_STRAIGHT ; - vtbRight.GetAngle( vtbLeft, dAng) ; - vtbRight.Normalize() ; - // la PolyLine che utilizzo la posso ricavare da quella calcolata sopra - plLoop.EraseLastUPoint() ; // apro il loop - plLoop.EraseLastUPoint() ; // tolgo il punto di contatto sull'offset - // creo il loop defininendo i punti - PolyLine plLoopB ; - plLoopB.AddUPoint( 0, ptbRight) ; - dAngStep = ceil( dAng / dStepRotDeg) ; - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptbRight ; - ptRot.Rotate( ptCenter, vtNorm, i * ( dAng / dAngStep)) ; - plLoopB.AddUPoint( i, ptRot) ; - } - plLoopB.AddUPoint( dAngStep, ptbLeft) ; - // creo la superficie Top Bevel - PtrOwner pStmbTop_start( CreateSurfTriMesh()) ; - if ( IsNull( pStmbTop_start) || - ! pStmbTop_start->CreateByTwoCurves( plLoop, plLoopB, ISurfTriMesh::RLT_MINDIST) || - ! pStmbTop_start->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmbTop_start) ; - // creo la superificie Bottom Bevel - PtrOwner pStmbBottom_start( CloneSurfTriMesh( pStmbTop_start)) ; - if ( IsNull( pStmbBottom_start) || ! pStmbBottom_start->Mirror( ptCen, vtNorm)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmbBottom_start) ; - // creo la superficie perpendicolare alla guida - PolyLine plLoopB1 = plLoopB ; - plLoopB1.Mirror( ptCen, vtNorm) ; - PtrOwner pStmPerp( CreateSurfTriMesh()) ; - if ( IsNull( pStmPerp) || - ! pStmPerp->CreateByTwoCurves( plLoopB, plLoopB1, ISurfTriMesh::RLT_MINDIST) || - ! pStmPerp->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmPerp) ; } - // se l'offset interno della guida è aperto... + + ISURFTMPOVECTOR vSurfLatTop ; + ISURFTMPOVECTOR vSurfLat ; + + // a) se non ha associate allora collassa in un punto/curva ad una quota opportuna + if ( vAssociatedIdx.empty()) { + + double dLimitOffs ; + if ( ! CalcCurveLimitOffset( *vFatCrvs1[i], dLimitOffs)) + return nullptr ; + OffsetCurve OffsCrv ; + OffsCrv.Make( vFatCrvs1[i], dLimitOffs, ICurve::OFF_FILLET) ; + + PtrOwner pSrfLatT( CreateBasicSurfTriMesh()) ; + if ( IsNull( pSrfLatT)) + return nullptr ; + + Point3d ptOffs ; Vector3d vtOut ; + if ( OffsCrv.GetPointOffset( ptOffs, vtOut)) { + // se collassa in un punto + ptOffs.Translate( - dBevelV / dBevelH * dLimitOffs * vtNorm) ; + pSrfLatT->CreateByPointCurve( ptOffs, vPL1[i]) ; + pSrfLatT->Invert() ; + } + else { + // se collassa in una curva + PtrOwner pAssociatedCrv( ConvertCurveToComposite( OffsCrv.GetLongerCurve())) ; + if ( IsNull( pAssociatedCrv)) + return nullptr ; + pAssociatedCrv->Translate( - dBevelV / dBevelH * dLimitOffs * vtNorm) ; + + Point3d ptStart ; vFatCrvs1[i]->GetStartPoint( ptStart) ; + double dPar ; int nFlag ; + DistPointCurve( ptStart, *pAssociatedCrv).GetParamAtMinDistPoint(0, dPar, nFlag) ; + pAssociatedCrv->ChangeStartPoint( dPar) ; + + PolyLine PL2 ; + pAssociatedCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2) ; + pSrfLatT->CreateByTwoCurves( PL2, vPL1[i], ISurfTriMesh::RLT_MINDIST) ; + } + vSurfLatTop.emplace_back( Release( pSrfLatT)) ; + } + + + // b) se ha una sola associata costruisco la rigata tra le due curve + else if ( vAssociatedIdx.size() == 1) { + + ICurveComposite* pAssociatedCrv = GetCurveComposite( vFatCrvs2[vAssociatedIdx[0]]) ; + if ( pAssociatedCrv == nullptr) + return nullptr ; + + // per avere rigata ottimale modifico il punto di inizio della seconda curva + Point3d ptStart ; vFatCrvs1[i]->GetStartPoint( ptStart) ; + double dPar ; int nFlag ; + DistPointCurve( ptStart, *pAssociatedCrv).GetParamAtMinDistPoint( 0, dPar, nFlag) ; + pAssociatedCrv->ChangeStartPoint( dPar) ; + + PolyLine PL2 ; + pAssociatedCrv->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2) ; + + PtrOwner pSrfLatT( CreateBasicSurfTriMesh()) ; + if ( IsNull( pSrfLatT) || ! pSrfLatT->CreateByTwoCurves( PL2, vPL1[i], ISurfTriMesh::RLT_MINDIST)) + return nullptr ; + vSurfLatTop.emplace_back( Release( pSrfLatT)) ; + + PtrOwner pSrfLat( CreateBasicSurfTriMesh()) ; + if ( IsNull( pSrfLat) || ! pSrfLat->CreateByExtrusion( PL2, ( - dDimV + 2 * dBevelV) * vtNorm)) + return nullptr ; + pSrfLat->Invert() ; + vSurfLat.emplace_back( Release( pSrfLat)) ; + } else { - // aggiungo il cap sull'inizio - Point3d ptStart ; - pGuide->GetStartPoint( ptStart) ; - // calcolo l'angolo di rotazione per screwing faccia Top e Bottom - Point3d ptSLeft ; pCrvL->GetStartPoint( ptSLeft) ; - Point3d ptSRight ; pCrvR->GetStartPoint( ptSRight) ; - Vector3d vtLeft = ptSLeft - ptStart ; - Vector3d vtRight = ptSRight - ptStart ; - double dAng = ANG_STRAIGHT ; - vtLeft.GetAngle( vtRight, dAng) ; - vtLeft.Normalize() ; - PolyLine plLoop ; - // creo il loop defininendo i punti - plLoop.AddUPoint( 0, ptSLeft) ; // primo punto - double dAngStep = ceil( dAng / dStepRotDeg) ; - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptSLeft ; - ptRot.Rotate( ptStart, vtNorm, i * ( dAng / dAngStep)) ; - plLoop.AddUPoint( i, ptRot) ; + bRepair = true ; + + // superfici verticali + for ( int j = 0 ; j < ssize( vAssociatedIdx) ; j ++) { + PolyLine PL2 ; + vFatCrvs2[vAssociatedIdx[j]]->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2) ; + PtrOwner pSrfLat( CreateBasicSurfTriMesh()) ; + if ( IsNull( pSrfLat) || ! pSrfLat->CreateByExtrusion( PL2, ( - dDimV + 2 * dBevelV) * vtNorm)) + return nullptr ; + pSrfLat->Invert() ; + vSurfLat.emplace_back( Release( pSrfLat)) ; } - plLoop.AddUPoint( dAngStep, ptSRight) ; // ultimo punto - plLoop.AddUPoint( dAngStep + 1, ptSLeft) ; // polyline chiusa - // creo la superficie Top - PtrOwner pStmTop_start( CreateSurfTriMesh()) ; - if ( IsNull( pStmTop_start) || ! pStmTop_start->CreateByFlatContour( plLoop)) + + // collego le curve tramite bisettori + ICurveComposite* pFatCrv2 = Connect( pGuide, vFatCrvs2, vAssociatedIdx, dDimH, dBevelH, dBevelV, vtNorm, nCapType) ; + if ( pFatCrv2 == nullptr) return nullptr ; - stmSoup.AddSurfTriMesh( *pStmTop_start) ; - // creo la superificie Bottom - PtrOwner pStmBottom_start( CloneSurfTriMesh( pStmTop_start)) ; - if ( IsNull( pStmBottom_start) || ! pStmBottom_start->Mirror( ptCen, vtNorm)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmBottom_start) ; - // calcolo l'angolo di rotazione per la faccia Top del bevel - ptStart.Translate( - dBevelV * vtNorm) ; - Point3d ptSbLeft ; pCrvLb->GetStartPoint( ptSbLeft) ; - Point3d ptSbRight ; pCrvRb->GetStartPoint( ptSbRight) ; - Vector3d vtbLeft = ptSbLeft - ptStart ; - Vector3d vtbRight = ptSbRight - ptStart ; - dAng = ANG_STRAIGHT ; - vtbLeft.GetAngle( vtbRight, dAng) ; - vtbLeft.Normalize() ; - plLoop.EraseLastUPoint() ; // apro il loop - // creo il loop defininendo i punti - PolyLine plLoopB ; - plLoopB.AddUPoint( 0, ptSbLeft) ; - dAngStep = ceil( dAng / dStepRotDeg) ; // primo punto - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptSbLeft ; - ptRot.Rotate( ptStart, vtNorm, i * ( dAng / dAngStep)) ; - plLoopB.AddUPoint( i, ptRot) ; + + // individuo i punti ottimali dove spezzare le polylines per avere delle rigate ottimali + DBLVECTOR vPar1, vPar2 ; + Associate( GetCurveComposite( vFatCrvs1[i]), pFatCrv2, vtNorm, vPar1, vPar2) ; + PolyLine PL2 ; + pFatCrv2->ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL2) ; + POLYLINEVECTOR vPolyLine1 = TrimPolyLine( vPL1[i], vPar1) ; + POLYLINEVECTOR vPolyLine2 = TrimPolyLine( PL2, vPar2) ; + + for ( int j = 0 ; j < ssize( vPolyLine1) ; j ++) { + + if ( vPolyLine1[j].GetPointNbr() == 1 ) { + // collassa + Point3d pt1 ; vPolyLine1[j].GetFirstPoint( pt1) ; + Point3d pt2 ; vPolyLine2[j].GetFirstPoint( pt2) ; + Point3d pt3 ; vPolyLine2[j].GetLastPoint( pt3) ; + + vPolyLine2[j].Close() ; + PtrOwner pSrfLatT( CreateBasicSurfTriMesh()) ; + if ( IsNull( pSrfLatT )) + return nullptr ; + pSrfLatT->CreateByFlatContour( vPolyLine2[j]) ; + vSurfLatTop.emplace_back( Release( pSrfLatT)) ; + + Triangle3d trExtra ; + trExtra.Set( pt1, pt2, pt3) ; + stmSoup.AddTriangle( trExtra) ; + trExtra.Mirror( ptCen, vtNorm) ; + stmSoup.AddTriangle( trExtra) ; + } + else { + PtrOwner pSrfLatT( CreateBasicSurfTriMesh()) ; + if ( IsNull( pSrfLatT)) + return nullptr ; + pSrfLatT->CreateByTwoCurves( vPolyLine1[j], vPolyLine2[j], ISurfTriMesh::RLT_MINDIST) ; + pSrfLatT->Invert() ; + vSurfLatTop.emplace_back( Release( pSrfLatT)) ; + } } - plLoopB.AddUPoint( dAngStep, ptSbRight) ; // ultimo punto - // creo la superficie Top Bevel - PtrOwner pStmbTop_start( CreateSurfTriMesh()) ; - if ( IsNull( pStmbTop_start) || - ! pStmbTop_start->CreateByTwoCurves( plLoop, plLoopB, ISurfTriMesh::RLT_MINDIST) || - ! pStmbTop_start->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmbTop_start) ; - // creo la superificie Bottom Bevel - PtrOwner pStmbBottom_start( CloneSurfTriMesh( pStmbTop_start)) ; - if ( IsNull( pStmbBottom_start) || ! pStmbBottom_start->Mirror( ptCen, vtNorm)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmbBottom_start) ; - // creo la superficie perpendicolare alla guida - PolyLine plLoopB1 = plLoopB ; - plLoopB1.Mirror( ptCen, vtNorm) ; - PtrOwner pStmPerp_start( CreateSurfTriMesh()) ; - if ( IsNull( pStmPerp_start) || - ! pStmPerp_start->CreateByTwoCurves( plLoopB, plLoopB1, ISurfTriMesh::RLT_MINDIST) || - ! pStmPerp_start->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmPerp_start) ; - // aggiungo il cap sulla fine - Point3d ptEnd ; - pGuide->GetEndPoint( ptEnd) ; - // calcolo l'angolo di rotazione per screwing faccia Top e Bottom - pCrvL->GetEndPoint( ptSLeft) ; - pCrvR->GetEndPoint( ptSRight) ; - vtLeft = ptSLeft - ptEnd ; - vtRight = ptSRight - ptEnd ; - dAng = ANG_STRAIGHT ; - vtRight.GetAngle( vtLeft, dAng) ; - vtRight.Normalize() ; - plLoop.Clear() ; - // creo il loop defininendo i punti - plLoop.AddUPoint( 0, ptSRight) ; - dAngStep = ceil( dAng / dStepRotDeg) ; // primo punto - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptSRight ; - ptRot.Rotate( ptEnd, vtNorm, i * ( dAng / dAngStep)) ; - plLoop.AddUPoint( i, ptRot) ; - } - plLoop.AddUPoint( dAngStep, ptSLeft) ; // ultimo punto - plLoop.AddUPoint( dAngStep + 1, ptSRight) ; // polyline chiusa - // creo la superficie Top - PtrOwner pStmTop_end( CreateSurfTriMesh()) ; - if ( IsNull( pStmTop_end) || ! pStmTop_end->CreateByFlatContour( plLoop)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmTop_end) ; - // creo la superificie Bottom - PtrOwner pStmBottom_end( CreateSurfTriMesh()) ; - if ( IsNull( pStmBottom_end) || - ! pStmBottom_end->CopyFrom( pStmTop_end) || - ! pStmBottom_end->Mirror( ptCen, vtNorm)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmBottom_end) ; - // calcolo l'angolo di rotazione per la faccia Top del bevel - ptEnd.Translate( - dBevelV * vtNorm) ; - pCrvLb->GetEndPoint( ptSbLeft) ; - pCrvRb->GetEndPoint( ptSbRight) ; - vtbLeft = ptSbLeft - ptEnd ; - vtbRight = ptSbRight - ptEnd ; - dAng = ANG_STRAIGHT ; - vtbRight.GetAngle( vtbLeft, dAng) ; - vtbRight.Normalize() ; - plLoop.EraseLastUPoint() ; // apro il loop - // creo il loop defininendo i punti - plLoopB.Clear() ; - plLoopB.AddUPoint( 0, ptSbRight) ; - dAngStep = ceil( dAng / dStepRotDeg) ; // primo punto - for ( int i = 1 ; i < dAngStep ; ++ i) { - Point3d ptRot = ptSbRight ; - ptRot.Rotate( ptEnd, vtNorm, i * ( dAng / dAngStep)) ; - plLoopB.AddUPoint( i, ptRot) ; - } - plLoopB.AddUPoint( dAngStep, ptSbLeft) ; // ultimo punto - // creo la superficie Top Bevel - PtrOwner pStmbTop_end( CreateSurfTriMesh()) ; - if ( IsNull( pStmbTop_end) || - ! pStmbTop_end->CreateByTwoCurves( plLoop, plLoopB, ISurfTriMesh::RLT_MINDIST) || - ! pStmbTop_end->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmbTop_end) ; - // creo la superificie Bottom Bevel - PtrOwner pStmbBottom_end( CloneSurfTriMesh( pStmbTop_end)) ; - if ( IsNull( pStmbBottom_end) || ! pStmbBottom_end->Mirror( ptCen, vtNorm)) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmbBottom_end) ; - // creo la superficie perpendicolare alla guida - plLoopB1 = plLoopB ; - plLoopB1.Mirror( ptCen, vtNorm) ; - PtrOwner pStmPerp_end( CreateSurfTriMesh()) ; - if ( IsNull( pStmPerp_end) || - ! pStmPerp_end->CreateByTwoCurves( plLoopB, plLoopB1, ISurfTriMesh::RLT_MINDIST) || - ! pStmPerp_end->Invert()) - return nullptr ; - stmSoup.AddSurfTriMesh( *pStmPerp_end) ; } - // completo unione e recupero la superficie risultante - if ( ! stmSoup.End()) - return nullptr ; - pSTM.Set( stmSoup.GetSurf()) ; - } - else { - // completo unione e recupero la superficie risultante - if ( ! stmSoup.End()) - return nullptr ; - pSTM.Set( stmSoup.GetSurf()) ; + + // inserisco le superfici laterali verticali + for ( int j = 0 ; j < ssize( vSurfLat) ; j ++) + stmSoup.AddSurfTriMesh( *vSurfLat[j]) ; + + // inserisco le superfici laterali rigate e il loro mirror + for ( int j = 0 ; j < ssize( vSurfLatTop) ; j ++) { + stmSoup.AddSurfTriMesh( *vSurfLatTop[j]) ; + vSurfLatTop[j]->Mirror( ptCen, vtNorm) ; + stmSoup.AddSurfTriMesh( *vSurfLatTop[j]) ; + } } + + if ( ! stmSoup.End()) + return nullptr ; + + PtrOwner pSTM ; + pSTM.Set( stmSoup.GetSurf()) ; + if ( IsNull( pSTM)) + return nullptr ; + + // se ho spezzato per la superficie laterale, rischio di aver creato Tjunctions + if ( bRepair) + pSTM->Repair() ; + // salvo tolleranza lineare usata e imposto angolo per smooth pSTM->SetLinearTolerance( dLinTol) ; pSTM->SetSmoothAngle( 20) ; @@ -960,7 +1540,6 @@ GetSurfTriMeshBeveledRectSwept( double dDimH, double dDimV, double dBevelH, doub return Release( pSTM) ; } - //------------------------------------------------------------------------------- ISurfTriMesh* GetSurfTriMeshRectSwept( double dDimH, double dDimV, double dBevelH, double dBevelV, const ICurve* pGuide, int nCapType, double dLinTol) diff --git a/Voronoi.cpp b/Voronoi.cpp index 3698b2b..09bf2b6 100644 --- a/Voronoi.cpp +++ b/Voronoi.cpp @@ -828,10 +828,19 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) Point3d ptTemp ; Vector3d vtDir ; if ( ! pCrv->GetParamAtPoint( pt, dPar, 100 * EPS_SMALL) || ! pCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptTemp, &vtDir)) - return false ; + continue ; vtDir.Normalize() ; - vResult.emplace_back( pt, vtDir) ; + // verifico che il punto non sia già stato trovato + bool bAdd = true ; + for ( int j = 0 ; j < ssize( vResult) ; j ++) { + if ( AreSamePointApprox( vResult[j].first, pt)) { + bAdd = false ; + break ; + } + } + if ( bAdd) + vResult.emplace_back( pt, vtDir) ; } }