diff --git a/EgtGeomKernel.rc b/EgtGeomKernel.rc index 9821844..fa9b849 100644 Binary files a/EgtGeomKernel.rc and b/EgtGeomKernel.rc differ diff --git a/OffsetCurve.cpp b/OffsetCurve.cpp index f6974a2..c5a6cb7 100644 --- a/OffsetCurve.cpp +++ b/OffsetCurve.cpp @@ -60,6 +60,8 @@ OffsetCurve::Reset( void) } } m_CrvLst.clear() ; + m_pt = P_INVALID ; + m_vt = V_INVALID ; return true ; } @@ -704,6 +706,18 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType) double dCorr = ( dDist > 0 ? - VRONI_OFFS_TOL : VRONI_OFFS_TOL) ; voronoiObj->CalcOffset( vOffs, dDist + dCorr, nType) ; } + // se ancora vuoto calcolo i punti speciali di offset ( punti e direzioni sui bisettore alla distanza richiesta) + if ( vOffs.empty()) { + PNTVECTVECTOR vPntOffs ; + voronoiObj->CalcSpecialPointOffset( vPntOffs, dDist) ; + // NB al momento vengono gestiti solo i casi in cui vi è un unico punto di offset. Se si ottengono più punti di offset + // ( e.g. alcune curve aperte) non se ne restiusce nessuno. Da estendere, se necessario, individuando i punti dal lato + // di offset richiesto + if ( vPntOffs.size() == 1) { + m_pt = vPntOffs[0].first ; + m_vt = vPntOffs[0].second ; + } + } } for ( int i = 0 ; i < ( int)vOffs.size() ; i ++) @@ -733,10 +747,21 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType) pCrv->Scale( GLOB_FRM, 1 / dExtrOnN, 1, 1) ; pCrv->ToGlob( frCopy) ; } + if ( m_pt.IsValid()) { + m_pt.Scale( GLOB_FRM, 1 / dExtrOnN, 1, 1) ; + m_pt.ToGlob( frCopy) ; + m_vt.Scale( GLOB_FRM, 1 / dExtrOnN, 1, 1) ; + m_vt.ToGlob( frCopy) ; + } + } else if ( bNeedRef) { for ( auto pCrv : m_CrvLst) pCrv->ToGlob( frCopy) ; + if ( m_pt.IsValid()) { + m_pt.ToGlob( frCopy) ; + m_vt.ToGlob( frCopy) ; + } } // assegno estrusione e spessore come curva originale e unisco parti allineate @@ -814,6 +839,20 @@ OffsetCurve::GetShorterCurve( void) return pCrv ; } +//---------------------------------------------------------------------------- +bool +OffsetCurve::GetPointOffset( Point3d& pt, Vector3d& vt) +{ + // verifico se valori validi da restituire + if ( ! m_pt.IsValid() || ! m_vt.IsValid()) + return false ; + + pt = m_pt ; + vt = m_vt ; + + return true ; +} + //---------------------------------------------------------------------------- bool PreviousIsLine( ICURVEPLIST::const_iterator iIter, const ICURVEPLIST& CrvLst, bool bClosed) diff --git a/Voronoi.cpp b/Voronoi.cpp index adaea83..ff0a190 100644 --- a/Voronoi.cpp +++ b/Voronoi.cpp @@ -574,7 +574,7 @@ Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) if ( m_vroni->IsWMATEdge( i)) { PtrOwner pCrv( GetBisectorCurve( i)) ; if ( ! IsNull( pCrv) && pCrv->IsValid()) - vCrvs.emplace_back( Release( pCrv)) ; + vCrvs.emplace_back( Release( pCrv)) ; } } @@ -594,7 +594,7 @@ bool Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) { vOffs.clear() ; - + if ( ! IsValid()) return false ; @@ -767,6 +767,76 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) return true ; } +//---------------------------------------------------------------------------- +bool +Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) +{ + // calcola i punti e le tangenti sui bisettori del medial axis in corrispondenza del valore di offset richiesto + + vResult.clear() ; + + if ( abs( dOffs) < EPS_SMALL) + return true ; + + if ( ! IsValid()) + return false ; + + try { + // verifico se necessario ricalcolo Voronoi + UpdateVoronoi( dOffs) ; + + // indivudio lato medial axis per curve chiuse ( suppongo di chiamare la funzione dalla singola curva, quindi vale controllare + // la chiusura solo sulla prima curva. Eventualmente da estendere) + bool bLeft = true, bRight = true ; + if ( m_vpCrvs[0]->IsClosed()) { + bLeft = dOffs < 0 ; + bRight = ! bLeft ; + } + + // calcolo medial axis + m_vroni->apiComputeWMAT( false, 0.0, 0.0, false, bLeft, bRight) ; + + for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) { + // verifico se il lato appartiene al medial axis + if ( m_vroni->IsWMATEdge( i)) { + // verifico se coinvolto dall'offset + double dParS, dParE ; + m_vroni->GetBisectorParams( i, dParS, dParE) ; + if ( dParS > dParE) + swap( dParS, dParE) ; + if ( abs( dOffs) < dParS || abs( dOffs) > dParE) + continue ; + + // calcolo il punto sul bisettore in corrispondenza dell'offset + Point3d pt ; + m_vroni->GetBisectorPointAtParam( i, abs( dOffs), pt.v) ; + + // calcolo il vettore tangente + PtrOwner pCrv( GetBisectorCurve( i)) ; + if ( IsNull( pCrv)) + return false ; + double dPar ; + Point3d ptTemp ; + Vector3d vtDir ; + if ( ! pCrv->GetParamAtPoint( pt, dPar, 100 * EPS_SMALL) || ! pCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptTemp, &vtDir)) + return false ; + vtDir.Normalize() ; + + vResult.emplace_back( pt, vtDir) ; + } + } + + // libero la memoria di vroni utilizzata per calcolare bisettori + m_vroni->apiFreeBisectorBuffer() ; + } + catch (...) { + LOG_ERROR( GetEGkLogger(), m_vroni->GetExceptionMessage()) ; + return false ; + } + + return true ; +} + //---------------------------------------------------------------------------- bool Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bool bSquareMids) @@ -886,14 +956,24 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs) } else { PtrOwner pArc( CreateBasicCurveArc()) ; - pArc->SetC2P( ptC, ptS, ptE) ; - // verifico orientamento - double dAng = pArc->GetAngCenter() ; - if ( ( nType == CCW && dAng < - EPS_ANG_SMALL) || ( nType == CW && dAng > EPS_ANG_SMALL)) - pArc->ToExplementary() ; - // aggiungo alla composita - if ( ! pCrvOffs->AddCurve( Release( pArc))) - return false ; + if ( ! pArc->SetC2P( ptC, ptS, ptE)) { + // se raggio minore di EPS_SMALL approssimo con linea + if ( AreSamePointApprox( ptC, ptS)) { + if ( ! pCrvOffs->AddLine( ptE)) + return false ; + } + else + return false ; + } + else { + // verifico orientamento + double dAng = pArc->GetAngCenter() ; + if ( ( nType == CCW && dAng < - EPS_ANG_SMALL) || ( nType == CW && dAng > EPS_ANG_SMALL)) + pArc->ToExplementary() ; + // aggiungo alla composita + if ( ! pCrvOffs->AddCurve( Release( pArc))) + return false ; + } } // setto come info la sottocurva da cui si è generata diff --git a/Voronoi.h b/Voronoi.h index 9e0254e..8f6e1fc 100644 --- a/Voronoi.h +++ b/Voronoi.h @@ -56,6 +56,7 @@ class Voronoi bool CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound = VORONOI_STD_BOUND) ; bool CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) ; bool CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) ; + bool CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) ; bool CalcFatCurve( ICURVEPOVECTOR& vOffs, double dOffs, bool bSquareEnds, bool bSquareMids) ; bool CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) ; bool CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) ;