Compare commits

...

106 Commits

Author SHA1 Message Date
Daniele Bariletti ee6175825e Merge branch 'ZMap_CrackedSurfTM' 2026-07-17 17:24:30 +02:00
Daniele Bariletti a69be04cf7 EgtGeomKernel :
- milgiorie e correzioni alla funzione per ottenere lo ZMap da una trimesh con crack.
2026-07-17 17:24:11 +02:00
Daniele Bariletti fa71f3c38d EgtGeomKernel :
- aggiunto parametro alla CreateFromSurfTm di VolZMap per poter lavorare anche con una SurfTm non chiusa per colpa di crepe.
- aggiunte sottofunzioni relative.
2026-07-16 09:20:13 +02:00
Dario Sassi e88169af12 EgtGeomKernel 3.1g3 :
- ricompilazione con cambio versione.
2026-07-14 18:20:41 +02:00
Dario Sassi 488bdd3ca2 EgtGeomKernel :
- correzione a calcolo Silhouette di Trimesh (versioni dirette dai triangoli).
2026-07-13 17:49:55 +02:00
Daniele Bariletti 0f0397c20c EgtGeomKernel :
- rimossa variabile inutilizzata.
2026-07-13 12:21:01 +02:00
Daniele Bariletti c1988dd442 EgtGeomKernel :
- correzione e miglioria a offset3d e SurfExtend.
2026-07-13 12:05:26 +02:00
Daniele Bariletti b5f5a22145 EgtGeomKernel :
- aggiunta commento.
2026-07-13 12:03:17 +02:00
Daniele Bariletti 7f4bd1ef24 EgtGeomKernel :
- piccola correzione al VM 5assi.
2026-07-13 11:58:13 +02:00
Dario Sassi afe3000635 EgtGeomKernel 3.1g2 :
- ricompilazione con cambio versione.
2026-07-10 13:27:47 +02:00
Daniele Bariletti 5bd2b869f8 EgtGeomKernel :
- miglioria alla gestione della RemoveAlignedPoints con limite sulla lunghezza.
2026-07-09 14:44:51 +02:00
Daniele Bariletti 4d3b7ea6cf EgtGeomKernel :
- aggiunta funzione per l'approsimazione di curve con limitazione sulla lunghezza dei singoli tratti.
2026-07-08 17:26:51 +02:00
Daniele Bariletti f0137d26f4 EgtGeomKernel :
- migliorie e correzioni a SurfExtend e Offset3d.
2026-07-07 16:13:17 +02:00
Daniele Bariletti dc46c92c95 EgtGeomKernel :
- aggiunta funzione per gestione spigoli in SurfExtend
- correzioni a SurfExtend.
2026-07-07 09:13:18 +02:00
Daniele Bariletti 53cd3c26b9 EgtGeomKernel :
- rimozione flag debug.
2026-07-06 08:50:09 +02:00
Dario Sassi e194679232 EgtGeomKernel 3.1g1 :
- ricompilazione con cambio versione.
2026-07-03 18:41:11 +02:00
Daniele Bariletti fca95f609a EgtGeomKernel :
- correzioni e migliorie alla SurfExtend.
2026-07-03 15:33:10 +02:00
Daniele Bariletti 063322e528 EgtGeomKernel :
- correzioni e migliorie all'offset3d e SurfExtend.
2026-07-01 14:33:58 +02:00
Daniele Bariletti 01342aebe5 EgtGeomKernel :
- piccola correzione a ProjectCurveOnSurf
- miglioria a SurfExtend, usando direttamente i dati del bordo della trimesh, anziché proiettare il bordo sulla superficie stessa.
2026-06-30 15:48:27 +02:00
Riccardo Elitropi c41dde0da0 EgtGeomKernel 3.1f6 :
- In CalcPocketing aggiunta gestione di lati chiusi da trattare come aperti per ZigZag/OneWay/Spiral.
2026-06-30 12:30:22 +02:00
Daniele Bariletti ef12fe8bd1 EgtGeomKernel :
- miglioria dell'offset3d e del SurfExtend.
2026-06-30 09:22:32 +02:00
Daniele Bariletti c1a2912970 EgtGeomKernel :
- correzioni e migliorie a offset3d e surfextend.
2026-06-25 15:26:00 +02:00
Dario Sassi 576eb1cb73 EgtGeomKernel 3.1f5 :
- ricompilazione con cambio versione.
2026-06-25 13:03:56 +02:00
Riccardo Elitropi d3ce75b2e8 EgtGeomKernel :
- in SurfTriMesh aggiunto parametro Opzionale di tolleranza lineare per i metodi di Silhouette.
2026-06-25 11:08:13 +02:00
Daniele Bariletti 337d5b6d80 Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2026-06-24 15:42:03 +02:00
Daniele Bariletti 487ed0b61f EgtGeomKernel :
- piccola correzione.
2026-06-24 15:42:00 +02:00
Riccardo Elitropi 8c67f1aebf EgtGeomKernel :
- in CalcPocketing correzione sull'ordine degli Offset per i casi Spiral.
2026-06-24 15:41:31 +02:00
Daniele Bariletti 1c4198d31c EgtGeomKernel :
- correzioni e migliorie a offset3d
- creato enum per angoli di una curva proiettata su superficie.
- aggiunta funzione per l'estensione delle superfici.
2026-06-24 15:14:50 +02:00
Daniele Bariletti 0c7f3d5fd8 EgtGeomKernel :
- miglioria nella creazione dell'offset 3d
- aggiunta messaggio di errore nel log per le ruled guided.
2026-06-23 15:08:40 +02:00
Daniele Bariletti 4cdcfe1b8b EgtGeomKernel :
- correzioni all'offset 3d.
2026-06-22 12:00:24 +02:00
Dario Sassi 96cb7e5cc3 EgtGeomKernel 3.1f4 :
- ricompilazione con cambio versione.
2026-06-19 18:58:07 +02:00
Daniele Bariletti dd28697e48 EgtGeomKernel :
- correzioni alla creazione della ruled smooth.
2026-06-19 12:29:21 +02:00
Daniele Bariletti d7d19a07c6 EgtGeomKernel :
- tolti flag di debug.
2026-06-19 09:17:06 +02:00
Riccardo Elitropi 25e2a903c7 EgtGeomKernel :
- in CalcPocketing aggiunto parametro bOpenOutRaw.
2026-06-19 08:53:09 +02:00
Daniele Bariletti 8e18211735 EgtGeomKernel :
- correzioni all'offset 3d.
- unificazione della funzione per la correzione dell'offset 3d.
2026-06-18 16:23:45 +02:00
Riccardo Elitropi a53ead679e EgtGeomKernel :
- in CalcPocketing per lavorazioni conformal aggiunta la possibilità di lavorare una regione mantenendo l'utensile al suo interno.
2026-06-18 10:55:24 +02:00
Daniele Bariletti 9b80d32f34 EgtGeomKernel :
- riportate le correzioni dal MachKernel.
2026-06-17 12:02:32 +02:00
Daniele Bariletti 52b95982fb EgtGeomKernel :
- correzione all'identificazione di angoli concavi e convessi nella proiezione di curve su superfici.
- miglioria all'offset 3d.
2026-06-16 17:51:02 +02:00
Riccardo Elitropi 92d8f4414e EgtGeomKernel :
- in CalcPocketing aggiunto algoritmo ordinamento Offset per lavorazioni Spiral.
2026-06-16 12:42:36 +02:00
SaraP f48bf06f64 EgtGeomKernel 3.1f3 :
- migliorie nella creazione di solidi swept con sezione rettangolare smussata
- correzioni errori e aggiunte funzioni per calcolo bisettori di Voronoi
- aggiunto parametro a GetChainedCurves per fermare su biforcazione
- piccola miglioria a AssociatePolyLinesMinDistPoints.
2026-06-15 09:57:55 +02:00
Daniele Bariletti 490f3fc54c Merge branch '5AxTrimming' 2026-06-15 08:38:46 +02:00
Daniele Bariletti b7b05fb3e1 EgtGeomKernel :
- correzione e miglioria dell'offset 3d delle curve.
2026-06-12 16:48:00 +02:00
Daniele Bariletti 1cfd283f26 EgtGeomKernel :
- prima versione dell'offset 3d (da correggere).
2026-06-11 18:05:15 +02:00
Daniele Bariletti 1f47402215 EgtGeomKernel :
- piccola correzione.
2026-06-09 16:50:20 +02:00
Daniele Bariletti 55e2983991 EgtGeomKernel :
- correzione alla gestione delle normali in IntersLineCyl.
- modifiche alla chiamata della funzione IntesLineCyl in VolZMap.
2026-06-09 15:51:46 +02:00
Riccardo Elitropi 7c85ea2d43 EgtGeomKernel :
- in CalcPocketing modifiche stilistiche.
2026-06-09 15:22:55 +02:00
Daniele Bariletti 1c49379ee1 EgtGeomKernel 3.1f2 :
- aggiunta modalità per IntersLineCyl
- spostate funzioni relative
- cambiuo versione.
2026-06-09 12:28:39 +02:00
Riccardo Elitropi 481d81a8d2 EgtGeomKernel :
- in CalcPocketing piccola correzione.
2026-06-09 09:51:46 +02:00
Daniele Bariletti 68e25e10e8 EgtGeomKernel :
- controllo più fine e piccolo miglioramento per identificaizone zone concave smooth.
2026-06-08 12:38:18 +02:00
Riccardo Elitropi 88410333e9 EgtGeomKernel :
- in SurfTriMesh::GetSilhouette aggiunti controlli.
2026-06-08 12:22:25 +02:00
Daniele Bariletti 6bbedc812f EgtGeomKernel 3.1f1 :
- cambio versione.
2026-06-05 14:20:19 +02:00
Daniele Bariletti 4e6dd05aa9 EgtGeomKernel :
- miglioria nella gestione degli angoli interni per lavorazioni a 5 assi.
2026-06-05 10:08:16 +02:00
Riccardo Elitropi a5684b2bf3 EgtGeomKernel :
- piccola correzione in CalcPocketing.
2026-05-29 13:25:47 +02:00
SaraP 119bbe0bcb EgtGeomKernel :
- prime migliorie nella creazione di solidi swept con sezione rettangolare e bevel ( prima versione, da sistemare caps flat e none)
- correzione in Voronoi.
2026-05-28 15:30:41 +02:00
Riccardo Elitropi 35b903e8a0 EgtGeomKernel 3.1e5 :
- in CalcPocketing piccole migliorie e correzioni per ZigZag.
2026-05-27 17:28:50 +02:00
Daniele Bariletti 979597084d EgtGeomKernel :
- migliorie e correzioni a RuledSmooth.
2026-05-26 11:27:27 +02:00
Daniele Bariletti 02742ee80f Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2026-05-22 10:41:25 +02:00
Daniele Bariletti a2bcc4d682 EgtGeomKernel :
- migliorata funzione per l'interpolazione di direzioni per la lavorazione di trimming.
2026-05-22 10:41:09 +02:00
Dario Sassi cbd487e4ff EgtGeomKernel 3.1e4 :
- modifiche a VerifyConnection di TriMesh per renderla abbastanza veloce con superfici patologiche.
2026-05-21 12:47:21 +02:00
Riccardo Elitropi 37aaa98df6 EgtGeomKernel 3.1e3 :
- in CalcPocketing aggiunta gestione per ToolCompensation.
2026-05-14 15:24:47 +02:00
Dario Sassi 2dcaa57aa3 EgtGeomKernel :
- modifiche a RMF per avere la tangente media sul punto di calcolo (utile solo se la curva non è G1)
- modifiche a GetSurfTriMeshSwept per avere RMF anche con curve piane garantendo la retrocompatibilità.
2026-05-14 13:02:47 +02:00
Riccardo Elitropi ba7379e752 EgtGeomKernel :
- In CalcPocketing aggiunto flag per Conventional Milling.
2026-05-12 09:34:56 +02:00
Daniele Bariletti 6646aee01c EgtGeomKernel :
- estratta funzione per trovare il punto corrispondente sulla seconda curva di una coppia di curve da sincronizzare.
- pulizia codice.
2026-05-08 17:25:32 +02:00
Riccardo Elitropi 7f8382f1b8 EgtGeomKernel :
- In CalcPocketing correzione entrate per utensili grandi su contorni aperti piccoli.
2026-05-08 17:23:01 +02:00
Daniele Bariletti 4bcdb03598 EgtGeomKernel 3.1e2 :
- piccola modifica
- cambio versione.
2026-05-07 14:28:07 +02:00
Dario Sassi 68e9be7901 EgtGeomKernel 3.1e1 :
- ricompilazione con cambio versione.
2026-05-07 12:23:08 +02:00
Daniele Bariletti 9e3bac4a68 Merge branch 'Trimming' 2026-05-07 11:18:56 +02:00
Daniele Bariletti 1fee7b8e49 Merge branch 'master' into Trimming 2026-05-07 11:18:09 +02:00
Daniele Bariletti f668d7ac11 EgtGeomKernel :
- cambiata distanza di campionamento in trimming.
2026-05-07 11:17:52 +02:00
Daniele Bariletti 4a1c13154f EgtGeomKernel :
- migliorie a regolarize.
2026-05-07 11:16:37 +02:00
Daniele Bariletti 68a9848748 EgtGeomKernel :
- miglioramenti alla regolarize.
2026-05-06 12:51:20 +02:00
Daniele Bariletti f5059166ed Merge branch 'master' into Trimming 2026-05-05 14:32:25 +02:00
Daniele Bariletti ad7f209fc9 EgtGeomKernel :
- correzione all'autointersezione di curve.
2026-05-05 13:32:25 +02:00
Daniele Bariletti 8b5bfb6e19 EgtGeomKernel :
- separazione delle due versioni di regolarize.
2026-05-05 09:11:27 +02:00
Daniele Bariletti 1efd17f6ee EgtGeomKernel :
- pulizia.
2026-04-29 11:23:15 +02:00
Daniele Bariletti b8caeb49e0 EgtGeomKernel :
- miglioria alla regolarize.
2026-04-29 11:17:57 +02:00
Daniele Bariletti a9fc259745 Merge branch 'master' into Trimming 2026-04-28 12:08:24 +02:00
Daniele Bariletti bbc98fe282 EgtGeomKernel :
- cambiata la chiamata a ModifyJoint
- cambiato nome alla ModifySingleCurve
- estesa la ModifyJoint con tolleranza
- modifiche stilistiche e pulizia codice.
2026-04-28 11:09:34 +02:00
Riccardo Elitropi a445ddd89b EgtGeomKernel :
- in CalcPocketing aggiunto prototipo per riconoscimento di svuotatura di un foro.
2026-04-28 11:04:42 +02:00
Daniele Bariletti e874b2eb36 Merge branch 'master' into Trimming 2026-04-27 16:01:59 +02:00
Daniele Bariletti a45faa4793 EgtGeomKernel :
- correzioni e migliorie a Regolarize.
2026-04-27 16:01:00 +02:00
Daniele Bariletti 344f0da7ff EgtGeomKernel :
- tolto flag di debug.
2026-04-27 15:06:27 +02:00
Daniele Bariletti cea869c6ee EgtGeomKernel :
- correzione al commit precedente.
2026-04-27 15:05:45 +02:00
Daniele Bariletti 8ad2887c38 Merge branch 'master' into Trimming 2026-04-27 15:04:02 +02:00
Daniele Bariletti 2b1d2a512d EgtGeomKernel :
- rimosso flag di debug.
2026-04-27 15:03:49 +02:00
Daniele Bariletti a55770d702 EgtGeomKernel :
- migliorata la Regolarize delle rigate per trimming.
- aggiunte funzioni di utilità per le CurveComposite.
2026-04-27 14:58:23 +02:00
Dario Sassi 2e4b1cdd40 EgtGeomKernel :
- spostamento di sorgente in cartella filtro.
2026-04-22 18:31:20 +02:00
Daniele Bariletti 3ffc0b40d8 EgtGeomKernel :
- tolto flag di debug.
2026-04-22 16:12:30 +02:00
Daniele Bariletti cd2cde40da EgtGeomKernel:
- correzioni alla regolarize.
2026-04-22 16:11:46 +02:00
Daniele Bariletti efc656a72c Merge branch 'Trimming' 2026-04-21 15:05:12 +02:00
Daniele Bariletti e1eb139aee Merge branch 'master' into Trimming 2026-04-21 15:04:54 +02:00
Daniele Bariletti e7d25b2d0e EgtGeomKernel :
- correzioni e migliorie a regolarize dei bordi per trimming.
2026-04-21 15:04:24 +02:00
Riccardo Elitropi ce05ce577c EgtGeomKernel 3.1d4 :
- In Voronoi migliorati i controlli sulla chiusura delle curve (copyright Sara)
- in CalcPocketing corrette le funzioni del calcolo delle Feed e migliorati i controlli sugli ingressi.
2026-04-20 15:05:03 +02:00
Daniele Bariletti ae2cac48d1 Merge branch 'master' into Trimming 2026-04-17 13:34:47 +02:00
Daniele Bariletti 37e9a05347 EgtGeomKernel :
- nuova versione regolarize.
2026-04-17 13:34:17 +02:00
Daniele Bariletti 02cb8a0d3c EgtGeomKernel :
- aggiornamento versione di RuledSmooth.
- aggiunta controlli.
- prima versione della regolarizzazione di curve bezier composte.
2026-04-16 09:41:22 +02:00
Dario Sassi 6942f5fc23 EgtGeomKernel :
- nella proiezione di curve su superfici aggiunto paramtetro bFromVsTo.
2026-04-15 08:54:32 +02:00
Riccardo Elitropi 6c4bf3f05a EgtGeomKernel :
- in CalcPocketing migliorati i controlli per i casi a Trapezio.
- in CAvToolTriangle migliorata la creazione del frame Locale in CAvDiskTriangle per direzioni generiche di vDiskAx e vtMove.
2026-04-14 19:07:16 +02:00
Daniele Bariletti 4bc8590ce9 Merge branch 'master' into Trimming 2026-04-14 12:08:17 +02:00
Daniele Bariletti 5b68e33d1f EgtGeomKernel :
- correzione al VM 5 assi.
2026-04-14 11:59:17 +02:00
Daniele Bariletti a70f7ee9c9 Merge branch 'Trimming' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel into Trimming 2026-04-14 10:56:00 +02:00
Daniele Bariletti 95a070413a EgtGeomKernel :
- miglioria nel posizionamento delle curve di sync.
2026-04-14 10:53:24 +02:00
Riccardo Elitropi 223489e80d EgtGeomKernel 3.1d3 :
- in CalcPocketing piccola modifica alle tolleranze per casi a Trapezio.
2026-04-13 15:26:34 +02:00
Daniele Bariletti f6a535d94c EgtGeomKernel :
- tolto flag di debug.
2026-04-13 14:29:59 +02:00
Daniele Bariletti dbc3e7d2bf Merge branch 'NewRuled' 2026-04-10 18:20:59 +02:00
Riccardo Elitropi b3ebb35d01 EgtGeomKernel :
- aggiunte prime funzioni di Trimming.
2025-12-22 17:15:02 +01:00
36 changed files with 6672 additions and 2091 deletions
+2 -4
View File
@@ -2440,12 +2440,10 @@ CAvDiskTriangle( const Point3d& ptDiskCen, const Vector3d& vtDiskAx, double dDis
// Allontanamento dall'interno
double dEscapeDist = max( DiskTriaInteriorEscapeDistGenMot( ptDiskCen, vtDiskAx, dDiskRad, trTria, vtMove), 0.) ;
// Allontanamento dalla frontiera
Vector3d vtMoveOrt = vtMove - vtMove * vtDiskAx * vtDiskAx ;
Vector3d vtMoveOrt = OrthoCompo( vtMove, vtDiskAx) ;
vtMoveOrt.Normalize() ;
Frame3d DiskFrame ;
Vector3d vtJ = vtDiskAx ^ vtMoveOrt ;
vtJ.Normalize() ;
DiskFrame.Set( ptDiskCen, vtMoveOrt, vtJ, vtDiskAx) ;
DiskFrame.Set( ptDiskCen, vtDiskAx, vtMoveOrt) ;
Triangle3d trTriaLoc = trTria ;
Vector3d vtMoveLoc = vtMove ;
trTriaLoc.ToLoc( DiskFrame) ;
+1565 -784
View File
File diff suppressed because it is too large Load Diff
+31 -2
View File
@@ -41,7 +41,7 @@ GEOOBJ_REGISTER( CRV_ARC, NGE_C_ARC, CurveArc) ;
class ArcApproxer
{
public :
ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const CurveArc& arArc) ;
ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const CurveArc& arArc, double dMaxLen = INFINITO) ;
bool GetPoint( double& dU, Point3d& ptP) ;
private :
@@ -1177,6 +1177,30 @@ CurveArc::ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLin
return true ;
}
//----------------------------------------------------------------------------
bool
CurveArc::ApproxWithLimitedLines( double dLinTol, double dAngTolDeg, int nType, double dMaxLen, PolyLine& PL) const
{
// pulisco la polilinea
PL.Clear() ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// eseguo approssimazione
bool bInside = true ;
ArcApproxer aAppr( dLinTol, dAngTolDeg, bInside, *this, dMaxLen) ;
double dU ;
Point3d ptPos ;
while ( aAppr.GetPoint( dU, ptPos)) {
if ( ! PL.AddUPoint( dU, ptPos))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveArc::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const
@@ -2170,7 +2194,7 @@ CurveArc::Flip( void)
// usando il versore medio dal centro e moltiplicandolo per il coefficiente ( 2 / ( 1 + cosA)).
// Il versore dell'ultimo punto è già stato calcolato per il penultimo.
//----------------------------------------------------------------------------
ArcApproxer::ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const CurveArc& arArc)
ArcApproxer::ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const CurveArc& arArc, double dMaxLen)
{
// inizializzazioni
m_nTotPnt = 0 ;
@@ -2195,6 +2219,11 @@ ArcApproxer::ArcApproxer( double dLinTol, double dAngTolDeg, bool bInside, const
dAngStepDeg = sqrt( 8 * dLinTolRel) * RADTODEG ;
else
dAngStepDeg = sqrt( 8 * dLinTolRel / ( 1 + dLinTolRel)) * RADTODEG ;
if ( dMaxLen < INFINITO) {
double dAngStepMaxLen = 2 * asin( dMaxLen / ( 2 * arArc.GetRadius())) * RADTODEG ;
dAngStepDeg = min( dAngStepDeg, dAngStepMaxLen) ;
}
dAngStepDeg = min( dAngStepDeg, dAngTolDeg) ;
// dall'angolo al centro ricavo il numero di passi
+1
View File
@@ -111,6 +111,7 @@ class CurveArc : public ICurveArc, public IGeoObjRW
bool GetArea( Plane3d& plPlane, double& dArea) const override
{ return CurveGetArea( *this, plPlane, dArea) ; }
bool ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const override ;
bool ApproxWithLimitedLines( double dLinTol, double dAngTolDeg, int nType, double dMaxLen, PolyLine& PL) const override ;
bool ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const override ;
bool ApproxWithArcsEx( double dLinTol, double dAngTolDeg, double dLinFea, PolyArc& PA) const override
{ return ApproxWithArcs( dLinTol, dAngTolDeg, PA) ; }
+175 -7
View File
@@ -25,19 +25,24 @@
#include "IntersLineLine.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include "/EgtDev/Include/EGkUiUnits.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EGkIntersCurvePlane.h"
#include "/EgtDev/Include/EGkCurveByInterp.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#define EIGEN_NO_IO
#include "/EgtDev/Extern/Eigen/Dense"
#define SAVEAPPROX 0
#define SAVECURVEPASSED 0
#define SAVELINEARAPPROX 0
#if SAVEAPPROX || SAVECURVEPASSED || SAVELINEARAPPROX
#define SAVESYNCLINES 0
#if SAVEAPPROX || SAVECURVEPASSED || SAVELINEARAPPROX || SAVESYNCLINES
#include "/EgtDev/Include/EGkGeoPoint3d.h"
static int nCrvPassed = 0 ;
std::vector<IGeoObj*> VT ;
std::vector<Color> VC ;
#include "/EgtDev/Include/EGkGeoObjSave.h"
#endif
@@ -1595,8 +1600,10 @@ FitWithBezier( const ICurve* pCrvOrig, const PNTVECTOR& vPnt, DBLVECTOR& vParam,
//----------------------------------------------------------------------------
ICurve*
ApproxCurveWithBezier( const ICurve* pCrv , double dTol)
ApproxCurveWithBezier( const ICurve* pCrv , double dTol, const Vector3d& vtStart, const Vector3d& vtEnd)
{
if ( pCrv == nullptr || ! pCrv->IsValid())
return nullptr ;
#if SAVECURVEPASSED
SaveGeoObj( pCrv->Clone(), "D:\\Temp\\bezier\\approxWithBezier\\CurveDaApprossimare\\"+ToString(nCrvPassed) + ".nge") ;
@@ -1668,6 +1675,10 @@ ApproxCurveWithBezier( const ICurve* pCrv , double dTol)
VCT3DVECTOR vPrevDer ;
VCT3DVECTOR vNextDer ;
ComputeAkimaTangents( false, vParam, vPnt, vPrevDer, vNextDer) ;
if ( ! AreSameVectorExact(vtStart, V_NULL)) {
vNextDer[0] = vtStart ;
vPrevDer.back() = vtEnd ;
}
int nOverSampling = ssize( vPntOverSampling) ;
vParam.resize( nOverSampling) ;
@@ -1718,7 +1729,11 @@ CalcApproxError( const ICurve* pCrvOri, const ICurve* pCrvNew, double& dErr, int
// controllo l'errore effettivo campionando più finemente
double dLenOri = 0 ; pCrvOri->GetLength( dLenOri) ;
double dLenNew = 0 ; pCrvNew->GetLength( dLenNew) ;
dErr = 0 ;
Point3d ptStart0 ; pCrvOri->GetStartPoint( ptStart0) ;
Point3d ptStart1 ; pCrvNew->GetStartPoint( ptStart1) ;
Point3d ptEnd0 ; pCrvOri->GetEndPoint( ptEnd0) ;
Point3d ptEnd1 ; pCrvNew->GetEndPoint( ptEnd1) ;
dErr = max( Dist( ptStart1, ptStart0), Dist( ptEnd1, ptEnd0)) ;
for ( int i = 1 ; i < nPoints ; ++i) {
Point3d ptOri, ptNew ;
double dParOri, dParNew ;
@@ -2637,7 +2652,7 @@ ResetCurveVoronoi( const ICurve& crvC)
//----------------------------------------------------------------------------
bool
GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert)
GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert, bool bHaltOnFork)
{
if ( ssize( vCrv) == 1)
return true ;
@@ -2655,7 +2670,7 @@ GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert)
}
INTVECTOR vIds ;
Point3d ptStart = ORIG ;
while ( chainCrv.GetChainFromNear( ptStart, false, vIds)) {
while ( chainCrv.GetChainFromNear( ptStart, bHaltOnFork, vIds)) {
int nFirst = vIds[0] ;
bool bInvert = false ;
if ( nFirst < 0)
@@ -2687,3 +2702,156 @@ GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert)
}
return true ;
}
//----------------------------------------------------------------------------
double
CalcWeightVal( double dLen, const ICurve* pCrv, const Vector3d vtCurr1, const Point3d& ptCurr1, double dCoeff, double dMyDist, double& dUStep2)
{
pCrv->GetParamAtLength( dLen, dUStep2) ;
Point3d ptStep2 ; Vector3d vtStep2 = V_NULL ;
pCrv->GetPointD1D2( dUStep2, ICurve::FROM_MINUS, ptStep2, &vtStep2) ; vtStep2.Normalize() ;
double dStepCos2 = vtCurr1 * vtStep2 ;
double dDist = Dist( ptCurr1, ptStep2) ;
return (1 - dStepCos2) + dCoeff * dDist / dMyDist ;
}
//----------------------------------------------------------------------------
bool
GetIsoPointOnSecondCurve( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2, double dUCurr1, double& dUCurr2, double dMyDist, double dUPrev2,
double dLenPrev2, double& dLenCurr2, double dLen2)
{
Point3d ptCurr1 ;
Vector3d vtCurr1 ;
pCrvEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurr1, &vtCurr1) ;
vtCurr1.Normalize() ;
// --- Piano di taglio per punto a minima distanza
IntersCurvePlane ICP( *pCrvEdge2, ptCurr1, vtCurr1) ;
int nIndParCloser = - 1, nIndPointCloser = -1 ;
double dSqMinDist = INFINITO ;
for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) {
IntCrvPlnInfo aInfo ;
if ( ICP.GetIntCrvPlnInfo( nInfo, aInfo) && aInfo.Ici[0].dU > dUPrev2) {
if ( nIndParCloser == -1)
nIndParCloser = nInfo ;
double dSqDist = SqDist( ptCurr1, aInfo.Ici[0].ptI) ;
if ( dSqDist < dSqMinDist) {
dSqMinDist = dSqDist ;
nIndPointCloser = nInfo ;
}
}
}
bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ;
if ( bOkPlane) {
// Se gli indici sono tra loro coerenti allora ho individuato il punto
if ( nIndParCloser == nIndPointCloser) {
IntCrvPlnInfo aInfo ;
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfo) ;
dUCurr2 = aInfo.Ici[0].dU ;
}
// Se gli indici sono discordi, devo scegliere quale dei due punti tenere
else {
// scelgo il punto più vicino al corrente
IntCrvPlnInfo aInfoPt, aInfoPar ;
ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ;
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ;
dUCurr2 = ( SqDist( ptCurr1, aInfoPt.Ici[0].ptI) < SqDist( ptCurr1, aInfoPar.Ici[0].ptI) ?
aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ;
#if SAVESYNCLINES
VT.clear() ; VC.clear() ;
VT.emplace_back( pCrvEdge1->Clone()) ; VC.emplace_back( Color( 0, 128, 255)) ;
VT.emplace_back( pCrvEdge2->Clone()) ; VC.emplace_back( Color( 0, 128, 255)) ;
PtrOwner<IGeoPoint3d> ptCurr1Geo( CreateGeoPoint3d()) ; ptCurr1Geo->Set( ptCurr1) ;
VT.emplace_back( Release( ptCurr1Geo)) ; VC.emplace_back( BLUE) ;
PtrOwner<IGeoPoint3d> ptPar( CreateGeoPoint3d()) ; ptPar->Set( aInfoPar.Ici[0].ptI) ;
PtrOwner<IGeoPoint3d> ptPt( CreateGeoPoint3d()) ; ptPt->Set( aInfoPt.Ici[0].ptI) ;
VT.emplace_back( Release( ptPar)) ; VC.emplace_back( LIME) ;
VT.emplace_back( Release( ptPt)) ; VC.emplace_back( FUCHSIA) ;
SaveGeoObj( VT, VC, "C:\\Temp\\bezier\\ruled\\TestTrimmingPlane.nge") ;
#endif
}
// Verifico di non essermi allontanato troppo
double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ;
bOkPlane = ( dLen < dLenPrev2 + 2. * dMyDist) ;
}
if ( ! bOkPlane) {
// --- Altrimenti, cerco il punto a minima distanza
DistPointCurve DPC( ptCurr1, *pCrvEdge2) ;
int nFlag ;
bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrev2, dUCurr2, nFlag) && dUCurr2 > dUPrev2) ;
// Verifico di non essermi allontanato troppo
if ( bOkMinDist) {
double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ;
bOkMinDist = ( dLen < dLenPrev2 + 2. * dMyDist) ;
}
if ( ! bOkMinDist) {
// --- Aumento la distanza corrente del passo di campionamento
double dLen = Clamp( dLenPrev2 + dMyDist, 0., dLen2) ;
pCrvEdge2->GetParamAtLength( dLen, dUCurr2) ;
}
}
// Recupero il punto corrente e la direzione tangente sul secondo bordo
pCrvEdge2->GetLengthAtParam( dUCurr2, dLenCurr2) ;
Point3d ptCurr2 ;
Vector3d vtCurr2 ;
pCrvEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_MINUS, ptCurr2, &vtCurr2) ;
vtCurr2.Normalize() ;
// Verifico se le direzioni tangenti sono tra di loro circa parallele
const double COS_ANG_TOL = cos( 15. * DEGTORAD) ;
const double COS_SMALL_ANG_TOL = cos( 4. * DEGTORAD) ;
double dSearchLen = dMyDist / 2 ;
int NUM_STEP = 10 ;
const double dCoeff = 0.1 ;
double dCos = vtCurr1 * vtCurr2 ;
double dDistCurr = Dist( ptCurr1, ptCurr2) ;
double dMin = (1 - dCos) + dCoeff * dDistCurr / dMyDist ;
double bUpdated = false ;
// se poco fuori tolleranza controllo se ho un punto abbastanza vicino con la stessa tangente
if ( vtCurr1 * vtCurr2 < COS_SMALL_ANG_TOL) {
// Se tanto fuori dalla tolleranza, recupero il miglior versore tangente sul secondo bordo nell'intervallo successivo di lunghezza ( 2. * dMyDist)
if ( vtCurr1 * vtCurr2 < COS_ANG_TOL) {
dSearchLen = dMyDist ;
NUM_STEP = 20 ;
}
pCrvEdge2->GetLengthAtPoint( ptCurr2, dLenCurr2) ;
double dLimInfLen2 = Clamp( dLenCurr2 - dSearchLen, dLenPrev2, dLen2) ;
double dLimSupLen2 = Clamp( dLenCurr2 + dSearchLen, dLenPrev2, dLen2) ;
// faccio un campionamento grossolano e poi campiono più finemente in prossimità dei minimi
DBLVECTOR vVal ;
for ( int i = 0 ; i <= NUM_STEP ; ++ i) {
double dLen = dLimInfLen2 + i * ( dLimSupLen2 - dLimInfLen2) / NUM_STEP ;
double dUStep2 ;
vVal.push_back( CalcWeightVal( dLen, pCrvEdge2, vtCurr1, ptCurr1, dCoeff, dMyDist, dUStep2)) ;
if ( vVal.back() < dMin) {
dMin = vVal.back() ;
dUCurr2 = dUStep2 ;
}
}
DBLDBLVECTOR vInterv ;
for ( int i = 1 ; i < ssize(vVal) - 1 ; ++i) {
if ( vVal[i] < vVal[i-1] && vVal[i] < vVal[i+1])
vInterv.emplace_back( dLimInfLen2 + ( i - 1) * ( dLimSupLen2 - dLimInfLen2) / NUM_STEP,
dLimInfLen2 + ( i + 1) * ( dLimSupLen2 - dLimInfLen2) / NUM_STEP) ;
}
if ( ssize( vInterv) != 0) {
for ( int j = 0 ; j < ssize( vInterv) ; ++j) {
for ( int i = 0 ; i <= NUM_STEP ; ++ i) {
double dLen = vInterv[j].first + i * ( vInterv[j].second - vInterv[j].first) / NUM_STEP ;
double dUStep2 ;
double dVal = CalcWeightVal( dLen, pCrvEdge2, vtCurr1, ptCurr1, dCoeff, dMyDist, dUStep2) ;
if ( dVal < dMin) {
dUCurr2 = dUStep2 ;
dMin = dVal ;
bUpdated = true ;
}
}
}
}
}
// se il parametro è cambiato devo ricalcolare la lunghezza, che viene restituita
if ( bUpdated)
pCrvEdge2->GetLengthAtParam( dUCurr2, dLenCurr2) ;
return true ;
}
+1 -2
View File
@@ -34,5 +34,4 @@ bool CurveDump( const ICurve& crvC, std::string& sOut, bool bMM, const char* szN
bool CopyExtrusion( const ICurve* pSouCrv, ICurve* pDestCrv) ;
bool CopyThickness( const ICurve* pSouCrv, ICurve* pDestCrv) ;
ICurveBezier* ApproxCurveBezierWithSingleCubic( const ICurve* pCrv) ;
Voronoi* GetCurveVoronoi( const ICurve& crvC) ;
bool GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert) ;
Voronoi* GetCurveVoronoi( const ICurve& crvC) ;
+54 -4
View File
@@ -1432,7 +1432,7 @@ CurveBezier::ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, Poly
//----------------------------------------------------------------------------
bool
CurveBezier::FlatOrSplit( int nLev, const CurveBezier& crvBez, double dParStart, double dParEnd,
double dLinTol, double dAngTolDeg, PolyLine& PL) const
double dLinTol, double dAngTolDeg, PolyLine& PL, double dMaxLen) const
{
// se raggiunto il massimo livello di recursione ...
const int MAX_LEV = 10 ;
@@ -1461,7 +1461,10 @@ CurveBezier::FlatOrSplit( int nLev, const CurveBezier& crvBez, double dParStart,
}
// se distanza entro tolleranza
if ( dMaxSqDist <= ( dLinTol * dLinTol)) {
bool bSplit = dMaxSqDist > ( dLinTol * dLinTol) ;
if ( dMaxLen < INFINITO)
bSplit = bSplit || Dist( crvBez.m_vPtCtrl[0], crvBez.m_vPtCtrl[m_nDeg]) > dMaxLen ;
if ( ! bSplit) {
// deviazione angolare tra primo e ultimo tratto del poligono di controllo (grado >= 1)
Vector3d vtDirI = crvBez.m_vPtCtrl[1] - crvBez.m_vPtCtrl[0] ;
Vector3d vtDirF = crvBez.m_vPtCtrl[m_nDeg] - crvBez.m_vPtCtrl[m_nDeg-1] ;
@@ -1495,18 +1498,65 @@ CurveBezier::FlatOrSplit( int nLev, const CurveBezier& crvBez, double dParStart,
// prima metà
crvBez1 = crvBez ;
crvBez1.TrimEndAtParam( dParDiv) ;
if ( ! FlatOrSplit( nLev + 1, crvBez1, dParStart, dParMid, dLinTol, dAngTolDeg, PL))
if ( ! FlatOrSplit( nLev + 1, crvBez1, dParStart, dParMid, dLinTol, dAngTolDeg, PL, dMaxLen))
return false ;
// seconda metà
crvBez1 = crvBez ;
crvBez1.TrimStartAtParam( dParDiv) ;
if ( ! FlatOrSplit( nLev + 1, crvBez1, dParMid, dParEnd, dLinTol, dAngTolDeg, PL))
if ( ! FlatOrSplit( nLev + 1, crvBez1, dParMid, dParEnd, dLinTol, dAngTolDeg, PL, dMaxLen))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ApproxWithLimitedLines( double dLinTol, double dAngTolDeg, int nType, double dMaxLen, PolyLine& PL) const
{
// pulisco la polilinea
PL.Clear() ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// se di primo grado, basta inserire gli estremi
if ( m_nDeg == 1) {
PL.AddUPoint( 0, m_vPtCtrl[0]) ;
PL.AddUPoint( 1, m_vPtCtrl[m_nDeg]) ;
PL.AdjustForMaxSegmentLen( dMaxLen) ;
return true ;
}
// limiti minimi su tolleranza e deviazione angolare
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ;
// inserisco il punto iniziale
if ( ! PL.AddUPoint( 0, m_vPtCtrl[0]))
return false ;
// verifico se va divisa
if ( ! FlatOrSplit( 0, *this, 0, 1, dLinTol, dAngTolDeg, PL, dMaxLen))
return false ;
// se è stato inserito un solo punto, aggiungo il finale
if ( PL.GetPointNbr() == 1)
return PL.AddUPoint( 1, m_vPtCtrl[m_nDeg]) ;
// altrimenti, se l'ultimo punto non coincide con il finale lo sostituisco (distano al max di dLinTol)
else {
Point3d ptLast ;
PL.GetLastPoint( ptLast) ;
if ( ! AreSamePointApprox( ptLast, m_vPtCtrl[m_nDeg])) {
PL.EraseLastUPoint() ;
return PL.AddUPoint( 1, m_vPtCtrl[m_nDeg]) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveBezier::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const
+2 -1
View File
@@ -111,6 +111,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW
bool GetArea( Plane3d& plPlane, double& dArea) const override
{ return CurveGetArea( *this, plPlane, dArea) ; }
bool ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const override ;
bool ApproxWithLimitedLines( double dLinTol, double dAngTolDeg, int nType, double dMaxLen, PolyLine& PL) const override ;
bool ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const override ;
bool ApproxWithArcsEx( double dLinTol, double dAngTolDeg, double dLinFea, PolyArc& PA) const override
{ return ApproxWithArcs( dLinTol, dAngTolDeg, PA) ; }
@@ -188,7 +189,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW
bool GetSegmentParam( double dLen, double& dCurrLen, double& dSegLen,
double& dUIni, double& dUFin) const ;
bool FlatOrSplit( int nLev, const CurveBezier& crvBez, double dParStart, double dParEnd,
double dLinTol, double dAngTolDeg, PolyLine& PL) const ;
double dLinTol, double dAngTolDeg, PolyLine& PL, double dMaxLen = INFINITO) const ;
bool ApproxWithArcsXY(double dLinTol, double dAngTolDeg, PolyArc& PA) const;
bool BiArcOrSplit(int nLev, PolyLine& PL, double dLinTol, double dAngTolDeg, PolyArc& PA) const;
bool ToPowerBase( PolynomialPoint3d& pol3P) const ;
+228 -1
View File
@@ -1460,6 +1460,68 @@ CurveComposite::ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, P
return PL.RemoveAlignedPoints( dLinTol) ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::ApproxWithLimitedLines( double dLinTol, double dAngTolDeg, int nType, double dMaxLen, PolyLine& PL) const
{
// funziona solo con le modalità standard e special
if ( nType != APL_STD && nType != APL_SPECIAL && nType != APL_SPECIAL_INT)
return false ;
// pulisco la polilinea
PL.Clear() ;
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// limiti minimi su tolleranza e deviazione angolare
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dAngTolDeg = max( dAngTolDeg, ANG_TOL_MIN_DEG) ;
// se speciale, approssimo ogni singola entità e conservo le estremità interne (joint)
if ( nType == APL_SPECIAL || nType == APL_SPECIAL_INT) {
// eseguo approssimazione
double dStartPar = 0 ;
for ( auto& pCrv : m_CrvSmplS) {
// assegno estrusione e spessore della curva composita
pCrv->SetExtrusion( m_VtExtr) ;
pCrv->SetThickness( m_dThick) ;
// recupero approssimazione per curva semplice
PolyLine PLSmpl ;
if ( ! pCrv->ApproxWithLimitedLines( dLinTol, dAngTolDeg, nType, dMaxLen, PLSmpl))
return false ;
// se richiesto almeno un punto interno con curve non rettilinee e ci sono solo gli estremi
if ( nType == APL_SPECIAL_INT && pCrv->GetType() != CRV_LINE && PLSmpl.GetPointNbr() == 2) {
// aggiungo il punto interno
Point3d ptMid ;
if ( ! pCrv->GetMidPoint( ptMid))
return false ;
double dU ;
PLSmpl.GetLastU( dU) ;
dU /= 2 ;
PNTULIST& List = PLSmpl.GetUPointList() ;
List.insert( ++ List.begin(), { ptMid, dU}) ;
}
// ripristino estrusione e spessore della curva semplice (annullandoli)
pCrv->SetExtrusion( V_NULL) ;
pCrv->SetThickness( 0) ;
// la accodo opportunamente a quella della curva composita
if ( ! PL.Join( PLSmpl, dStartPar))
return false ;
// incremento inizio parametro per prossima curva semplice
dStartPar += 1 ;
}
}
else if ( nType == APL_STD) {
if ( ! ApproxWithLimitedLines( dLinTol, dAngTolDeg, APL_SPECIAL, dMaxLen, PL))
return false ;
PL.RemoveAlignedPoints( dLinTol, false, dMaxLen) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const
@@ -1967,7 +2029,120 @@ CurveComposite::AddJoint( double dU)
//----------------------------------------------------------------------------
bool
CurveComposite::ModifyJoint( int nU, const Point3d& ptNewJoint)
CurveComposite::ModifyJoint( int nU, const Point3d& ptNewJoint, double dTol)
{
int nCrvCount = GetCurveCount() ;
// verifico l'indice della giunzione
if ( nU < 0 || nU > nCrvCount)
return false ;
// salvo le vecchie curve e nel caso le ripristino
int nPrevCrv = -1 ;
// recupero l'indice e il puntatore alla curva precedente (se esiste)
if ( nU >= 0)
nPrevCrv = nU - 1 ;
else if ( IsClosed())
nPrevCrv = nCrvCount - 1 ;
PtrOwner<CurveComposite> pOrigCrv( CreateBasicCurveComposite()) ;
if ( nPrevCrv >= 0)
pOrigCrv->AddCurve( m_CrvSmplS[ nPrevCrv]->Clone()) ;
// recupero il puntatore alla curva successiva (se esiste)
int nNextCrv = -1 ;
if ( nU < nCrvCount)
nNextCrv = nU ;
else if ( IsClosed())
nNextCrv = 0 ;
else
nNextCrv = - 1 ;
if ( nNextCrv >= 0)
pOrigCrv->AddCurve( m_CrvSmplS[ nNextCrv]->Clone()) ;
int nCrvNmbr = GetCurveCount() ;
int nFlagDel = DeletedCurve::NONE ;
if ( ! ModifyJoint( nU, ptNewJoint, &nFlagDel))
return false ;
bool bErasedSomeCrv = nCrvCount > GetCurveCount() ;
bool bErasedPrev = ( nFlagDel == DeletedCurve::PREV) ;
bool bErasedNext = ( nFlagDel == DeletedCurve::NEXT) ;
if ( ( bErasedPrev && nNextCrv == -1) || ( bErasedNext && nPrevCrv == -1)) {
// se sono su un estremo di una curva aperta e ho cancellato la sottocurva di estremità devo verificare che fosse più piccola della tolleranza
if ( bErasedPrev && nNextCrv == -1) {
Point3d ptOrigEnd ; pOrigCrv->GetEndPoint( ptOrigEnd) ;
Point3d ptNewEnd ; GetEndPoint( ptNewEnd) ;
if ( Dist( ptOrigEnd, ptNewEnd) > dTol)
m_CrvSmplS.push_back( Release( pOrigCrv)) ;
return true ;
}
if ( bErasedNext && nPrevCrv == -1) {
Point3d ptOrigStart ; pOrigCrv->GetStartPoint( ptOrigStart) ;
Point3d ptNewStart ; GetStartPoint( ptNewStart) ;
if ( Dist( ptOrigStart, ptNewStart) > dTol)
m_CrvSmplS.insert( m_CrvSmplS.begin(), Release( pOrigCrv)) ;
return true ;
}
}
double dStart ;
double dEnd ;
if ( bErasedPrev) {
dStart = nU ;
dEnd = nNextCrv + 1 ;
}
else if ( bErasedNext) {
dStart = nPrevCrv ;
dEnd = nU ;
if ( nU == 0)
dStart -= 1 ;
}
else { // ! bErasedSomeCrv
dStart = ( nPrevCrv != -1 ? nPrevCrv : 0) ;
dEnd = ( nNextCrv != -1 ? nNextCrv + 1 : nCrvNmbr) ;
}
PtrOwner<ICurve> pNewCurve( CopyParamRange( dStart, dEnd)) ;
double dErr = 0 ;
if ( ! CalcApproxError( pOrigCrv, pNewCurve, dErr, 6) || dErr > dTol) {
// se ho fallito il check o la variazione è superiore alla tolleranza richiesta, ripristino le curve originali
if ( ! bErasedSomeCrv) {
if ( nNextCrv != -1) {
delete m_CrvSmplS[nNextCrv] ;
m_CrvSmplS[nNextCrv] = pOrigCrv->RemoveFirstOrLastCurve( true) ;
}
if ( nPrevCrv != -1) {
delete m_CrvSmplS[nPrevCrv] ;
m_CrvSmplS[nPrevCrv] = pOrigCrv->RemoveFirstOrLastCurve( true) ;
}
}
else {
if ( bErasedNext) {
int nPos = nU == 0 ? nPrevCrv - 1 : nU ;
delete m_CrvSmplS[nPos] ;
if ( nU == 0) {
m_CrvSmplS[nPos] = pOrigCrv->RemoveFirstOrLastCurve( false) ;
nPos = 0 ;
}
else
m_CrvSmplS[nPos] = pOrigCrv->RemoveFirstOrLastCurve( true) ;
m_CrvSmplS.insert( m_CrvSmplS.begin() + nPos, pOrigCrv->RemoveFirstOrLastCurve( true)) ;
}
else {
int nPos = nU == 0 ? nU : nPrevCrv ;
delete m_CrvSmplS[nPos] ;
if ( nU == 0) {
m_CrvSmplS[nPos] = pOrigCrv->RemoveFirstOrLastCurve( true) ;
nPos = nCrvNmbr - 1 ;
}
else
m_CrvSmplS[nPos] = pOrigCrv->RemoveFirstOrLastCurve( true) ;
m_CrvSmplS.insert( m_CrvSmplS.begin() + nPos, pOrigCrv->RemoveFirstOrLastCurve( true)) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::ModifyJoint( int nU, const Point3d& ptNewJoint, int* pnFlagDel)
{
// verifico lo stato
if ( m_nStatus != OK)
@@ -1977,6 +2152,8 @@ CurveComposite::ModifyJoint( int nU, const Point3d& ptNewJoint)
// verifico l'indice della giunzione
if ( nU < 0 || nU > nCrvCount)
return false ;
if ( pnFlagDel != nullptr)
*pnFlagDel = DeletedCurve::NONE ;
// recupero l'indice e il puntatore alla curva precedente (se esiste)
int nPrevCrv = -1 ;
if ( nU > 0)
@@ -2005,6 +2182,8 @@ CurveComposite::ModifyJoint( int nU, const Point3d& ptNewJoint)
if ( AreSamePointApprox( ptStart, ptNewJoint)) {
delete pPrevCrv ;
m_CrvSmplS.erase( m_CrvSmplS.begin() + nPrevCrv) ;
if ( pnFlagDel != nullptr)
*pnFlagDel = DeletedCurve::PREV ;
}
// altrimenti diventa un segmento di retta
else {
@@ -2024,6 +2203,8 @@ CurveComposite::ModifyJoint( int nU, const Point3d& ptNewJoint)
if ( AreSamePointApprox( ptNewJoint, ptEnd)) {
delete pNextCrv ;
m_CrvSmplS.erase( m_CrvSmplS.begin() + nNextCrv) ;
if ( pnFlagDel != nullptr)
*pnFlagDel = DeletedCurve::NEXT ;
}
// altrimenti diventa un segmento di retta
else {
@@ -3858,3 +4039,49 @@ CurveComposite::GetOnlyPoint(Point3d& ptStart) const
ptStart = m_ptStart ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::ReplaceSingleCurve( int nSubCrv, ICurve* pNewCurveToAdd, double dTolStartEnd, double dTolAlong)
{
// prendo il possesso e verifico la curva
PtrOwner<ICurve> pNewCurve( pNewCurveToAdd) ;
if ( IsNull( pNewCurve) || ! pNewCurve->IsValid())
return false ;
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico l'indice sia sensato
if ( nSubCrv < 0 || nSubCrv > GetCurveCount())
return false ;
// verifico che start e end coincidano entro la tolleranza
Point3d ptStart ; m_CrvSmplS[nSubCrv]->GetStartPoint( ptStart) ;
Point3d ptEnd ; m_CrvSmplS[nSubCrv]->GetEndPoint( ptEnd) ;
Point3d ptNewStart ; pNewCurve->GetStartPoint( ptNewStart) ;
Point3d ptNewEnd ; pNewCurve->GetEndPoint( ptNewEnd) ;
if ( ! AreSamePointApprox( ptStart, ptNewStart) || ! AreSamePointApprox( ptEnd, ptNewEnd)) {
// se i punti di inizio e fine non sono entro EPS_SMALL ma sono entro la tolleranza passata allora modifico la curva da aggiungere
if ( AreSamePointEpsilon( ptStart, ptNewStart, dTolStartEnd) && AreSamePointEpsilon( ptEnd, ptNewEnd, dTolStartEnd)) {
if ( ! pNewCurve->ModifyStart( ptStart) || ! pNewCurve->ModifyEnd( ptEnd))
return false ;
}
else
return false ;
}
// se presente una tolleranza lungo la curva controllo che sia rispettata
if ( dTolAlong < INFINITO) {
double dErr = 0 ;
CalcApproxError( m_CrvSmplS[nSubCrv], pNewCurve, dErr, 20) ;
if ( dErr > dTolAlong)
return false ;
}
delete m_CrvSmplS[nSubCrv] ;
m_CrvSmplS[nSubCrv] = Release( pNewCurve) ;
return true ;
}
+9 -1
View File
@@ -26,6 +26,9 @@ class Voronoi ;
//----------------------------------------------------------------------------
class CurveComposite : public ICurveComposite, public IGeoObjRW
{
public :
enum DeletedCurve { NONE = 0, PREV = 1, NEXT = 2 } ;
public : // IGeoObj
~CurveComposite( void) override ;
CurveComposite* Clone( void) const override ;
@@ -109,6 +112,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW
bool GetArea( Plane3d& plPlane, double& dArea) const override
{ return CurveGetArea( *this, plPlane, dArea) ; }
bool ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const override ;
bool ApproxWithLimitedLines( double dLinTol, double dAngTolDeg, int nType, double dMaxLen, PolyLine& PL) const override ;
bool ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const override ;
bool ApproxWithArcsEx( double dLinTol, double dAngTolDeg, double dLinFea, PolyArc& PA) const override ;
ICurve* CopyParamRange( double dUStart, double dUEnd) const override ;
@@ -156,7 +160,9 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW
bool AddArc2P( const Point3d& ptOther, const Point3d& ptNew, bool bEndOrStart = true) override ;
bool AddArcTg( const Point3d& ptNew, bool bEndOrStart = true) override ;
bool AddJoint( double dU) override ;
bool ModifyJoint( int nU, const Point3d& ptNewJoint) override ;
bool ModifyJoint( int nU, const Point3d& ptNewJoint) override
{ return ModifyJoint( nU, ptNewJoint, nullptr) ; }
bool ModifyJoint( int nU, const Point3d& ptNewJoint, double dTol) override ; // verifico se le curve interessate sono in tolleranza con la versione prima della modifica
bool RemoveJoint( int nU) override ;
bool MoveCurve( int nCrv, const Vector3d& vtMove) override ;
bool ModifyCurveToArc( int nCrv, const Point3d& ptMid) override ;
@@ -178,6 +184,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW
bool SetCurveTempParam( int nCrv, double dParam, int nParamInd = 0) override ;
bool GetCurveTempParam( int nCrv, double& dParam, int nParamInd = 0) const override ;
bool GetOnlyPoint( Point3d& ptStart) const override ;
bool ReplaceSingleCurve( int nSubCrv, ICurve* pNewCurve, double dTolStartEnd, double dTolAlong = INFINITO) override ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
@@ -211,6 +218,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW
bool SimpleOffsetXY( double dDist, int nType = OFF_FILLET, double dMaxAngExt = ANG_RIGHT) ;
bool IsOneCircle( Point3d& ptCen, Vector3d& vtN, double& dRad, bool& bCCW) const ;
bool CalcVoronoiObject( void) const ;
bool ModifyJoint( int nU, const Point3d& ptNewJoint, int* pnFlagDel) ;
private :
enum Status { ERR = 0, OK = 1, TO_VERIFY = 2, IS_A_POINT = 3} ;
+28
View File
@@ -514,6 +514,34 @@ CurveLine::ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLi
return true ;
}
//----------------------------------------------------------------------------
bool
CurveLine::ApproxWithLimitedLines( double dLinTol, double dAngTolDeg, int nType, double dMaxLen, PolyLine& PL) const
{
// pulisco la polilinea
PL.Clear() ;
// la curva deve essere validata
if ( m_nStatus != OK)
return false ;
// inserisco lo start
PL.AddUPoint( 0, m_PtStart) ;
double dLen = Dist( m_PtStart, m_PtEnd) ;
if ( dLen > dMaxLen) {
int nStep = int( ceil( dLen / dMaxLen)) ;
for ( int i = 1 ; i < nStep ; ++i) {
double dPar = 1. / nStep * i ;
PL.AddUPoint( dPar, Media( m_PtStart, m_PtEnd, dPar)) ;
}
}
// inserisco l'end
PL.AddUPoint( 1, m_PtEnd) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveLine::ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const
+1
View File
@@ -112,6 +112,7 @@ class CurveLine : public ICurveLine, public IGeoObjRW
bool GetArea( Plane3d& plPlane, double& dArea) const override
{ return false ; }
bool ApproxWithLines( double dLinTol, double dAngTolDeg, int nType, PolyLine& PL) const override ;
bool ApproxWithLimitedLines( double dLinTol, double dAngTolDeg, int nType, double dMaxLen, PolyLine& PL) const override ;
bool ApproxWithArcs( double dLinTol, double dAngTolDeg, PolyArc& PA) const override ;
bool ApproxWithArcsEx( double dLinTol, double dAngTolDeg, double dLinFea, PolyArc& PA) const override
{ return ApproxWithArcs( dLinTol, dAngTolDeg, PA) ; }
BIN
View File
Binary file not shown.
+1
View File
@@ -324,6 +324,7 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClCompile Include="IntersLineVolZmap.cpp" />
<ClCompile Include="IntersPlaneVolZmap.cpp" />
<ClCompile Include="IntersLineSurfBez.cpp" />
<ClCompile Include="OffsetCurve3d.cpp" />
<ClCompile Include="Trimming.cpp" />
<ClCompile Include="MultiGeomDB.cpp" />
<ClCompile Include="SurfTriMeshOffset.cpp" />
+6
View File
@@ -573,6 +573,12 @@
<ClCompile Include="CAvSurfFrMove.cpp">
<Filter>File di origine\GeoCollisionAvoid</Filter>
</ClCompile>
<ClCompile Include="Trimming.cpp">
<Filter>File di origine\GeoStriping</Filter>
</ClCompile>
<ClCompile Include="OffsetCurve3d.cpp">
<Filter>File di origine\GeoOffset</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
+9 -6
View File
@@ -198,13 +198,16 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
// se coincidono U e ptInt tra A e B
if ( abs( m_Info[i].IciA[0].dU - m_Info[j].IciB[0].dU) < EPS_SMALL &&
AreSamePointXYEpsilon( m_Info[i].IciA[0].ptI, m_Info[j].IciB[0].ptI, 10 * EPS_SMALL)) {
// se non è alla fine di curva chiusa
if ( ! bCrvAClosed || abs( m_Info[j].IciA[0].dU - dCrvBSpan) > EPS_SMALL)
// elimino la seconda
EraseOtherInfo( i, j) ;
else
// elimino la prima
// se j è alla fine di curva chiusa
// se j è alla fine di curva chiusa e la prima intersezione è di overlap con partenza dall'inizio ( compreso nel caso precedente)
// oppure se i è all'inizio di curva chiusa e l'intersezione successiva a j è di overlap con lo stesso parametro
if ( bCrvAClosed && (( abs( m_Info[j].IciA[0].dU - dCrvBSpan) < EPS_SMALL) ||
( i == 0 && ssize(m_Info) > 2 && m_Info[i].IciA[0].dU < EPS_SMALL && m_Info[j+1].bOverlap && abs( m_Info[j].IciA[0].dU - m_Info[j+1].IciA[0].dU) < EPS_SMALL)))
// elimino la prima
EraseCurrentInfo( i, j) ;
else
// elimino la seconda
EraseOtherInfo( i, j) ;
break ;
}
}
+171 -53
View File
@@ -15,6 +15,7 @@
#include "stdafx.h"
#include "IntersLineCyl.h"
#include "/EgtDev/Include/EGkFrame3d.h"
#include "/EgtDev/Include/EGkIntersLineCylinder.h"
#include "/EgtDev/Include/ENkPolynomialRoots.h"
using namespace std ;
@@ -25,99 +26,176 @@ using namespace std ;
// In caso di intersezione viene restituito true e i parametri in dU1 e dU2.
//----------------------------------------------------------------------------
bool
IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
double dRad, double dHeight,
double& dU1, double& dU2)
IntersLineCyl( const Point3d& ptP, const Vector3d& vtV, double dH, double dRad, bool bTapLow, bool bTapUp,
double& dU1, Point3d& ptInt1, Vector3d& vtN1, double& dU2, Point3d& ptInt2, Vector3d& vtN2, bool bIgnoreTap, bool bInvertNormals)
{
// Verifico il versore
if ( vtL.IsSmall())
dU1 = NAN ;
dU2 = NAN ;
// Verifico il versore
if ( vtV.IsSmall())
return false ;
// Verifico il cilindro
if ( dRad < EPS_SMALL || dHeight < EPS_SMALL)
// Verifico il cilindro
if ( dRad < EPS_SMALL || dH < EPS_SMALL)
return false ;
// Determino le eventuali intersezioni con le due basi a quota minima e massima (solo se linea non parallela ad esse)
// Determino le eventuali intersezioni con le due basi a quota minima e massima (solo se linea non parallela ad esse)
int nBasInt = 0 ;
if ( abs( vtL.z) > EPS_ZERO) {
if ( abs( vtV.z) > EPS_ZERO) {
// le linee tangenti al cilindro non sono considerate intersecanti
double EpsRad = ( vtL.IsZeroXY() ? - EPS_SMALL : EPS_SMALL) ;
Point3d ptInt1 = ptL + ( ( 0 - ptL.z) / vtL.z) * vtL ;
if ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y < dRad * dRad + 2 * dRad * EpsRad) {
dU1 = ( ptInt1 - ptL) * vtL ;
double dEpsRad = ( vtV.IsZeroXY() ? - EPS_SMALL : EPS_SMALL) ;
if ( bIgnoreTap)
dEpsRad = 0. ;
ptInt1 = ptP + ( ( 0 - ptP.z) / vtV.z) * vtV ;
if ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y < dRad * dRad + 2 * dRad * dEpsRad) {
nBasInt += 1 ;
vtN1 = - Z_AX ;
dU1 = ( ( 0 - ptP.z) / vtV.z) ;
}
Point3d ptInt2 = ptL + ( ( dHeight - ptL.z) / vtL.z) * vtL ;
if ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y < dRad * dRad + 2 * dRad * EpsRad) {
dU2 = ( ptInt2 - ptL) * vtL ;
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
if ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y < dRad * dRad + 2 * dRad * dEpsRad) {
nBasInt += 2 ;
vtN2 = Z_AX ;
dU2 = ( ( dH - ptP.z) / vtV.z) ;
}
}
// Se la linea interseca entrambe le basi, si sono trovate le due intersezioni
// Se la linea interseca entrambe le basi, si sono trovate le due intersezioni
if ( nBasInt == 3) {
if ( dU1 > dU2)
if ( dU1 > dU2) {
swap( dU1, dU2) ;
// Trovate intersezioni
swap( ptInt1, ptInt2) ;
swap( vtN1, vtN2) ;
}
if ( bInvertNormals) {
vtN1 *= - 1 ;
vtN2 *= - 1 ;
}
// Trovate intersezioni
return true ;
}
// Determino le intersezioni con la superficie laterale del cilindro
DBLVECTOR vdCoeff{ ptL.x * ptL.x + ptL.y * ptL.y - dRad * dRad,
2 * ( ptL.x * vtL.x + ptL.y * vtL.y),
vtL.x * vtL.x + vtL.y * vtL.y} ;
// Determino le intersezioni con la superficie laterale del cilindro
DBLVECTOR vdCoeff{ ptP.x * ptP.x + ptP.y * ptP.y - dRad * dRad,
2 * ( ptP.x * vtV.x + ptP.y * vtV.y),
vtV.x * vtV.x + vtV.y * vtV.y} ;
DBLVECTOR vdRoots ;
int nRoot = PolynomialRoots( 2, vdCoeff, vdRoots) ;
// Elimino le soluzioni cha danno intersezioni fuori dai limiti in Z del cilindro
// Epsilon per piani di tappo
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
if ( bIgnoreTap) {
dEpsLow = 0. ;
dEpsUp = 0. ;
}
// Elimino le soluzioni cha danno intersezioni fuori dai limiti in Z del cilindro
if ( nRoot == 2) {
double dIntZ2 = ptL.z + vdRoots[1] * vtL.z ;
if ( dIntZ2 < 0 - EPS_SMALL || dIntZ2 > dHeight + EPS_SMALL)
double dIntZ2 = ptP.z + vdRoots[1] * vtV.z ;
if ( dIntZ2 < 0 + dEpsLow || dIntZ2 > dH + dEpsUp)
-- nRoot ;
}
if ( nRoot >= 1) {
double dIntZ1 = ptL.z + vdRoots[0] * vtL.z ;
if ( dIntZ1 < 0 - EPS_SMALL || dIntZ1 > dHeight + EPS_SMALL) {
double dIntZ1 = ptP.z + vdRoots[0] * vtV.z ;
if ( dIntZ1 < 0 + dEpsLow || dIntZ1 > dH + dEpsUp) {
if ( nRoot == 2)
vdRoots[0] = vdRoots[1] ;
-- nRoot ;
}
}
// Due soluzioni: la retta interseca due volte la superficie laterale
// Due soluzioni: la retta interseca due volte la superficie laterale
if ( nRoot == 2) {
// Punti di intersezione con la superficie del cilindro
ptInt1 = ptP + vdRoots[0] * vtV ;
ptInt2 = ptP + vdRoots[1] * vtV ;
dU1 = vdRoots[0] ;
dU2 = vdRoots[1] ;
if ( dU1 > dU2)
// Determino le normali
vtN1.Set( ptInt1.x, ptInt1.y, 0) ;
vtN1.Normalize() ;
vtN2.Set( ptInt2.x, ptInt2.y, 0) ;
vtN2.Normalize() ;
if ( dU1 > dU2) {
swap( dU1, dU2) ;
// Trovate intersezioni
return true ;
}
// Una soluzione : la retta interseca la superficie laterale e un piano
else if ( nRoot == 1) {
// Se piano superiore
if ( nBasInt == 2) {
dU1 = vdRoots[0] ;
swap( ptInt1, ptInt2) ;
swap( vtN1, vtN2) ;
}
// altrimenti piano inferiore
else if ( nBasInt == 1) {
dU2 = vdRoots[0] ;
if ( bInvertNormals) {
vtN1 *= - 1 ;
vtN2 *= - 1 ;
}
// altrimenti niente
else
return false ;
if ( dU1 > dU2)
swap( dU1, dU2) ;
// Trovate intersezioni
// Trovate intersezioni
return true ;
}
// Nessuna soluzione : nessuna intersezione
// Una soluzione : la retta interseca la superficie laterale e un piano
else if ( nRoot == 1) {
// Se piano superiore
if ( nBasInt == 2) {
// Punto di intersezione
dU1 = vdRoots[0] ;
ptInt1 = ptP + vdRoots[0] * vtV ;
// Normale alla superficie del cilindro verso l'interno
vtN1.Set( ptInt1.x, ptInt1.y, 0) ;
vtN1.Normalize() ;
}
// altrimenti piano inferiore
else if ( nBasInt == 1) {
// Punto di intersezione
dU2 = vdRoots[0] ;
ptInt2 = ptP + vdRoots[0] * vtV ;
// Normale alla superficie del cilindro verso l'interno
vtN2.Set( ptInt2.x, ptInt2.y, 0) ;
vtN2.Normalize() ;
}
// altrimenti niente
else
return false ;
if ( dU1 > dU2) {
swap( dU1, dU2) ;
swap( ptInt1, ptInt2) ;
swap( vtN1, vtN2) ;
}
if ( bInvertNormals) {
vtN1 *= - 1 ;
vtN2 *= - 1 ;
}
// Trovate intersezioni
return true ;
}
// Nessuna soluzione : nessuna intersezione
else
return false ;
}
//----------------------------------------------------------------------------
// Riferimento con origine nel centro della base e asse di simmetria coincidente con l'asse Z.
// La funzione restituisce true in caso di intersezione, false altrimenti.
//----------------------------------------------------------------------------
bool
IntersLineCyl( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& CylFrame, double dH, double dRad, bool bTapLow, bool bTapUp,
double& dU1, Point3d& ptInt1, Vector3d& vtN1, double& dU2, Point3d& ptInt2, Vector3d& vtN2, bool bIgnoreTap, bool bInvertNormals)
{
// Porto la linea nel riferimento del cilindro
Point3d ptP = GetToLoc( ptLineSt, CylFrame) ;
Vector3d vtV = GetToLoc( vtLineDir, CylFrame) ;
if ( IntersLineCyl( ptP, vtV, dH, dRad, bTapLow, bTapUp,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap, bInvertNormals))
{
ptInt1.ToGlob( CylFrame) ;
vtN1.ToGlob( CylFrame) ;
ptInt2.ToGlob( CylFrame) ;
vtN2.ToGlob( CylFrame) ;
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
// Linea e cilindro sono nel medesimo riferimento.
// Il cilindro è definito con centro della base, asse, raggio e altezza.
@@ -133,7 +211,13 @@ IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
if ( ! frCyl.Set( ptCyl, vtCyl))
return false ;
// Ora eseguo i conti nel riferimento intrinseco
return IntersLineCyl( GetToLoc( ptL, frCyl), GetToLoc( vtL, frCyl), dRad, dHeight, dU1, dU2) ;
bool bTapLow = false ;
bool bTapUp = false ;
bool bIgnoreTap = true ;
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
return IntersLineCyl( ptL, vtL, frCyl, dHeight, dRad, bTapLow, bTapUp,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap) ;
}
//----------------------------------------------------------------------------
@@ -144,7 +228,7 @@ IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
bool
IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
const Point3d& ptCyl1, const Point3d& ptCyl2, double dRad,
double& dU1, double& dU2)
double& dU1, double& dU2)
{
// Determino asse ed altezza del cilindro
Vector3d vtCyl = ptCyl2 - ptCyl1 ;
@@ -157,5 +241,39 @@ IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
if ( ! frCyl.Set( ptCyl1, vtCyl))
return false ;
// Ora eseguo i conti nel riferimento intrinseco
return IntersLineCyl( GetToLoc( ptL, frCyl), GetToLoc( vtL, frCyl), dRad, dHeight, dU1, dU2) ;
bool bTapLow = false ;
bool bTapUp = false ;
bool bIgnoreTap = true ;
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
return IntersLineCyl( ptL, vtL, frCyl, dHeight, dRad, bTapLow, bTapUp,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap) ;
}
//----------------------------------------------------------------------------
// linea già nel riferimento intrinseco del cilindro
//----------------------------------------------------------------------------
bool IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
double dRad, double dHeight,
double& dU1, double& dU2)
{
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
bool bTapLow = false, bTapUp = false ;
bool bIgnoreTap = true ;
return IntersLineCyl( ptL, vtL, dHeight, dRad, bTapLow, bTapUp,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap) ;
}
//----------------------------------------------------------------------------
// funzione esposta per altre dll
//----------------------------------------------------------------------------
bool
IntersLineCyl( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& CylFrame, double dH, double dRad,
double& dU1, Point3d& ptInt1, Vector3d& vtN1, double& dU2, Point3d& ptInt2, Vector3d& vtN2)
{
return IntersLineCyl( ptLineSt, vtLineDir, CylFrame, dH, dRad, false, false,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, true, false) ;
}
+23 -4
View File
@@ -20,17 +20,27 @@
// Il cilindro è centrato sull'asse Z e appoggiato sul piano XY.
// Con intersezione viene restituito true e i parametri in dU1 e dU2.
//----------------------------------------------------------------------------
bool IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
double dRad, double dHeight,
double& dU1, double& dU2) ;
bool
IntersLineCyl( const Point3d& ptP, const Vector3d& vtV, double dH, double dRad, bool bTapLow, bool bTapUp,
double& dU1, Point3d& ptInt1, Vector3d& vtN1, double& dU2, Point3d& ptInt2, Vector3d& vtN2, bool bIgnoreTap = false, bool bInvertNormals = false) ;
// come sopra ma passo il riferimento intrinseco del cilindro in cui portare la linea
bool
IntersLineCyl( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& CylFrame, double dH, double dRad, bool bTapLow, bool bTapUp,
double& dU1, Point3d& ptInt1, Vector3d& vtN1, double& dU2, Point3d& ptInt2, Vector3d& vtN2, bool bIgnoreTap = false, bool bInvertNormals = false) ;
//----------------------------------------------------------------------------
inline bool
TestIntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
double dRad, double dHeight)
{
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
double dU1, dU2 ;
return IntersLineCyl( ptL, vtL, dRad, dHeight, dU1, dU2) ;
bool bTapLow = false, bTapUp = false ;
bool bIgnoreTap = true ;
return IntersLineCyl( ptL, vtL, dHeight, dRad, bTapLow, bTapUp, dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, bIgnoreTap) ;
}
//----------------------------------------------------------------------------
@@ -50,3 +60,12 @@ bool IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
bool IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
const Point3d& ptCyl1, const Point3d& ptCyl2, double dRad,
double& dU1, double& dU2) ;
//----------------------------------------------------------------------------
// // Linea e cilindro sono nel medesimo riferimento.
// Il cilindro è definito con raggio e altezza. ( la linea è già nel riferimento intrinseco del cilindro)
// In caso di intersezione viene restituito true e i parametri in dU1 e dU2.
//----------------------------------------------------------------------------
bool IntersLineCyl( const Point3d& ptL, const Vector3d& vtL,
double dRad, double dHeight,
double& dU1, double& dU2) ;
+794
View File
@@ -0,0 +1,794 @@
//----------------------------------------------------------------------------
// EgalTech 2026
//----------------------------------------------------------------------------
// File : OffsetCurve3d.cpp Data : 10.06.26 Versione : 3.1f1
// Contenuto : Classe per offset di Curve 3d.
//
//
//
// Modifiche : 10.06.26 DB Creazione modulo.
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "GeoConst.h"
#include "CurveLine.h"
#include "CurveComposite.h"
#include "RemoveCurveDefects.h"
#include "IntersLineCyl.h"
#include "/EgtDev/Include/EGkPoint3d.h"
#include "/EgtDev/Include/EGkPolyLine.h"
#include "/EgtDev/Include/EGkOffsetCurve3d.h"
#include "/EgtDev/Include/EGkIntersLinePlane.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include <algorithm>
using namespace std ;
#define SAVECRVORIG 0
#define SAVEOFFDIR 0
#define SAVECYL 0
#define SAVEOFFSET 0
#if SAVECRVORIG || SAVEOFFDIR || SAVECYL || SAVEOFFSET
#include "/EgtDev/Include/EGkColor.h"
#include "/EgtDev/Include/EGkGeoVector3d.h"
vector<IGeoObj*> vGeo ;
vector<Color> vCol ;
#include "CurveArc.h"
#include "/EgtDev/Include/EGkGeoObjSave.h"
#include "/EgtDev/Include/EGkStmFromCurves.h"
#endif
//----------------------------------------------------------------------------
OffsetCurve3d::~OffsetCurve3d( void)
{
Reset() ;
}
//----------------------------------------------------------------------------
bool
OffsetCurve3d::Reset( void)
{
for ( auto& pCrv : m_CrvLst) {
if ( pCrv != nullptr) {
delete pCrv ;
pCrv = nullptr ;
}
}
m_CrvLst.clear() ;
return true ;
}
//----------------------------------------------------------------------------
bool
OffsetCurve3d::Make( const PNT5AXVECTOR& vPnt5Ax, double dOffDist, int nType)
{
// la funzione è pensata per lavorare con il risultato dell'operazione ProjectCurveOnSurf
// vOffDir devono essere normalizzati
// mi aspetto che siano più o meno perpendicolari alla curva
// pulisco tutto
Reset() ;
INTVECTOR vFlag ;
VCT3DVECTOR vOffDir ;
PolyLine PL ;
for ( int i = 0 ; i < ssize( vPnt5Ax) ; ++i) {
PL.AddUPoint( i, vPnt5Ax[i].ptP) ;
vOffDir.push_back( vPnt5Ax[i].vtDir1) ;
if ( vPnt5Ax[i].nFlag > 0)
vFlag.push_back( vPnt5Ax[i].nFlag) ;
else
return false ;
}
PtrOwner<CurveComposite> pCrv( CreateBasicCurveComposite()) ;
if ( ! pCrv->FromPolyLine( PL))
return false ;
#if SAVECRVORIG || SAVEOFFDIR
vGeo.clear() ;
vCol.clear() ;
vGeo.push_back( pCrv->Clone()) ;
vCol.push_back( AQUA) ;
#if SAVEOFFDIR
Point3d ptBase ; PL.GetFirstPoint( ptBase) ;
for ( int i = 0 ; i < ssize( vOffDir) ; ++i) {
IGeoVector3d* pVec = CreateGeoVector3d() ;
pVec->Set( vOffDir[i] * dOffDist, ptBase) ;
PL.GetNextPoint( ptBase) ;
vGeo.push_back( pVec) ;
vCol.push_back( BLUE) ;
}
#endif
#if ! SAVECYL && ! SAVEOFFSET
SaveGeoObj( vGeo, vCol, "C:\\Temp\\curve offset 3d\\crvoffset.nge") ;
#endif
#endif
// verifico se la curva è un segmento di retta
bool bIsLine = PL.GetPointNbr() == 2 ;
if ( bIsLine) {
// faccio l'offset di una linea
return true ;
}
// se offset nullo, copio la curva ed esco
if ( abs( dOffDist) < 10 * EPS_SMALL) {
PtrOwner<CurveComposite> pCopy( CreateBasicCurveComposite()) ;
if ( IsNull( pCopy) || ! pCopy->CopyFrom( pCrv))
return false ;
// unisco parti allineate (tranne gli estremi)
pCopy->MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG, false) ;
// sposto in lista
m_CrvLst.push_back( Release( pCopy)) ;
return true ;
}
bool bClosed = pCrv->IsClosed() ;
// identifico le zone circostanti un angolo interno
for ( int i = 0 ; i < ssize( vPnt5Ax) ; ++i) {
if ( vFlag[i] == OffsetCurve3d::AngType::ANG_CONC) {
// scorro indietro e avanti flaggando i tratti da controllare
int nPrev = i - 1 ;
if ( nPrev < 0)
nPrev = ssize( vPnt5Ax) - 1;
int nNext = i + 1 ;
if ( nNext >= ssize( vPnt5Ax))
nNext = 0 ;
double dAng = acos( vPnt5Ax[nPrev].vtDir1 * vPnt5Ax[nNext].vtDir1) * RADTODEG ;
double dDistAngConc = dOffDist * tan( ( dAng / 2) * DEGTORAD) ;
int c = nPrev ;
while ( Dist( vPnt5Ax[i].ptP, vPnt5Ax[c].ptP) < dDistAngConc) {
vFlag[c] = OffsetCurve3d::AngType::ANG_BEFORE_CONC ;
--c ;
if ( c < 0) {
if ( bClosed)
c = ssize( vPnt5Ax) - 1 ;
else
break ;
}
}
vFlag[c] = OffsetCurve3d::AngType::ANG_BEFORE_CONC ;
// scorro in avanti
c = nNext ;
while ( c < ssize( vPnt5Ax) - 1 && Dist( vPnt5Ax[i].ptP, vPnt5Ax[c].ptP) < dDistAngConc) {
vFlag[c] = OffsetCurve3d::AngType::ANG_AFTER_CONC ;
++c ;
if ( c == ssize( vPnt5Ax) - 1) {
if ( bClosed)
c = 0 ;
else
break ;
}
}
vFlag[c] = OffsetCurve3d::AngType::ANG_AFTER_CONC ;
i = c ;
}
}
for ( int i = 1 ; i < ssize( vFlag) - 1 ; ++i) {
if ( vFlag[i-1] == OffsetCurve3d::AngType::ANG_SMOOTH_CONC &&
vFlag[i+1] == OffsetCurve3d::AngType::ANG_SMOOTH_CONC &&
vFlag[i] != OffsetCurve3d::AngType::ANG_SMOOTH_CONC)
vFlag[i] = OffsetCurve3d::AngType::ANG_SMOOTH_CONC ;
}
double dRadCorr ;
Point3d ptPrev ; pCrv->GetStartPoint( ptPrev) ;
ptPrev += vOffDir[0] * dOffDist ;
Vector3d vtCorrPrev ;
Vector3d vtTangPrev ;
Vector3d vtDirPrev ; pCrv->GetStartDir( vtDirPrev) ;
if ( bClosed) {
Vector3d vtDirLast ; pCrv->GetEndDir( vtDirLast) ;
if ( vFlag[0] != OffsetCurve3d::AngType::ANG_CVEX)
vtTangPrev = Media( vtDirLast, vtDirPrev) ;
else if ( vFlag[0] == OffsetCurve3d::AngType::ANG_CVEX && vFlag.back() != OffsetCurve3d::AngType::ANG_CVEX)
vtTangPrev = vtDirLast ;
else
vtTangPrev = vtDirPrev ;
}
const ICurve* pCrvPrev = pCrv->GetFirstCurve() ;
const ICurve* pCrvCurr ;
OFFSETSEGVEC vOffsetCrvs ;
Vector3d vtDirPrevOff = V_INVALID ;
int nRejected = 0 ;
int nClosure = bClosed ? 1 : 0 ;
bool bCheckingClosure = false ;
bool bPlanarConcCvex = false ;
for ( int i = 1 ; i <= pCrv->GetCurveCount() + nClosure ; ++i) {
int nCurr = i ;
int nPrev = i - 1 ;
if ( i > pCrv->GetCurveCount()) {
nCurr = 0 ;
bCheckingClosure = true ;
}
if ( ! bCheckingClosure)
pCrvCurr = pCrv->GetNextCurve() ;
if ( pCrvCurr == nullptr && bClosed)
pCrvCurr = pCrv->GetFirstCurve() ;
Vector3d vtOffDir = vOffDir[nCurr] ;
Vector3d vtDirCurr ;
if ( pCrvCurr != nullptr)
pCrvCurr->GetStartDir( vtDirCurr) ;
else
vtDirCurr = vtDirPrev ;
pCrvPrev->GetStartDir( vtDirPrev) ;
Vector3d vtTang ;
// so che ci sono due punti in stretta prossimità dell'angolo, quindi discrimino tra la tangeten prima e dopo l'angolo
// negli altri casi faccio la media
if ( vFlag[nCurr] != OffsetCurve3d::AngType::ANG_CVEX)
vtTang = Media( vtDirCurr, vtDirPrev) ;
else if ( vFlag[nCurr] == OffsetCurve3d::AngType::ANG_CVEX && vFlag[nPrev] != OffsetCurve3d::AngType::ANG_CVEX)
vtTang = vtDirPrev ;
else
vtTang = vtDirCurr ;
vtTang.Normalize() ;
Vector3d vtCorr = vtOffDir ;
double dCorrK = 1 ;
//if ( vFlag[nCurr] == OffsetCurve3d::AngType::ANG_CONC) {
// double dHalfAlfa = acos( vtTang * vtTangPrev) * RADTODEG ;
// dCorrK = 1 / sin( ( 90 - dHalfAlfa) * DEGTORAD) ;
//}
Point3d ptP ;
if ( pCrvCurr != nullptr)
pCrvCurr->GetStartPoint( ptP) ;
else
pCrvPrev->GetEndPoint( ptP) ;
dRadCorr = dOffDist ;
ptP = ptP + dRadCorr * dCorrK * vtCorr ;
// se secondo punto di angolo esterno di fianco, inserisco movimenti intermedi
if ( vFlag[nCurr] == OffsetCurve3d::AngType::ANG_CVEX && vFlag[nPrev] == OffsetCurve3d::AngType::ANG_CVEX && bPlanarConcCvex) {
double dAlfa = acos( vtTang * vtTangPrev) ;
double dDelta = dOffDist * tan( dAlfa / 4) ;
Point3d ptAdd1 = ptPrev + dDelta * vtTangPrev ;
ICurveLine* pCL1 = CreateBasicCurveLine() ;
pCL1->Set( ptPrev, ptAdd1) ;
vOffsetCrvs.emplace_back( pCL1, OffsetCurve3d::AngType::ANG_CVEX, -1) ;
Point3d ptAdd2 = ptP - dDelta * vtTang ;
ICurveLine* pCL2 = CreateBasicCurveLine() ;
pCL2->Set( ptAdd1, ptAdd2) ;
vOffsetCrvs.emplace_back( pCL2, OffsetCurve3d::AngType::ANG_CVEX, -1) ;
ptPrev = ptAdd2 ;
}
Vector3d vtAng = vtDirPrev ^ vtDirCurr ;
const double COS_ANG_MAX_PLANAR = 0.7 ;
bPlanarConcCvex = false ;
if ( ! vtAng.IsSmall() && vtAng.Normalize())
bPlanarConcCvex = abs( vtAng * vOffDir[nCurr]) < COS_ANG_MAX_PLANAR ;
if ( ! bCheckingClosure) {
Vector3d vtDirCurrOff = ptP - ptPrev ; vtDirCurrOff.Normalize() ;
double dProj = 1 ;
if ( vtDirPrevOff.IsValid())
dProj = vtDirCurrOff * vtDirPrevOff ;
// prima di inserirlo controllo che il tratto non torni indietro
if ( ( vFlag[nCurr] != ANG_STR || dProj > - 0.966) && Dist( ptPrev, ptP) > 2 * EPS_SMALL) {
// aggiungo tratto
ICurveLine* pCL = CreateBasicCurveLine() ;
pCL->Set( ptPrev, ptP) ;
vOffsetCrvs.emplace_back( pCL, vFlag[nCurr], i - 1) ;
// aggiorno punto precedente
ptPrev = ptP ;
vtCorrPrev = vtCorr ;
vtTangPrev = vtTang ;
vtDirPrev = vtDirCurr ;
if ( i < pCrv->GetCurveCount())
pCrvPrev = pCrvCurr ;
vtDirPrevOff = vtDirCurrOff ;
}
else
++nRejected ;
}
}
// se chiusa aggiungo il tratto di chiusura
if ( bClosed) {
Point3d ptPS ; vOffsetCrvs.front().pCrv->GetStartPoint( ptPS) ;
ICurveLine* pCL = CreateBasicCurveLine() ;
Point3d ptPE ; vOffsetCrvs.back().pCrv->GetEndPoint( ptPE) ;
pCL->Set( ptPE, ptPS) ;
// aggiungo solo se valida, quindi se non sono già coincidenti
if ( pCL->IsValid())
vOffsetCrvs.emplace_back( pCL, OffsetCurve3d::AngType::ANG_STR, -1) ;
}
// qui faccio la correzione per gli angoli interni
EDITCRVINFOVEC vEditInfo ;
if ( ! CalcAdjustConcavePartsInPath( pCrv, vOffsetCrvs, dOffDist, vEditInfo))
return false ;
if ( nType == OFFTYPE::PLANECUT) {
if ( ! CalcAdjustConcavePartsPlaneCut( pCrv, vPnt5Ax, vOffsetCrvs, dOffDist, vEditInfo))
return false ;
}
// applico le modifiche calcolate
for ( int i = ssize( vEditInfo) - 1 ; i >= 0 ; --i) {
if ( vEditInfo[i].nFlag == EditCrvInfo::NOEDIT)
continue ;
else if ( vEditInfo[i].nFlag == EditCrvInfo::DEL)
vOffsetCrvs.erase( vOffsetCrvs.begin() + i) ;
else if ( vEditInfo[i].nFlag == EditCrvInfo::EDIT) {
if ( vEditInfo[i].ptStart.IsValid())
vOffsetCrvs[vEditInfo[i].nId].pCrv->ModifyStart( vEditInfo[i].ptStart) ;
if ( vEditInfo[i].ptEnd.IsValid())
vOffsetCrvs[vEditInfo[i].nId].pCrv->ModifyEnd( vEditInfo[i].ptEnd) ;
vOffsetCrvs[vEditInfo[i].nId].nParent = -2 ;
}
}
// scorro tutto il vettore delle linee di offset e unisco aggiungendo una linea dove ne ho cancellate
for ( int i = 0 ; i < ssize( vOffsetCrvs) - 1 ; ++i) {
Point3d ptEndCurr, ptStartNext ;
vOffsetCrvs[i].pCrv->GetEndPoint( ptEndCurr) ;
vOffsetCrvs[i+1].pCrv->GetStartPoint( ptStartNext) ;
if ( ! AreSamePointApprox( ptEndCurr, ptStartNext)) {
ICurveLine* pCL = CreateBasicCurveLine() ;
pCL->Set( ptEndCurr, ptStartNext) ;
vOffsetCrvs.emplace_back( pCL, OffsetCurve3d::AngType::ANG_STR,-1) ;
rotate( vOffsetCrvs.begin() + i + 1, vOffsetCrvs.end() - 1, vOffsetCrvs.end()) ;
++i ;
}
}
#if SAVEOFFSET || SAVECYL
#if SAVEOFFSET
for ( int i = 0 ; i < ssize( vOffsetCrvs) ; ++i) {
vGeo.push_back( vOffsetCrvs[i].pCrv->Clone()) ;
if ( vOffsetCrvs[i].nParent == -2)
vCol.push_back( LIME) ;
else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_SMOOTH_CONC)
vCol.push_back( GREEN) ;
else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_STR)
vCol.push_back( PURPLE) ;
else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_CVEX)
vCol.push_back( RED) ;
else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_BEFORE_CONC)
vCol.push_back( OLIVE) ;
else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_AFTER_CONC)
vCol.push_back( YELLOW) ;
else if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_CONC)
vCol.push_back( Color(0,64,0)) ; //dark green
}
#endif
SaveGeoObj( vGeo, vCol, "C:\\Temp\\curve offset 3d\\crvoffset.nge") ;
#endif
// qua andrebbe gestito con una chain ( ptorebbero essere più di una curva)
PtrOwner<ICurveComposite> pCrvOffset( CreateBasicCurveComposite()) ;
for ( int i = 0 ; i < ssize( vOffsetCrvs) ; ++i) {
if ( ! pCrvOffset->AddCurve( Release( vOffsetCrvs[i].pCrv)))
return false ;
}
m_CrvLst.push_back( Release( pCrvOffset)) ;
return true ;
// raccordi
//// ordino le curve in ordine decrescente di lunghezza
//if ( m_CrvLst.size() > 1) {
// for ( auto pCrv : m_CrvLst) {
// double dLen ;
// if ( pCrv->GetLength( dLen))
// pCrv->SetTempProp( int( 1000 * dLen)) ;
// else
// pCrv->SetTempProp( 0) ;
// }
// m_CrvLst.sort( []( const ICurve* pA, const ICurve* pB) { return ( pA->GetTempProp() > pB->GetTempProp()) ; }) ;
//}
//// se originale era chiusa, verifico le risultanti e se necessario cerco di chiuderle
//if ( bClosed) {
// for ( auto pCrv : m_CrvLst) {
// CurveComposite* pCrvCo = GetBasicCurveComposite( pCrv) ;
// if ( pCrvCo != nullptr)
// pCrvCo->Close() ;
// }
//}
//return true ;
}
//----------------------------------------------------------------------------
ICurve*
OffsetCurve3d::GetCurve( void)
{
return GetLongerCurve() ;
}
//----------------------------------------------------------------------------
ICurve*
OffsetCurve3d::GetLongerCurve( void)
{
if ( m_CrvLst.empty())
return nullptr ;
// le curve sono ordinate in senso decrescente di lunghezza
ICurve* pCrv = m_CrvLst.front() ;
m_CrvLst.pop_front() ;
return pCrv ;
}
//----------------------------------------------------------------------------
ICurve*
OffsetCurve3d::GetShorterCurve( void)
{
if ( m_CrvLst.empty())
return nullptr ;
// le curve sono ordinate in senso decrescente di lunghezza
ICurve* pCrv = m_CrvLst.back() ;
m_CrvLst.pop_back() ;
return pCrv ;
}
//----------------------------------------------------------------------------
bool
IsPointInsideCylinder( const Point3d& ptTest, const Cyl& offCyl, double dLinTol)
{
Point3d ptTestLoc = ptTest ; ptTestLoc.ToLoc( offCyl.frCyl) ;
if ( ptTestLoc.z > offCyl.dH || ptTestLoc.z < 0)
return false ;
double dDist = ptTestLoc.x * ptTestLoc.x + ptTestLoc.y * ptTestLoc.y ;
double dRadSq = ( offCyl.dRad - dLinTol) * ( offCyl.dRad - dLinTol) ;
if ( dDist > dRadSq)
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
CalcAdjustConcavePartsInPath( const ICurveComposite* pCrv, const OFFSETSEGVEC& vOffsetCrvs, double dRad, EDITCRVINFOVEC& vEditInfo)
{
const double dLinTol = 0 * EPS_SMALL ;
for ( int i = 0 ; i < ssize( vOffsetCrvs) ; ++i) {
int nFlag = vOffsetCrvs[i].nFlag ;
// considero tutt le zone concave
if ( nFlag >= OffsetCurve3d::AngType::ANG_CONC) {
// scorro i prossimi finchè trovo la fine della zona concava
// controllo se devo considerare anche tratti prima dello start
INTVECTOR vLines ;
if ( i == 0) {
INTVECTOR vLinesAdd ;
int c = ssize( vOffsetCrvs) - 1 ;
nFlag = vOffsetCrvs[c].nFlag ;
while ( nFlag >= OffsetCurve3d::AngType::ANG_CONC) {
vLinesAdd.push_back( c) ;
--c ;
if ( c > 0)
nFlag = vOffsetCrvs[c].nFlag ;
}
// inserisco il vettore al contrario, in modo che sia in ordine crescente
vLines.insert( vLines.end(), vLinesAdd.rbegin(), vLinesAdd.rend()) ;
}
bool bDone = false ;
nFlag = vOffsetCrvs[i].nFlag ;
while ( nFlag >= OffsetCurve3d::AngType::ANG_CONC) {
vLines.push_back( i) ;
++i ;
if ( i < ssize( vOffsetCrvs))
nFlag = vOffsetCrvs[i].nFlag ;
else {
bDone = true ;
break ;
}
}
// se sto ricominciando, esco dal for ( il tratto finale è già stato considerato insieme al tratto iniziale)
if ( bDone)
break ;
CYLVECT vCyl ;
// creo un cilindro della dimensione del raggio
for ( int j = 0 ; j < ssize( vLines) ; ++j) {
if ( vOffsetCrvs[vLines[j]].nParent == -1)
continue ;
const ICurve* pSubCrv = pCrv->GetCurve( vOffsetCrvs[vLines[j]].nParent) ;
Point3d ptStart, ptEnd ;
pSubCrv->GetStartPoint( ptStart) ;
pSubCrv->GetEndPoint( ptEnd) ;
// cilindri con asse sul parent
Vector3d vtHeight = ptEnd - ptStart ;
double dHeight = vtHeight.Len() ;
vtHeight.Normalize() ;
vCyl.emplace_back( ptStart, vtHeight, dHeight, dRad, dLinTol) ;
#if SAVECYL
CurveArc ca ; ca.Set( ptStart, vtHeight, dRad) ;
ISurfTriMesh* pSurfTm = GetSurfTriMeshByExtrusion( &ca, vtHeight * dHeight, false, 2 * EPS_SMALL) ;
vGeo.push_back( pSurfTm) ;
vCol.push_back( LGRAY) ;
#endif
}
// controllo l'end di ogni linea per verificare se sta nel cilindro definito da uno degli altri tratti
// controllo tutto i punti
bool bErasedSomePart = false ;
bool bCheckStart = false ;
vector<INTINTVECTOR> vEditZones ;
for ( int j = 0 ; j < ssize( vLines) ; ++j) {
Point3d ptStart, ptEnd ;
const ICurve* pSubCrv = vOffsetCrvs[vLines[j]].pCrv ;
if ( pSubCrv == nullptr)
return false ;
pSubCrv->GetEndPoint( ptEnd) ;
pSubCrv->GetStartPoint( ptStart) ;
// se stanno in uno dei cilindri degli altri tratti della zona concava
bool bToErase = false ;
for ( int k = 0 ; k < ssize( vCyl) ; ++k) {
if ( j == k)
continue ;
bToErase = IsPointInsideCylinder( ptEnd, vCyl[k], dLinTol) ;
bool bStartInsideCyl = false ;
if ( bCheckStart && ! bToErase) {
bStartInsideCyl = IsPointInsideCylinder( ptStart, vCyl[k], dLinTol) ;
bToErase = bToErase || bStartInsideCyl ;
}
if ( bToErase) {
bErasedSomePart = true ;
if ( ! bStartInsideCyl)
bCheckStart = true ;
if ( vEditZones.empty() || vEditZones.back().back().first != vLines[j-1])
vEditZones.emplace_back() ;
vEditZones.back().emplace_back( vLines[j], j) ;
if ( ! bStartInsideCyl && j < ssize( vLines) - 1) {
vEditZones.back().emplace_back( vLines[j+1], j + 1) ;
++j ;
}
break ;
}
}
if ( ! bToErase) {
bCheckStart = false ;
vEditInfo.emplace_back( vLines[j], EditCrvInfo::NOEDIT) ;
}
}
if ( bErasedSomePart) {
// calcolo le intersezioni effettive del primo e ultimo tratto cancellati con i cilindri che li hanno cancellati
for ( int z = 0 ; z < ssize( vEditZones) ; ++z) {
INTINTVECTOR& vInters = vEditZones[z] ;
if ( ssize( vInters) == 1)
continue ;
for ( int j = 0 ; j < ssize( vInters) ; ++j) {
// cancello i tratti intermedi
if ( j > 0 && j < ssize( vInters) - 1) {
vEditInfo.emplace_back( vInters[j].first, EditCrvInfo::DEL) ;
continue ;
}
// per il primo e ultimo controllo le intersezioni con tutti i cilindri
PtrOwner<ICurve> pCL ( vOffsetCrvs[vInters[j].first].pCrv->Clone()) ;
Point3d ptStart ; pCL->GetStartPoint( ptStart) ;
Vector3d vtStart ; pCL->GetStartDir( vtStart) ;
double dLen ; pCL->GetLength( dLen) ;
double dUTrim = ( j == 0 ? INFINITO : 0) ;
Point3d ptTrim = P_INVALID ;
for ( int k = 0 ; k < ssize( vCyl) ; ++k) {
if ( vInters[j].second == k)
continue ;
Point3d ptInt1 = P_INVALID, ptInt2 = P_INVALID ;
double dU1, dU2 ;
Vector3d vtN1, vtN2 ;
if ( IntersLineCyl( ptStart, vtStart * dLen, vCyl[k].frCyl, vCyl[k].dH, vCyl[k].dRad, false, false, dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, true)) {
bool bUpdate = ( j == 0 ? dU1 < dUTrim : dU1 > dUTrim) ;
bUpdate = bUpdate && ptInt1.IsValid() && dU1 > 0 && dU1 < 1 ;
bUpdate = bUpdate && vtN1 * vtStart < 0 ;
if ( bUpdate) {
dUTrim = dU1 ;
ptTrim = ptInt1 ;
}
bUpdate = ( j == 0 ? dU2 < dUTrim : dU2 > dUTrim) ;
bUpdate = bUpdate && ptInt2.IsValid() && dU2 > 0 && dU2 < 1 ;
bUpdate = bUpdate && vtN2 * vtStart > 0 ;
if ( bUpdate) {
dUTrim = dU2 ;
ptTrim = ptInt2 ;
}
}
}
if ( j == 0) {
if ( ptTrim.IsValid()) {
bool bOk = pCL->ModifyEnd( ptTrim) ;
double dNewLen ;
if ( bOk)
pCL->GetLength( dNewLen) ;
if ( ( ! bOk || dNewLen < 0.1) && vInters[0].first != 0) { // se fosse il primo allora potrei modificare il successivo
int nPrev = vInters[0].first - 1 ;
vInters[0].first = nPrev ;
int c = 1 ;
while( vEditInfo.end()[-c].nId != nPrev)
++c ;
vEditInfo.end()[-c].nFlag = EditCrvInfo::EDIT ;
vEditInfo.end()[-c].ptEnd = ptTrim ;
vEditInfo.emplace_back( nPrev + 1, EditCrvInfo::DEL) ;
}
else
vEditInfo.emplace_back( vInters[0].first, EditCrvInfo::EDIT, P_INVALID, ptTrim) ;
}
else
vEditInfo.emplace_back( vInters[0].first, EditCrvInfo::EDIT, P_INVALID, P_INVALID) ;
}
else {
if ( ptTrim.IsValid()) {
bool bOk = pCL->ModifyStart( ptTrim) ;
double dNewLen ;
if ( bOk)
pCL->GetLength( dNewLen) ;
if ( ( ! bOk || dNewLen < 0.1) && vInters[j].first != ssize( vOffsetCrvs) - 1) { // se fosse l'ultima curva allora potrei modificare la precedente
int nNext = vInters[j].first + 1 ;
vInters[j].first = nNext ;
vEditInfo.emplace_back( nNext - 1, EditCrvInfo::DEL) ;
int c = 1 ;
while ( vEditInfo.end()[-c].nId != nNext && c < ssize( vEditInfo))
++c ;
if ( vEditInfo.end()[-c].nId == nNext) {
vEditInfo.end()[-c].nFlag = EditCrvInfo::EDIT ;
vEditInfo.end()[-c].ptStart = ptTrim ;
}
else
vEditInfo.emplace_back( nNext, EditCrvInfo::EDIT, ptTrim, P_INVALID) ;
}
else
vEditInfo.emplace_back( vInters[j].first, EditCrvInfo::EDIT, ptTrim, P_INVALID) ;
}
else
vEditInfo.emplace_back( vInters[j].first, EditCrvInfo::EDIT, P_INVALID, P_INVALID) ;
}
}
}
}
i = vLines.back() ;
}
else {
if ( vEditInfo.empty() || vEditInfo.back().nId != i)
vEditInfo.emplace_back( i, EditCrvInfo::NOEDIT) ;
}
}
sort( vEditInfo.begin(), vEditInfo.end(), []( EditCrvInfo& a, EditCrvInfo& b) { return a.nId < b.nId ;}) ;
return true ;
}
//----------------------------------------------------------------------------
bool
CalcAdjustConcavePartsPlaneCut( const ICurveComposite* pCrv, const PNT5AXVECTOR& vPnt5Ax, const OFFSETSEGVEC& vOffsetCrvs,
double dRad, EDITCRVINFOVEC& vEditInfo)
{
// calcolo come tagliare il percorso negli angoli misti concavo/convesso
// il taglio al percorso lo faccio usando il piano definito dalla direzione di offset
// se una delle due direzioni è perpendicolare al piano formato dai due tratti, la cui joint è il punto corrente, allora non faccio nulla
for ( int i = 0 ; i < ssize( vOffsetCrvs) ; ++i) {
if ( vOffsetCrvs[i].nFlag == OffsetCurve3d::AngType::ANG_CVEX) {
// se ho 2 tratti convex di fila, ho un convex non planar e se ho anche un angolo importante tra i due lati, devo correggere
// se ho 4 tratti convex di fila, ho un convex planar e non devo fare nulla
int c = 1 ;
while ( i + c < ssize( vOffsetCrvs) && vOffsetCrvs[i + c].nFlag == OffsetCurve3d::AngType::ANG_CVEX)
++c ;
if ( c == 4) {
i += 3 ;
continue ;
}
// trovo i due piani e taglio i tratti prima e dopo lo spigolo
int nParent = vOffsetCrvs[i].nParent ; // sottocurva di pCrv che ha generato il tratto di offset
Point3d pt ; pCrv->GetCurve( nParent)->GetEndPoint( pt) ;
int nNextParent = nParent + 1 ;
bool bCheckingStart = false ;
if ( nNextParent > pCrv->GetCurveCount() - 1) {
if ( ! pCrv->IsClosed())
return false ;
nNextParent = 0 ;
bCheckingStart = true ;
}
Vector3d vtDirNext ; pCrv->GetCurve( nNextParent)-> GetStartDir( vtDirNext) ;
Vector3d vtDirPrev ; pCrv->GetCurve( nParent)-> GetEndDir( vtDirPrev) ;
// punti che rappresentano la pCrv ( quindi pCrv->GetCurveCount() == ssize( vPnt5Ax) - 1)
Vector3d vtNNext ;
Vector3d vtNPrev ;
if ( ! bCheckingStart) {
vtNNext = vPnt5Ax[nNextParent].vtDir2 ^ vtDirNext ;
vtNPrev = vPnt5Ax[nNextParent].vtDir1 ^ vtDirPrev ;
}
else {
vtNNext = vPnt5Ax[nNextParent].vtDir1 ^ vtDirNext ;
vtNPrev = vPnt5Ax[nNextParent].vtDir2 ^ vtDirPrev ;
}
Plane3d plNext ; plNext.Set( pt, vtNNext) ;
Plane3d plPrev ; plPrev.Set( pt, vtNPrev) ;
Point3d ptPrev ;
Point3d ptNext ;
// interseco con il piano precedente prendendo i tratti successivi
bool bFound = false ;
// parto a confrontare i segmenti successivi a quelli identificati come concavi
if ( ! bCheckingStart)
c = i + 2 ;
else // se sono arrivato a fine curva di una curva chiusa controllo con lo start
c = 1 ;
while ( ! bFound && c > 0) {
Point3d ptInt ;
Point3d ptStart, ptEnd ;
vOffsetCrvs[c].pCrv->GetStartPoint( ptStart) ;
vOffsetCrvs[c].pCrv->GetEndPoint( ptEnd) ;
IntersLinePlane( ptStart, ptEnd, plPrev, ptInt, false) ;
Vector3d vtDir ; vOffsetCrvs[c].pCrv->GetStartDir( vtDir) ;
double dLen ; vOffsetCrvs[c].pCrv->GetLength( dLen) ;
double dU = ( ptInt - ptStart).Len() / dLen ;
if ( vtDir * ( ptInt - ptStart) < 0)
dU *= -1 ;
if ( dU < 1) {
ptNext = ptInt ;
bFound = true ;
}
else
++c ;
}
// salvo la modifica nel vettore edit
int nNext = c ;
vEditInfo[c].nFlag = EditCrvInfo::EditFlag::EDIT ;
vEditInfo[c].ptStart = ptNext ;
// interseco con il piano successivo prendendo i tratti precedenti
bFound = false ;
c = i - 1 ;
while ( ! bFound && c < ssize( vOffsetCrvs)) {
Point3d ptInt ;
Point3d ptStart, ptEnd ;
vOffsetCrvs[c].pCrv->GetStartPoint( ptStart) ;
vOffsetCrvs[c].pCrv->GetEndPoint( ptEnd) ;
IntersLinePlane( ptStart, ptEnd, plNext, ptInt, false) ;
Vector3d vtDir ; vOffsetCrvs[c].pCrv->GetStartDir( vtDir) ;
double dLen ; vOffsetCrvs[c].pCrv->GetLength( dLen) ;
double dU = ( ptInt - ptStart).Len() / dLen ;
if ( vtDir * ( ptInt - ptStart) < 0)
dU *= -1 ;
if ( dU > 0) {
ptPrev = ptInt ;
bFound = true ;
}
else
--c ;
}
// salvo la modifica nel vettore edit
int nPrev = c ;
vEditInfo[c].nFlag = EditCrvInfo::EditFlag::EDIT ;
vEditInfo[c].ptEnd = ptPrev ;
// tengo solo il punto più esterno
double dLen1 = Dist( ptPrev, pt) ;
double dLen2 = Dist( ptNext, pt) ;
if ( dLen1 > dLen2)
vEditInfo[nNext].ptStart = ptPrev ;
else
vEditInfo[nPrev].ptStart = ptNext ;
// setto come da cancellare tutti i tratti nel mezzo
if ( ! bCheckingStart) {
c = nPrev + 1 ;
while ( c < nNext) {
vEditInfo[c].nFlag = EditCrvInfo::EditFlag::DEL ;
++c ;
}
}
else {
c = nPrev + 1 ;
while ( c < ssize( vEditInfo)) {
vEditInfo[c].nFlag = EditCrvInfo::EditFlag::DEL ;
++c ;
}
c = 0 ;
while ( c < nNext) {
vEditInfo[c].nFlag = EditCrvInfo::EditFlag::DEL ;
++c ;
}
}
if ( ! bCheckingStart)
i = nNext ;
}
}
return true ;
}
+72 -37
View File
@@ -761,7 +761,7 @@ DouglasPeuckerSimplification( const PNTUVECTOR& vPtU, const double dSqTol, const
// se la distanza massima trovata è sopra la tolleranza, allora controllo la parte di PolyLine tra
// (nIndStart, nMaxInd) e quella tra (nMaxInd, nIndEnd)
if ( dMaxSqDist > dSqTol) {
if ( dMaxSqDist > dSqTol) {
// inserisco il punto
vInd.push_back( nMaxInd) ;
// split
@@ -775,7 +775,7 @@ DouglasPeuckerSimplification( const PNTUVECTOR& vPtU, const double dSqTol, const
//----------------------------------------------------------------------------
bool
PolyLine::RemoveAlignedPoints( double dToler, bool bStartEnd)
PolyLine::RemoveAlignedPoints( double dToler, bool bStartEnd, double dMaxLen)
{
// se non ci sono almeno 3 punti, esco subito
if ( m_lUPoints.size() < 3)
@@ -792,34 +792,65 @@ PolyLine::RemoveAlignedPoints( double dToler, bool bStartEnd)
// vettore indici dei punti rimanenti
INTVECTOR vInd ; vInd.reserve( vPtU.size()) ;
// se aperta
if ( ! IsClosed()) {
// considero tutti i punti della PolyLine
vInd.push_back( 0) ;
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, 0, int( vPtU.size()) - 1, vInd))
return false ;
vInd.push_back( int( vPtU.size()) - 1) ;
}
// altrimenti chiusa
else {
// cerco il punto più distante dal primo
double dMaxDist = 0. ;
int nMaxInd = 0 ;
for ( int i = 1 ; i < int( vPtU.size()) ; ++ i) {
double dCurrDist = Dist( vPtU[0].first, vPtU[i].first) ;
if ( dCurrDist > dMaxDist) {
dMaxDist = dCurrDist ;
nMaxInd = i ;
}
if ( dMaxLen > INFINITO - 1) {
// se aperta
if ( ! IsClosed()) {
// considero tutti i punti della PolyLine
vInd.push_back( 0) ;
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, 0, int( vPtU.size()) - 1, vInd))
return false ;
vInd.push_back( int( vPtU.size()) - 1) ;
}
// altrimenti chiusa
else {
// cerco il punto più distante dal primo
double dMaxDist = 0. ;
int nMaxInd = 0 ;
for ( int i = 1 ; i < int( vPtU.size()) ; ++ i) {
double dCurrDist = Dist( vPtU[0].first, vPtU[i].first) ;
if ( dCurrDist > dMaxDist) {
dMaxDist = dCurrDist ;
nMaxInd = i ;
}
}
// recupero due PolyLine di approssimazione
vInd.push_back( 0) ;
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, 0, nMaxInd, vInd))
return false ;
vInd.push_back( nMaxInd) ;
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, nMaxInd, int( vPtU.size()) - 1, vInd))
return false ;
vInd.push_back( int( vPtU.size()) - 1) ;
}
}
else {
// raggruppo i punti della polyline a gruppi che stanno entro la lunghezza massima e ad ognuno applico Douglas
vInd.push_back(0) ;
int i = 0 ;
while ( i < ssize(vPtU) - 1) {
int nLast = i + 1 ;
while ( nLast < ssize( vPtU) && Dist( vPtU[i].first, vPtU[nLast].first) <= dMaxLen)
++nLast ;
// l'ultimo punto era oltre il limite
--nLast ;
// sicurezza: almeno un passo avanti
if ( nLast == i)
nLast = i + 1 ;
// mantieni l'estremo del tratto
if ( vInd.back() != nLast)
vInd.push_back( nLast) ;
// semplifica il tratto interno
if ( nLast - i > 1) {
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, i, nLast, vInd))
return false ;
}
i = nLast ;
}
// recupero due PolyLine di approssimazione
vInd.push_back( 0) ;
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, 0, nMaxInd, vInd))
return false ;
vInd.push_back( nMaxInd) ;
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, nMaxInd, int( vPtU.size()) - 1, vInd))
return false ;
vInd.push_back( int( vPtU.size()) - 1) ;
}
// ordino in senso crescente
@@ -1618,6 +1649,9 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV
int nPnt2 = PL2.GetPointNbr() ;
if ( nPnt1 == 0 || nPnt2 == 0)
return false ;
bool bClosed1 = PL1.IsClosed() ;
bool bClosed2 = PL2.IsClosed() ;
// indica la presenza di punti interni in comune tra le due polylines
bCommonInternalPoints = false ;
@@ -1663,6 +1697,10 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV
if ( nMinJ < nLastJ)
nMinJ = nLastJ ;
// se la curva è chiusa il primo e l'ultimo punto coincidono, verifico quale conviene considerare
if ( bClosed2 && nMinJ == nTotP2 - 1 && nLastJ == 0)
nMinJ = 0 ;
// verifica se è un punto interno in comune con l'altra polyline
if ( i < nTotP1 - 1 && dDist < EPS_SMALL && abs( dMinDistPar - floor( dMinDistPar + 0.5)) < EPS_SMALL)
bCommonInternalPoints = true ;
@@ -1693,6 +1731,9 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV
if ( nMinI < nLastI)
nMinI = nLastI ;
if ( bClosed1 && nMinI == nTotP1 - 1 && nLastI == 0)
nMinI = 0 ;
if ( j < nTotP2 - 1 && dDist < EPS_SMALL && abs( dMinDistPar - floor( dMinDistPar + 0.5)) < EPS_SMALL)
bCommonInternalPoints = true ;
@@ -1991,17 +2032,11 @@ MatchPolyLinesAddingPoints( const PolyLine& PL1, const PolyLine& PL2, int nType,
nAddedSpan = 0 ;
nCrv1 = 0 ;
nCrv2 = 0 ;
bool bLast1 = false ;
bool bLast2 = false ;
while ( nAddedSpan < nPnt) {
if ( nCrv1 >= nPnt1) {
if ( nCrv1 >= nPnt1)
nCrv1 = nPnt1 - 1 ;
bLast1 = true ;
}
if ( nCrv2 >= nPnt2) {
if ( nCrv2 >= nPnt2)
nCrv2 = nPnt2 - 1 ;
bLast2 = true ;
}
bool bRep1 = vbRep1[nCrv1] ;
bool bRep2 = vbRep2[nCrv2] ;
const ICurve* pSubCrv1 = cc1.GetCurve( nCrv1) ;
+517 -94
View File
@@ -13,6 +13,7 @@
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include <cmath>
#include "SurfTriMesh.h"
#include "SurfBezier.h"
#include "GeoConst.h"
@@ -32,14 +33,6 @@ using namespace std ;
const double COS_ANG_LIM = 0.0175 ;
// Angolo massimo tra normali per effettuare bisezione su spigolo
const double COS_ANG_MAX_CORNER = 0.8660 ;
// Tipologia di punto
const int P5AX_TO_DELETE = -1 ; // da cancellare
const int P5AX_OUT = 0 ; // aggiunto prima di inizio o dopo fine
const int P5AX_STD = 1 ; // standard
const int P5AX_CVEX = 2 ; // su angolo convesso
const int P5AX_CONC = 3 ; // in angolo concavo
const int P5AX_BEFORE_CONC = 4 ; // adiacente ad angolo concavo
const int P5AX_AFTER_CONC = 5 ; // adiacente ad angolo concavo
//----------------------------------------------------------------------------
static double
@@ -64,6 +57,7 @@ PointsInTolerance( const PNT5AXVECTOR& vPt5ax, int nPrec, int nCurr, int nNext,
static bool
AddPointsOnCorners( PNT5AXVECTOR& vPt5ax)
{
const double dSinSmallAngle = sin( 0.5 * DEGTORAD) ;
for ( int i = 1 ; i < ssize( vPt5ax) ; ++ i) {
// precedente
int j = i - 1 ;
@@ -79,18 +73,47 @@ AddPointsOnCorners( PNT5AXVECTOR& vPt5ax)
Point3d ptInt ;
if ( IntersLinePlane( ptEdge, vtEdge, 1, plPlane3, ptInt, false) == ILPT_YES) {
// verifico se spigolo convesso o concavo
bool bConvex ;
if ( ! AreSamePointApprox( ptInt, vPt5ax[j].ptP))
bConvex = ( ( vPt5ax[j].vtDir1 ^ ( ptInt - vPt5ax[j].ptP)) * vtEdge > 0) ;
else
bConvex = (( vPt5ax[i].vtDir1 ^ ( ptInt - vPt5ax[i].ptP)) * vtEdge < 0) ;
double dProjPrev = ( vPt5ax[i].ptP - vPt5ax[j].ptP) * vPt5ax[j].vtDir1 ;
double dProjCurr = ( vPt5ax[j].ptP - vPt5ax[i].ptP) * vPt5ax[i].vtDir1 ;
bool bConvex = ( abs( dProjCurr) > abs( dProjPrev) ? dProjCurr < 0 : dProjPrev < 0) ;
int nPrev = i - 1 ;
if ( i < ssize( vPt5ax) - 2 && ! AreSameVectorExact(vPt5ax[i - 1].vtDir1, vPt5ax[i - 1].vtDir2)) {
int z = nPrev - 1 ;
// se vtDir1 e vtDir2 sono diverse allora sono su uno spigolo
double dProjPrev2 = ( vPt5ax[z].ptP - vPt5ax[nPrev].ptP) * vPt5ax[nPrev].vtDir2 ;
double dProjCurr2 = ( vPt5ax[i].ptP - vPt5ax[nPrev].ptP) * vPt5ax[nPrev].vtDir1 ;
// se uno dei due è convesso allora considero convesso l'angolo
bConvex = dProjPrev2 < EPS_SMALL || dProjCurr2 < EPS_SMALL ;
}
bool bValidIntersAfterJ = true ;
bool bValidIntersBeforeI = true ;
if ( i > 2) {
// verifico che l'intersezione sia tra i e j e non prima di j
int k = i - 2 ;
bValidIntersAfterJ = ( ptInt - vPt5ax[j].ptP) * ( vPt5ax[j].ptP - vPt5ax[k].ptP) > 0 ;
bool bBetweenIAndJ = ( ptInt - vPt5ax[j].ptP) * ( vPt5ax[i].ptP - vPt5ax[j].ptP) > 0 ;
bValidIntersAfterJ = bValidIntersAfterJ && bBetweenIAndJ ;
}
if ( i < ssize( vPt5ax) - 1) {
// verifico anche che l'intersezione non sia dopo i
int h = i + 1 ;
bValidIntersBeforeI = ( ptInt - vPt5ax[i].ptP) * ( vPt5ax[h].ptP - vPt5ax[i].ptP) < 0 ;
bool bBetweenIAndJ = ( ptInt - vPt5ax[i].ptP) * ( vPt5ax[i].ptP - vPt5ax[j].ptP) < 0 ;
bValidIntersBeforeI = bValidIntersBeforeI && bBetweenIAndJ ;
}
bool bValidInters = ( bValidIntersAfterJ && bValidIntersBeforeI) ;
// se convesso, metto due punti con direzione appena prima e appena dopo
if ( bConvex) {
Vector3d vtLine1 = ptInt - vPt5ax[j].ptP ; double dLen1 = vtLine1.Len() ;
Vector3d vtLine2 = vPt5ax[i].ptP - ptInt ; double dLen2 = vtLine2.Len() ;
if ( dLen1 > 2 * EPS_SMALL) {
if ( dLen1 > 10 * EPS_SMALL && bValidIntersAfterJ) {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt - vtLine1 / dLen1 * 2 * EPS_SMALL ;
if ( bValidInters)
Pt5ax.ptP = ptInt - vtLine1 / dLen1 * 2 * EPS_SMALL ;
else {
Vector3d vtNewLine = vPt5ax[i].ptP - vPt5ax[j].ptP ; vtNewLine.Normalize() ;
Pt5ax.ptP = vPt5ax[i].ptP - vtNewLine * 2 * EPS_SMALL ;
}
Pt5ax.vtDir1 = vPt5ax[j].vtDir1 ;
Pt5ax.vtDir2 = vPt5ax[j].vtDir2 ;
Pt5ax.vtDirU = vPt5ax[j].vtDirU ;
@@ -102,9 +125,14 @@ AddPointsOnCorners( PNT5AXVECTOR& vPt5ax)
}
else
vPt5ax[j].nFlag = P5AX_CVEX ;
if ( dLen2 > 2 * EPS_SMALL) {
if ( dLen2 > 10 * EPS_SMALL && bValidIntersBeforeI) {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt + vtLine2 / dLen2 * 2 * EPS_SMALL ;
if ( bValidInters)
Pt5ax.ptP = ptInt + vtLine2 / dLen2 * 2 * EPS_SMALL ;
else {
Vector3d vtNewLine = vPt5ax[i].ptP - vPt5ax[j].ptP ; vtNewLine.Normalize() ;
Pt5ax.ptP = vPt5ax[j].ptP + vtNewLine * 2 * EPS_SMALL ;
}
Pt5ax.vtDir1 = vPt5ax[i].vtDir1 ;
Pt5ax.vtDir2 = vPt5ax[i].vtDir2 ;
Pt5ax.vtDirU = vPt5ax[i].vtDirU ;
@@ -133,6 +161,72 @@ AddPointsOnCorners( PNT5AXVECTOR& vPt5ax)
}
}
}
else {
// guardo se la proiezione il tratto successivo, lungo la normale precedente + maggiore di un angolo minimo ( angolo interno smooth)
Vector3d vtDirNext = vPt5ax[i].ptP - vPt5ax[j].ptP ;
vtDirNext.Normalize() ;
double dProj1 = vtDirNext * vPt5ax[j].vtDir1 ;
double dProj2 = ( - vtDirNext) * vPt5ax[i].vtDir1 ;
if ( ( abs( dProj1) > abs( dProj2) ? dProj1 > dSinSmallAngle : dProj2 > dSinSmallAngle)) {
// se concavo senza spigolo netto segnalo zona concava smooth
vPt5ax[i].nFlag = P5AX_SMOOTH_CONC ;
}
}
}
int i = 0 ;
int j = ssize( vPt5ax) - 1 ;
bool bClosed = AreSamePointApprox( vPt5ax[i].ptP, vPt5ax[j].ptP) ;
// se la curva è chiusa controllo inizio e fine
if ( bClosed) {
// se normali tra corrente e precedente oltre limite
int k = i + 1 ;
int z = j - 1 ;
double dProjPrev = ( vPt5ax[z].ptP - vPt5ax[j].ptP) * vPt5ax[i].vtDir1 ;
double dProjCurr = ( vPt5ax[k].ptP - vPt5ax[i].ptP) * vPt5ax[j].vtDir1 ;
if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER) {
bool bConvex = ( abs( dProjCurr) > abs( dProjPrev) ? dProjCurr < 0 : dProjPrev < 0) ;
if ( i < ssize( vPt5ax) - 2 && ! AreSameVectorExact(vPt5ax.back().vtDir1, vPt5ax.back().vtDir2)) {
int z = j - 1 ;
// se vtDir1 e vtDir2 sono diverse allora sono su uno spigolo
double dProjPrev2 = ( vPt5ax[z].ptP - vPt5ax[j].ptP) * vPt5ax[j].vtDir2 ;
double dProjCurr2 = ( vPt5ax[i].ptP - vPt5ax[j].ptP) * vPt5ax[j].vtDir1 ;
// se uno dei due è convesso allora considero convesso l'angolo
bConvex = dProjPrev2 < EPS_SMALL || dProjCurr2 < EPS_SMALL ;
}
if ( bConvex) {
vPt5ax[i].nFlag = P5AX_CVEX ;
vPt5ax[i].vtDir2 = vPt5ax[j].vtDir1 ;
vPt5ax[j].nFlag = P5AX_CVEX ;
}
else {
vPt5ax[i].nFlag = P5AX_CONC ;
vPt5ax[j].nFlag = P5AX_CONC ;
Vector3d vtDir1 = Media( vPt5ax[i].vtDir1, vPt5ax[j].vtDir1) ; vtDir1.Normalize() ;
Vector3d vtDir2 = Media( vPt5ax[i].vtDir2, vPt5ax[j].vtDir2) ; vtDir2.Normalize() ;
Vector3d vtDirU = Media( vPt5ax[i].vtDirU, vPt5ax[j].vtDirU) ; vtDirU.Normalize() ;
Vector3d vtDirV = Media( vPt5ax[i].vtDirV, vPt5ax[j].vtDirV) ; vtDirV.Normalize() ;
vPt5ax[i].vtDir1 = vtDir1 ;
vPt5ax[j].vtDir1 = vtDir1 ;
vPt5ax[i].vtDir2 = vtDir2 ;
vPt5ax[j].vtDir2 = vtDir2 ;
vPt5ax[i].vtDirU = vtDirU ;
vPt5ax[j].vtDirU = vtDirU ;
vPt5ax[i].vtDirV = vtDirV ;
vPt5ax[j].vtDirV = vtDirV ;
}
}
else if ( abs( dProjPrev) > abs( dProjCurr) ? dProjPrev > dSinSmallAngle : dProjCurr > dSinSmallAngle) {
vPt5ax[i].nFlag = P5AX_SMOOTH_CONC ;
vPt5ax[j].nFlag = P5AX_SMOOTH_CONC ;
}
}
// riscorro tutto il vettore per vedere se ho creato delle zone concave smooth frammentate (separate solo da un tratto non classificato concavo), che quindi uniformo
for ( int i = 1 ; i < ssize( vPt5ax) - 1 ; ++ i) {
if ( vPt5ax[i].nFlag != P5AX_SMOOTH_CONC && vPt5ax[i-1].nFlag == P5AX_SMOOTH_CONC && vPt5ax[i+1].nFlag == P5AX_SMOOTH_CONC)
vPt5ax[i].nFlag = P5AX_SMOOTH_CONC ;
}
return true ;
}
@@ -344,7 +438,7 @@ ProjectPointOnSurf( const Point3d& ptP, const CISURFPVECTOR& vpSurf, double dPar
//----------------------------------------------------------------------------
bool
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf,
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax)
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax, bool bNormOrTang)
{
// controllo le tolleranze
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
@@ -364,21 +458,118 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf,
vPt5ax.reserve( PL.GetPointNbr()) ;
// proietto i punti della polilinea sulla superficie secondo la direzione di minima distanza
double dPar ;
Point3d ptP ;
bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ;
double dPar, dParNext ;
Point3d ptP, ptPNext ;
Vector3d vtDirPrev = V_INVALID ;
if ( PL.IsClosed()) {
Point3d pt1, pt2 ;
PL.GetLastLine( pt1, pt2) ;
vtDirPrev = pt2 - pt1 ;
}
Vector3d vtLast ; PL.GetLastULine( &dPar, &ptP, &dParNext, &ptPNext) ;
vtLast = ptPNext - ptP ; vtLast.Normalize() ;
bool bFound = PL.GetFirstULine( &dPar, &ptP, &dParNext, &ptPNext) ;
Vector3d vtFirst = ptPNext - ptP ; vtFirst.Normalize() ;
bool bClosed = PL.IsClosed() ;
bool bLast = false ;
Vector3d vtNormPrev = V_INVALID ;
Point3d ptPrev ;
bool bFirst = true ;
while ( bFound) {
// se trovo proiezione, la salvo
Point5ax Pt5ax ;
if ( ProjectPointOnSurf( ptP, vpSurf, dPar, Pt5ax))
vPt5ax.emplace_back( Pt5ax) ;
// passo al successivo
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
// controllo che la normale trovata sia in linea con la precedente, se i due tratti erano abbastanza allineati
bool bRecalc = false ;
if ( bFirst)
bRecalc = true ;
if ( ssize( vPt5ax) > 2) {
Point5ax& pt5Curr = vPt5ax.back() ;
Point5ax& pt5Prev = vPt5ax.end()[-2] ;
Point5ax& pt5PrevPrev = vPt5ax.end()[-3] ;
Vector3d vtDirCurr = pt5Curr.ptP - pt5Prev.ptP ; vtDirCurr.Normalize() ;
Vector3d vtDirPrev = pt5Prev.ptP - pt5PrevPrev.ptP ; vtDirPrev.Normalize() ;
double dProjDir = vtDirCurr * vtDirPrev ;
if ( dProjDir > COS_ANG_MAX_CORNER) {
double dProjNorm = vPt5ax.back().vtDir1 * vtNormPrev ;
if ( dProjNorm < COS_ANG_MAX_CORNER)
bRecalc = true ;
}
}
Vector3d vtDirNext = ptPNext - ptP ; vtDirNext.Normalize() ;
// se sono arrivato ad uno spigolo tengo la normale appena prima dello spigolo
if ( bRecalc) {
Point3d ptAlter ;
if ( ! bFirst) {
Vector3d vtDirPrev = ptP - ptPrev ; vtDirPrev.Normalize() ;
ptAlter = ptP - vtDirPrev * 5 * EPS_SMALL ;
}
else
ptAlter = ptP + vtDirNext * 5 * EPS_SMALL ;
Point5ax Pt5axRec ;
if ( ProjectPointOnSurf( ptAlter, vpSurf, dPar, Pt5axRec)) {
// aggiorno solo la vtDir1, la vtDir2 la mantengo con la normale successiva allo spigolo
if ( Pt5axRec.vtDir1 * Pt5ax.vtDir1 < COS_ANG_MAX_CORNER)
vPt5ax.back().vtDir1 = Pt5axRec.vtDir1 ;
}
}
else if ( ssize( vPt5ax) > 1 && vPt5ax.back().vtDir1 * vPt5ax.end()[-2].vtDir1 < COS_ANG_MAX_CORNER) {
// se la normale corrente è sufficientemente diversa dalla precedente e i tratti non erano allineati
// controllo se il punto precedente erano su uno spigolo, ricalcolando in un punto appena oltre
Point3d ptAlter = ptPrev + ( ptP - ptPrev) * 5 * EPS_SMALL ;
Point5ax Pt5axRec ;
if ( ProjectPointOnSurf( ptAlter, vpSurf, dPar, Pt5axRec)) {
// aggiorno solo la vtDir1, la vtDir2 la mantengo con la normale successiva allo spigolo
if ( Pt5axRec.vtDir1 * Pt5ax.vtDir1 < COS_ANG_MAX_CORNER)
vPt5ax.end()[-2].vtDir1 = Pt5axRec.vtDir1 ;
}
}
if ( bLast && bClosed) {
// controllo se il punto finale è di spigolo
if ( vPt5ax.back().vtDir1 * vPt5ax.front().vtDir1 < COS_ANG_MAX_CORNER) {
vPt5ax.back().vtDir2 = vPt5ax.front().vtDir1 ;
vPt5ax.front().vtDir2 = vPt5ax.back().vtDir1 ;
}
}
vtNormPrev = vPt5ax.back().vtDir1 ;
// se richiesta la tangente anziché la normale allora modifico il vettore associato al punto
Vector3d vtDir ;
if ( ! bNormOrTang) {
Vector3d vtNorm = vPt5ax.back().vtDir1 ;
if ( bFirst)
vtDir = vtDirNext ;
else
vtDir = vtDirPrev ;
// in caso sia stato superato l'angolo limite dò priorità alla direzione precedente
if ( vtDirPrev.IsValid() && (! bFirst || ( bFirst && bClosed))) {
double dProj = vtDir * vtDirPrev ;
if ( dProj > COS_ANG_MAX_CORNER)
vtDir = Media( vtDir, vtDirPrev) ;
}
vtDirPrev = vtDirNext ;
Vector3d vtTang = vtDir ^ vtNorm ; vtTang.Normalize() ;
vPt5ax.back().vtDir1 = vtTang ;
vPt5ax.back().vtDir2 = vtTang ;
}
// passo al successivo
ptPrev = ptP ;
bFound = PL.GetNextULine( &dPar, &ptP, &dParNext, &ptPNext) ;
// se sono arrivato alla fine aggiungo l'ultimo punto
if ( ! bFound && ! bLast) {
bLast = true ;
bFound = true ;
}
if ( bFirst)
bFirst = false ;
}
// se richiesto, inserimento punti intermedi in presenza di spigoli
if ( bSharpEdges)
AddPointsOnCorners( vPt5ax) ;
if ( bSharpEdges) {
if ( ! AddPointsOnCorners( vPt5ax))
return false ;
}
// rimozione punti in eccesso rispetto alle tolleranze
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
@@ -393,7 +584,7 @@ typedef std::vector<IntersParLinesSurfTm*> INTPARLINESTMPVECTOR ;
//----------------------------------------------------------------------------
static bool
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const Frame3d& frRefLine, const INTPARLINESTMPVECTOR& vpIntPLSTM,
double dPar, Point5ax& Pt5ax)
double dPar, bool bFromVsTo, Point5ax& Pt5ax)
{
// intersezione retta di proiezione con superfici (conservo l'intersezione più alta)
Point3d ptL = GetToLoc( ptP, frRefLine) ;
@@ -402,23 +593,48 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const Frame
for ( int i = 0 ; i < ssize( vpIntPLSTM) ; ++ i) {
ILSIVECTOR vIntRes ;
if ( vpIntPLSTM[i]->GetInters( ptL, 1, vIntRes, false)) {
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
if ( nI >= 0) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
if ( dU > dUref) {
// se dalla direzione
if ( bFromVsTo) {
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
if ( nI >= 0) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
if ( dU > dUref) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
}
}
}
// altrimenti verso la direzione
else {
// cerco la prima intersezione valida a partire dalla prima (è la più alta)
int nI = 0 ;
while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
++nI ;
// se trovata
if ( nI < ssize( vIntRes)) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ;
if ( dU < dUref) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
}
}
}
}
@@ -455,7 +671,7 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const Frame
//----------------------------------------------------------------------------
bool
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vector3d& vtDir,
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax)
double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax)
{
// sistemazioni per tipo di superficie
CISRFTMPVECTOR vpSurfTm ;
@@ -521,7 +737,7 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vect
while ( bFound) {
// se trovo proiezione, la salvo
Point5ax Pt5ax ;
if ( ProjectPointOnSurf( ptP, vpSurfTm, frRefLine, vpIntPLSTM, dPar, Pt5ax))
if ( ProjectPointOnSurf( ptP, vpSurfTm, frRefLine, vpIntPLSTM, dPar, bFromVsTo, Pt5ax))
vPt5ax.emplace_back( Pt5ax) ;
// passo al successivo
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
@@ -543,7 +759,8 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vect
//----------------------------------------------------------------------------
static bool
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const IGeoPoint3d& gpRef, double dPar, Point5ax& Pt5ax)
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const IGeoPoint3d& gpRef, double dPar, bool bFromVsTo,
Point5ax& Pt5ax)
{
// punto di riferimento
Point3d ptMin = gpRef.GetPoint() ;
@@ -558,23 +775,48 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const IGeoP
for ( int i = 0 ; i < ssize( vpStm) ; ++ i) {
ILSIVECTOR vIntRes ;
if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) {
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
if ( nI >= 0) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
if ( dU > dUref) {
// se dal punto
if ( bFromVsTo) {
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
if ( nI >= 0) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
if ( dU > dUref) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
}
}
}
// altrimenti verso il punto
else {
// cerco la prima intersezione valida a partire dalla prima (è la più alta)
int nI = 0 ;
while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
++nI ;
// se trovata
if ( nI < ssize( vIntRes)) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ;
if ( dU < dUref) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
}
}
}
}
@@ -612,7 +854,7 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const IGeoP
//----------------------------------------------------------------------------
bool
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeoPoint3d& gpRef,
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax)
double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax)
{
// sistemazioni per tipo di superficie
CISRFTMPVECTOR vpSurfTm ;
@@ -663,7 +905,7 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeo
while ( bFound) {
// se trovo proiezione, la salvo
Point5ax Pt5ax ;
if ( ProjectPointOnSurf( ptP, vpSurfTm, gpRef, dPar, Pt5ax))
if ( ProjectPointOnSurf( ptP, vpSurfTm, gpRef, dPar, bFromVsTo, Pt5ax))
vPt5ax.emplace_back( Pt5ax) ;
// passo al successivo
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
@@ -681,7 +923,8 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeo
//----------------------------------------------------------------------------
static bool
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurve& crRef, double dPar, Point5ax& Pt5ax)
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurve& crRef, double dPar, bool bFromVsTo,
Point5ax& Pt5ax)
{
// punto a minima distanza
DistPointCurve dPC( ptP, crRef) ;
@@ -699,23 +942,48 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurv
for ( int i = 0 ; i < ssize( vpStm) ; ++ i) {
ILSIVECTOR vIntRes ;
if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) {
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
if ( nI >= 0) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
if ( dU > dUref) {
// se dalla curva
if ( bFromVsTo) {
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
if ( nI >= 0) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
if ( dU > dUref) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
}
}
}
// altrimenti verso la curva
else {
// cerco la prima intersezione valida a partire dalla prima (è la più alta)
int nI = 0 ;
while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
++nI ;
// se trovata
if ( nI < ssize( vIntRes)) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ;
if ( dU < dUref) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
}
}
}
}
@@ -738,7 +1006,7 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurv
// assegno valori al punto 5assi
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = vtN ;
Pt5ax.vtDir2 = vtLine ;
Pt5ax.vtDir2 = ( bFromVsTo ? vtLine : -vtLine) ;
Pt5ax.vtDirU = V_NULL ;
Pt5ax.vtDirV = V_NULL ;
Pt5ax.dPar = dPar ;
@@ -754,7 +1022,7 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurv
//----------------------------------------------------------------------------
bool
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICurve& crRef,
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax)
double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax)
{
// Sistemazioni per tipo di superficie
CISRFTMPVECTOR vpSurfTm ;
@@ -805,7 +1073,7 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICur
while ( bFound) {
// se trovo proiezione, la salvo
Point5ax Pt5ax ;
if ( ProjectPointOnSurf( ptP, vpSurfTm, crRef, dPar, Pt5ax))
if ( ProjectPointOnSurf( ptP, vpSurfTm, crRef, dPar, bFromVsTo, Pt5ax))
vPt5ax.emplace_back( Pt5ax) ;
// passo al successivo
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
@@ -823,7 +1091,8 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICur
//----------------------------------------------------------------------------
static bool
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const SurfTriMesh& stmRef, double dPar, Point5ax& Pt5ax)
ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const SurfTriMesh& stmRef, double dPar, bool bFromVsTo,
Point5ax& Pt5ax)
{
// punto sulla superficie guida a minima distanza
DistPointSurfTm dPS( ptP, stmRef) ;
@@ -850,23 +1119,48 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const SurfT
for ( int i = 0 ; i < ssize( vpStm) ; ++ i) {
ILSIVECTOR vIntRes ;
if ( IntersLineSurfTm( ptP, vtLine, dLineLen, *vpStm[i], vIntRes, false)) {
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
if ( nI >= 0) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
if ( dU > dUref) {
// se dalla superficie
if ( bFromVsTo) {
// cerco la prima intersezione valida a partire dall'ultima (è la più alta)
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
if ( nI >= 0) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU2 : IntRes.dU) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU2 : vIntRes[nI].dU) ;
if ( dU > dUref) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
}
}
}
// altrimenti verso la superficie
else {
// cerco la prima intersezione valida a partire dalla prima (è la più alta)
int nI = 0 ;
while ( nI < ssize( vIntRes) && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
++nI ;
// se trovata
if ( nI < ssize( vIntRes)) {
if ( nInd < 0) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
else {
double dUref = (( IntRes.nILTT == ILTT_SEGM || IntRes.nILTT == ILTT_SEGM_ON_EDGE) ? IntRes.dU : IntRes.dU2) ;
double dU = (( vIntRes[nI].nILTT == ILTT_SEGM || vIntRes[nI].nILTT == ILTT_SEGM_ON_EDGE) ? vIntRes[nI].dU : vIntRes[nI].dU2) ;
if ( dU < dUref) {
IntRes = vIntRes[nI] ;
nInd = i ;
}
}
}
}
}
@@ -911,7 +1205,7 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const SurfT
//----------------------------------------------------------------------------
bool
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISurf& sfRef,
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax)
double dLinTol, double dMaxSegmLen, bool bSharpEdges, bool bFromVsTo, PNT5AXVECTOR& vPt5ax)
{
// sistemazioni per tipo di superficie
CISRFTMPVECTOR vpSurfTm ;
@@ -983,7 +1277,7 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISur
while ( bFound) {
// se trovo proiezione, la salvo
Point5ax Pt5ax ;
if ( ProjectPointOnSurf( ptP, vpSurfTm, *pRefTm, dPar, Pt5ax))
if ( ProjectPointOnSurf( ptP, vpSurfTm, *pRefTm, dPar, bFromVsTo, Pt5ax))
vPt5ax.emplace_back( Pt5ax) ;
// passo al successivo
bFound = PL.GetNextUPoint( &dPar, &ptP) ;
@@ -998,3 +1292,132 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISur
return true ;
}
//----------------------------------------------------------------------------
bool
GetCurveOnSurfInfo( const ICurve& crCrv, const ISurfTriMesh& pSurf,
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax, bool bNormOrTang)
{
// controllo le tolleranze
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
// approssimo la curva con una polilinea entro la tolleranza
PolyLine PL ;
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
if ( ! crCrv.ApproxWithLimitedLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, MAX_SEG_LEN, PL))
return false ;
PL.RemoveAlignedPoints( dLinTol, false, MAX_SEG_LEN) ;
// Pulisco e riservo spazio nel vettore dei punti risultanti
vPt5ax.clear() ;
vPt5ax.reserve( PL.GetPointNbr()) ;
// proietto i punti della polilinea sulla superficie secondo la direzione di minima distanza
double dPar, dParNext ;
Point3d ptP, ptPNext ;
Vector3d vtDirPrev = V_INVALID ;
if ( PL.IsClosed()) {
Point3d pt1, pt2 ;
PL.GetLastLine( pt1, pt2) ;
vtDirPrev = pt2 - pt1 ;
}
Vector3d vtLast ; PL.GetLastULine( &dPar, &ptP, &dParNext, &ptPNext) ;
vtLast = ptPNext - ptP ; vtLast.Normalize() ;
bool bFound = PL.GetFirstULine( &dPar, &ptP, &dParNext, &ptPNext) ;
Vector3d vtFirst = ptPNext - ptP ; vtFirst.Normalize() ;
bool bClosed = PL.IsClosed() ;
bool bLast = false ;
Point3d ptPrev ;
bool bFirst = true ;
const ICurveComposite* pCC = GetCurveComposite( &crCrv) ;
int nTria = -1 ;
Triangle3dEx trTria ;
while ( bFound) {
// se trovo proiezione, la salvo
Point5ax Pt5ax ;
Pt5ax.ptP = ptP ;
Pt5ax.dPar = dPar ;
double dDecimal ;
bool bJoint = modf( dPar, &dDecimal) == 0.0 ;
int nCrv = int( bJoint ? dPar - 1 : dPar) ;
if ( nCrv < 0)
nCrv = 0 ;
int nTriaCurr ; pCC->GetCurveTempProp( nCrv, nTriaCurr, 0) ;
if ( nTriaCurr != nTria)
pSurf.GetTriangle( nTriaCurr, trTria) ;
if ( ! CalcNormal( ptP, trTria, Pt5ax.vtDir1))
Pt5ax.vtDir1 = trTria.GetN() ;
nTria = nTriaCurr ;
if ( bJoint) {
int nPar = int( dPar) ;
if ( bClosed && nPar > pCC->GetCurveCount() - 1)
nPar = 0 ;
int nTria2 ; pCC->GetCurveTempProp( nPar, nTria2, 0) ;
Triangle3dEx trTria2 ; pSurf.GetTriangle( nTria2, trTria2) ;
if ( ! CalcNormal( ptP, trTria2, Pt5ax.vtDir2))
Pt5ax.vtDir2 = trTria2.GetN() ;
nTria = nTria2 ;
trTria = trTria2 ;
}
else
Pt5ax.vtDir2 = Pt5ax.vtDir1 ;
Pt5ax.vtDirU = V_NULL ;
Pt5ax.vtDirV = V_NULL ;
Pt5ax.nFlag = P5AX_STD ;
vPt5ax.emplace_back( Pt5ax) ;
Vector3d vtDirNext = ptPNext - ptP ; vtDirNext.Normalize() ;
// se richiesta la tangente anziché la normale allora modifico il vettore associato al punto
Vector3d vtDir ;
if ( ! bNormOrTang) {
Vector3d vtNorm = vPt5ax.back().vtDir1 ;
if ( bFirst)
vtDir = vtDirNext ;
else
vtDir = vtDirPrev ;
// in caso sia stato superato l'angolo limite dò priorità alla direzione precedente
bool bEdge = false ;
if ( vtDirPrev.IsValid() && (! bFirst || ( bFirst && bClosed))) {
double dProj = vtDirNext * vtDirPrev ;
bEdge = dProj < COS_ANG_MAX_CORNER ;
if ( ! bEdge)
vtDir = Media( vtDirNext, vtDirPrev) ;
}
vtDirPrev = vtDirNext ;
bEdge = bEdge || ! AreSameVectorExact( vPt5ax.back().vtDir1, vPt5ax.back().vtDir2) ;
Vector3d vtTang = vtDir ^ vtNorm ; vtTang.Normalize() ;
vPt5ax.back().vtDir1 = vtTang ;
if ( bEdge) {
Vector3d vtTang2 = vtDirNext ^ vPt5ax.back().vtDir2 ;
vtTang2.Normalize() ;
vPt5ax.back().vtDir2 = vtTang2 ;
}
else
vPt5ax.back().vtDir2 = vtTang ;
}
// passo al successivo
ptPrev = ptP ;
bFound = PL.GetNextULine( &dPar, &ptP, &dParNext, &ptPNext) ;
// se sono arrivato alla fine aggiungo l'ultimo punto
if ( ! bFound && ! bLast) {
bLast = true ;
bFound = true ;
}
if ( bFirst)
bFirst = false ;
}
// se richiesto, inserimento punti intermedi in presenza di spigoli
if ( bSharpEdges) {
if ( ! AddPointsOnCorners( vPt5ax))
return false ;
}
// rimozione punti in eccesso rispetto alle tolleranze
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
return true ;
}
+10 -3
View File
@@ -92,11 +92,18 @@ RotationMinimizingFrame::GetFrameAtParam( const Frame3d& frAct, const double dPa
Vector3d vtCurrR = frAct.VersX() ;
Vector3d vtCurrT = frAct.VersZ() ;
// punto i-esimo sulla curva e suo vettore tangente
// punto i-esimo sulla curva e suo vettore tangente medio
Point3d ptNextM, ptNextP ;
Vector3d vtNextM, vtNextP ;
if ( ! m_pCrv->GetPointD1D2( dParNext, ICurve::FROM_MINUS, ptNextM, &vtNextM) ||
! m_pCrv->GetPointD1D2( dParNext, ICurve::FROM_PLUS, ptNextP, &vtNextP) ||
! vtNextM.Normalize() || ! vtNextP.Normalize())
return false ;
Point3d ptNext ;
Vector3d vtNextT ;
if ( ! m_pCrv->GetPointD1D2( dParNext, ICurve::FROM_MINUS, ptNext, &vtNextT) ||
! vtNextT.Normalize())
ptNext = Media( ptNextM, ptNextP) ;
vtNextT = Media( vtNextM, vtNextP) ;
if ( ! vtNextT.Normalize())
return false ;
// controllo per casi degeneri
+2 -2
View File
@@ -735,7 +735,7 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou
//-------------------------------------------------------------------------------
ISurfBezier*
GetSurfBezierRuledSmooth( const ICurve* pCurve1, const ICurve* pCurve2, double dSampleLen)
GetSurfBezierRuledSmooth( const ICurve* pCurve1, const ICurve* pCurve2, BIPNTVECTOR& vSyncLines, double dSampleLen)
{
// verifica parametri
if ( pCurve1 == nullptr || pCurve2 == nullptr)
@@ -762,7 +762,7 @@ GetSurfBezierRuledSmooth( const ICurve* pCurve1, const ICurve* pCurve2, double d
// creo e setto la superficie trimesh
PtrOwner<SurfBezier> pSbz( CreateBasicSurfBezier()) ;
if ( IsNull( pSbz) || ! pSbz->CreateSmoothRuledByTwoCurves( pCC1, pCC2, dSampleLen))
if ( IsNull( pSbz) || ! pSbz->CreateSmoothRuledByTwoCurves( pCC1, pCC2, dSampleLen, vSyncLines))
return nullptr ;
// restituisco la superficie
+1362 -556
View File
File diff suppressed because it is too large Load Diff
+402 -231
View File
@@ -52,11 +52,12 @@
#define SAVEMATCHCURVES 0
#define SAVEFAILEDTREE 0
#define SAVELIMITSURF 0
#define SAVEPACEDISO 1
#define SAVEPACEDISO 0
#if SAVEFAILEDTRIANGULATION || SAVEREBUILTISO || SAVERULEDISO || SAVERULEDGUIDEDISO || SAVEMATCHCURVES \
|| SAVEFAILEDTREE || SAVELIMITSURF || SAVEPACEDISO
#include "/EgtDev/Include/EGkGeoObjSave.h"
std::vector<IGeoObj*> vGeo ;
std::vector<Color> vCol ;
#endif
using namespace std ;
@@ -4501,55 +4502,6 @@ ChangeStartForClosed( PolyLine& plU0, PolyLine& plU1, ICurveComposite* pCrvU0, I
return true ;
}
static bool
GetEdgeSplitByAngTol( const PolyLine& PL, double dAngTol, BOOLVECTOR& vEdgeSplit)
{
int nPoints = PL.GetPointNbr() ;
vEdgeSplit.clear() ;
vEdgeSplit.resize( nPoints) ;
fill( vEdgeSplit.begin(), vEdgeSplit.end(), false) ;
bool bClosed = PL.IsClosed() ;
// Recupero l'insieme di punti associati alla PolyLine
PNTVECTOR vPoints ; vPoints.reserve( nPoints) ;
Point3d ptCurr = P_INVALID ;
// aggiungo come primo punto il penultimo punto della polyline in modo da analizzare direttamente anche la chiusura ( se è una polyline chiusa)
PL.GetLastPoint( ptCurr) ;
PL.GetPrevPoint( ptCurr) ;
vPoints.emplace_back( ptCurr) ;
bool bFound = PL.GetFirstPoint( ptCurr) ;
while ( bFound) {
vPoints.emplace_back( ptCurr) ;
bFound = PL.GetNextPoint( ptCurr) ;
}
Vector3d vtTanCurr = V_INVALID, vtTanNext = V_INVALID ;
// cos della tolleranza angolare massima
double dCosTol = cos( dAngTol * DEGTORAD) ;
for ( int nP = 0 ; nP < nPoints - 2 ; ++ nP) {
// Recupero il punto corrente e i due punti successivi
Point3d& ptCurr = vPoints[nP] ;
Point3d& ptNext = vPoints[nP + 1] ;
Point3d& ptNextNext = vPoints[nP + 2] ;
// Recupero i versori tangenti definiti dai tre punti ( ptCurr|ptNext e ptNext|ptNextNext)
if ( nP == 0) {
vtTanCurr = ptNext - ptCurr ;
vtTanCurr.Normalize() ;
}
else
vtTanCurr = vtTanNext ;
vtTanNext = ptNextNext - ptNext ; vtTanNext.Normalize() ;
// Calcolo il Coseno tra i due versori
double dCos = vtTanCurr * vtTanNext ;
// Se oltre la tolleranza allora ho incontrato un edge
if ( dCos < dCosTol)
vEdgeSplit[nP] = true ;
}
if ( ! bClosed)
vEdgeSplit[0] = false ;
return true ;
}
static bool
GetEdgeSplitByAngTol( const ICurveComposite* pCC, double dAngTol, BOOLVECTOR& vEdgeSplit)
{
@@ -5896,15 +5848,31 @@ SurfBezier::CreateByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, int
return true ;
}
// Struttura per Spigolo
struct SharpEdge {
double dParU ;
Point3d ptEdge ;
Vector3d vtTanPrev, vtTanAft ;
Vector3d vtTanPrev, vtTanNext ;
SharpEdge( double dU, const Point3d ptE, const Vector3d& vtTP, const Vector3d& vtTA)
: dParU( dU), ptEdge( ptE), vtTanPrev( vtTP), vtTanAft( vtTA) {}
: dParU( dU), ptEdge( ptE), vtTanPrev( vtTP), vtTanNext( vtTA) {}
} ;
typedef vector<SharpEdge> SHARPEDGEVECTOR ;
// Struttura per Punto a Curvatura Massima
struct CurvaturePoint {
double dParU ;
Point3d ptCurvature ;
Vector3d vtTanPrev, vtTanNext ;
CurvaturePoint( double dU, const Point3d ptE, const Vector3d& vtTP, const Vector3d& vtTA)
: dParU( dU), ptCurvature( ptE), vtTanPrev( vtTP), vtTanNext( vtTA) {}
} ;
typedef vector<SharpEdge> SHARPEDGEVECTOR ;
// ---------------------------------------------------------------------------
// Calcolo delle Curve di Sync tra gli spigoli di una curva e l'altra curva nella sua integrità
// [Dato un vettore di SharpEdge di una Curva di Bordo si calcola la Linea di Sincronizzazione tra ognuno di essi
// e l'altra Curva di Bordo]
// -> Restituisce un vettore di Linee di Sincronizzazione
static bool
CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite* pCompoSubEdge, const SHARPEDGEVECTOR& vSharpSubEdge,
BIPNTVECTOR& vSyncLines)
@@ -5919,13 +5887,20 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite*
if ( vSharpEdge.empty())
return true ;
// Se il numero di Spigoli coincide, allora li unisco sequenzialmente tra loro ( considerazione buona ???)
if ( ssize( vSharpEdge) == ssize( vSharpSubEdge)) {
for ( int i = 0 ; i < ssize( vSharpEdge) ; ++ i)
vSyncLines.emplace_back( vSharpEdge[i].ptEdge, vSharpSubEdge[i].ptEdge) ;
return false ;
}
// Scorro gli SharpEdges
double dUPrevSubEdge = 0., dUCurrSubEdge = 0. ;
for ( const SharpEdge& mySharpEdge : vSharpEdge) {
// Recupero il parametro sulla curva di sincronizzazione
// --- Piano di taglio per punto a distanza minima
IntersCurvePlane ICP( *pCompoSubEdge, mySharpEdge.ptEdge, Media( mySharpEdge.vtTanPrev, mySharpEdge.vtTanAft)) ;
IntersCurvePlane ICP( *pCompoSubEdge, mySharpEdge.ptEdge, Media( mySharpEdge.vtTanPrev, mySharpEdge.vtTanNext)) ;
int nIndParCloser = -1, nIndPointCloser = -1 ;
double dSqMinDist = INFINITO ;
for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) {
@@ -5940,7 +5915,7 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite*
}
}
}
bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ;
bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ;
if ( bOkPlane) {
// Se gli indici sono tra loro coerenti allora ho individuato il punto
if ( nIndParCloser == nIndPointCloser) {
@@ -5948,30 +5923,31 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite*
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfo) ;
dUCurrSubEdge = aInfo.Ici[0].dU ;
}
// Se gli indici sono discordi, devo scegliere quale dei due punti tenere
else {
// scelgo il punto più vicino al corrente
IntCrvPlnInfo aInfoPt, aInfoPar ;
ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ;
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ;
dUCurrSubEdge = ( SqDist( mySharpEdge.ptEdge, aInfoPt.Ici[0].ptI) < SqDist( mySharpEdge.ptEdge, aInfoPar.Ici[0].ptI) ?
aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ;
}
}
// Se gli indici sono discordi, devo scegliere quale dei due punti tenere
else {
// scelgo il punto più vicino al corrente
IntCrvPlnInfo aInfoPt, aInfoPar ;
ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ;
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ;
dUCurrSubEdge = ( SqDist( mySharpEdge.ptEdge, aInfoPt.Ici[0].ptI) < SqDist( mySharpEdge.ptEdge, aInfoPar.Ici[0].ptI) ?
aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ;
if ( ! bOkPlane) {
// --- Altrimenti, cerco il punto a minima distanza
DistPointCurve DPC( mySharpEdge.ptEdge, *pCompoSubEdge) ;
int nFlag ;
bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrevSubEdge, dUCurrSubEdge, nFlag) && dUCurrSubEdge > dUPrevSubEdge) ;
if ( ! bOkMinDist) {
// --- Eh.... bho ( se arrivo qui non so che fare...)
double dUStart, dUEnd ;
pCompoSubEdge->GetDomain( dUStart, dUEnd) ;
dUCurrSubEdge = ( dUEnd - dUCurrSubEdge) / 2. ;
}
if ( ! bOkPlane) {
// --- Altrimenti, cerco il punto a minima distanza
DistPointCurve DPC( mySharpEdge.ptEdge, *pCompoSubEdge) ;
int nFlag ;
bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrevSubEdge, dUCurrSubEdge, nFlag) && dUCurrSubEdge > dUPrevSubEdge) ;
if ( ! bOkMinDist) {
// --- Alla peggio mi posiziono a metà tra la posizione corrente e quella finale
double dPrevLen ; pCompoSubEdge->GetLengthAtParam( dUPrevSubEdge, dPrevLen) ;
double dLen ; pCompoSubEdge->GetLength( dLen) ;
pCompoSubEdge->GetParamAtLength( ( dPrevLen + dLen) / 2., dUCurrSubEdge) ;
}
}
// Verifico se tale parametro può essere avvicinato ad uno Spigolo presente sulla curva
// NB. Come descitto sopra gli spigoli in generale è meglio sincronizzarli tra loro
if ( ! vSharpSubEdge.empty()) {
const double EDGE_LEN_TOL = 5. ;
for ( const SharpEdge& mySharpSubEdge : vSharpSubEdge) {
@@ -6001,7 +5977,7 @@ CalcSyncPointFromEdge( const SHARPEDGEVECTOR& vSharpEdge, const ICurveComposite*
}
// ---------------------------------------------------------------------------
// Debug [Gestione Edge in Quadrangolazioni]
// Gestione degli spigoli all'interno della Quadrangolazione corrente
static bool
ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComposite* pSubEdge2, BIPNTVECTOR& vSyncLines)
{
@@ -6020,7 +5996,7 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
SHARPEDGEVECTOR vSharpEdges2 ; vSharpEdges2.reserve( max( 0, nCrv2 - 1)) ;
// --- Cerco gli Spigoli sul SottoTratto del primo bordo
// Se la CurvaA ha solo una sottocurva, non faccio nulla
// Se la CurvaA ha più di una sottocurva, verifico l'esistenza di Spigoli (Sharp Edges)
if ( nCrv1 > 1) {
Point3d ptCurr1 ;
// Scorro le sottocurve
@@ -6029,17 +6005,17 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
double dU = double( nCrv + 1) ;
// Recupero le tangenti prima e dopo tale parametro
Vector3d vtTanPrev ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr1, &vtTanPrev) ;
Vector3d vtTanAft ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr1, &vtTanAft) ;
Vector3d vtTanNext ; pSubEdge1->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr1, &vtTanNext) ;
// Verifico se ho uno spigolo
vtTanPrev.Normalize() ;
vtTanAft.Normalize() ;
if ( vtTanPrev * vtTanAft < COS_EDGE_LIMIT)
vSharpEdges1.emplace_back( dU, ptCurr1, vtTanPrev, vtTanAft) ;
vtTanNext.Normalize() ;
if ( vtTanPrev * vtTanNext < COS_EDGE_LIMIT)
vSharpEdges1.emplace_back( dU, ptCurr1, vtTanPrev, vtTanNext) ;
}
}
// --- Cerco gli spigoli sul Sottotratto del secondo bordo
// Se la Curva B ha solo una sottocurva, non faccio nulla
// Se la Curva B ha più di una sottocurva, verifico l'esistena di Spigoli (Sharp Edges)
if ( nCrv2 > 1) {
Point3d ptCurr2 ;
// Scorro le sottocurve
@@ -6048,24 +6024,24 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
double dU = double( nCrv + 1) ;
// Recupero le tangenti prima e dopo tale parametro
Vector3d vtTanPrev ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_MINUS, ptCurr2, &vtTanPrev) ;
Vector3d vtTanAft ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr2, &vtTanAft) ;
Vector3d vtTanNext ; pSubEdge2->GetPointD1D2( dU, ICurve::FROM_PLUS, ptCurr2, &vtTanNext) ;
// Verifico se ho uno spigolo
vtTanPrev.Normalize() ;
vtTanAft.Normalize() ;
if ( vtTanPrev * vtTanAft < COS_EDGE_LIMIT)
vSharpEdges2.emplace_back( dU, ptCurr2, vtTanPrev, vtTanAft) ;
vtTanNext.Normalize() ;
if ( vtTanPrev * vtTanNext < COS_EDGE_LIMIT)
vSharpEdges2.emplace_back( dU, ptCurr2, vtTanPrev, vtTanNext) ;
}
}
// Se non ho alcuno spigolo, allora non faccio nulla
// Se non ho alcuno spigolo per entrambe le curve di Bordo, non faccio nulla
if ( vSharpEdges1.empty() && vSharpEdges2.empty())
return true ;
// Recupero le Curve di Sincronizzazione dell'Edge 1 sull'Edge 2
// Recupero le Curve di Sincronizzazione associate agli spigoli dal primo Bordo al secondo Bordo
BIPNTVECTOR vSyncLines1 ;
CalcSyncPointFromEdge( vSharpEdges1, pSubEdge2, vSharpEdges2, vSyncLines1) ;
// Recupero le Curve di Sincronizzazione dell'Edge 2 sull'Egde 1
// Recupero le Curve di Sincronizzazione associate agli spigoli dal secondo Bordo al primo Bordo
BIPNTVECTOR vSyncLines2 ;
CalcSyncPointFromEdge( vSharpEdges2, pSubEdge1, vSharpEdges1, vSyncLines2) ;
@@ -6078,7 +6054,7 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
}) ;
}) ;
// Ordino tutte le curve in base al parametro dU della curva principale
// Ordino tutte le curve in base al parametro dU della prima curva di Bordo
vector<pair<BIPOINT, double>> vSyncLinesPar ; vSyncLinesPar.reserve( vSyncLines1.size() + vSyncLines2.size()) ;
for ( BIPOINT& SyncLine1 : vSyncLines1) {
vSyncLinesPar.emplace_back( make_pair( make_pair( SyncLine1.first, SyncLine1.second),
@@ -6094,9 +6070,227 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
return SyncLineParA.second < SyncLineParB.second ;
}) ;
// Restituisco il risultato
for ( auto Iter = vSyncLinesPar.begin() ; Iter != vSyncLinesPar.end() ; ++ Iter)
vSyncLines.emplace_back( Iter->first) ;
// Controllo che le linee di sincronizzazione non si intreccino e restituisco il risultato
// NB. Inserisco solo che curve che progressivamente non si intrecciano sulla seconda curva di Bordo
double dUSecondPrev = EPS_PARAM ;
for ( auto Iter = vSyncLinesPar.begin() ; Iter != vSyncLinesPar.end() ; ++ Iter) {
double dUSecondCurr ; pSubEdge2->GetParamAtPoint( ( *Iter).first.second, dUSecondCurr, TOL) ;
if ( dUSecondCurr > dUSecondPrev + EPS_SMALL) {
vSyncLines.emplace_back( Iter->first) ;
dUSecondPrev = dUSecondCurr ;
}
}
return true ;
}
// ---------------------------------------------------------------------------
// Calcolo delle Curve di Sync per evitare Twist
static bool
ManageTwistInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComposite* pSubEdge2, BIPNTVECTOR& vSyncLines, bool& bEraseLastIso)
{
// Verifica validità delle curve
if ( pSubEdge1 == nullptr || ! pSubEdge1->IsValid() || pSubEdge2 == nullptr || ! pSubEdge2->IsValid())
return false ;
const double COS_LIMIT = cos( 50. * DEGTORAD) ;
const int NUM_SAMPLE_PNT = 20 ;
const int nStepSkip = NUM_SAMPLE_PNT / 10 ;
#if DEBUG_CURVATURE
vector<pair<Point3d, double>> _vPtK1 ;
vector<pair<Point3d, double>> _vPtK2 ;
IGeomDB* pGeomDB = GetCurrGeomDB() ;
VERIFY_GEOMDB( pGeomDB, false)
#endif
int nLastSync = ssize( vSyncLines) ;
// --- Verifico il cambiamento di Deviazione angolare tra Inizio-Fine della prima curva di Bordo
Vector3d vtS1 ; pSubEdge1->GetStartDir( vtS1) ;
Vector3d vtE1 ; pSubEdge1->GetEndDir( vtE1) ;
double dLen1 = - EPS_SMALL ;
double dLen2 = - EPS_SMALL ;
pSubEdge1->GetLength( dLen1) ;
pSubEdge2->GetLength( dLen2) ;
double dMyDist = min( dLen1, dLen2) * 0.85 ;
bool bSplit1 = ( vtS1 * vtE1 < COS_LIMIT) ;
if ( bSplit1) {
// Individuo il punto a Curvatura Massima
double dKMax1 = - INFINITO + 1, dUK1Max = - EPS_SMALL ;
Point3d ptKMax1 ; Vector3d vtTanKMax1Prev, vtTanKMax1Next ;
for ( int i = nStepSkip ; i <= NUM_SAMPLE_PNT - nStepSkip ; ++ i) {
// Ricavo la Lunghezza corrente e il parametro dU associato
double dCurrLen1 = Clamp( i * ( dLen1 / NUM_SAMPLE_PNT), 0., dLen1) ;
double dUCurr1 ; pSubEdge1->GetParamAtLength( dCurrLen1, dUCurr1) ;
// Calcolo la Curvatura
Point3d ptCurrSub1 ;
Vector3d vtCurrSub1Der1Prev, vtCurrSub1Der2Prev, vtCurrSub1Der1Next, vtCurrSub1Der2Next ;
pSubEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurrSub1, &vtCurrSub1Der1Prev, &vtCurrSub1Der2Prev) ;
pSubEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_PLUS, ptCurrSub1, &vtCurrSub1Der1Next, &vtCurrSub1Der2Next) ;
Vector3d vtCurrSub1Der1 = Media( vtCurrSub1Der1Prev, vtCurrSub1Der1Next) ;
Vector3d vtCurrSub1Der2 = Media( vtCurrSub1Der2Prev, vtCurrSub1Der2Next) ;
double dCurrK1 = ( vtCurrSub1Der1 ^ vtCurrSub1Der2).Len() / max( EPS_SMALL, Pow( vtCurrSub1Der1.Len(), 3)) ;
// Se maggiore della massima trovata, aggiorno la massima
if ( dCurrK1 > dKMax1) {
dKMax1 = dCurrK1 ;
ptKMax1 = ptCurrSub1 ;
dUK1Max = dUCurr1 ;
vtTanKMax1Prev = vtCurrSub1Der1Prev ;
vtTanKMax1Next = vtCurrSub1Der1Next ;
}
#if DEBUG_CURVATURE
_vPtK1.emplace_back( make_pair( ptCurrSub1, dCurrK1)) ;
#endif
}
vtTanKMax1Prev.Normalize() ;
vtTanKMax1Next.Normalize() ;
// Calcolo la nuova linea di sincronizzazione
CurvaturePoint myCurvaturePoint( dUK1Max, ptKMax1, vtTanKMax1Prev, vtTanKMax1Next) ;
double dUOn2 ; double dLenCurr2 ;
GetIsoPointOnSecondCurve( pSubEdge1, pSubEdge2, dUK1Max, dUOn2, dMyDist, 0, 0, dLenCurr2, dLen2) ;
Point3d ptOn2 ; pSubEdge2->GetPointD1D2( dUOn2, ICurve::FROM_MINUS, ptOn2) ;
vSyncLines.emplace_back( ptKMax1, ptOn2) ;
}
// --- Verifico il cambiamento di Deviazione angolare tra Inizio-Fine del tratto per la prima curva di Bordo
Vector3d vtS2 ; pSubEdge2->GetStartDir( vtS2) ;
Vector3d vtE2 ; pSubEdge2->GetEndDir( vtE2) ;
bool bSplit2 = ( vtS2 * vtE2 < COS_LIMIT) ;
if ( bSplit2) {
// Individuo il punto a Curvatura Massima
double dKMax2 = - INFINITO + 1, dUK2Max = - EPS_SMALL ;
Point3d ptKMax2 ; Vector3d vtTanKMax2Prev, vtTanKMax2Next ;
for ( int i = nStepSkip ; i <= NUM_SAMPLE_PNT - nStepSkip ; ++ i) {
// Ricavo la Lunghezza corrente e il parametro dU associato
double dCurrLen2 = Clamp( i * ( dLen2 / NUM_SAMPLE_PNT), 0., dLen2) ;
double dUCurr2 ; pSubEdge2->GetParamAtLength( dCurrLen2, dUCurr2) ;
// Calcolo la Curvatura
Point3d ptCurrSub2 ;
Vector3d vtCurrSub2Der1Prev, vtCurrSub2Der2Prev, vtCurrSub2Der1Next, vtCurrSub2Der2Next ;
pSubEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_MINUS, ptCurrSub2, &vtCurrSub2Der1Prev, &vtCurrSub2Der2Prev) ;
pSubEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_PLUS, ptCurrSub2, &vtCurrSub2Der1Next, &vtCurrSub2Der2Next) ;
Vector3d vtCurrSub2Der1 = Media( vtCurrSub2Der1Prev, vtCurrSub2Der1Next) ;
Vector3d vtCurrSub2Der2 = Media( vtCurrSub2Der2Prev, vtCurrSub2Der2Next) ;
double dCurrK2 = ( vtCurrSub2Der1 ^ vtCurrSub2Der2).Len() / max( EPS_SMALL, Pow( vtCurrSub2Der1.Len(), 3)) ;
// Se maggiore della massima trovata, aggiorno la massima
if ( dCurrK2 > dKMax2) {
dKMax2 = dCurrK2 ;
ptKMax2 = ptCurrSub2 ;
dUK2Max = dUCurr2 ;
vtTanKMax2Prev = vtCurrSub2Der1Prev ;
vtTanKMax2Next = vtCurrSub2Der1Next ;
}
#if DEBUG_CURVATURE
_vPtK1.emplace_back( make_pair( ptCurrSub2, dCurrK2)) ;
#endif
}
vtTanKMax2Prev.Normalize() ;
vtTanKMax2Next.Normalize() ;
// Calcolo la nuova linea di sincronizzazione
CurvaturePoint myCurvaturePoint( dUK2Max, ptKMax2, vtTanKMax2Prev, vtTanKMax2Next) ;
double dUOn1 ; double dLenCurr1 ;
GetIsoPointOnSecondCurve( pSubEdge2, pSubEdge1, dUK2Max, dUOn1, dMyDist, 0, 0, dLenCurr1, dLen1) ;
Point3d ptOn1 ; pSubEdge1->GetPointD1D2( dUOn1, ICurve::FROM_MINUS, ptOn1) ;
vSyncLines.emplace_back( ptOn1, ptKMax2) ;
}
#if DEBUG_CURVATURE // Curvatura minima -> AQUA | Curvatura massima -> ORANGE
auto [itMin1, itMax1] = std::minmax_element( _vPtK1.begin(), _vPtK1.end(), [](auto const& A, auto const& B) {
return A.second < B.second ;
}) ;
double _dK1Max = itMax1->second ;
double _dK1Min = itMin1->second ;
for ( int i = 0 ; i < ssize( _vPtK1) ; ++ i) {
double _t = 0. ;
if ( _dK1Max > _dK1Min)
_t = ( _vPtK1[i].second - _dK1Min) / ( _dK1Max - _dK1Min) ;
double _dh = 30 - 180. ; // AQUA -> HSV( 180, 1, 1) | ORANGE -> HSV( 30, 1, 1)
if ( _dh > 180.) _dh -= 360.0 ;
if ( _dh < -180.0) _dh += 360.0 ;
double _h = 180. + _t * _dh ;
if ( _h < 0.0) _h += 360.0 ;
if ( _h >= 360.0) _h -= 360.0 ;
PtrOwner<IGeoPoint3d> _ptC( CreateGeoPoint3d()) ; _ptC->Set( _vPtK1[i].first) ;
int _nId = pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, Release( _ptC)) ;
pGeomDB->SetMaterial( _nId, Color( GetColorFromHSV( HSV( _h, 1., 1.)))) ;
}
auto [itMin2, itMax2] = std::minmax_element( _vPtK2.begin(), _vPtK2.end(), [](auto const& A, auto const& B) {
return A.second < B.second ;
}) ;
double _dK2Max = itMax2->second ;
double _dK2Min = itMin2->second ;
for ( int i = 0 ; i < ssize( _vPtK2) ; ++ i) {
double _t = 0. ;
if ( _dK2Max > _dK2Min)
_t = ( _vPtK2[i].second - _dK2Min) / ( _dK2Max - _dK2Min) ;
double _dh = 30 - 180. ; // CYAN -> HSV( 180, 1, 1) | ORANGE -> HSV( 30, 1, 1)
if ( _dh > 180.) _dh -= 360.0 ;
if ( _dh < -180.0) _dh += 360.0 ;
double _h = 180. + _t * _dh ;
if ( _h < 0.0) _h += 360.0 ;
if ( _h >= 360.0) _h -= 360.0 ;
PtrOwner<IGeoPoint3d> _ptC( CreateGeoPoint3d()) ; _ptC->Set( _vPtK2[i].first) ;
int _nId = pGeomDB->AddGeoObj( GDB_ID_NULL, GDB_ID_ROOT, Release( _ptC)) ;
pGeomDB->SetMaterial( _nId, Color( GetColorFromHSV( HSV( _h, 1., 1.)))) ;
}
#endif
// Se non ho alcuna linea di sincronizzazione, non faccio nulla
if ( vSyncLines.empty() || ( ! bSplit2 && ! bSplit1))
return true ;
const double TOL = 250. * EPS_SMALL ;
// Elimino tutte le curve di Sincronizzazione a ridosso degli estremi della Quadrangolazione
// NB. Risultano ridondanti, creano SottoQuadrangolazioni molto strette o possono Inclinare eccssivamente l'Utensile
// NB. Così facendo evito anche di creare curve di Sync lungo le diagonali della Quadrangolazione
const double LEN_TOL = 2. ;
const double dParTol = 0.1 ;
double dLenPrev1 = - LEN_TOL, dLenPrev2 = - LEN_TOL ;
for ( int i = nLastSync ; i < ssize( vSyncLines) ; ++ i) {
double dSyncLen1 ; pSubEdge1->GetLengthAtPoint( vSyncLines[i].first, dSyncLen1, TOL) ;
bool bErase = ( dSyncLen1 < max( LEN_TOL, dParTol * dLen1) || dSyncLen1 - dLenPrev1 < LEN_TOL) ;
bEraseLastIso = dSyncLen1 > min( dLen1 - LEN_TOL, ( 1 - dParTol) * dLen1) ;
if ( ! bErase) {
double dSyncLen2 ; pSubEdge2->GetLengthAtPoint( vSyncLines[i].second, dSyncLen2, TOL) ;
bErase = ( dSyncLen2 < max( LEN_TOL, dParTol * dLen2) || dSyncLen2 - dLenPrev2 < LEN_TOL) ;
bEraseLastIso = bEraseLastIso || dSyncLen2 > min( dLen2 - LEN_TOL, ( 1 - dParTol) * dLen2) ;
dLenPrev2 = dSyncLen2 ;
}
if ( bErase && ! bEraseLastIso) {
vSyncLines.erase( vSyncLines.begin() + i) ;
-- i ;
}
dLenPrev1 = dSyncLen1 ;
if ( bEraseLastIso)
break ;
}
if ( vSyncLines.empty())
return true ;
// Se due curve di Sincronizzazione rimaste
if ( ssize( vSyncLines) - nLastSync == 2) {
// Se si sovrappongono, ne elimino una
if ( AreSamePointEpsilon( vSyncLines.end()[-2].first, vSyncLines.end()[-1].first, LEN_TOL) &&
AreSamePointEpsilon( vSyncLines.end()[-2].second, vSyncLines.end()[-1].second, LEN_TOL))
vSyncLines.pop_back() ;
}
// Se due curve di Sincronizzazione rimaste
if ( ssize( vSyncLines) - nLastSync == 2) {
// Ordino tutte le linee di sincronizzazione in base al parametro dU della curva principale
double dU0 ; pSubEdge1->GetParamAtPoint( vSyncLines.end()[-2].first, dU0, TOL) ;
double dU1 ; pSubEdge1->GetParamAtPoint( vSyncLines.end()[-1].first, dU1, TOL) ;
if ( dU0 > dU1 - EPS_SMALL)
swap( vSyncLines.end()[-2], vSyncLines[-1]) ;
// Verifico che le curve non si intreccino
pSubEdge2->GetParamAtPoint( vSyncLines.end()[-2].second, dU0, TOL) ;
pSubEdge2->GetParamAtPoint( vSyncLines.end()[-1].second, dU1, TOL) ;
if ( dU0 > dU1 - EPS_SMALL)
vSyncLines.pop_back() ; // lascio solo la prima... ( bisognerebbe scegliere quale lasciare con un criterio migliore ?)
}
// se ne ho due tengo solo la prima
if ( ssize( vSyncLines) - nLastSync == 2)
vSyncLines.pop_back() ;
return true ;
}
@@ -6104,14 +6298,29 @@ ManageEdgesInQuadrangulation( const ICurveComposite* pSubEdge1, const ICurveComp
//----------------------------------------------------------------------------
bool
SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen)
{
BIPNTVECTOR vSyncLines ;
return CreateSmoothRuledByTwoCurves( pCurve0, pCurve1, dSampleLen, vSyncLines) ;
}
//----------------------------------------------------------------------------
bool
SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen, BIPNTVECTOR& vSyncLines)
{
// converto in bezier le curve iniziali
PtrOwner<ICurveBezier> pCrvEdge1( GetCurveBezier( CurveToBezierCurve( pCurve0, 3, false))) ;
PtrOwner<ICurveBezier> pCrvEdge2( GetCurveBezier( CurveToBezierCurve( pCurve1, 3, false))) ;
PtrOwner<ICurveComposite> pCrvEdge1( ConvertCurveToComposite(CurveToBezierCurve( pCurve0, 3, false))) ;
PtrOwner<ICurveComposite> pCrvEdge2( ConvertCurveToComposite(CurveToBezierCurve( pCurve1, 3, false))) ;
if ( IsNull( pCrvEdge1) || IsNull( pCrvEdge2))
return false ;
#if SAVEPACEDISO
vGeo.clear() ;
vCol.clear() ;
#endif
// Verifico che la distanza di campionamento sia ammissibile
double dMyDist = Clamp( dSampleLen, 2., 30.) ; // 20.0 sembra un passo di campionamento ideale
// Recupero parametri iniziali
double dLen1 ; pCrvEdge1->GetLength( dLen1) ;
double dLen2 ; pCrvEdge2->GetLength( dLen2) ;
@@ -6124,155 +6333,113 @@ SurfBezier::CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* p
Point3d ptPrev1, ptCurr1 ; pCrvEdge1->GetStartPoint( ptPrev1) ;
Point3d ptPrev2, ptCurr2 ; pCrvEdge2->GetStartPoint( ptPrev2) ;
Vector3d vtCurr1 = V_NULL, vtCurr2 = V_NULL ;
BIPNTVECTOR vEdgeSyncLines ;
while ( dLenPrev1 + dSampleLen < dLen1 - EPS_ZERO) {
// Recupero dU, Point3d e dLen corrente sul primo bordo, per un incremento del passo di campionamento
dLenCurr1 = Clamp( dLenPrev1 + dSampleLen, 0., dLen1) ;
while ( dLenPrev1 + dMyDist < dLen1 - EPS_ZERO) {
// Recupero dU, Point3d e dLen corrente sul primo bordo, per un incremento del passo di campionamento
dLenCurr1 = Clamp( dLenPrev1 + dMyDist, 0., dLen1) ;
pCrvEdge1->GetParamAtLength( dLenCurr1, dUCurr1) ;
// se sono abbastanza vicino ad una joint allora prendo quel punto
double dUClosestJoint1 = round( dUCurr1) ;
double dLenAlt1 = 0 ; pCrvEdge1->GetLengthAtParam( dUClosestJoint1, dLenAlt1) ;
if ( abs( dLenCurr1 - dLenAlt1) < 1)
dUCurr1 = dUClosestJoint1 ;
pCrvEdge1->GetPointD1D2( dUCurr1, ICurve::FROM_MINUS, ptCurr1, &vtCurr1) ;
vtCurr1.Normalize() ;
#if DEBUG_SYNCLINES
PtrOwner<IGeoPoint3d> ptGeo1( CreateGeoPoint3d()) ; ptGeo1->Set( ptCurr1) ;
PtrOwner<IGeoVector3d> vtGeo1( CreateGeoVector3d()) ; vtGeo1->Set( 5. * vtCurr1, ptCurr1) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay1, Release( ptGeo1)) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay1, Release( vtGeo1)) ;
#endif
#if DEBUG_SYNCLINES
PtrOwner<IGeoPoint3d> ptGeo1( CreateGeoPoint3d()) ; ptGeo1->Set( ptCurr1) ;
PtrOwner<IGeoVector3d> vtGeo1( CreateGeoVector3d()) ; vtGeo1->Set( 5. * vtCurr1, ptCurr1) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay1, Release( ptGeo1)) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay1, Release( vtGeo1)) ;
#endif
// --- Piano di taglio per punto a minima distanza
IntersCurvePlane ICP( *pCrvEdge2, ptCurr1, vtCurr1) ;
int nIndParCloser = - 1, nIndPointCloser = -1 ;
double dSqMinDist = INFINITO ;
for ( int nInfo = 0 ; nInfo < ICP.GetIntersCount() ; ++ nInfo) {
IntCrvPlnInfo aInfo ;
if ( ICP.GetIntCrvPlnInfo( nInfo, aInfo) && aInfo.Ici[0].dU > dUPrev2) {
if ( nIndParCloser == -1)
nIndParCloser = nInfo ;
double dSqDist = SqDist( ptCurr1, aInfo.Ici[0].ptI) ;
if ( dSqDist < dSqMinDist) {
dSqMinDist = dSqDist ;
nIndPointCloser = nInfo ;
}
}
}
bool bOkPlane = ( nIndParCloser != -1 && nIndPointCloser != -1) ;
if ( bOkPlane) {
// Se gli indici sono tra loro coerenti allora ho individuato il punto
if ( nIndParCloser == nIndPointCloser) {
IntCrvPlnInfo aInfo ;
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfo) ;
dUCurr2 = aInfo.Ici[0].dU ;
}
// Se gli indici sono discordi, devo scegliere quale dei due punti tenere
else {
// scelgo il punto più vicino al corrente
IntCrvPlnInfo aInfoPt, aInfoPar ;
ICP.GetIntCrvPlnInfo( nIndPointCloser, aInfoPt) ;
ICP.GetIntCrvPlnInfo( nIndParCloser, aInfoPar) ;
dUCurr2 = ( SqDist( ptCurr1, aInfoPt.Ici[0].ptI) < SqDist( ptCurr1, aInfoPar.Ici[0].ptI) ?
aInfoPt.Ici[0].dU : aInfoPar.Ici[0].dU) ;
#if DEBUG_SYNCLINES && 0
VT.clear() ; VC.clear() ;
VT.emplace_back( pCrvEdge1->Clone()) ; VC.emplace_back( Color( 0, 128, 255)) ;
VT.emplace_back( pCrvEdge2->Clone()) ; VC.emplace_back( Color( 0, 128, 255)) ;
PtrOwner<IGeoPoint3d> ptCurr1Geo( CreateGeoPoint3d()) ; ptCurr1Geo->Set( ptCurr1) ;
VT.emplace_back( Release( ptCurr1Geo)) ; VC.emplace_back( BLUE) ;
PtrOwner<IGeoPoint3d> ptPar( CreateGeoPoint3d()) ; ptPar->Set( aInfoPar.Ici[0].ptI) ;
PtrOwner<IGeoPoint3d> ptPt( CreateGeoPoint3d()) ; ptPt->Set( aInfoPt.Ici[0].ptI) ;
VT.emplace_back( Release( ptPar)) ; VC.emplace_back( LIME) ;
VT.emplace_back( Release( ptPt)) ; VC.emplace_back( FUCHSIA) ;
SaveGeoObj( VT, VC, "C:\\Temp\\TestTrimmingPlane.nge") ;
#endif
}
// Verifico di non essermi allontanato troppo
double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ;
bOkPlane = ( dLen < dLenPrev2 + 2. * dSampleLen) ;
}
if ( ! bOkPlane) {
// --- Altrimenti, cerco il punto a minima distanza
DistPointCurve DPC( ptCurr1, *pCrvEdge2) ;
int nFlag ;
bool bOkMinDist = ( DPC.GetParamAtMinDistPoint( dUPrev2, dUCurr2, nFlag) && dUCurr2 > dUPrev2) ;
// Verifico di non essermi allontanato troppo
if ( bOkMinDist) {
double dLen ; pCrvEdge2->GetLengthAtParam( dUCurr2, dLen) ;
bOkMinDist = ( dLen < dLenPrev2 + 2. * dSampleLen) ;
}
if ( ! bOkMinDist) {
// --- Aumento la distanza corrente del passo di campionamento
double dLen = Clamp( dLenPrev2 + dSampleLen, 0., dLen2) ;
pCrvEdge2->GetParamAtLength( dLen, dUCurr2) ;
}
}
GetIsoPointOnSecondCurve( pCrvEdge1, pCrvEdge2, dUCurr1, dUCurr2, dMyDist, dUPrev2, dLenPrev2, dLenCurr2, dLen2) ;
// Recupero il punto corrente e la direzione tangente sul secondo bordo
pCrvEdge2->GetLengthAtParam( dUCurr2, dLenCurr2) ;
pCrvEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_MINUS, ptCurr2, &vtCurr2) ;
vtCurr2.Normalize() ;
// Verifico se le direzioni tangenti sono tra di loro circa parallele
const double COS_ANG_TOL = cos( 15. * DEGTORAD) ;
if ( vtCurr1 * vtCurr2 < COS_ANG_TOL) {
// Se fuori dalla tolleranza, recupero il miglior versore tangente sul secondo bordo nell'intervallo successivo di lunghezza ( 2. * dSampleLen)
pCrvEdge2->GetLengthAtPoint( ptCurr2, dLenCurr2) ;
double dLimInfLen2 = Clamp( dLenCurr2 - dSampleLen, dLenPrev2, dLen2) ;
double dLimSupLen2 = Clamp( dLenCurr2 + dSampleLen, dLenPrev2, dLen2) ;
// [Controllo migliorabile, magari mendiante metodo di bisezione (?)]
const int NUM_STEP = 20 ;
double dMinCos = - 1. - EPS_ZERO ;
const double DEGTOL = 5. ;
for ( int i = 0 ; i <= NUM_STEP ; ++ i) {
double dLen = dLimInfLen2 + i * ( dLimSupLen2 - dLimInfLen2) / NUM_STEP ;
double dUStep2 ; pCrvEdge2->GetParamAtLength( dLen, dUStep2) ;
Point3d ptStep2 ; Vector3d vtStep2 = V_NULL ;
pCrvEdge2->GetPointD1D2( dUStep2, ICurve::FROM_MINUS, ptStep2, &vtStep2) ; vtStep2.Normalize() ;
double dStepCos2 = vtCurr1 * vtStep2 ;
double dAngTol = ( i < NUM_STEP / 2 ? ( 2. * DEGTOL) / NUM_STEP * i :
( - 2. * DEGTOL) / NUM_STEP * ( i - NUM_STEP)) ;
double dCosTol = 1. - cos( dAngTol * DEGTORAD) ;
if ( dStepCos2 + dCosTol > dMinCos) {
ptCurr2 = ptStep2 ;
vtCurr2 = vtStep2 ;
dUCurr2 = dUStep2 ;
dMinCos = dStepCos2 + dCosTol ;
}
}
}
#if DEBUG_SYNCLINES
PtrOwner<IGeoPoint3d> ptGeo2( CreateGeoPoint3d()) ; ptGeo2->Set( ptCurr2) ;
PtrOwner<IGeoVector3d> vtGeo2( CreateGeoVector3d()) ; vtGeo2->Set( 5. * vtCurr2, ptCurr2) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay2, Release( ptGeo2)) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay2, Release( vtGeo2)) ;
#endif
// debug
//// Inserisco le curve di sincronizzazione nel Layer di destinazine
// PtrOwner<ICurveLine> pLine( CreateCurveLine()) ; pLine->Set( ptCurr1, ptCurr2) ;
// pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrp, Release( pLine)) ;
// --- Analisi degli spigoli all'interno della Quadrangolazione ---
// Perchè si fa questa cosa ? Perchè parametrizzando per la lunghezza i SottoTratti ricavati, non è sempre detto
// che uno spigolo di una curva sia sincronizzato con lo spigolo di un'altra ( se questi esistono)... Pertanto
// la Bezier Ruled ricavata non è detto che sia in grado di approssimare lo spigolo correttamente, potrebbe sdondarlo
PtrOwner<ICurveComposite> pCrvQuad1( ConvertCurveToComposite( pCrvEdge1->CopyParamRange( dUPrev1, dUCurr1))) ;
PtrOwner<ICurveComposite> pCrvQuad2( ConvertCurveToComposite( pCrvEdge2->CopyParamRange( dUPrev2, dUCurr2))) ;
ManageEdgesInQuadrangulation( pCrvQuad1, pCrvQuad2, vEdgeSyncLines) ;
//debug
//for ( int i = 0 ; i < ssize( vEdgeSyncLines) ; ++ i) {
// PtrOwner<ICurveLine> pLine( CreateCurveLine()) ; pLine->Set( vEdgeSyncLines[i].first, vEdgeSyncLines[i].second) ;
// int nNewId = pGeomDB->AddGeoObj( GDB_ID_NULL, nDestGrp, Release( pLine)) ;
// pGeomDB->SetMaterial( nNewId, GREEN) ;
//////////////////////////N.B.: se si aggiunge questo pezzo bisogna anche gestire il fatto che i punti precedentemente aggiunti potrebbero non stare più sulla curva modificata!!!
//// verifico se sono vicino ad una joint esistente allora modifico la curva 2
//double dUClosestJoint2 = round( dUCurr2) ;
//double dLenAlt2 = 0 ; pCrvEdge2->GetLengthAtParam( dUClosestJoint2, dLenAlt2) ;
//if ( abs( dLenCurr2 - dLenAlt2) < 1) {
// Point3d ptNewJoint ; pCrvEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_MINUS, ptNewJoint) ;
// if ( pCrvEdge2->ModifyJoint( int( dUClosestJoint2), ptNewJoint))
// dUCurr2 = dUClosestJoint2 ;
//}
// Aggiorno i parametri
pCrvEdge2->GetPointD1D2( dUCurr2, ICurve::FROM_MINUS, ptCurr2, &vtCurr2) ;
#if DEBUG_SYNCLINES
PtrOwner<IGeoPoint3d> ptGeo2( CreateGeoPoint3d()) ; ptGeo2->Set( ptCurr2) ;
PtrOwner<IGeoVector3d> vtGeo2( CreateGeoVector3d()) ; vtGeo2->Set( 5. * vtCurr2, ptCurr2) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay2, Release( ptGeo2)) ;
pGeomDB->AddGeoObj( GDB_ID_NULL, nLay2, Release( vtGeo2)) ;
#endif
vSyncLines.emplace_back( ptCurr1, ptCurr2) ;
// --- Analisi degli spigoli all'interno della Quadrangolazione corrente ---
// NB. Non è sempre detto che uno spigolo di una curva sia sincronizzato con lo spigolo di un'altra ( se questi esistono)...
// Pertanto la Bezier Ruled ricavata non è detto che sia in grado di approssimare lo spigolo correttamente, potrebbe sdondarlo
PtrOwner<ICurveComposite> pCrvQuad1( ConvertCurveToComposite( pCrvEdge1->CopyParamRange( dUPrev1, dUCurr1))) ;
PtrOwner<ICurveComposite> pCrvQuad2( ConvertCurveToComposite( pCrvEdge2->CopyParamRange( dUPrev2, dUCurr2))) ;
BIPNTVECTOR vEdgeSyncLines ;
ManageEdgesInQuadrangulation( pCrvQuad1, pCrvQuad2, vEdgeSyncLines) ;
// --- Aggiunta di Linee di Sync all'interno della Quandrangolazione corrente ---
// Perchè parametrizzando per la lunghezza i SottoTratti ricavati, nel caso di elevate variazioni angolari tra l'inizio e la fine
// ( tra due curva di Sync) si potrebbero generare delle torsioni non volute
// -->! NB. Queste linee vengono create considerando le SubQuadrangolazioni con gli Spigoli. !<--
BIPNTVECTOR vTwistSyncLines ;
bool bEraseLastIso = false ;
if ( vEdgeSyncLines.empty())
ManageTwistInQuadrangulation( pCrvQuad1, pCrvQuad2, vTwistSyncLines, bEraseLastIso) ;
else {
BIPOINT SyncLinePrev, SyncLineNext ;
pCrvQuad1->GetStartPoint( SyncLinePrev.first) ;
pCrvQuad2->GetStartPoint( SyncLinePrev.second) ;
for ( int i = 0 ; i <= ssize( vEdgeSyncLines) ; ++ i) {
if ( i == ssize( vEdgeSyncLines)) {
pCrvQuad1->GetEndPoint( SyncLineNext.first) ;
pCrvQuad2->GetEndPoint( SyncLineNext.second) ;
}
else {
SyncLineNext.first = vEdgeSyncLines[i].first ;
SyncLineNext.second = vEdgeSyncLines[i].second ;
}
// Recupero i parametri correnti
double dUS1, dUE1, dUS2, dUE2 ;
pCrvQuad1->GetParamAtPoint( SyncLinePrev.first, dUS1) ;
pCrvQuad2->GetParamAtPoint( SyncLinePrev.second, dUS2) ;
pCrvQuad1->GetParamAtPoint( SyncLineNext.first, dUE1) ;
pCrvQuad2->GetParamAtPoint( SyncLineNext.second, dUE2) ;
PtrOwner<ICurveComposite> pCrvSubQuad1( ConvertCurveToComposite( pCrvQuad1->CopyParamRange( dUS1, dUE1))) ;
PtrOwner<ICurveComposite> pCrvSubQuad2( ConvertCurveToComposite( pCrvQuad2->CopyParamRange( dUS2, dUE2))) ;
ManageTwistInQuadrangulation( pCrvSubQuad1, pCrvSubQuad2, vTwistSyncLines, bEraseLastIso) ;
// Aggiorno i parametri
SyncLinePrev = SyncLineNext ;
}
bEraseLastIso = false ;
}
if ( bEraseLastIso) {
vSyncLines.pop_back() ;
double dQuadLen1 ; pCrvQuad1->GetLengthAtPoint( vTwistSyncLines[0].first, dQuadLen1) ;
dLenCurr1 = dLenPrev1 + dQuadLen1 ;
double dQuadLen2 ; pCrvQuad2->GetLengthAtPoint( vTwistSyncLines[0].second, dQuadLen2) ;
dLenCurr2 = dLenPrev2 + dQuadLen2 ;
}
// aggiungo le nuove curve ( non importa che siano ordinate per parametro)
vSyncLines.insert( vSyncLines.end(), vEdgeSyncLines.begin(), vEdgeSyncLines.end()) ;
vSyncLines.insert( vSyncLines.end(), vTwistSyncLines.begin(), vTwistSyncLines.end()) ;
// Aggiorno i parametri
ptPrev1 = ptCurr1 ; dUPrev1 = dUCurr1 ; dLenPrev1 = dLenCurr1 ;
ptPrev2 = ptCurr2 ; dUPrev2 = dUCurr2 ; dLenPrev2 = dLenCurr2 ;
}
return CreateByIsoParamSet( pCrvEdge1, pCrvEdge2, vEdgeSyncLines) ;
#if SAVEPACEDISO
SaveGeoObj( vGeo, vCol, "D:\\Temp\\bezier\\ruled\\trimming\\smooth.nge") ;
#endif
return CreateByIsoParamSet( pCrvEdge1, pCrvEdge2, vSyncLines) ;
}
//----------------------------------------------------------------------------
@@ -6779,14 +6946,18 @@ SurfBezier::CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, c
if ( vIso[c].dParam0 < dLastParam0) {
if ( dLastParam0 - vIso[c].dParam0 < EPS_ZERO)
vIso[c].dParam0 = dLastParam0 + EPS_PARAM ;
else
else {
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface couldn't be created with the isocurves provided") ;
return false ;
}
}
if ( vIso[c].dParam1 < dLastParam1) {
if ( dLastParam1 - vIso[c].dParam1 < EPS_ZERO)
vIso[c].dParam1 = dLastParam1 + EPS_PARAM ;
else
else {
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Bezier Surface couldn't be created with the isocurves provided") ;
return false ;
}
}
dLastParam0 = vIso[c].dParam0 ;
dLastParam1 = vIso[c].dParam1 ;
+1
View File
@@ -155,6 +155,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
bool SwapParameters( void) ;
bool LimitSurfToTrimmedRegion( void) override ;
bool CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen) override ;
bool CreateSmoothRuledByTwoCurves( const ICurve* pCurve0, const ICurve* pCurve1, double dSampleLen, BIPNTVECTOR& vSyncLines) override ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
+43 -17
View File
@@ -1150,7 +1150,7 @@ SurfTriMesh::MarchOneTria( int& nT, int& nV, int nTimeStamp,
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR& vPL, bool bAllTria) const
SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR& vPL, bool bAllTria, double dLinTol) const
{
// Verifico lo stato
if ( m_nStatus != OK)
@@ -1163,6 +1163,7 @@ SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR&
// Controlli su tolleranza
dTol = max( dTol, 100 * EPS_SMALL) ;
double dMyLinTol = max( EPS_SMALL, dLinTol) ;
// Determino il riferimento di proiezione
Frame3d frOCS ; frOCS.Set( ORIG, vtVers) ;
@@ -1182,14 +1183,16 @@ SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR&
( ! bAllTria && Tria.GetN() * vtVers > EPS_ZERO)) &&
Tria.Scale( frOCS, 1, 1, 0) && Tria.GetSqMinHeight() > SQ_EPS_SMALL) {
PtrOwner<SurfFlatRegion> pSfrTria( GetBasicSurfFlatRegion( GetSurfFlatRegionFromTriangle( Tria))) ;
if ( ! IsNull( pSfrTria)) {
if ( ! IsNull( pSfrTria) && pSfrTria->IsValid()) {
if ( bAllTria && Tria.GetN() * vtVers < 0)
pSfrTria->Invert() ;
pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ;
if ( IsNull( pSfr))
pSfr.Set( pSfrTria) ;
else
pSfr->Add( *pSfrTria) ;
else {
if ( ! pSfr->Add( *pSfrTria))
return false ;
}
}
}
// passo al successivo
@@ -1201,14 +1204,18 @@ SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR&
return false ;
// Effettuo contro-offset
pSfr->Offset( -dTol, ICurve::OFF_EXTEND) ;
if ( ! pSfr->Offset( -dTol, ICurve::OFF_EXTEND))
return false ;
// Recupero i contorni della regione
for ( int i = 0 ; i < pSfr->GetChunkCount() ; ++ i) {
for ( int j = 0 ; j < pSfr->GetLoopCount( i) ; ++ j) {
PolyLine PL ;
if ( pSfr->ApproxLoopWithLines( i, j, LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
vPL.emplace_back( PL) ;
if ( ! pSfr->ApproxLoopWithLines( i, j, dMyLinTol, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) {
vPL.clear() ;
return false ;
}
vPL.emplace_back( PL) ;
}
}
@@ -1217,7 +1224,7 @@ SurfTriMesh::GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR&
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR& vPL, bool bAllTria) const
SurfTriMesh::GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR& vPL, bool bAllTria, double dLinTol) const
{
// Verifico lo stato
if ( m_nStatus != OK)
@@ -1230,6 +1237,7 @@ SurfTriMesh::GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR&
// Controlli su tolleranza
dTol = max( dTol, 100 * EPS_SMALL) ;
double dMyLinTol = max( EPS_SMALL, dLinTol) ;
// Determino il riferimento di proiezione
Frame3d frOCS ; frOCS.Set( plPlane.GetPoint(), vtVers) ;
@@ -1253,14 +1261,16 @@ SurfTriMesh::GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR&
// lo proietto sul piano e creo la regione
if ( pgTria.Scale( frOCS, 1, 1, 0)) {
PtrOwner<SurfFlatRegion> pSfrTria( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLine( pgTria.GetPolyLine()))) ;
if ( ! IsNull( pSfrTria)) {
if ( ! IsNull( pSfrTria) && pSfrTria->IsValid()) {
if ( bAllTria && Tria.GetN() * vtVers < 0)
pSfrTria->Invert() ;
pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ;
if ( IsNull( pSfr))
pSfr.Set( pSfrTria) ;
else
pSfr->Add( *pSfrTria) ;
else {
if ( ! pSfr->Add( *pSfrTria))
return false ;
}
}
}
}
@@ -1274,14 +1284,18 @@ SurfTriMesh::GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR&
return true ;
// Effettuo contro-offset
pSfr->Offset( -dTol, ICurve::OFF_EXTEND) ;
if ( ! pSfr->Offset( -dTol, ICurve::OFF_EXTEND))
return false ;
// Recupero i contorni della regione
for ( int i = 0 ; i < pSfr->GetChunkCount() ; ++ i) {
for ( int j = 0 ; j < pSfr->GetLoopCount( i) ; ++ j) {
PolyLine PL ;
if ( pSfr->ApproxLoopWithLines( i, j, LIN_TOL_STD, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
vPL.emplace_back( PL) ;
if ( ! pSfr->ApproxLoopWithLines( i, j, dMyLinTol, ANG_TOL_STD_DEG, ICurve::APL_STD, PL)) {
vPL.clear() ;
return false ;
}
vPL.emplace_back( PL) ;
}
}
@@ -3810,12 +3824,19 @@ SurfTriMesh::VerifyConnection( bool bShellsAndParts) const
BBox3d b3Box ;
PtrOwner<ISurfTriMesh> pStmShell ;
} ;
// vettore di shell con vettori dei propri triangoli (per accelerare nei casi degeneri)
INTMATRIX mShellTria( m_nShells) ;
for ( int i = 0 ; i < ssize( m_vTria) ; ++ i) {
if ( m_vTria[i].nShell < m_nShells)
mShellTria[m_vTria[i].nShell].push_back( i) ;
}
// classificazione delle shell
vector<SHELLINFO> vOuterShells ;
vector<SHELLINFO> vInnerShells ;
INTVECTOR vOpenShells ;
for ( int nSh = 0 ; nSh < m_nShells ; ++ nSh) {
// se la shell è chiusa
if ( IsShellClosed( nSh)) {
if ( ssize( mShellTria[nSh]) >= 4 && IsShellClosed( nSh)) {
// creo una superficie clonata dalla shell
PtrOwner<ISurfTriMesh> pStmShell( CloneShell( nSh)) ;
if ( IsNull( pStmShell) || ! pStmShell->IsValid())
@@ -3827,7 +3848,9 @@ SurfTriMesh::VerifyConnection( bool bShellsAndParts) const
BBox3d b3Box ;
pStmShell->GetLocalBBox( b3Box, BBF_STANDARD) ;
// la inserisco nel vettore opportuno
if ( dVol > 0)
if ( abs( dVol) < 1 * 1 * EPS_SMALL)
vOpenShells.push_back( nSh) ;
else if ( dVol > 0)
vOuterShells.emplace_back( nSh, dVol, b3Box, Release( pStmShell)) ;
else
vInnerShells.emplace_back( nSh, dVol, b3Box, Release( pStmShell)) ;
@@ -3979,6 +4002,7 @@ SurfTriMesh::IsShellClosed( int nShell) const
return false ;
// ciclo sui triangoli della shell
bool bClosed = true ;
int nTriaCnt = 0 ;
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
// se triangolo non cancellato e della shell
if ( m_vTria[i].nIdVert[0] != SVT_DEL && m_vTria[i].nShell == nShell) {
@@ -3989,10 +4013,12 @@ SurfTriMesh::IsShellClosed( int nShell) const
bClosed = false ;
break ;
}
else
++ nTriaCnt ;
}
}
// restituisco il risultato
return bClosed ;
return ( bClosed && nTriaCnt >= 4) ;
}
//----------------------------------------------------------------------------
+3 -2
View File
@@ -16,6 +16,7 @@
#include "ObjGraphicsMgr.h"
#include "DllMain.h"
#include "GeoObjRW.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkHashGrids3d.h"
#include "/EgtDev/Include/EGkPointGrid3d.h"
@@ -295,8 +296,8 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool GetTriangleSmoothNormals( int nId, TriNormals3d& TNrms) const override ;
SurfTriMesh* CloneTriangle( int nT) const override ;
bool GetLoops( POLYLINEVECTOR& vPL) const override ;
bool GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR& vPL, bool bAllTria = false) const override ;
bool GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR& vPL, bool bAllTria = false) const override ;
bool GetSilhouette( const Vector3d& vtDir, double dTol, POLYLINEVECTOR& vPL, bool bAllTria = false, double dLinTol = LIN_TOL_STD) const override ;
bool GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR& vPL, bool bAllTria = false, double dLinTol = LIN_TOL_STD) const override ;
int GetFacetCount( void) const override ;
int GetFacetSize( void) const override
{ return int( m_vFacet.size()) ; }
+648 -117
View File
@@ -36,13 +36,13 @@
#include "/EgtDev/Include/EGkIntersLineBox.h"
#include "/EgtDev/Include/EGkIntersCurvePlane.h"
#include "/EgtDev/Include/EGkSurfTriMeshAux.h"
#include "/EgtDev/Include/EGkRotationMinimizingFrame.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include <thread>
#include <future>
#include <numeric>
// -------------------------- Debug --------------------------------------------
#define DEBUG 0
#define DEBUG_BASIC_BORDERS 0
#define DEBUG_CHAIN_CURVES 0
#define DEBUG_ANG_APPROX 0
@@ -63,11 +63,12 @@
#define DEBUG_EDGES 0
#define DEBUG_SHAPE_STM 0
#define DEBUG_HOLES 0
#define DEBUG_SMOOTH_CURVATURE 0
#if DEBUG_BASIC_BORDERS || DEBUG_CHAIN_CURVES || DEBUG_ANG_APPROX || DEBUG_BEZIER_INTERP || \
DEBUG_FACE_SEARCH || DEBUG_FACE_SEARCH_TRIA_MODIF || DEBUG_BRK_POINTS || DEBUG_BRK_THICK || \
DEBUG_BRK || DEBUG_BORDERS_BY_NORMALS || DEBUG_SYNC_POINTS || DEBUG_SYNC_INTERPOLATION || \
DEBUG_BEZIER_RULED || DEBUG_CURVATURE || DEBUG_SIMPLE_PATCHES || DEBUG_SURF_PATCHES || \
DEBUG_RAW_EDGES || DEBUG_EDGES || DEBUG_SHAPE_STM || DEBUG_HOLES || DEBUG
DEBUG_RAW_EDGES || DEBUG_EDGES || DEBUG_SHAPE_STM || DEBUG_HOLES || DEBUG_SMOOTH_CURVATURE
#include "CurveLine.h"
#include "/EgtDev/Include/EGkGeoObjSave.h"
#include "/EgtDev/Include/EgtPerfCounter.h"
@@ -284,58 +285,6 @@ GetPointSetByAngTol( const PolyLine& PL, double dAngTol, POLYLINEVECTOR& vPL)
return true ;
}
//-----------------------------------------------------------------------------
// Funzione per spezzare una curva compo in diversi tratti in corrispondenza
// di cambi di direzione maggiori della tolleranza angolare passata
static bool
SplitCurveCompoByAngTol( const ICurveComposite* pCC, double dAngTol, ICRVCOMPOPOVECTOR& vCC)
{
int nCurves = pCC->GetCurveCount() ;
vCC.emplace_back( CreateCurveComposite()) ;
vCC.back()->AddCurve( pCC->GetCurve(0)->Clone()) ;
// Cos della tolleranza angolare massima
double dCosTol = cos( dAngTol * DEGTORAD) ;
for ( int nC = 0 ; nC < nCurves - 2; ++ nC) {
// Recupero l'angolo tra la fine della curva corrente e l'inizio della successiva
const ICurve* pCrvCurr = pCC->GetCurve( nC) ;
const ICurve* pCrvNext = pCC->GetCurve( nC + 1) ;
Vector3d vtCurrEnd ; pCrvCurr->GetEndDir( vtCurrEnd) ;
Vector3d vtNextStart ; pCrvNext->GetStartDir( vtNextStart) ;
// Calcolo il Coseno tra i due versori
double dCos = vtCurrEnd * vtNextStart ;
// Se dentro alla tolleranza, allora i punti apparterranno alla stessa curva
if ( dCos > dCosTol) {
// Aggiungo la curva
vCC.back()->AddCurve( pCrvNext->Clone()) ;
}
// Se tratto al di fuori della tolleranza, devo definire una nuova curva
else {
vCC.emplace_back( CreateCurveComposite()) ;
vCC.back()->AddCurve( pCrvNext->Clone()) ;
}
}
// Se curva originale chiusa
if ( pCC->IsClosed() && ssize( vCC) > 1) {
// Se ho più tratti, potrei riunire il primo con l'ultimo
const ICurve* pCrvFirst = pCC->GetCurve( 0) ;
const ICurve* pCrvLast = pCC->GetCurve( nCurves - 1) ;
Vector3d vtFirstStart ; pCrvFirst->GetEndDir( vtFirstStart) ;
Vector3d vtLastEnd ; pCrvLast->GetStartDir( vtLastEnd) ;
// Calcolo il Coseno tra i due versori
double dCos = vtFirstStart * vtLastEnd ;
// Se dentro alla tolleranza, allora i punti appartengono alla stessa curva
if ( dCos > dCosTol) {
// Aggiungo la curva
vCC.back()->AddCurve( Release( vCC.front())) ;
vCC.erase( vCC.begin()) ;
}
}
return true ;
}
////-----------------------------------------------------------------------------
//// Funzione che approssima la curva di bordo per la costruzione della Bezier Ruled mediante
//// Patches di curve di Bezier
@@ -3584,10 +3533,11 @@ IsBorderAButtonHole( const PolyLine& PL, double dLinTol, double dAngTol, Frame3d
//-----------------------------------------------------------------------------
static bool
InterpolateSyncCurvesOnEndGuidePoints( const ICurveComposite* pGuide, const ICurveComposite* pOtherGuide,
const Plane3d& plStart, const Plane3d& plEnd, double dLinTol,
BIPNTVECTOR& vBiPts)
const Plane3d& plStart, const Plane3d& plEnd, const Vector3d vtAuxStart, const Vector3d vtAuxEnd,
double dLinTol, BIPNTVECTOR& vBiPts)
{
vBiPts.clear() ;
const double dLinAngTol = 15 * EPS_SMALL ; // tolleranza sulla lunghezza della corda dell'angolo di tolleranza
// Verifico che le curve siano valide
if ( pGuide == nullptr || ! pGuide->IsValid() ||
@@ -3617,52 +3567,134 @@ InterpolateSyncCurvesOnEndGuidePoints( const ICurveComposite* pGuide, const ICur
// Interpolo le normali dei piani rispetto a tale valore
Vector3d vtN = Media( plStart.GetVersN(), plEnd.GetVersN(), dInterPar) ;
vtN.Normalize() ;
Vector3d vtAux = Media( vtAuxStart, vtAuxEnd, dInterPar) ; vtAux.Normalize() ;
// Definisco il piano di intersezione
Point3d ptCurr ;
if ( ! pCrv->GetEndPoint( ptCurr))
return false ;
// con i piani
#if DEBUG_SYNC_INTERPOLATION
Frame3d frPl ; frPl.Set( ptCurr, vtN) ;
PtrOwner<IGeoFrame3d> frCurr( CreateGeoFrame3d()) ; frCurr->Set( frPl) ;
VT.emplace_back( Release( frCurr)) ;
VC.emplace_back( WHITE) ;
SaveGeoObj( VT, VC, "C:\\Temp\\SyncLinesPlanes.nge") ;
SaveGeoObj( VT, VC, "C:\\Temp\\trimming\\interpolate\\SyncLinesPlanes.nge") ;
#endif
// Recupero il parametro di intersezione tra la curva e il piano
#if 0
VT.clear() ; VC.clear() ;
PtrOwner<IGeoPoint3d> PT( CreateGeoPoint3d()) ; PT->Set( ptCurr) ;
VT.emplace_back( Release( PT)) ;
VC.emplace_back( AQUA) ;
PtrOwner<IGeoVector3d> VECT( CreateGeoVector3d()) ; VECT->Set( vtN) ;
VECT->ChangeBase( ptCurr) ;
PtrOwner<ICurveArc> pArc( CreateCurveArc()) ; pArc->Set( ptCurr, vtN, 1000.) ;
PtrOwner<ISurfFlatRegion> pSfrPlane( CreateSurfFlatRegion()) ;
pSfrPlane->AddExtLoop( Release( pArc)) ;
VT.emplace_back( Release( pSfrPlane)) ;
VC.emplace_back( Color( 0., 0., 0., .5)) ;
VT.emplace_back( Release( VECT)) ;
VC.emplace_back( BLUE) ;
VT.emplace_back( pOtherGuide->Clone()) ;
VC.emplace_back( WHITE) ;
SaveGeoObj( VT, VC, "C:\\Temp\\SyncLinesPlanes.nge") ;
#endif
IntersCurvePlane IntCP( *pOtherGuide, ptCurr, vtN) ;
if ( IntCP.GetIntersCount() == 0)
return false ; // ambiguità
// Recupero il punto della prima intersezione trovata
Point3d ptInt ;
double dPar ;
if ( ! IntCP.GetIntersPointNearTo( ptCurr, ptInt, dPar))
return false ;
#if DEBUG_SYNC_INTERPOLATION
PtrOwner<IGeoPoint3d> ptG( CreateGeoPoint3d()) ; ptG->Set( ptInt) ;
VT.emplace_back( Release( ptG)) ;
VC.emplace_back( WHITE) ;
SaveGeoObj( VT, VC, "C:\\Temp\\SyncLinesPlanes.nge") ;
if ( false) {
VT.clear() ; VC.clear() ;
PtrOwner<IGeoPoint3d> PT( CreateGeoPoint3d()) ; PT->Set( ptCurr) ;
VT.emplace_back( Release( PT)) ;
VC.emplace_back( AQUA) ;
PtrOwner<IGeoVector3d> VECT( CreateGeoVector3d()) ; VECT->Set( vtN) ;
VECT->ChangeBase( ptCurr) ;
PtrOwner<ICurveArc> pArc( CreateCurveArc()) ; pArc->Set( ptCurr, vtN, 1000.) ;
PtrOwner<ISurfFlatRegion> pSfrPlane( CreateSurfFlatRegion()) ;
pSfrPlane->AddExtLoop( Release( pArc)) ;
VT.emplace_back( Release( pSfrPlane)) ;
VC.emplace_back( Color( 0., 0., 0., .5)) ;
VT.emplace_back( Release( VECT)) ;
VC.emplace_back( BLUE) ;
VT.emplace_back( pOtherGuide->Clone()) ;
VC.emplace_back( WHITE) ;
SaveGeoObj( VT, VC, "C:\\Temp\\trimming\\interpolate\\SyncLinesPlanes.nge") ;
}
#endif
// Memorizzo tale punto
vBiPts.emplace_back( make_pair( ptCurr, ptInt)) ;
IntersCurvePlane IntCP( *pOtherGuide, ptCurr, vtN) ;
bool bFound = false ;
if ( IntCP.GetIntersCount() != 0) {
// Recupero il punto della prima intersezione trovata
Point3d ptIntClosest ;
double dPar ;
IntCP.GetIntersPointNearTo( ptCurr, ptIntClosest, dPar) ;
// verifico che sia allineato con la direzione che dovrebbe avere
Vector3d vtDir = ptIntClosest - ptCurr ;
vtDir.Normalize() ;
double dDiff = (vtDir - vtAux).Len() ;
if ( dDiff < dLinAngTol) {
#if DEBUG_SYNC_INTERPOLATION
PtrOwner<IGeoPoint3d> ptG( CreateGeoPoint3d()) ; ptG->Set( ptIntClosest) ;
VT.emplace_back( Release( ptG)) ;
VC.emplace_back( WHITE) ;
SaveGeoObj( VT, VC, "C:\\Temp\\trimming\\interpolate\\SyncLinesPlanes.nge") ;
#endif
//Memorizzo tale punto
vBiPts.emplace_back( make_pair( ptCurr, ptIntClosest)) ;
bFound = true ;
}
else if ( IntCP.GetIntersCount() > 1) {
double dMinDiff = INFINITO ;
Point3d ptBest ;
for ( int j = 0 ; j < IntCP.GetIntersCount() ; ++j) {
IntCrvPlnInfo icpi ; IntCP.GetIntCrvPlnInfo( j, icpi) ;
Point3d ptInt = icpi.Ici->ptI ;
double dDiff = ( ptInt - ptCurr).Len() ;
if ( dDiff < dMinDiff) {
dMinDiff = dDiff ;
ptBest = ptInt ;
}
}
if ( dMinDiff < dLinAngTol)
bFound = true ;
}
}
if ( ! bFound) {
// applico la direzione desiderata nel punto corrente della guida
// calcolo la lunghezza dell'isocurva in quella zona
Point3d ptS1, ptS2 ;
pGuide->GetStartPoint( ptS1) ;
pOtherGuide->GetStartPoint( ptS2);
double dDistRef = Dist( ptS1, ptS2) ;
double dParamOther = -1. ;
int nFlag = -1 ;
Point3d ptEnd = ptCurr + (vtAux * dDistRef) ;
if ( ! DistPointCurve( ptEnd, *pOtherGuide).GetParamAtMinDistPoint( 0, dParamOther, nFlag))
return false ;
// nell'intorno del più vicino, cerco l'isocurva più vicina alla direzione desiderata
Point3d ptBest ;
double dMinDiff = INFINITO ;
double dSearchLen = 3. ;
double dStepLen = 0.1 ;
double dCurrLenOther ; pOtherGuide->GetLengthAtParam( dParamOther, dCurrLenOther) ;
double dLenOther ; pOtherGuide->GetLength( dLenOther) ;
dCurrLenOther -= dSearchLen ;
dCurrLenOther = Clamp( dCurrLenOther, 0., dLenOther) ;
for ( int j = 0 ; j < 2 * dSearchLen / dStepLen ; ++j) {
dCurrLenOther += j * dStepLen ;
if ( dCurrLenOther > dLenOther)
break ;
double dCurrParOther = 0 ; pOtherGuide->GetParamAtLength( dCurrLenOther, dCurrParOther) ;
Point3d ptCurrOther ; pOtherGuide->GetPointD1D2( dCurrParOther, ICurve::FROM_MINUS, ptCurrOther) ;
Vector3d vtDir = ptCurrOther - ptCurr ; vtDir.Normalize() ;
double dDiff = ( vtDir - vtAux).Len() ;
if ( dDiff < dMinDiff) {
dMinDiff = dDiff ;
ptBest = ptCurrOther ;
}
#if DEBUG_SYNC_INTERPOLATION
VT.clear() ;
VC.clear() ;
VT.emplace_back( pGuide->Clone()) ;
VC.emplace_back( BLUE) ;
VT.emplace_back( pOtherGuide->Clone()) ;
VC.emplace_back( BLUE) ;
PtrOwner<IGeoVector3d> vtFirst( CreateGeoVector3d()) ; vtFirst->Set( -vtN * 12, ptCurrOther) ;
VT.emplace_back( Release( vtFirst)) ;
VC.emplace_back( AQUA) ;
PtrOwner<IGeoVector3d> vtCurr( CreateGeoVector3d()) ; vtCurr->Set( -vtDir * 12, ptCurrOther) ;
VT.emplace_back( Release( vtCurr)) ;
VC.emplace_back( WHITE) ;
SaveGeoObj( VT, VC, "C:\\Temp\\trimming\\interpolate\\SyncLinesPlanes.nge") ;
#endif
}
if ( dMinDiff < 2 * dLinAngTol)
vBiPts.emplace_back( make_pair( ptCurr, ptBest)) ;
}
}
return true ;
@@ -3947,8 +3979,8 @@ GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2,
! pCompoEdge1->IsValid() || ! pCompoEdge2->IsValid())
return false ;
// Controllo sulla tolleranza lineare
double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
//// Controllo sulla tolleranza lineare
//double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
#if DEBUG_SYNC_POINTS
VT.clear() ; VC.clear() ;
@@ -3959,26 +3991,26 @@ GetTrimmingSurfBzSyncPoints( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2,
#endif
// Definisco la superficie di Bezier rigata
PtrOwner<SurfBezier> pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuled( pCompoEdge1, pCompoEdge2, ISurfBezier::RLT_B_MINDIST_PLUS, dMyLinTol))) ;
PtrOwner<SurfBezier> pSBzRuled( GetBasicSurfBezier( GetSurfBezierRuledSmooth( pCompoEdge1, pCompoEdge2, vSyncPoints, 20.0))) ;
if ( IsNull( pSBzRuled) || ! pSBzRuled->IsValid())
return false ;
// Recupero i punti di sincronizzazione e li restituisco
ICURVEPOVECTOR vCrv ;
pSBzRuled->GetAllPatchesIsocurves( false, vCrv) ;
vSyncPoints.reserve( vCrv.size()) ;
for ( int i = 0 ; i < ssize( vCrv) ; ++ i) {
if ( ! IsNull( vCrv[i]) && vCrv[i]->IsValid()) {
#if DEBUG_SYNC_POINTS
VT.emplace_back( vCrv[i]->Clone()) ;
VC.emplace_back( LIME) ;
#endif
Point3d ptStart ; vCrv[i]->GetStartPoint( ptStart) ;
Point3d ptEnd ; vCrv[i]->GetEndPoint( ptEnd) ;
if ( ! AreSamePointApprox( ptStart, ptEnd))
vSyncPoints.emplace_back( make_pair( ptStart, ptEnd)) ;
}
}
//// Recupero i punti di sincronizzazione e li restituisco
// ICURVEPOVECTOR vCrv ;
// pSBzRuled->GetAllPatchesIsocurves( false, vCrv) ;
// vSyncPoints.reserve( vCrv.size()) ;
// for ( int i = 0 ; i < ssize( vCrv) ; ++ i) {
// if ( ! IsNull( vCrv[i]) && vCrv[i]->IsValid()) {
// #if DEBUG_SYNC_POINTS
// VT.emplace_back( vCrv[i]->Clone()) ;
// VC.emplace_back( LIME) ;
// #endif
// Point3d ptStart ; vCrv[i]->GetStartPoint( ptStart) ;
// Point3d ptEnd ; vCrv[i]->GetEndPoint( ptEnd) ;
// if ( ! AreSamePointApprox( ptStart, ptEnd))
// vSyncPoints.emplace_back( make_pair( ptStart, ptEnd)) ;
// }
// }
#if DEBUG_SYNC_POINTS
SaveGeoObj( VT, VC, "C:\\Temp\\BorderSyncPoints.nge") ;
@@ -4009,7 +4041,7 @@ GetTrimmingSyncInterpolation( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2,
// Verifico i valori delle tolleranze
double dMyLinTol = Clamp( dLinTol, EPS_SMALL, 1e5 * EPS_SMALL) ;
double dMyAngTol = Clamp( dAngTol, EPS_ANG_SMALL, 60.) ;
//double dMyAngTol = Clamp( dAngTol, EPS_ANG_SMALL, 60.) ;
// Verifico le due curve di sincronizzazione abbiano gli estremi sulle due curve di bordo
Point3d ptS1 ; pSync1->GetStartPoint( ptS1) ;
@@ -4117,18 +4149,18 @@ GetTrimmingSyncInterpolation( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2,
Vector3d vtStart1, vtStart2 ;
if ( ! pCompoGuide1->GetStartDir( vtStart1) || ! pCompoGuide2->GetStartDir( vtStart2))
return false ;
Vector3d vtAux = ptE1 - ptS1 ; vtAux.Normalize() ;
Vector3d vtAuxStart = ptE1 - ptS1 ; vtAuxStart.Normalize() ;
Vector3d vtMTan = Media( vtStart1, vtStart2) ; vtMTan.Normalize() ;
Vector3d vtN = OrthoCompo( vtMTan, vtAux) ; vtN.Normalize() ;
Vector3d vtN = OrthoCompo( vtMTan, vtAuxStart) ; vtN.Normalize() ;
Plane3d plStart ;
if ( ! plStart.Set( ptS1, vtN))
return false ;
Vector3d vtEnd1, vtEnd2 ;
if ( ! pCompoGuide1->GetEndDir( vtEnd1) || ! pCompoGuide2->GetEndDir( vtEnd2))
return false ;
vtAux = ptE2 - ptS2 ; vtAux.Normalize() ;
Vector3d vtAuxEnd = ptE2 - ptS2 ; vtAuxEnd.Normalize() ;
vtMTan = Media( vtEnd1, vtEnd2) ; vtMTan.Normalize() ;
vtN = OrthoCompo( vtMTan, vtAux) ; vtN.Normalize() ;
vtN = OrthoCompo( vtMTan, vtAuxEnd) ; vtN.Normalize() ;
Plane3d plEnd ;
if ( ! plEnd.Set( ptS2, vtN))
return false ;
@@ -4147,13 +4179,15 @@ GetTrimmingSyncInterpolation( const ICurve* pCrvEdge1, const ICurve* pCrvEdge2,
// Curve di Sincronizzazione del Bordo 1 sul Bordo 2
BIPNTVECTOR vBiPts1 ;
if ( ! InterpolateSyncCurvesOnEndGuidePoints( pCompoGuide1, pCompoGuide2, plStart, plEnd, dMyLinTol, vBiPts1))
if ( ! InterpolateSyncCurvesOnEndGuidePoints( pCompoGuide1, pCompoGuide2, plStart, plEnd, vtAuxStart, vtAuxEnd, dMyLinTol, vBiPts1))
return false ;
vtAuxStart *= -1 ;
vtAuxEnd *= -1 ;
// Curve di Sincronizzazione del Bordo 2 sul Bordo 1
BIPNTVECTOR vBiPts2 ;
if ( ! InterpolateSyncCurvesOnEndGuidePoints( pCompoGuide2, pCompoGuide1, plStart, plEnd, dMyLinTol, vBiPts2))
return false ;
//if ( ! InterpolateSyncCurvesOnEndGuidePoints( pCompoGuide2, pCompoGuide1, plStart, plEnd, vtAuxStart, vtAuxEnd, dMyLinTol, vBiPts2))
// return false ;
// Restituisco le Curve di Sincronizzazione
// [Da Bordo 1 a Bordo 2 originale]
@@ -4219,7 +4253,8 @@ GetTrimmingRuledBezier( const CISURFPVECTOR& vSurf, const ICurve* pCrvEdge1,
// Se non ho punti di controllo forzati
if ( vSyncPoints.empty()) {
pSurfBz.Set( GetSurfBezierRuledSmooth( pCompoEdge1, pCompoEdge2, 10)) ;
BIPNTVECTOR vSyncLines ;
pSurfBz.Set( GetSurfBezierRuledSmooth( pCompoEdge1, pCompoEdge2, vSyncLines, 20.0)) ;
if ( IsNull( pSurfBz) || ! pSurfBz->IsValid()) {
LOG_ERROR( GetEGkLogger(), "Error in Trimming : Ruled Bezier invalid") ;
return nullptr ;
@@ -4950,3 +4985,499 @@ GetTrimmingHoleBorders( const CISURFPVECTOR& vpSurf, const Point3d& ptRef, doubl
return true ;
}
struct PntInfo{
Point3d pt ;
double dDist ;
Vector3d vtPos ;
PntInfo( const Point3d& _pt, double _dDist, const Vector3d& _vtPos) :
pt( _pt), dDist( _dDist), vtPos( _vtPos) {;}
};
typedef vector<PntInfo> PNTINFOVECTOR ;
//------------------------------------------------------------------------------
static bool
FillPntInfo( const PNTVECTOR& vPnt, const ICurveComposite* pCC, PNTINFOVECTOR& vPntInfo)
{
for ( int i = 0 ; i < ssize( vPnt) - 3 ; i+=3) {
bool bOk = false ;
const ICurveBezier* pSubCrv = GetCurveBezier( pCC->GetCurve( i / 3)) ;
for ( int j = i == 0 ? 0 : 1 ; j <= 3 ; ++j) {
Point3d pt = pSubCrv->GetControlPoint( j, &bOk) ;
double dDist = 0 ;
Vector3d vtPos = V_NULL ;
if ( j > 0 && j < 3){
DistPointCurve dpc( pt, *pSubCrv) ;
dpc.GetDist( dDist) ;
int nFlag = - 1 ;
Point3d ptMinDist ;
dpc.GetMinDistPoint( 0., ptMinDist, nFlag) ;
vtPos = pt - ptMinDist ;
}
vPntInfo.emplace_back( pt, dDist, vtPos) ;
}
}
return true ;
}
//------------------------------------------------------------------------------
static bool
RemoveInflexionPoints( PNTVECTOR& vPnt, PNTINFOVECTOR& vPntInfo, PNTINFOVECTOR& vPntRefInfo)
{
// se trovo tre punti di fila che sono dallo stesso lato, opposto a quello degli altri punti attorno, allora cerco di spostarli lungo la
// normale alla superficie in modo da evitare cambi di concavità
bool bSameSideAsPrev = true ;
double dSmallDist = 5 * EPS_SMALL ;
for ( int i = 2 ; i < ssize( vPntInfo) - 2 ; ++i) {
// se è un punto di split o sta sulla curva vado avanti
if ( vPntInfo[i].dDist < dSmallDist)
continue ;
int nPrev = vPntInfo[i-1].dDist < EPS_ZERO ? i - 2 : i - 1 ;
double dProj = vPntInfo[i].vtPos * vPntInfo[nPrev].vtPos ;
bSameSideAsPrev = dProj > EPS_ZERO ;
if ( abs(dProj) < EPS_ZERO){
int nPrevPrev = nPrev - 1 ;
dProj = vPntInfo[i].vtPos * vPntInfo[nPrevPrev].vtPos ;
bSameSideAsPrev = dProj > EPS_ZERO ;
}
if ( ! bSameSideAsPrev) {
// devo verificare anche che sia diverso anche dal successivo ( o dal quello dopo ancora, se il successivo sta sulla curva)
bool bCurrOrPrev = vPntInfo[i+1].dDist < EPS_ZERO ;
int nFirst, nSecond, nThird ;
if ( bCurrOrPrev) {
nFirst = i ;
nSecond = i + 1 ;
nThird = i + 2 ;
}
else {
nFirst = i - 2 ;
nSecond = i - 1 ;
nThird = i ;
}
int nNext = bCurrOrPrev ? i + 2 : i + 1 ;
// se il successivo è diverso ho un terzetto anomalo da aggiustare
// altrimenti ho un cambio naturale di concavità
if ( vPntInfo[i].vtPos * vPntInfo[nNext].vtPos < 0 || vPntInfo[nNext].dDist < dSmallDist) {
// ruoto il terzetto fino a matchare la tangente sull'altra curva
// ruoto il punto solo se non stava già esattamente sulla SubCrv ( che suppongo essere un tratto rettilineo)
if ( vPntInfo[nFirst].dDist > dSmallDist) {
Vector3d vtCurr = vPntInfo[nSecond].pt - vPntInfo[nFirst].pt ;
Vector3d vtRef = vPntRefInfo[nSecond].pt - vPntRefInfo[nFirst].pt ;
Vector3d vtAx = vPntRefInfo[nSecond].pt - vPntInfo[nSecond].pt ;
bool bDet = false ;
double dAng = 0 ; vtCurr.GetRotation(vtRef, vtAx, dAng, bDet) ;
if ( abs(dAng) > 170)
dAng = 180 - dAng ;
vPnt[nFirst].Rotate( vPnt[nSecond], vtAx, dAng) ;
}
if ( vPntInfo[nThird].dDist > dSmallDist) {
Vector3d vtCurr = vPntInfo[nThird].pt - vPntInfo[nSecond].pt ;
Vector3d vtRef = vPntRefInfo[nThird].pt - vPntRefInfo[nSecond].pt ;
Vector3d vtAx = vPntRefInfo[nSecond].pt - vPntInfo[nSecond].pt ;
bool bDet = false ;
double dAng = 0 ; vtCurr.GetRotation(vtRef, vtAx, dAng, bDet) ;
if ( abs(dAng) > 170)
dAng = 180 - dAng ;
vPnt[nThird].Rotate( vPnt[nSecond], vtAx, dAng) ;
}
if ( bCurrOrPrev)
i += 2 ;
}
}
}
return true ;
}
// Funzione per la regolarizzazione delle curve di bordo di una lavorazione di trim
// Le curve vengono modificate entro una data tolleranza, in modo che
ISurfBezier*
RegolarizeBordersLocallyRMF( const ISurfBezier* pSurfBz, const BIPOINT& bpIsoStart, const BIPOINT& bpIsoEnd, double dTol)
{
#if DEBUG_SMOOTH_CURVATURE
VT.clear() ;
#endif
// prendo per buone le isocurve di inizio e fine tratto e devo identificare tra loro le isocurve che creano troppo twist e che sono da raddrizzare
Point3d ptS1 = bpIsoStart.first ;
Point3d ptS2 = bpIsoEnd.first ;
Vector3d vtDir1 = bpIsoStart.second - ptS1 ;
Vector3d vtDir2 = bpIsoEnd.second - ptS2 ;
int nDegU, nDegV, nSpanU, nSpanV ;
bool bRat, bTrimmed ;
pSurfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrimmed) ;
if ( nDegU != 3)
return nullptr ;
// individuo quali isocurve sono state indicate come inizio e fine
PtrOwner<ICurveComposite> pCrv1( pSurfBz->GetSingleEdge3D( false, 2)) ;
PtrOwner<ICurveComposite> pCrv2( pSurfBz->GetSingleEdge3D( false, 0)) ;
// inverto la curva corrispondente al bordo 2 della bezier per avere le due guide concordi
pCrv2->Invert() ;
double dParS1 = -1 ; double dParS2 = -1 ;
if ( ! pCrv1->GetParamAtPoint( ptS1, dParS1) || ! pCrv1->GetParamAtPoint( ptS2, dParS2))
return nullptr ;
int nUS1 = int ( dParS1) * nDegU ;
int nUS2 = int ( dParS2) * nDegU ;
if ( nUS1 > nUS2) {
swap( nUS1, nUS2) ;
swap( dParS1, dParS2) ;
swap( ptS1, ptS2) ;
swap( vtDir1, vtDir2) ;
}
PtrOwner<ICurveComposite> pCrvOrig1( ConvertCurveToComposite( pCrv1->CopyParamRange( dParS1, dParS2))) ;
PtrOwner<ICurveComposite> pCrvOrig2( ConvertCurveToComposite( pCrv2->CopyParamRange( dParS1, dParS2))) ;
/////////////////////// versione con RMF
// campiono finemente la prima curva e ottengo il punto che dovrebbe stare sull'altra curva
Vector3d vtTang1 ; pCrvOrig1->GetStartDir( vtTang1) ;
Frame3d frStart1 ; frStart1.Set( ptS1, vtTang1, vtDir1) ; // uso la tangente (come z) e l'isocurva in V (come x) per il frame iniziale
RotationMinimizingFrame rmf ; rmf.Set( pCrvOrig1, frStart1) ;
double dLenTot = 0. ; pCrvOrig1->GetLength( dLenTot) ;
double dStep = dLenTot / ceil( dLenTot) ;
FRAME3DVECTOR vRMF ;
rmf.GetFramesByStep( dStep, true, vRMF) ;
PNTVECTOR vPnt1 ;
PolyLine PL2 ;
double dLenCurr = 0. ;
double dWidth = vtDir1.Len() ;
for ( int i = 0 ; i < ssize( vRMF) ; ++i) {
double dPar ; pCrvOrig1->GetParamAtLength( dLenCurr, dPar) ;
Point3d pt0 ; pCrvOrig1->GetPointD1D2( dPar, ICurve::FROM_MINUS, pt0) ;
Point3d pt1 = pt0 + vRMF[i].VersX() * dWidth ;
vPnt1.push_back( pt1) ;
PL2.AddUPoint( i, pt1) ;
dLenCurr += dStep ;
}
CurveComposite CCToApprox2 ; CCToApprox2.FromPolyLine( PL2) ;
Vector3d vtStart2 ; pCrvOrig2->GetStartDir( vtStart2) ;
Vector3d vtEnd2 ; pCrvOrig2->GetEndDir( vtEnd2) ;
PtrOwner<ICurveComposite> pCC2( ConvertCurveToComposite( ApproxCurveWithBezier( &CCToApprox2, 0.05, vtStart2, vtEnd2))) ;
if ( IsNull( pCC2) || ! pCC2->IsValid())
return nullptr ;
// dalla seconda ricostruisco la prima
Vector3d vtTang2 ; pCC2->GetStartDir( vtTang2) ;
Frame3d frStart2 ; frStart2.Set( bpIsoStart.second, vtTang2, vtDir1) ; // uso la tangente (come z) e l'isocurva in V (come x) per il frame iniziale
RotationMinimizingFrame rmf2 ; rmf2.Set( pCC2, frStart2) ;
double dLenTot2 = 0. ; pCC2->GetLength( dLenTot2) ;
double dStep2 = dLenTot2 / ceil( dLenTot2) ;
FRAME3DVECTOR vRMF2 ;
rmf2.GetFramesByStep( dStep2, true, vRMF2) ;
PNTVECTOR vPnt0 ;
PolyLine PL1 ;
double dLenCurr2 = 0. ;
for ( int i = 0 ; i < ssize( vRMF2) ; ++i) {
double dPar ; pCC2->GetParamAtLength( dLenCurr2, dPar) ;
Point3d pt1 ; pCC2->GetPointD1D2( dPar, ICurve::FROM_MINUS, pt1) ;
Point3d pt0 = pt1 - vRMF2[i].VersX() * dWidth ;
vPnt0.push_back( pt0) ;
PL1.AddUPoint( i, pt0) ;
dLenCurr2 += dStep2 ;
}
CurveComposite CCToApprox1 ; CCToApprox1.FromPolyLine( PL1) ;
Vector3d vtStart1 ; pCrvOrig1->GetStartDir( vtStart1) ;
Vector3d vtEnd1 ; pCrvOrig1->GetEndDir( vtEnd1) ;
PtrOwner<ICurveComposite> pCC1( ConvertCurveToComposite( ApproxCurveWithBezier( &CCToApprox1, 0.05, vtStart1, vtEnd1))) ;
if ( IsNull( pCC1) || ! pCC1->IsValid())
return nullptr ;
#if DEBUG_SMOOTH_CURVATURE
for( int i = 0 ; i < ssize( vPnt1) ; ++i) {
PtrOwner<IGeoPoint3d> pPT( CreateGeoPoint3d()) ; pPT->Set( vPnt1[i]) ;
VT.push_back( Release( pPT)) ;
}
for( int i = 0 ; i < ssize( vPnt0) ; ++i) {
PtrOwner<IGeoPoint3d> pPT( CreateGeoPoint3d()) ; pPT->Set( vPnt0[i]) ;
VT.push_back( Release( pPT)) ;
}
VT.push_back( pCC1->Clone()) ;
VT.push_back( pCC2->Clone()) ;
SaveGeoObj( VT, "C:\\Temp\\bezier\\ruled\\smoothness\\regolarized_RMF.nge") ;
#endif
// controllo di essere rimasto in tolleranza
double dErr = 0 ;
CalcApproxError( pCrvOrig1, pCC1, dErr, 20) ;
if ( dErr > dTol)
return nullptr ;
dErr = 0 ;
CalcApproxError( pCrvOrig2, pCC2, dErr, 20) ;
if ( dErr > dTol)
return nullptr ;
// creo una surf di bezier uguale a quella di partenza, ma a cui cambio la parte da modificare
PtrOwner<SurfBezier> pNewSurf( CreateBasicSurfBezier()) ;
int nNewCrvs = pCC1->GetCurveCount() ;
if ( pCC2->GetCurveCount() != nNewCrvs)
return nullptr ;
int nDiff = nNewCrvs - pCrvOrig1->GetCurveCount() ;
pNewSurf->Init( nDegU, nDegV, nSpanU, nSpanV, bRat) ;
// copio la parte uguale
for ( int i = 0 ; i < nSpanU * nDegU + 1 ; ++i) {
if ( i > nUS1 && i < nUS2)
continue ;
bool bOk = false ;
Point3d pt = pSurfBz->GetControlPoint( i, 0, &bOk) ;
int nNewI = i ;
if ( i > nUS2)
nNewI = i + nDiff ;
pNewSurf->SetControlPoint( nNewI, 0, pt) ;
pt = pSurfBz->GetControlPoint( i, 1, &bOk) ;
pNewSurf->SetControlPoint( nNewI, 1, pt) ;
}
// aggiungo la parte diversa
for ( int i = 0 ; i < nNewCrvs * nDegU + 1 ; ++i) {
int nSub = i / 3 ;
int nPnt = i % 3 ;
if ( nSub == nNewCrvs) {
--nSub ;
nPnt = 3 ;
}
const ICurveBezier* pSubCrv1 = GetCurveBezier( pCC1->GetCurve( nSub)) ;
Point3d pt = pSubCrv1->GetControlPoint( nPnt) ;
int nNewI = i + nUS1 ;
pNewSurf->SetControlPoint( nNewI, 0, pt) ;
const ICurveBezier* pSubCrv2 = GetCurveBezier( pCC2->GetCurve( nSub)) ;
pt = pSubCrv2->GetControlPoint( nPnt) ;
pNewSurf->SetControlPoint( nNewI, 1, pt) ;
}
return Release( pNewSurf) ;
}
//------------------------------------------------------------------------------
// Funzione per la regolarizzazione delle curve di bordo di una lavorazione di trim
// Le curve vengono modificate entro una data tolleranza, in modo che
ISurfBezier*
RegolarizeBordersLocally( const ISurfBezier* pSurfBz, const BIPOINT& bpIsoStart, const BIPOINT& bpIsoEnd, double dTol, int nType)
{
if ( nType == RegolarizeType::RMF)
return RegolarizeBordersLocallyRMF( pSurfBz, bpIsoStart, bpIsoEnd, dTol) ;
#if DEBUG_SMOOTH_CURVATURE
VT.clear() ;
#endif
// prendo per buone le isocurve di inizio e fine tratto e devo identificare tra loro le isocurve che creano troppo twist e che sono da raddrizzare
Point3d ptS1 = bpIsoStart.first ;
Point3d ptS2 = bpIsoEnd.first ;
Vector3d vtDir1 = bpIsoStart.second - ptS1 ;
Vector3d vtDir2 = bpIsoEnd.second - ptS2 ;
//double dInterpolateAngTol = 4 ;
//double dAngInterp = 0 ;
//vtDir1.GetAngle( vtDir2, dAngInterp) ;
//bool bInterpolate = dAngInterp > dInterpolateAngTol ;
int nDegU, nDegV, nSpanU, nSpanV ;
bool bRat, bTrimmed ;
pSurfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrimmed) ;
if ( nDegU != 3)
return nullptr ;
// individuo quali isocurve sono state indicate come inizio e fine
PtrOwner<ICurveComposite> pCrv1( pSurfBz->GetSingleEdge3D( false, 2)) ;
PtrOwner<ICurveComposite> pCrv2( pSurfBz->GetSingleEdge3D( false, 0)) ;
// inverto la curva corrispondente al bordo 2 della bezier per avere le due guide concordi
pCrv2->Invert() ;
double dParS1 = -1 ; double dParS2 = -1 ;
if ( ! pCrv1->GetParamAtPoint( ptS1, dParS1) || ! pCrv1->GetParamAtPoint( ptS2, dParS2))
return nullptr ;
int nUS1 = int ( dParS1) * nDegU ;
int nUS2 = int ( dParS2) * nDegU ;
bool bInverted = false ;
if ( nUS1 > nUS2) {
swap( nUS1, nUS2) ;
swap( dParS1, dParS2) ;
swap( ptS1, ptS2) ;
swap( vtDir1, vtDir2) ;
bInverted = true ;
}
PtrOwner<ICurve> pCrvOrig1( pCrv1->CopyParamRange( dParS1, dParS2)) ;
PtrOwner<ICurve> pCrvOrig2( pCrv2->CopyParamRange( dParS1, dParS2)) ;
double dLen = 0 ; pCrvOrig1->GetLength( dLen) ;
///// versione con correzioni a mano
Point3d ptPrevS = ptS1 ;
Point3d ptPrevE = ! bInverted ? bpIsoStart.second : bpIsoEnd.second ;
Vector3d vtIsoPrev = ptPrevE - ptPrevS ; vtIsoPrev.Normalize() ;
Point3d ptBez ; Vector3d vtNCurr ;
pSurfBz->GetPointNrmD1D2( dParS1, 0.5, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptBez, vtNCurr) ;
int nPoints = ( nUS2 - nUS1) * nDegU + 1 ;
PNTVECTOR vPnt0 ; vPnt0.reserve( nPoints) ; vPnt0.push_back( ptPrevS) ;
PNTVECTOR vPnt1 ; vPnt1.reserve( nPoints) ; vPnt1.push_back( ptPrevE) ;
// salvo il secondo punto di controllo della patch
bool bOk = false ;
Point3d ptSecond1Curr = pSurfBz->GetControlPoint( nUS1 + 1, 0, &bOk) ;
vPnt0.push_back( ptSecond1Curr) ;
Point3d ptSecond2Curr = pSurfBz->GetControlPoint( nUS1 + 1, 1, &bOk) ;
vPnt1.push_back( ptSecond2Curr) ;
// scorro le isocurve di separazione tra patch
for ( int i = nUS1 + 3 ; i < nUS2 ; i +=3) {
// recupero precedente e successivo
Point3d ptThird1Prev = pSurfBz->GetControlPoint( i - 1, 0, &bOk) ;
Point3d ptThird2Prev = pSurfBz->GetControlPoint( i - 1, 1, &bOk) ;
Point3d ptSecond1Next = pSurfBz->GetControlPoint( i + 1, 0, &bOk) ;
Point3d ptSecond2Next = pSurfBz->GetControlPoint( i + 1, 1, &bOk) ;
// recupero corrente e verifico la torsione
Point3d ptCurr1 = pSurfBz->GetControlPoint( i, 0, &bOk) ;
Point3d ptCurr2 = pSurfBz->GetControlPoint( i, 1, &bOk) ;
Vector3d vtIsoCurr = ptCurr2 - ptCurr1 ;
double dDist = vtIsoCurr.Len() ;
vtIsoCurr.Normalize() ;
//Vector3d vtDirPrev = vtIsoPrev ^ vtNPrev ;
Vector3d vtDirCurr = ptSecond1Next - ptCurr1 ; vtDirCurr.Normalize() ;
double dLenCurr = 0 ; pCrvOrig1->GetLengthAtParam( i, dLenCurr) ;
double dCoeff = dLenCurr / dLen ;
Vector3d vtIsoInterp = Media( vtDir1, vtDir2, dCoeff) ; vtIsoInterp.Normalize() ;
bool bDet = false ;
//double dAng = 0 ; vtIsoCurr.GetRotation( vtIsoPrev, vtDirPrev, dAng, bDet) ;
double dAng = 0 ; vtIsoCurr.GetRotation( vtIsoInterp, vtDirCurr, dAng, bDet) ;
vtNCurr = vtDirCurr ^ vtIsoCurr ; vtNCurr.Rotate( vtDirCurr, dAng) ;
double dSinAngTol = sin( 5 * DEGTORAD) ;
Vector3d vtPrev1 = ptCurr1 - ptThird1Prev ; vtPrev1.Normalize() ;
Vector3d vtNext1 = ptSecond1Next - ptCurr1 ; vtNext1.Normalize() ;
bool bAngularPoint1 = ! AreSameVectorEpsilon( vtPrev1, vtNext1, dSinAngTol) ;
Vector3d vtPrev2 = ptCurr2 - ptThird2Prev ; vtPrev2.Normalize() ;
Vector3d vtNext2 = ptSecond2Next - ptCurr2 ; vtNext2.Normalize() ;
bool bAngularPoint2 = ! AreSameVectorEpsilon( vtPrev2, vtNext2, dSinAngTol) ;
if ( abs( dAng) > 0) {
// se l'isocurva di separazione dalla patch successiva è torta rispetto alla precedente
// allora prendo il penultimo punto della curva precedente, il punto di joint e il secondo della prossima e li sposto lungo la normale della superficie
dDist *= dAng * DEGTORAD / 2 ;
if ( ! bAngularPoint1) {
// se non ho un punto angoloso muovo tutto il terzetto insieme
ptThird1Prev -= vtNCurr * dDist ;
ptSecond1Next -= vtNCurr * dDist ;
ptCurr1 -= vtNCurr * dDist ;
}
else {
// altrimenti sposto solo il punto corrente verso la congiungente tra il precedente e il successivo
DistPointLine dpl( ptCurr1, ptThird1Prev, ptSecond1Next, true) ;
Point3d ptMinDist ; dpl.GetMinDistPoint( ptMinDist) ;
Vector3d vtCorrDir = ptMinDist - ptCurr1 ; vtCorrDir.Normalize() ;
double dProjDir = vtNCurr * vtCorrDir ;
if ( dProjDir < 0)
LOG_ERROR( GetEGkLogger(), "Error : regolarizing crv0 near an angular point") ;
double dDistCorr = min( dDist, Dist( ptMinDist, ptCurr1)) ;
ptCurr1 -= vtCorrDir * dDistCorr ;
}
if ( ! bAngularPoint2) {
ptThird2Prev += vtNCurr * dDist ;
ptSecond2Next += vtNCurr * dDist ;
ptCurr2 += vtNCurr * dDist ;
}
else {
// altrimenti sposto solo il punto corrente verso la congiungente tra il precedente e il successivo
DistPointLine dpl( ptCurr2, ptThird2Prev, ptSecond2Next, true) ;
Point3d ptMinDist ; dpl.GetMinDistPoint( ptMinDist) ;
Vector3d vtCorrDir = ptMinDist - ptCurr2 ; vtCorrDir.Normalize() ;
double dProjDir = vtNCurr * vtCorrDir ;
if ( dProjDir < 0)
LOG_ERROR( GetEGkLogger(), "Error : regolarizing crv1 near an angular point") ;
double dDistCorr = min( dDist, Dist( ptMinDist, ptCurr2)) ;
ptCurr2 += vtCorrDir * dDistCorr ;
}
}
vPnt0.push_back( ptThird1Prev) ;
vPnt0.push_back( ptCurr1) ;
vPnt0.push_back( ptSecond1Next) ;
vPnt1.push_back( ptThird2Prev) ;
vPnt1.push_back( ptCurr2) ;
vPnt1.push_back( ptSecond2Next) ;
//vtIsoPrev = ptCurr2 - ptCurr1 ; vtIsoPrev.Normalize() ;
//vtNPrev = ( ptSecond1Next - ptCurr1) ^ vtIsoPrev ; vtNPrev.Normalize() ;
}
// aggiungo gli ultimi due punti
Point3d ptThird1Prev = pSurfBz->GetControlPoint( nUS2 - 1, 0, &bOk) ;
vPnt0.push_back( ptThird1Prev) ;
Point3d ptFourth1Curr = pSurfBz->GetControlPoint( nUS2, 0, &bOk) ;
vPnt0.push_back( ptFourth1Curr) ;
Point3d ptThird2Prev = pSurfBz->GetControlPoint( nUS2 - 1, 1, &bOk) ;
vPnt1.push_back( ptThird2Prev) ;
Point3d ptFourth2Curr = pSurfBz->GetControlPoint( nUS2, 1, &bOk) ;
vPnt1.push_back( ptFourth2Curr) ;
PtrOwner<ICurveComposite> pCC1( CreateCurveComposite()) ;
PtrOwner<ICurveComposite> pCC2( CreateCurveComposite()) ;
for ( int i = 0 ; i < ssize( vPnt0) - 3 ; i+=3) {
PtrOwner<ICurveBezier> cb1( CreateCurveBezier()) ; cb1->Init( 3, false) ;
cb1->SetControlPoint( 0, vPnt0[i]) ;
cb1->SetControlPoint( 1, vPnt0[i+1]) ;
cb1->SetControlPoint( 2, vPnt0[i+2]) ;
cb1->SetControlPoint( 3, vPnt0[i+3]) ;
pCC1->AddCurve( Release( cb1)) ;
PtrOwner<ICurveBezier> cb2( CreateCurveBezier()) ; cb2->Init( 3, false) ;
cb2->SetControlPoint( 0, vPnt1[i]) ;
cb2->SetControlPoint( 1, vPnt1[i+1]) ;
cb2->SetControlPoint( 2, vPnt1[i+2]) ;
cb2->SetControlPoint( 3, vPnt1[i+3]) ;
pCC2->AddCurve( Release( cb2)) ;
}
////// N.B.:dovrei tener conto anche della patch PRECEDENTE e SUCCESSIVA a quelle indicate, altrimenti non vedo se ho creato flessi al bordo della zona
#if DEBUG_SMOOTH_CURVATURE
VT.push_back( pCC1->Clone()) ;
VT.push_back( pCC2->Clone()) ;
SaveGeoObj( VT, "C:\\Temp\\bezier\\ruled\\smoothness\\regolarized_first_step.nge") ;
#endif
// ora verifico l'eventuale presenza di cambi di concavità non desiderati
// se ne trovo su una curva e non sull'altra allora ruoto il terzetto di punti della curva con flesso in modo
// da matchare la tangente dell'altra curva
PNTINFOVECTOR vPntInfo1, vPntInfo2 ;
FillPntInfo( vPnt0, pCC1, vPntInfo1) ;
FillPntInfo( vPnt1, pCC2, vPntInfo2) ;
RemoveInflexionPoints( vPnt0, vPntInfo1, vPntInfo2) ;
RemoveInflexionPoints( vPnt1, vPntInfo2, vPntInfo1) ;
pCC1->Clear() ;
pCC2->Clear() ;
for ( int i = 0 ; i < ssize( vPnt0) - 3 ; i+=3) {
PtrOwner<ICurveBezier> cb1( CreateCurveBezier()) ; cb1->Init( 3, false) ;
cb1->SetControlPoint( 0, vPnt0[i]) ;
cb1->SetControlPoint( 1, vPnt0[i+1]) ;
cb1->SetControlPoint( 2, vPnt0[i+2]) ;
cb1->SetControlPoint( 3, vPnt0[i+3]) ;
pCC1->AddCurve( Release( cb1)) ;
PtrOwner<ICurveBezier> cb2( CreateCurveBezier()) ; cb2->Init( 3, false) ;
cb2->SetControlPoint( 0, vPnt1[i]) ;
cb2->SetControlPoint( 1, vPnt1[i+1]) ;
cb2->SetControlPoint( 2, vPnt1[i+2]) ;
cb2->SetControlPoint( 3, vPnt1[i+3]) ;
pCC2->AddCurve( Release( cb2)) ;
}
// controllo di essere rimasto in tolleranza
double dErr = 0 ;
CalcApproxError( pCrvOrig1, pCC1, dErr, 20) ;
if ( dErr > dTol)
return nullptr ;
CalcApproxError( pCrvOrig2, pCC2, dErr, 20) ;
if ( dErr > dTol)
return nullptr ;
PtrOwner<ISurfBezier> pNewSurf( pSurfBz->Clone()) ;
// aggiorno i punti di controllo della superficie di bezier
for ( int i = 0 ; i < ssize( vPnt0) ; ++i) {
pNewSurf->SetControlPoint( nUS1 + i, 0, vPnt0[i]) ;
pNewSurf->SetControlPoint( nUS1 + i, 1, vPnt1[i]) ;
}
#if DEBUG_SMOOTH_CURVATURE
VT.clear() ;
VT.push_back( Release(pCC1)) ;
VT.push_back( Release(pCC2)) ;
SaveGeoObj( VT, "C:\\Temp\\bezier\\ruled\\smoothness\\regolarized.nge") ;
#endif
return Release( pNewSurf) ;
}
+18 -5
View File
@@ -37,6 +37,19 @@ struct AppliedVector {
int nPropIndex ;
} ;
struct IntersToCheck {
Point3d ptInters ;
Vector3d vtN ;
double dU ;
int nG ;
int nI ;
int nJ ;
IntersToCheck( const Point3d& _ptI, const Vector3d& _vtN, double _dU, int _nG, int _nI, int _nJ) :
ptInters( _ptI), vtN( _vtN), dU( _dU), nG( _nG), nI( _nI), nJ( _nJ) { ;}
};
typedef std::vector<IntersToCheck> INTTOCHECKVEC ;
//----------------------------------------------------------------------------
class VolZmap : public IVolZmap, public IGeoObjRW
{
@@ -84,7 +97,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool Create( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex, int* nError = nullptr) override ;
bool CreateEmpty( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex, int* nError = nullptr) override ;
bool CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double dStep, bool bTriDex, int* nError = nullptr) override ;
bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 0, int* nError = nullptr) override ;
bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 0, int* nError = nullptr, bool bForceClosed = false) override ;
int GetBlockCount( void) const override ;
int GetBlockUpdatingCounter( int nBlock) const override ;
bool GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const override ;
@@ -393,9 +406,6 @@ class VolZmap : public IVolZmap, public IGeoObjRW
double& dU1, double& dU2) const ;
bool GetDepthWithDexel( const Point3d& ptP, const Vector3d& vtDir, double& dInLength, double& dOutLength) const ;
bool GetDepthWithVoxel( const Point3d& ptP, const Vector3d& vtDir, double& dInLength, double& dOutLength) const ;
bool IntersLineCylinder( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& CylFrame, double dH, double dRad, bool bTapLow, bool bTapUp,
Point3d& ptInt1, Vector3d& vtN1, Point3d& ptInt2, Vector3d& vtN2) const ;
bool IntersLineEllipticalCylinder( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& CircFrame, double dRad, double dLongMvLen, double dOrtMvLen,
bool bTapLow, bool bTapUp,
@@ -466,11 +476,14 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool CDeSimpleTorus( const Frame3d& frTorus, double dMaxRad, double dMinRad, bool bPrecise = false) const ;
// Funzione per crezione solido in parallelo
bool CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM, bool bForceClosed) ;
bool AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
bool SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
bool AdjustDexelThroughCracks( int nG, const Vector3d& vtLen, const INTTOCHECKVEC& vIntToCheck, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, const IntersParLinesSurfTm& intPLSTM) ;
DBLDBLVECTOR GetNeighbours( int nG, int nI, int nJ, double dPar) ;
// Funzioni per Offset di superfici
bool InitVolZMapOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ;
bool InitVolZMapThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ;
-121
View File
@@ -2071,127 +2071,6 @@ VolZmap::CDeSurfTm( const ISurfTriMesh& tmSurf, double dSafeDist, bool bPrecise)
return false ;
}
//----------------------------------------------------------------------------
// Riferimento con origine nel centro della base e asse di simmetria coincidente con l'asse Z.
// La funzione restituisce true in caso di intersezione, false altrimenti.
//----------------------------------------------------------------------------
bool
VolZmap::IntersLineCylinder( const Point3d& ptLineSt, const Vector3d& vtLineDir,
const Frame3d& CylFrame, double dH, double dRad, bool bTapLow, bool bTapUp,
Point3d& ptInt1, Vector3d& vtN1, Point3d& ptInt2, Vector3d& vtN2) const
{
// Porto la linea nel riferimento del cilindro
Point3d ptP = GetToLoc( ptLineSt, CylFrame) ;
Vector3d vtV = GetToLoc( vtLineDir, CylFrame) ;
// Determino le eventuali intersezioni con le due basi a quota minima e massima (solo se linea non parallela ad esse)
int nBasInt = 0 ;
if ( abs( vtV.z) > EPS_ZERO) {
// le linee tangenti al cilindro non sono considerate intersecanti
double dEpsRad = ( vtV.IsZeroXY() ? - EPS_SMALL : EPS_SMALL) ;
ptInt1 = ptP + ( ( 0 - ptP.z) / vtV.z) * vtV ;
if ( ptInt1.x * ptInt1.x + ptInt1.y * ptInt1.y < dRad * dRad + 2 * dRad * dEpsRad) {
nBasInt += 1 ;
vtN1 = Z_AX ;
}
ptInt2 = ptP + ( ( dH - ptP.z) / vtV.z) * vtV ;
if ( ptInt2.x * ptInt2.x + ptInt2.y * ptInt2.y < dRad * dRad + 2 * dRad * dEpsRad) {
nBasInt += 2 ;
vtN2 = - Z_AX ;
}
}
// Se la linea interseca entrambe le basi, si sono trovate le due intersezioni
if ( nBasInt == 3) {
// Porto i punti e i versori nel riferimento globale
ptInt1.ToGlob( CylFrame) ;
vtN1.ToGlob( CylFrame) ;
ptInt2.ToGlob( CylFrame) ;
vtN2.ToGlob( CylFrame) ;
// Trovate intersezioni
return true ;
}
// Determino le intersezioni con la superficie laterale del cilindro
DBLVECTOR vdCoeff{ ptP.x * ptP.x + ptP.y * ptP.y - dRad * dRad,
2 * ( ptP.x * vtV.x + ptP.y * vtV.y),
vtV.x * vtV.x + vtV.y * vtV.y} ;
DBLVECTOR vdRoots ;
int nRoot = PolynomialRoots( 2, vdCoeff, vdRoots) ;
// Epsilon per piani di tappo
double dEpsLow = ( bTapLow ? - EPS_SMALL : EPS_SMALL) ;
double dEpsUp = ( bTapUp ? EPS_SMALL : - EPS_SMALL) ;
// Elimino le soluzioni cha danno intersezioni fuori dai limiti in Z del cilindro
if ( nRoot == 2) {
double dIntZ2 = ptP.z + vdRoots[1] * vtV.z ;
if ( dIntZ2 < 0 + dEpsLow || dIntZ2 > dH + dEpsUp)
-- nRoot ;
}
if ( nRoot >= 1) {
double dIntZ1 = ptP.z + vdRoots[0] * vtV.z ;
if ( dIntZ1 < 0 + dEpsLow || dIntZ1 > dH + dEpsUp) {
if ( nRoot == 2)
vdRoots[0] = vdRoots[1] ;
-- nRoot ;
}
}
// Due soluzioni: la retta interseca due volte la superficie laterale
if ( nRoot == 2) {
// Punti di intersezione con la superficie del cilindro
ptInt1 = ptP + vdRoots[0] * vtV ;
ptInt2 = ptP + vdRoots[1] * vtV ;
// Determino le normali
vtN1.Set( -ptInt1.x, -ptInt1.y, 0) ;
vtN1.Normalize() ;
vtN2.Set( -ptInt2.x, -ptInt2.y, 0) ;
vtN2.Normalize() ;
// Porto i punti e i versori nel riferimento globale
ptInt1.ToGlob( CylFrame) ;
vtN1.ToGlob( CylFrame) ;
ptInt2.ToGlob( CylFrame) ;
vtN2.ToGlob( CylFrame) ;
// Trovate intersezioni
return true ;
}
// Una soluzione : la retta interseca la superficie laterale e un piano
else if ( nRoot == 1) {
// Se piano superiore
if ( nBasInt == 2) {
// Punto di intersezione
ptInt1 = ptP + vdRoots[0] * vtV ;
// Normale alla superficie del cilindro verso l'interno
vtN1.Set( -ptInt1.x, -ptInt1.y, 0) ;
vtN1.Normalize() ;
}
// altrimenti piano inferiore
else if ( nBasInt == 1) {
// Punto di intersezione
ptInt2 = ptP + vdRoots[0] * vtV ;
// Normale alla superficie del cilindro verso l'interno
vtN2.Set( -ptInt2.x, -ptInt2.y, 0) ;
vtN2.Normalize() ;
}
// altrimenti niente
else
return false ;
// Porto i punti e i versori nel riferimento globale
ptInt1.ToGlob( CylFrame) ;
vtN1.ToGlob( CylFrame) ;
ptInt2.ToGlob( CylFrame) ;
vtN2.ToGlob( CylFrame) ;
// Trovate intersezioni
return true ;
}
// Nessuna soluzione : nessuna intersezione
else
return false ;
}
//----------------------------------------------------------------------------
// Riferimento con origine nel vertice del cono e asse di simmetria coincidente con l'asse Z.
// La funzione restituisce true in caso di intersezione, false altrimenti.
+361 -10
View File
@@ -19,6 +19,7 @@
#include "GeoConst.h"
#include "/EgtDev/Include/EGkStmFromCurves.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
#include "/EgtDev/Include/EGkIntersLinePlane.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include <future>
@@ -542,7 +543,7 @@ VolZmap::CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double
//----------------------------------------------------------------------------
bool
VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM)
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM, bool bForceClosed)
{
if ( nMap < 0 || nMap > 2 ||
nInfI < 0 || nInfI > m_nNx[nMap] ||
@@ -553,6 +554,8 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
double dCosSmall = sin( EPS_ANG_SMALL * DEGTORAD) ;
INTTOCHECKVEC vIntToCheck ;
// Determinazione e ridimensionamento dei dexel interni alla trimesh
for ( int i = nInfI ; i < nSupI ; ++ i) {
for ( int j = nInfJ ; j < nSupJ ; ++ j) {
@@ -584,6 +587,14 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
int nInt = int( IntersectionResults.size()) ;
if ( nInt == 1) {
int nT = IntersectionResults[0].nT ;
int nF = Surf.GetFacetFromTria( nT) ;
Vector3d vtN ; Surf.GetFacetNormal( nF, vtN) ;
vIntToCheck.emplace_back( IntersectionResults[0].ptI, vtN, IntersectionResults[0].dU, nMap, i, j) ;
continue ;
}
int nPos = j * m_nNx[nMap] + i ;
bool bInside = false ;
@@ -592,6 +603,14 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
for ( int k = 0 ; k < nInt ; ++ k) {
if ( k > 0) {
int z = k - 1 ;
// controllo se l'intersezione corrente è coincidente con la precedente, per esempio se ILTT == 4 ( intersezione su un lato di un triangolo, quindi con 2 triangoli)
if ( IntersectionResults[k].dU - IntersectionResults[z].dU < EPS_SMALL &&
IntersectionResults[k].dCosDN - IntersectionResults[z].dCosDN < EPS_SMALL)
continue ;
}
int nIntType = IntersectionResults[k].nILTT ;
// Se c'è intersezione
@@ -601,7 +620,12 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
// entro nella superficie trimesh
if ( dCos < - dCosSmall) {
if ( bInside) {
// salvo la precedente, perché vuol dire che manca la sua uscita
// poi procedo con l'intersezione corrente
int z = k - 1 ;
vIntToCheck.emplace_back( IntersectionResults[z].ptI, vtInN, IntersectionResults[z].dU, nMap, i, j) ;
}
ptIn = IntersectionResults[k].ptI ;
int nT = IntersectionResults[k].nT ;
@@ -613,8 +637,7 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
}
// esco dalla superficie trimesh
else if ( dCos > dCosSmall && bInside) {
else if ( dCos > dCosSmall) {
Point3d ptOut = IntersectionResults[k].ptI ;
int nT = IntersectionResults[k].nT ;
@@ -623,6 +646,13 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
Vector3d vtOutN ;
Surf.GetFacetNormal( nF, vtOutN) ;
if ( ! bInside) {
// se l'intersezione è uscente, ma non ho un'entrata allora devo salvare l'intersezione corrente, perché è andata persa la sua entrata
// procedo poi con la prossima intersezione
vIntToCheck.emplace_back( IntersectionResults[k].ptI, vtOutN, IntersectionResults[k].dU, nMap, i, j) ;
continue ;
}
int nCurrentSize = int( m_Values[nMap][nPos].size()) ;
// Aggiungo un tratto al dexel
@@ -643,6 +673,12 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
}
}
}
if ( bForceClosed) {
if ( ! AdjustDexelThroughCracks( nMap, vtLen, vIntToCheck, ptMapOrig, Surf, intPLSTM))
return false ;
}
return true ;
}
@@ -834,11 +870,14 @@ VolZmap::SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ,
//----------------------------------------------------------------------------
bool
VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox, int* nError)
VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox, int* nError, bool bForceClosed)
{
// Se la superficie non è chiusa oppure orientata al contrario non ha senso continuare
double dVol ;
if ( ! Surf.IsClosed() || ! Surf.GetVolume( dVol) || dVol < 0)
if ( ( ! Surf.IsClosed() || ! Surf.GetVolume( dVol) || dVol < 0) && ! bForceClosed)
return false ;
if ( bForceClosed && ! bTriDex)
return false ;
// Assegno la dimensione della mappa 1 o 3
@@ -940,7 +979,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
IntersParLinesSurfTm intPLSTM( frMapFrame, Surf) ;
// Standarda è multithread
constexpr bool MULTITHREAD = true ;
constexpr bool MULTITHREAD = false ;
if ( MULTITHREAD) {
// Numero massimo di thread
@@ -956,7 +995,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG,
nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM)) ;
nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM), bForceClosed) ;
}
}
else {
@@ -968,7 +1007,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG,
0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM)) ;
0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM), bForceClosed) ;
}
}
@@ -987,7 +1026,7 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
// !!!! NON MULTITHREAD : SOLO PER DEBUG !!!!
else {
CreateMapPart( nG, 0, m_nNx[nG], 0, m_nNy[nG], vtLen, ptMapOrig, Surf, intPLSTM) ;
CreateMapPart( nG, 0, m_nNx[nG], 0, m_nNy[nG], vtLen, ptMapOrig, Surf, intPLSTM, bForceClosed) ;
}
}
@@ -1008,3 +1047,315 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
return bCompleted ;
}
DBLDBLVECTOR
VolZmap::GetNeighbours( int nG, int nI, int nJ, double dPar)
{
DBLDBLVECTOR vNeigh ;
// parto da in basso a sinistra e procedo per righe, saltando il punto corrente
if ( nI > 0 && nJ > 0)
vNeigh.emplace_back( nI - dPar, nJ - dPar) ;
if ( nJ > 0) {
vNeigh.emplace_back( nI, nJ - dPar) ;
if ( nI < m_nNx[nG] - dPar)
vNeigh.emplace_back( nI + dPar, nJ - dPar) ;
}
// passo alla fila contenente il punto corrente
if ( nI > 0)
vNeigh.emplace_back( nI - dPar, nJ) ;
if ( nI < m_nNx[nG] - dPar)
vNeigh.emplace_back( nI + dPar, nJ) ;
// passo alla fila successiva a quella del corrente
if ( nJ < m_nNy[nG] - dPar) {
if ( nI > 0)
vNeigh.emplace_back( nI - dPar, nJ + dPar) ;
vNeigh.emplace_back( nI, nJ + dPar) ;
if ( nI < m_nNx[nG])
vNeigh.emplace_back( nI + dPar, nJ + dPar) ;
}
return vNeigh ;
}
//----------------------------------------------------------------------------
bool
VolZmap::AdjustDexelThroughCracks( int nG, const Vector3d& vtLen, const INTTOCHECKVEC& vIntToCheck, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, const IntersParLinesSurfTm& intPLSTM)
{
double dAngSameFace = 45 ;
double dCosSmall = sin( EPS_ANG_SMALL * DEGTORAD) ;
// per ogni intersezione segnalata devo cercare sugli spilloni vicini l'intervallo con l'estremo più vicino a questa intersezione
// e usare l'altro estremo, insieme a quello degli altri spilloni vicini, per estrapolare quello mancante sullo spillone corrente
Vector3d vtAx ;
if ( nG == 0)
vtAx = Z_AX ;
else if ( nG == 1)
vtAx = X_AX ;
else if ( nG == 2)
vtAx = Y_AX ;
for ( const auto& itc : vIntToCheck) {
int nPos = itc.nJ * m_nNx[nG] + itc.nI ;
double dPosRef = itc.ptInters.v[( nG + 2) % 3] ;
// controllo se esiste già un intervallo con un estremo quasi coincidente a quello segnalato
// ed entrambi sono entrate o uscite
bool bNeedToReconstruct = true ;
for ( const auto& data: m_Values[nG][nPos]) {
if ( (( abs( dPosRef - data.dMin) < 10 * EPS_SMALL && ( itc.vtN * vtAx) * ( data.vtMinN * vtAx) > 0)) ||
(( abs( dPosRef - data.dMax) < 10 * EPS_SMALL && ( itc.vtN * vtAx) * ( data.vtMaxN * vtAx) > 0))) {
bNeedToReconstruct = false ;
break ;
}
}
if ( ! bNeedToReconstruct)
continue ;
DBLDBLVECTOR vNeigh = GetNeighbours( nG, itc.nI, itc.nJ, m_dStep) ;
PNTVECTOR vNeighInters ;
Vector3d vtMeanN = V_NULL ;
bool bSearchingInOrOut = itc.vtN * vtAx > 0 ;
bool bUseNeighInfo = true ;
for ( const auto& [i,j] : vNeigh) {
double dMinDist = INFINITO ;
double dCorrespInters = INFINITO ;
double dNearestPos = NAN ;
Vector3d vtNearestN ;
int nNeighPos = int( j) * m_nNx[nG] + int( i) ;
for ( const auto& data: m_Values[nG][nNeighPos]) {
double dDist1 = abs( dPosRef - data.dMin) ;
double dDist2 = abs( dPosRef - data.dMax) ;
if ( dDist1 < dMinDist || dDist2 < dMinDist) {
dMinDist = min( dDist1, dDist2) ;
// se sto cercando un ingresso
if ( bSearchingInOrOut) {
if ( data.vtMaxN * vtAx < 0) {
dNearestPos = data.dMax ;
vtNearestN = data.vtMaxN ;
dCorrespInters = data.dMin ;
}
else if ( data.vtMinN * vtAx < 0) {
dNearestPos = data.dMin ;
vtNearestN = data.vtMinN ;
dCorrespInters = data.dMax ;
}
}
// se sto cercando un'uscita
else {
if ( data.vtMaxN * vtAx > 0) {
dNearestPos = data.dMax ;
vtNearestN = data.vtMaxN ;
dCorrespInters = data.dMin ;
}
else if ( data.vtMinN * vtAx > 0) {
dNearestPos = data.dMin ;
vtNearestN = data.vtMinN ;
dCorrespInters = data.dMax ;
}
}
}
}
// verifico che il dNearestPos sia effettivamente associato al tratto che sto cercando di ricostruire
// e non ad un altro presente sullo spillone corrente
bool bAddNearest = true ;
for ( const auto& data: m_Values[nG][nPos]) {
double dDist1 = abs( dCorrespInters - data.dMin) ;
double dDist2 = abs( dCorrespInters - data.dMax) ;
if ( dDist1 < dMinDist || dDist2 < dMinDist) {
bAddNearest = false ;
break ;
}
}
if ( bAddNearest && isfinite( dNearestPos)) {
// controllo anche che i punti non siano troppo lontani tra loro, altrimenti
// il piano calcolato potrebbe essere una media troppo grezza
double dMaxDist = 3 * m_dStep ;
const bool bTooFar = any_of( vNeighInters.begin(), vNeighInters.end(),
[ dNearestPos, dMaxDist]( const Point3d& pt) {
return abs( pt.z - dNearestPos) > dMaxDist ;
}) ;
double dAng ;
if ( ! bTooFar) {
// controllo anche che gli angoli delle normali non cambino troppo
// calcolo l'angolo con la media delle precedenti perché il valore oltre cui
// considero le normali diverse è grande
vtNearestN.GetAngle( vtMeanN, dAng) ;
}
bAddNearest = ! bTooFar && dAng < dAngSameFace ;
if ( bAddNearest) {
double dX = ( i + 0.5) * m_dStep ;
double dY = ( j + 0.5) * m_dStep ;
vNeighInters.emplace_back( dX, dY, dNearestPos) ;
vtMeanN += vtNearestN ;
}
else {
bUseNeighInfo = false ;
break ;
}
}
}
Point3d ptInt ;
// se riesco uso i vicini per calcolare l'intersezione mancante
if ( bUseNeighInfo) {
// se non ci sono almeno tre punti, non allineati, non riesco a determinare il piano con cui tagliare lo spillone
if ( ssize( vNeighInters) < 3)
continue ;
else if ( ssize( vNeighInters) == 3){
// verifico che non siano allineati
if ( ( vNeighInters[0].x == vNeighInters[1].x && vNeighInters[0].x == vNeighInters[1].x) ||
( vNeighInters[0].y == vNeighInters[1].y && vNeighInters[0].y == vNeighInters[1].y))
continue ;
}
// se sono più di tre sicuramente non sono allieanti, visto che sono intorno allo spillone corrente
vtMeanN.Normalize() ;
Plane3d plLoc ;
PolyLine PL ; PL.FromPointVector( vNeighInters) ;
PL.IsFlat( plLoc, INFINITO) ;
// porto anche il punto dell'intersezione nel frame della griglia
Point3d ptKnown = itc.ptInters ;
Frame3d frGrid ;
if ( nG == 0)
frGrid.Set( ORIG, Frame3d::TOP) ;
else if ( nG == 1)
frGrid.Set( ORIG, Frame3d::RIGHT) ;
else if ( nG == 2)
frGrid.Set( ORIG, Z_AX, X_AX, Y_AX) ;
ptKnown.ToLoc( frGrid) ;
IntersLinePlane( ptKnown, Z_AX, INFINITO, plLoc, ptInt, false) ;
}
// altrimenti sposto di poco lo spillone e ricalcolo le intersezioni con la superficie, finché trovo l'intersezione mancante
else {
bool bFound = false ;
DBLVECTOR vSmallStep ;
vSmallStep.push_back( Clamp( 0.05 * m_dStep, 50 * EPS_SMALL, 1.)) ;
vSmallStep.push_back( Clamp( 0.2 * m_dStep, 50 * EPS_SMALL, 1.)) ;
// ciclo una raggiera di spilloni ( a distanza inferiore allo m_dStep) attorno allo spillone
// appena trova un'intersezione buona mi fermo
// se ciclando la raggiera non trovo un'intersezione valida allora potrei essermi spostato troppo poco dallo spillone originale e essere caduto ancora nella fessura
// quindi ciclo nuovamente aumentando un poco la distanza dallo spillone originale ( comunque sempre meno della distanza m_dStep)
for ( int c = 0 ; c < ssize( vSmallStep) ; ++c) {
DBLDBLVECTOR vSmallMoveNeigh = GetNeighbours( nG, itc.nI, itc.nJ, vSmallStep[c]) ;
for ( int n = 0 ; n < 8 ; ++n) {
double dX = ( vSmallMoveNeigh[n].first + 0.5) * m_dStep ;
double dY = ( vSmallMoveNeigh[n].second + 0.5) * m_dStep ;
Point3d ptP0( dX, dY, 0) ;
ILSIVECTOR IntersectionResults ;
intPLSTM.GetInters( ptP0, vtLen.v[(nG+2)%3], IntersectionResults) ;
// intervalli dalle intersezioni
vector<Data> vNewIntervals ;
bool bInside = false ;
Vector3d vtInN ;
Point3d ptIn ;
for ( int i = 0 ; i < ssize( IntersectionResults) ; ++i) {
// Se c'è intersezione
if ( IntersectionResults[i].nILTT != ILTT_NO) {
if ( i > 0) {
int z = i - 1 ;
// controllo se l'intersezione corrente è coincidente con la precedente, per esempio se ILTT == 4 ( intersezione su un lato di un triangolo, quindi con 2 triangoli)
if ( IntersectionResults[i].dU - IntersectionResults[z].dU < EPS_SMALL &&
IntersectionResults[i].dCosDN - IntersectionResults[z].dCosDN < EPS_SMALL)
continue ;
}
double dCos = IntersectionResults[i].dCosDN ;
// entro nella superficie trimesh
if ( dCos < - dCosSmall) {
ptIn = IntersectionResults[i].ptI ;
int nT = IntersectionResults[i].nT ;
int nF = Surf.GetFacetFromTria( nT) ;
Surf.GetFacetNormal( nF, vtInN) ;
bInside = true ;
}
// esco dalla superficie trimesh
else if ( dCos > dCosSmall && bInside) {
Point3d ptOut = IntersectionResults[i].ptI ;
int nT = IntersectionResults[i].nT ;
int nF = Surf.GetFacetFromTria( nT) ;
Vector3d vtOutN ;
Surf.GetFacetNormal( nF, vtOutN) ;
// Aggiungo un tratto al dexel
vNewIntervals.emplace_back() ;
// Aggiorno dati del tratto di dexel
vNewIntervals.back().dMin = ptIn.v[(nG+2)%3] - ptMapOrig.v[(nG+2)%3] ;
vNewIntervals.back().dMax = ptOut.v[(nG+2)%3] - ptMapOrig.v[(nG+2)%3] ;
vNewIntervals.back().vtMinN = vtInN ;
vNewIntervals.back().vtMaxN = vtOutN ;
vNewIntervals.back().nToolMin = 0 ;
vNewIntervals.back().nToolMax = 0 ;
vNewIntervals.back().nCompo = 0 ;
bInside = false ;
}
}
}
// controllo che abbia un intervallo in più rispetto a quelli di prima
if ( ssize( vNewIntervals) == ssize( m_Values[nG][nPos]) + 1) {
// dovrei verificare che quello in più sia effettivamente quello ricercato????
double dMinDist = INFINITO ;
for ( const auto& data : vNewIntervals) {
if ( abs( data.dMin - dPosRef) < dMinDist) {
dMinDist = abs( data.dMin - dPosRef) ;
ptInt.Set( itc.nI + 0.5, itc.nJ + 0.5, data.dMax) ;
vtMeanN = data.vtMaxN ;
bFound = true ;
}
if ( abs( data.dMax - dPosRef) < dMinDist) {
dMinDist = abs( data.dMax - dPosRef) ;
ptInt.Set( itc.nI + 0.5, itc.nJ + 0.5, data.dMin) ;
vtMeanN = data.vtMinN ;
bFound = true ;
}
}
}
if ( bFound)
break ;
}
if ( bFound)
break ;
}
// se cercando nei d'intorni dello spillone non ho trovato l'intersezione mancante, mi arrendo
if ( ! bFound)
continue ;
}
double dMin, dMax ;
Vector3d vtMinN, vtMaxN ;
if ( itc.dU < ptInt.z) {
dMin = itc.dU ;
dMax = ptInt.z ;
vtMinN = itc.vtN ;
vtMaxN = vtMeanN ;
}
else {
dMin = ptInt.z ;
dMax = itc.dU ;
vtMinN = vtMeanN ;
vtMaxN = itc.vtN ;
}
//// prima di aggiungere il tratto verifico che non si sovrapponga con un tratto già presente
//for ( const auto& data: m_Values[nG][nPos]) {
// if ( ( dMin > data.dMin && dMin < data.dMax) ||
// ( dMax > data.dMin && dMax < data.dMax) ||
// ( dMin < data.dMin && dMax > data.dMax))
// continue ;
//}
m_Values[nG][nPos].emplace_back() ;
m_Values[nG][nPos].back().dMin = dMin;
m_Values[nG][nPos].back().dMax = dMax ;
m_Values[nG][nPos].back().vtMinN = vtMinN ;
m_Values[nG][nPos].back().vtMaxN = vtMaxN ;
m_Values[nG][nPos].back().nToolMin = 0 ;
m_Values[nG][nPos].back().nToolMax = 0 ;
m_Values[nG][nPos].back().nCompo = 0 ;
std::sort( m_Values[nG][nPos].begin(), m_Values[nG][nPos].end(), []( Data& a, Data& b) { return a.dMin < b.dMin ;}) ;
}
return true ;
}
+6 -4
View File
@@ -21,6 +21,7 @@
#include "CurveLine.h"
#include "CurveArc.h"
#include "GeoConst.h"
#include "IntersLineCyl.h"
#include "/EgtDev/Include/EGkStmFromCurves.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
#include "/EgtDev/Include/EgtNumUtils.h"
@@ -968,12 +969,13 @@ VolZmap::CreateOffsetCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, d
Point3d ptC( ( i + 0.5) * m_dStep, ( j + 0.5) * m_dStep, 0) ;
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dH, abs( dOffs), true, true,
ptInt1, vtN1, ptInt2, vtN2)) {
double dU1, dU2 ;
if ( IntersLineCyl( ptC, Z_AX, CylFrame, dH, abs( dOffs), true, true,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, false)) {
if ( dOffs > 0.)
AddIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, -vtN1, -vtN2, nTool, nTool) ;
AddIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nTool, nTool) ;
else
SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nTool) ;
SubtractIntervalsForOffset( nGrid, i, j, ptInt1.z, ptInt2.z, -vtN1, -vtN2, nTool) ;
}
}
}
+33 -17
View File
@@ -21,6 +21,7 @@
#include "VolZmap.h"
#include "GeoConst.h"
#include "IntersLineBox.h"
#include "IntersLineCyl.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGkSurfBezier.h"
@@ -1770,6 +1771,8 @@ VolZmap::Comp_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, c
if ( bInverse)
nTotSurf += 4 ;
if ( bSmallMovement)
nTotSurf += 2 ;
int nSurfInd = 0 ;
vector<SurfBezForInters> vSurfBez( nTotSurf) ;
@@ -2607,7 +2610,15 @@ VolZmap::MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, co
// Calcolo angoli di rotazione utensile longitudinale e trasversale rispetto al movimento per eventuale suddivisione
double dAlongAngDeg, dAcrossAngDeg ;
GetAlongAcrossRotation( vtDs, vtDe, ptPe - ptPs, dAlongAngDeg, dAcrossAngDeg) ;
if ( m_vTool[m_nCurrTool].GetRadius() < 40)
GetAlongAcrossRotation( vtDs, vtDe, ptPe - ptPs, dAlongAngDeg, dAcrossAngDeg) ;
else {
// se è una lama uso un asse diverso per calcolare le rotaziona del vettore tool
Vector3d vtAxis = vtDs ^ vtDe ;
GetAlongAcrossRotation( vtDs, vtDe, vtAxis, dAlongAngDeg, dAcrossAngDeg) ;
swap( dAlongAngDeg, dAcrossAngDeg) ;
}
// Calcolo numero degli step di movimento
int nStepCnt = int( max( { abs( dAlongAngDeg) / ANG_ALONG_STEP, abs( dAcrossAngDeg) / ANG_ACROSS_STEP, 1.})) ;
@@ -2716,7 +2727,7 @@ VolZmap::MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, co
InitializePointsAndVectors( ptSti, ptEni, vtDSi, vtDEi, ptLs, ptLe, vtLs, vtLe) ;
// Standard è multithread
constexpr bool MULTITHREAD = false ;
constexpr bool MULTITHREAD = true ;
if ( MULTITHREAD) {
// Ciclo sulle mappe
vector<future<bool>> vRes( m_nMapNum) ;
@@ -6247,7 +6258,8 @@ VolZmap::CompCyl_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, co
Point3d ptC( ( i + 0.5) * m_dStep, ( j + 0.5) * m_dStep, 0) ;
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dH, dRad, bTapB, bTapT, ptInt1, vtN1, ptInt2, vtN2)) {
double dU1, dU2 ;
if ( IntersLineCyl( ptC, Z_AX, CylFrame, dH, dRad, bTapB, bTapT, dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, true)) {
SubtractIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nToolNum) ;
}
}
@@ -6292,8 +6304,9 @@ VolZmap::CompConus_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE,
Vector3d vtN1, vtN2 ;
// Cilindro
if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dH, dMaxRad, true, bTapT,
ptInt1, vtN1, ptInt2, vtN2)) {
double dU1, dU2 ;
if ( IntersLineCyl( ptC, Z_AX, CylFrame, dH, dMaxRad, true, bTapT,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, true)) {
SubtractIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nToolNum) ;
}
@@ -6472,7 +6485,8 @@ VolZmap::CompCyl_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE,
// Cilindro iniziale
CylFrame.ChangeOrig( ptITip) ;
if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dHei, dRad, bTapB, bTapT, ptInt1, vtN1, ptInt2, vtN2)) {
double dU1, dU2 ;
if ( IntersLineCyl( ptC, Z_AX, CylFrame, dHei, dRad, bTapB, bTapT, dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, true)) {
SubtractIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nToolNum) ;
}
@@ -6480,7 +6494,7 @@ VolZmap::CompCyl_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE,
// del sistema di riferimento, quindi usiamo lo stesso sistema sommando a ptC
// il vettore che congiunge le due origini.
CylFrame.ChangeOrig( ptITip + vtMove) ;
if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dHei, dRad, bTapB, bTapT, ptInt1, vtN1, ptInt2, vtN2)) {
if ( IntersLineCyl( ptC, Z_AX, CylFrame, dHei, dRad, bTapB, bTapT, dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, true)) {
SubtractIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nToolNum) ;
}
@@ -7067,7 +7081,8 @@ VolZmap::CompBall_Milling( int nGrid, const Point3d& ptLs, const Point3d& ptLe,
// Cilindro inviluppo della sfera
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dLengthPath, dRad, false, false, ptInt1, vtN1, ptInt2, vtN2)) {
double dU1, dU2 ;
if ( IntersLineCyl( ptC, Z_AX, CylFrame, dLengthPath, dRad, false, false, dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, true)) {
SubtractIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, nToolNum) ;
}
}
@@ -7215,15 +7230,15 @@ VolZmap::AddingCylinder( int nGrid, const Point3d& ptS, const Point3d& ptE, cons
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dHei, dRad, true, true,
ptInt1, vtN1, ptInt2, vtN2)) {
AddIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, - vtN1, - vtN2, CurrTool.GetToolNum()) ;
double dU1, dU2 ;
if ( IntersLineCyl( ptC, Z_AX, CylFrame, dHei, dRad, true, true,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, false)) {
AddIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, CurrTool.GetToolNum()) ;
}
if ( IntersLineCylinder( ptC - dLen1 * vtV1, Z_AX, CylFrame, dHei, dRad, true, true,
ptInt1, vtN1, ptInt2, vtN2)) {
AddIntervals( nGrid, i, j, ptInt1.z + dLen1 * vtV1.z, ptInt2.z + dLen1 * vtV1.z, - vtN1, - vtN2, CurrTool.GetToolNum()) ;
if ( IntersLineCyl( ptC - dLen1 * vtV1, Z_AX, CylFrame, dHei, dRad, true, true,
dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, false)) {
AddIntervals( nGrid, i, j, ptInt1.z + dLen1 * vtV1.z, ptInt2.z + dLen1 * vtV1.z, vtN1, vtN2, CurrTool.GetToolNum()) ;
}
if ( IntersLineMyPolyhedron( ptC, Z_AX, PolyFrame, dLen1, 2 * ( dRad + dMyTol), dHei + 2 * dMyTol, 0,
@@ -7619,8 +7634,9 @@ VolZmap::AddingSphere( int nGrid, const Point3d& ptS, const Point3d& ptE, double
// Cilindro inviluppo della sfera
Point3d ptInt1, ptInt2 ;
Vector3d vtN1, vtN2 ;
if ( IntersLineCylinder( ptC, Z_AX, CylFrame, dLengthPath, dRad, false, false, ptInt1, vtN1, ptInt2, vtN2)) {
AddIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, - vtN1, - vtN2, CurrTool.GetToolNum()) ;
double dU1, dU2 ;
if ( IntersLineCyl( ptC, Z_AX, CylFrame, dLengthPath, dRad, false, false, dU1, ptInt1, vtN1, dU2, ptInt2, vtN2, false, false)) {
AddIntervals( nGrid, i, j, ptInt1.z, ptInt2.z, vtN1, vtN2, CurrTool.GetToolNum()) ;
}
}
}
+91 -6
View File
@@ -434,6 +434,7 @@ Voronoi::GetBisectorCurve( int i)
pLine->Set( ptS, ptE) ;
pLine->SetTempParam( dParS, 0) ;
pLine->SetTempParam( dParE, 1) ;
pLine->SetTempProp( i) ;
pLine->ToGlob( m_Frame) ;
return pLine ;
}
@@ -454,6 +455,7 @@ Voronoi::GetBisectorCurve( int i)
pArc->SetC2P( ptC, ptS, ptE) ;
pArc->SetTempParam( dParS, 0) ;
pArc->SetTempParam( dParS, 1) ; // dParE = dParS
pArc->SetTempProp( i) ;
pArc->ToGlob( m_Frame) ;
return pArc ;
}
@@ -473,7 +475,7 @@ Voronoi::GetBisectorCurve( int i)
bool bInvert = false ;
double dPar1, dPar2 ;
m_vroni->GetApproxedBisectorParams( i, dPar1, dPar2) ;
if ( dPar1 > dPar2 + EPS_SMALL)
if ( dPar1 > dPar2)
bInvert = true ;
// punto iniziale
@@ -496,6 +498,11 @@ Voronoi::GetBisectorCurve( int i)
dParPrev = dPar ;
nCrvCount ++ ;
}
else if ( ( bInvert && j == 0) || ( ! bInvert && j == nPoints - 1)) {
// se estremo devo forzarlo
pCompo->ModifyEnd( pt) ;
dParPrev = dPar ;
}
// aggiorno per punto successivo
if ( bInvert)
j -- ;
@@ -506,6 +513,7 @@ Voronoi::GetBisectorCurve( int i)
// setto parametri sulla curva
pCompo->SetTempParam( dParS, 0) ;
pCompo->SetTempParam( dParPrev, 1) ;
pCompo->SetTempProp( i) ;
pCompo->ToGlob( m_Frame) ;
return pCompo ;
@@ -700,8 +708,8 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs)
// se necessario verifico se dal lato corretto rispetto ai siti di riferimento
if ( bLeft && bRight) {
// recupero i siti di riferimento
int nOrigCrv1, nOrigSubCrv1, nOrigCrv2, nOrigSubCrv2 ;
m_vroni->GetBisectorSites( i, nOrigCrv1, nOrigSubCrv1, nOrigCrv2, nOrigSubCrv2) ;
int nOrigCrv1, nOrigSubCrv1, nOrigSubPnt1, nOrigCrv2, nOrigSubCrv2, nOrigSubPnt2 ;
m_vroni->GetBisectorSites( i, nOrigCrv1, nOrigSubCrv1, nOrigSubPnt1, nOrigCrv2, nOrigSubCrv2, nOrigSubPnt2) ;
if ( nOrigCrv1 != -1) {
// verifico il lato rispetto al primo sito
pCrv->SetTempProp( nOrigSubCrv1 + 1, 0) ;
@@ -828,10 +836,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) ;
}
}
@@ -1014,8 +1031,17 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
RemoveCurveSmallParts( pCrvOffs, 5 * EPS_SMALL) ;
// aggiungo la curva alla lista degli offset
if ( ! IsNull( pCrvOffs) && pCrvOffs->IsValid() && pCrvOffs->GetCurveCount() > 0)
if ( ! IsNull( pCrvOffs) && pCrvOffs->IsValid() && pCrvOffs->GetCurveCount() > 0) {
// forzo chiusura
if ( ! pCrvOffs->IsClosed()) {
Point3d ptS ; pCrvOffs->GetStartPoint( ptS) ;
Point3d ptE ; pCrvOffs->GetEndPoint( ptE) ;
if ( SqDist( ptS, ptE) > 100. * SQ_EPS_SMALL)
return false ;
pCrvOffs->Close() ;
}
OffsList.push_back( Release( pCrvOffs)) ;
}
}
// libero la memoria di vroni dedicata agli offset
@@ -1243,3 +1269,62 @@ Voronoi::CalcLimitOffset( int nCrv, bool bLeft, double& dOffs)
return true ;
}
//---------------------------------------------------------------------------
bool
Voronoi::GetBisectorPointAtParam( int nCrv, double dPar, Point3d& ptP)
{
if ( ! IsValid())
return false ;
try {
if ( ! m_bVDComputed)
CalcVoronoi() ;
// verifico se il bisettore e il parametri richiesto sono sensati
if ( nCrv >= m_vroni->GetNumberOfEdges())
return false ;
double dParS, dParE ;
m_vroni->GetBisectorParams( nCrv, dParS, dParE) ;
if ( dParS > dParE)
swap( dParS, dParE) ;
if ( dPar < dParS || dPar > dParE)
return false ;
// calcolo il punto sul bisettore in corrispondenza dell'offset
m_vroni->GetBisectorPointAtParam( nCrv, dPar, ptP.v) ;
ptP.ToGlob( m_Frame) ;
return true ;
}
catch (...) {
LOG_ERROR( GetEGkLogger(), m_vroni->GetExceptionMessage()) ;
return false ;
}
}
//---------------------------------------------------------------------------
bool
Voronoi::GetBisectorSites( int nCrv, int& nCrv1, int& nSubCrv1, int& nSubPnt1, int& nCrv2, int& nSubCrv2, int& nSubPnt2)
{
if ( ! IsValid())
return false ;
try {
if ( ! m_bVDComputed)
CalcVoronoi() ;
// verifico se il bisettore è valido
if ( nCrv >= m_vroni->GetNumberOfEdges())
return false ;
// calcolo il punto sul bisettore in corrispondenza dell'offset
m_vroni->GetBisectorSites( nCrv, nCrv1, nSubCrv1, nSubPnt1, nCrv2, nSubCrv2, nSubPnt2) ;
return true ;
}
catch (...) {
LOG_ERROR( GetEGkLogger(), m_vroni->GetExceptionMessage()) ;
return false ;
}
}
+2
View File
@@ -60,6 +60,8 @@ class Voronoi
bool CalcFatCurve( ICURVEPOVECTOR& vOffs, double dOffs, bool bSquareEnds, bool bSquareMids, bool bMergeOnlySameProps = true) ;
bool CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) ;
bool CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) ;
bool GetBisectorPointAtParam( int nCrv, double dPar, Point3d& ptP) ;
bool GetBisectorSites( int nCrv, int& nCrv1, int& nSubCrv1, int& nSubPnt1, int& nCrv2, int& nSubCrv2, int& nSubPnt2) ;
bool Translate( const Vector3d& vtMove) ;
bool Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dAngDeg) ;