Compare commits

..

191 Commits

Author SHA1 Message Date
Daniele Bariletti 39360eefd7 EgtGeomKernel :
- raffinamento finale della intersCompoCompo.
2026-03-06 17:25:50 +01:00
Daniele Bariletti 6b5fb15c9b EgtGeomKernel :
- piccola correzione alla IntersCurveCurve.
2026-03-06 12:37:26 +01:00
Daniele Bariletti 4e698d4049 EgtGeomKernel :
- spostato rilevamento spike nelle intersezioni tra curve.
- pulizia codice.
2026-03-05 17:33:55 +01:00
Daniele Bariletti e20bd7fd0c Merge branch 'master' into NewMakeUniform 2026-03-04 15:55:39 +01:00
Daniele Bariletti 7e62acf351 EgtGeomKernel :
- aggiunta funzione per richiedere Part e Shell cui appartiene una faccia.
2026-03-04 15:55:25 +01:00
Daniele Bariletti 421bc2eb3b EgtGeomKernel :
- correzione alla make uniform.
2026-03-04 15:24:33 +01:00
Daniele Bariletti db98fa5d5a Merge branch 'master' into NewMakeUniform 2026-03-03 17:10:06 +01:00
Daniele Bariletti 5f28258d16 EgtGeomKernel :
- migliorie e correzioni all'importazione delle bezier.
- tolto limite alle bezier per rivoluzione.
2026-03-03 17:09:30 +01:00
Daniele Bariletti 8f06488b33 EgtGeomKernel :
- miglioramento all'intersezione tra curve.
2026-02-27 16:52:55 +01:00
Riccardo Elitropi ac7ba1b12c EgtGeomKernel :
- in CalcPocketing piccola miglioria su tolleranza trapezi.
2026-02-25 16:56:30 +01:00
Dario Sassi 67131a1482 EgtGeomKernel :
- salvato file come UTF-8.
2026-02-25 15:17:56 +01:00
Daniele Bariletti a92cba8697 Merge branch 'master' into NewMakeUniform 2026-02-24 12:36:18 +01:00
Daniele Bariletti 52cca7233e EgtGeomKernel 3.1b3 :
- correzione alle intersezioni tra curve.
- cambio versione.
2026-02-24 12:36:05 +01:00
Dario Sassi b2beed0fe0 EgtGeomKernel :
- ora From string per Color accette sia RGBA che RGB.
2026-02-24 08:39:23 +01:00
Daniele Bariletti 1f301b6100 Merge branch 'master' into NewMakeUniform 2026-02-23 16:26:55 +01:00
Daniele Bariletti c74ca4932f Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2026-02-23 16:26:29 +01:00
Daniele Bariletti fafcd67a2c EgtGeomKernel :
- correzione alle ruled guided.
2026-02-23 16:26:23 +01:00
Riccardo Elitropi 390cc3bd8b EgtGeomKernel :
- in trimming migliorata la gestione delle curve di sincronizzazione mediante interpolazione.
2026-02-23 15:47:14 +01:00
Daniele Bariletti b2ccda1b34 Merge branch 'master' into NewMakeUniform 2026-02-23 10:59:22 +01:00
Daniele Bariletti 69916e7756 EgtGeomKernel :
- correzione alla ruled guided.
2026-02-23 10:57:15 +01:00
Daniele Bariletti 3a7b6f1343 EgtGeomKernel :
- aggiunto flag Refined alla funzione GetLeaves.
2026-02-23 09:44:39 +01:00
Daniele Bariletti 71a054749c EgtGeomKernel :
- miglioria alla bezier ruled guided.
2026-02-23 09:35:04 +01:00
Daniele Bariletti 06d87d5c52 Merge branch 'master' into NewMakeUniform 2026-02-23 09:27:55 +01:00
Daniele Bariletti 6d544f93f4 EgtGeomKernel :
- miglioramento dell'approssimazione con curve di bezier.
2026-02-23 09:11:28 +01:00
Riccardo Elitropi 3c1a7ff1bb EgtGeomKernel 3.1b2 :
- in Trimming aggiunta prima versione di interpolazione per le curve di sincronizzazione.
2026-02-20 16:47:42 +01:00
Daniele Bariletti 73bedf4f55 EgkGeomKernel :
- correzione all'intersezione tra curva e piano.
2026-02-19 15:39:43 +01:00
Daniele Bariletti bae8d4651d EgtGeomKernel :
- piccola correzione alla Surf Bez Ruled Guided.
2026-02-19 11:50:44 +01:00
Riccardo Elitropi f9127ce64d EgtGeomKernel 3.1b1 :
- cambio di versione.
2026-02-17 10:00:13 +01:00
Riccardo Elitropi 86338db67d EgtGeomKernel :
- in CalcPocketing piccola correzione.
2026-02-17 09:24:18 +01:00
Daniele Bariletti 2438d1d23a Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2026-02-12 16:25:34 +01:00
Daniele Bariletti f790736fd7 EgtGeomKernel :
- modificata conversione da linea a bezier.
2026-02-12 16:25:28 +01:00
Daniele Bariletti 985b69ae33 EgtGeomKernel :
- correzione alla triangolazione delle bezier.
- riduzione della dimensione minima dei triangoli nelle surf bezier.
2026-02-12 16:17:11 +01:00
Riccardo Elitropi 6faf5ccde2 EgtGeomKernel 3.1a8 :
- in CalcPocketing migliorati i casi a trapezio.
2026-02-12 15:46:42 +01:00
Daniele Bariletti 2e129d7b06 EgtGeomKernel :
- tolto un argomento alla funzione ApproxCurveWithBezier.
2026-02-11 16:50:50 +01:00
Daniele Bariletti 2b7070e408 Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2026-02-11 15:27:04 +01:00
Daniele Bariletti 571a24b419 EgtGeomKernel :
- migliorata approssimazione con curve di bezier.
2026-02-11 15:26:57 +01:00
Dario Sassi 5f132ae3d3 EgtGeomKernel 3.1a7 :
- ricompilazione con cambio versione.
2026-02-11 12:20:15 +01:00
Riccardo Elitropi fe5a09281e EgtGeomKernel :
- rimozione memory leaks in CalcPocketing.
2026-02-11 11:31:08 +01:00
Riccardo Elitropi b66522de33 EgtGeomKernel 3.1a6 :
- in CalcPocketing migliorati i casi ottimizzati a Trapezio.
2026-02-10 17:03:46 +01:00
Daniele Bariletti e87ef178c2 EgtGeomKernel :
- correzione alla distanza punto- curva di bezier.
2026-02-10 15:42:03 +01:00
Dario Sassi 0987496caf EgtGeomKernel :
- piccoli aggiustamenti.
2026-02-09 12:48:38 +01:00
Riccardo Elitropi 5ad9c48285 EgtGeomKernel :
- in Trimming rimozione memory Leaks.
2026-02-09 11:21:06 +01:00
Dario Sassi ec6eb3e645 EgtGeomKernel :
- modifica a Trimming
- sistemazioni estetiche varie.
2026-02-09 08:24:16 +01:00
Daniele Bariletti 64c3363426 Merge branch 'NewApproxWithBezier' 2026-02-06 17:28:46 +01:00
Daniele Bariletti 2023ba3f7d EgtGeomKernel :
- modifica all'approssimazione delle curve tramite bezier.
2026-02-06 17:28:28 +01:00
Daniele Bariletti 27c1823a54 Merge branch 'master' into NewApproxWithBezier 2026-02-05 16:56:35 +01:00
Daniele Bariletti f111827545 EgtGeomKernel :
- modificata la CreateByExtrusion per le bezier.
2026-02-05 16:56:09 +01:00
Daniele Bariletti 7cdc1ba5a3 EgtGeomKernel :
- implementazione dell'approsimazione tramite curve di bezier.
2026-02-05 16:54:09 +01:00
Riccardo Elitropi 1d68a1ee8e EgtGeomKernel 3.1a5 :
- in Trimming aggiunte le funzioni per ricerca di fori e asole
- in Trimming migliorate e corrette le funzioni per la ricerca delle Patch dalle superfici
- in Trimming corrette le tolleranze lineari per le approssimazioni dei bordi
- in Trimming rimozione Memory Leaks e pulizia del codice.
2026-02-03 17:18:46 +01:00
Daniele Bariletti b426ccc04d EgtGeomKernel :
- modifica alla funzione MakeUniform: utilizzo solo di curve anziché di flat region.
2026-02-03 16:22:57 +01:00
Dario Sassi 6f7b614c3a EgtGeomKernel :
- corretta assegnazione valore.
2026-01-27 16:35:55 +01:00
Daniele Bariletti f02f29c543 EgtGeomKernel 3.1a4 :
- correzione all'intersezione LineLine
- correzione all'intersezione CompoCompo
- cambio versione.
2026-01-27 13:36:42 +01:00
Daniele Bariletti 06cfe1bb96 EgtGeomKernel :
- correzione alle bezier ruled per il match degli edge.
2026-01-27 10:21:51 +01:00
Riccardo Elitropi 736353bbac EgtGeomKernel :
- in Trimming piccole correzioni e migliorie.
2026-01-26 18:02:59 +01:00
Daniele Bariletti f4b3312672 EgtGeomKernel :
- disattivati salvataggi debug.
2026-01-26 13:08:47 +01:00
Daniele Bariletti 3178bb5f27 EgtGeomKernel :
- miglioramento della Bezier ruled
- miglioramento della Nezier ruled guided.
2026-01-26 12:34:32 +01:00
Riccardo Elitropi 552ce70231 EgtGeomKernel :
- in Trimming introdotta una prima approssimazione delle curve di bordo.
2026-01-23 17:57:18 +01:00
Riccardo Elitropi c2a79b2665 EgtGeomKernel :
- InTestSurfTmSurfTm affinato il controllo collisione quando una delle due superfici è chiusa e contiene l'altra.
In CalcPocketing aggiunta piccola miglioria.
2026-01-23 12:38:16 +01:00
Dario Sassi f72c949563 EgtGeomKernel :
- In TestSurfTmSurfTm aggiunto flag per segnalare collisione anche quando una delle due è chiusa e contiene l'altra.
2026-01-23 10:18:30 +01:00
Riccardo Elitropi bdcb00d1bd Merge commit '42fcb1847bca4340cf9cd283d095a6d5276cd86e' 2026-01-23 08:49:36 +01:00
Daniele Bariletti 42fcb1847b EgtGeomKernel :
- GetSurfBezierRuledGuided.
2026-01-22 11:23:58 +01:00
Riccardo Elitropi a7b36280f3 EgtGeomKernel :
- in Trimming semplificazione delle funzioni per le curve di sincronizzazione.
2026-01-21 18:27:28 +01:00
Daniele Bariletti cdef3931be EgtGeomKernel :
- spostata la funzione GetChainedCurves.
2026-01-21 10:05:54 +01:00
Riccardo Elitropi d3f2587cc2 EgtGeomKernel 3.1a3 :
- In Trimming aggiunta una prima versione per l'analisi dei triangoli durante la ricerca di facce piane
- In Trimming aggiunto l'ultilizzo delle Normali Smussate per recupero Edge mediate Estrusione
- In Trimming migliorata la gestione e la creazione delle Rigate di Bezier mediante curve di sincronizzazione.
2026-01-20 17:26:28 +01:00
Riccardo Elitropi d343f474e4 EgtGeomKernel :
- Aggiunti controlli in PolygonElevation.
2026-01-20 15:21:26 +01:00
Daniele Bariletti b7fee9696e EgtGeomKernel :
- piccola correzione.
2026-01-19 15:46:50 +01:00
Daniele Bariletti 4f48337f62 EgtGeomKernel :
- piccola correzione.
2026-01-19 15:31:56 +01:00
Daniele Bariletti 96907d5952 EgtGeomKernel :
- aggiunta di una funzionalità per il chain diretto di un vettore di curve.
2026-01-19 15:27:19 +01:00
Daniele Bariletti 3c5d2571fe EgtGeomKernel :
- piccola correzione.
2026-01-19 15:15:11 +01:00
Daniele Bariletti 7005bf43a4 Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2026-01-19 12:32:26 +01:00
Daniele Bariletti 4726cf4d35 EgtGeomKernel :
- cambiamento della chiamata alla GetSurfBezierRuledGuided.
2026-01-19 12:32:13 +01:00
Dario Sassi b971eda771 EgtGeomJKernel :
- in Zmap sostituiti mutex con atomic_flag.
2026-01-19 08:03:57 +01:00
Dario Sassi 3ded6fe87d EgtGeomKernel :
- piccole modifiche estetiche.
2026-01-16 18:44:36 +01:00
Riccardo Elitropi 5195c23dfb EgtGeomKernel :
- in CalcPocketing piccola modifica sulle Entrate per casi a Trapezio.
2026-01-16 17:27:33 +01:00
Daniele Bariletti 5f1255a625 EgtGeomKernel :
- piccola miglioria alla intersLineLine
- piccola correzione alla intersCurveCurve.
2026-01-16 15:12:01 +01:00
Daniele Bariletti 82accd45c1 EgtGeomKernel :
- piccola correzione.
2026-01-15 12:47:50 +01:00
Daniele Bariletti e46768b14b EgtGeomKernel :
- modificata la funzione per la creazione di una surf Bezier ruled guided.
2026-01-15 11:50:03 +01:00
Daniele Bariletti 32307efd78 Merge remote-tracking branch 'origin/master' 2026-01-14 08:49:12 +01:00
Daniele Bariletti e84df69f6f EgtGeomkernel :
- piccola correzione alla remove span
- aggiunto comando di debug.
2026-01-14 08:47:14 +01:00
Riccardo Elitropi 669f38a731 EgtGeomKernel 3.1a2 :
- In CalcPocketing aggiunti controlli per casi a Spirale e Trapezio in presenza di lati aperti.
2026-01-13 14:36:02 +01:00
Dario Sassi afef5597b2 EgtGeomKernel :
- tentaivo di correzione intersezione tra segmenti di retta quasi paralleli.
2026-01-12 08:15:06 +01:00
Riccardo Elitropi 4a0bd638fa EgtGeomKernel :
- in CalcPocketing migliorata la gestione dei punti iniziali dei percorsi nel caso dei Trapezi o di punti di riferimento generici.
2026-01-08 19:19:08 +01:00
Daniele Bariletti 4bfb38b9d5 EgtGeomKernel :
- piccola correzione alla triangolazione delle surf di bezier.
2026-01-07 12:28:11 +01:00
Daniele Bariletti 0d62cd9bbd EgtGeomKernel :
- aggiunta controlli e correzione al VM 5 assi in caso di movimento a perno sulla punta del tool.
2026-01-07 12:26:13 +01:00
Dario Sassi 913d5f60ca EgtGeomKernel :
- piccole sistemazioni per normali di vertici di Trimesh pesate su angoli.
2026-01-07 11:29:57 +01:00
Dario Sassi 3dddbdf5cd EgtGeomKernel :
- nelle TriMesh calcolo normali di vertici con peso da angoli
- in Zmap pezza per movimenti 5assi sul tip (da correggere veramente).
2026-01-07 09:23:02 +01:00
Dario Sassi 3245f7fe75 EgtGeomKernel :
- aggiunte funzioni di striping per trimming dei termoformati.
2026-01-04 20:39:33 +01:00
Dario Sassi f144cda136 EgtGeomKernel :
- modifiche per consentire di proiettare curve chiuse su superfici conservando i punti di inizio e fine.
2026-01-04 12:55:28 +01:00
Dario Sassi d374e133f0 EgtGeomKernel 3.1a1 :
- ricompilazione con cambio major versione.
2026-01-02 12:33:47 +01:00
Dario Sassi 0c435a646d EgtGeomKernel :
- migliorato controllo e sistemazione chiusura curva di intersezione piano con Zmap.
2025-12-30 19:24:56 +01:00
Dario Sassi d0ac226753 EgtGeomKernel :
- aggiunta lettura file Nge binari compressi.
2025-12-29 19:24:56 +01:00
Dario Sassi d92344f2bb EgtGeomKernel :
- - modifiche a NgeReader per semplificare e velocizzare lettura file binari.
2025-12-29 11:55:09 +01:00
Dario Sassi 51c584c6c4 EgtGeomKernel 2.7l6 :
- modifiche a NgeWriter per semplificare e velocizzare scrittura file binari (ora anche compressi).
2025-12-29 08:45:03 +01:00
Dario Sassi 176bbec8a7 EgtGeomKernel 2.7l3 :
- aggiunta funzione DuplicateGeomDB.
2025-12-23 15:35:32 +01:00
Daniele Bariletti a508da8b18 EgtGemoKernel :
- piccola correzione.
2025-12-19 15:58:30 +01:00
Daniele Bariletti 91ca84f77a EgtGeomKernel :
- miglioramento delle superfici di bezier.
- aggiunta di una funzione per l'eliminazione delle span collassate e di una per l'inversione dei paramettri di una superficie.
2025-12-19 15:03:19 +01:00
Dario Sassi d27fdb9904 EgtGeomKernel :
- piccole migliorie.
2025-12-16 13:03:59 +01:00
Daniele Bariletti 3b816e2a45 EgtGeomKernel :
- correzione alla conversione da sup nurbs a bezier.
2025-12-16 11:27:19 +01:00
Riccardo Elitropi 11a46ca58c EgtGeomKernel 2.7l2 :
- Modificate le funzioni di Offset per superfici TriMesh aperte
- Aggiunta la funzione per la creazione di Shell per TriMesh.
2025-12-15 11:35:15 +01:00
Dario Sassi 6e0aec3bec EgtGeomkernel :
- migliorie alle varie ProjectPointOnSurf per gestione corner esterni e interni.
2025-12-15 08:17:11 +01:00
Dario Sassi 11dd35af44 EgtGeomKernel :
- aggiunta funzione di proiezione a minima distanza di curva su superfcie
- migliorato LockAddErase per atomic_flag.
2025-12-09 08:14:56 +01:00
Dario Sassi 17fe5f0c9c EgtGeomKernel 2.7l1 :
- piccola ottimizzazione in LockAddErase.
2025-12-04 19:10:07 +01:00
Riccardo Elitropi c8e2d88bb7 EgtGeomKernel :
- Migliorata la gestione intersezioni Linea con Box.
2025-12-01 08:32:02 +01:00
Dario Sassi c6ac9fbcf8 EgtGeomKernel :
- migliorie al calcolo BBox di Zmap.
2025-11-24 19:27:08 +01:00
Daniele Bariletti e636e75b76 Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2025-11-24 13:07:48 +01:00
Daniele Bariletti a01346577f EgtGeomKernel :
- correzioni alle bezier.
2025-11-24 13:07:43 +01:00
Dario Sassi 61a5e53351 EgtGeomKernel :
- sistemazioni varie legate a scalature per aumentare la precisione.
2025-11-24 10:05:39 +01:00
Daniele Bariletti 739c17b4b6 EgtGeomKernel :
- piccola correzione.
2025-11-21 12:32:30 +01:00
Daniele Bariletti 144ef16b0b EgtGeomKernel :
- piccola modifica.
2025-11-21 09:21:37 +01:00
Daniele Bariletti 58c635cb9d EgtGeomKernel :
- piccola miglioria.
2025-11-20 16:12:56 +01:00
Daniele Bariletti a39b9a7651 EgtGeomKernel :
- correzioni alle bezier.
2025-11-20 12:26:08 +01:00
Daniele Bariletti 75889983de egtGeomKernel :
- correzione alle bezier.
2025-11-19 17:42:35 +01:00
Daniele Bariletti e4a14b629c EgtGeomKernel :
- aggiunta la possibilità di filtrare le intersezioni 3D di una IntersCurveCurve.
2025-11-19 13:09:46 +01:00
Daniele Bariletti 3640a17632 EgtGeomKernel :
- migliorata gestione della triangolazione per le bezier.
2025-11-19 11:24:21 +01:00
Daniele Bariletti 2a3f809e4e EgtGeomKernel :
- funzioni che restituiscono punti nel parametrico di una bezier ora li restituiscono riscalati.
2025-11-18 16:16:54 +01:00
Dario Sassi d7dd7b9f80 EgtGeomKernel 2.7k4 :
- cambio versione.
2025-11-15 11:05:43 +01:00
Dario Sassi cd48e2de3b EgtGeomKernel :
- varie correzioni ortografiche.
2025-11-15 11:00:21 +01:00
Daniele Bariletti 8f43efe282 EgtGeomKernel :
- correzione di commenti.
2025-11-14 15:49:28 +01:00
Daniele Bariletti 025bcbba1d EgtGeomKernel :
- correzione alla creazione guidata di bezier ruled.
2025-11-14 15:47:00 +01:00
Daniele Bariletti d0131deb40 EgtGeomKernel :
- tolto codice di debug.
2025-11-12 14:30:51 +01:00
Daniele Bariletti 1325f83291 Merge branch 'NewRuled' 2025-11-12 13:05:54 +01:00
Daniele Bariletti 961acdbc76 EgtGeomKernel :
- correzioni alla inters curve-piano
- migliorata la ruled con bezier.
2025-11-12 13:03:28 +01:00
Daniele Bariletti 6789d74abc Merge branch 'master' into NewRuled 2025-11-12 08:58:12 +01:00
Daniele Bariletti 062c92377e EgtGeomKernel :
- piccola correzione alla intersCurvePlane.
2025-11-12 08:57:31 +01:00
Daniele Bariletti 383f4c7abd GeomKernel :
- aggiunta funzione surf bez ruled guided.
2025-11-12 08:56:43 +01:00
Riccardo Elitropi 4cc6161918 EgtGeomKernel :
- in PolyLine corretta funzione per modifica al punto inziale.
2025-11-11 17:12:55 +01:00
Daniele Bariletti c0ebbee347 EgtGeomKernel :
- aggiunto default per parametro della unproject di una bezier.
2025-11-11 11:53:47 +01:00
Daniele Bariletti e3b4f5bd2d EgtGeomKernel :
- aggiunta la classe per l'intersezione curva-piano.
2025-11-11 11:53:13 +01:00
Daniele Bariletti 5df3ab6d98 EgtGeomKernel :
- migliorata la nuova versione di ruled.
2025-11-07 17:39:52 +01:00
Dario Sassi 63fb9a638b EgtGeomKernel 2.7k3 :
- a SimpleOffset di Curve aggiunto parametro opzionale dMaxAngExt (angolo esterno oltre il quale estendi diventa smussa) con default 90deg.
2025-11-06 18:49:55 +01:00
Riccardo Elitropi d62d6946c3 EgtGeomKernel :
- miglioramento della funzione per calcolo curvatura di una superficie TriMesh.
2025-11-06 13:04:40 +01:00
Dario Sassi 7f0237ced4 EgtGeomKernel :
- ricompilato con Eigen 3.4.1 perchè la versione 5.0.0 dà assert in debug 32bit.
2025-11-06 08:42:56 +01:00
Dario Sassi 23621630d5 EgtGeoMkernel :
- semplificazione interfaccia di GetCurvature di SurfTriMesh.
2025-11-05 11:29:02 +01:00
Riccardo Elitropi b3abcf73c3 EgtGeomKernel 2.7k2 :
- aggiunta funzione per il calcolo della curvatura in un vertice per una superficie TriMesh.
2025-11-04 16:02:04 +01:00
Daniele Bariletti 1219e9bd80 EtgGeomKernel :
- primo tentativo.
2025-11-04 14:37:34 +01:00
Dario Sassi dced59b9a1 EgtGeomKernel :
- piccolo miglioramento.
2025-11-03 18:04:52 +01:00
Dario Sassi 3bf2972089 Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-11-01 17:25:33 +01:00
Dario Sassi 6dd3ea5cc2 EgtGeomKernel 2.7k1 :
- aggiustamenti e ricompilazione per passaggio a C++ 20
2025-11-01 17:24:43 +01:00
Daniele Bariletti 592a92ebdb EgtGeomKernel :
- correzione alla getLoops.
2025-10-31 15:05:44 +01:00
Daniele Bariletti 1321742afe EgtGeomKernel :
- piccola correzione.
2025-10-31 13:21:37 +01:00
Daniele Bariletti f1f93124a0 EgtGeomKernel :
- correzione alle sup di bezier.
2025-10-31 13:16:10 +01:00
Daniele Bariletti c8e9d1e012 EgtGeomKernel :
- rimozione parti di debug.
2025-10-31 11:09:11 +01:00
Daniele Bariletti 7b0cd0939b Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2025-10-31 11:08:28 +01:00
Daniele Bariletti 3b5ab5089b EgtGeomKernel .
- ulteriore piccola correzione alle rigate.
2025-10-31 11:08:22 +01:00
Dario Sassi b36d919d8f EgtGeomKernel 2.7j5 :
- ricompilazione con cambio versione.
2025-10-31 09:44:03 +01:00
Daniele Bariletti e22a207f03 EgtGeomKernel :
- ulteriore miglioramento alle rigate con le bezier.
2025-10-30 15:28:53 +01:00
Daniele Bariletti 24dbef52c9 Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2025-10-30 12:06:46 +01:00
Daniele Bariletti 5498b1e25c EgtGeomKernel :
- miglioramento alle rigate con le bezier.
2025-10-30 12:06:39 +01:00
Dario Sassi 86851bb67e EgtGeomKernel 2.7j4 :
- ricompilazione con cambio versione.
2025-10-29 17:10:50 +01:00
Daniele Bariletti b99e12c56f EgtGeomKernel :
- aggiunta la classe per calcolare la distanza tra un punto e una surf bezier.
2025-10-29 14:50:02 +01:00
Daniele Bariletti 129b1b919e EgtGeomKernel :
- aggiunta funzione per restituire tutte le isoparametriche di bordo delle patch in un parametro
- migliorata la gestione del recupero delle isocurve.
2025-10-29 10:35:43 +01:00
Daniele Bariletti 711c250cfc EgtGeomKernel :
- migliorata la interpolate con curve di bezier.
2025-10-24 11:54:19 +02:00
Daniele Bariletti 0f05216474 Merge branch 'DevelopTemp' 2025-10-24 11:17:23 +02:00
Daniele Bariletti c57b7c95c1 EgtGeomKernel :
- piccola miglioria alle surf bez.
2025-10-24 11:17:12 +02:00
Daniele Bariletti 62e041ed8c EgtGeomKernel :
- correzione alle superfici di bezier.
2025-10-24 09:11:21 +02:00
Daniele Bariletti 2983454ce2 EgtGeomKernel :
- piccola correzione.
2025-10-22 15:09:34 +02:00
Daniele Bariletti 6d5046cb6d EgtGeomKernel :
- cambiata la gestione della razionalità delle curve di bezier durante le conversioni da curva generica a bezier.
2025-10-22 12:53:55 +02:00
Daniele Bariletti 91fcf43da9 EgtGeomKernel :
- piccola correzione.
2025-10-22 09:57:41 +02:00
Daniele Bariletti aef1a57e1c EgtGeomKernel :
- correzione alla chiamata della funzione CurveToBezierCurve.
2025-10-21 12:50:15 +02:00
Daniele Bariletti 71316bac6a EgtGeomKernel :
- surf di bezier restituisce solo edge raffinati.
- aggiornato il valore di default per la bezier raffinata.
2025-10-21 12:25:05 +02:00
Daniele Bariletti f1c4f06461 EgtGeomKernel :
- aggiunto paramentro MaxLen per l'interpolazione con le bezier.
2025-10-21 09:36:47 +02:00
Daniele Bariletti 412bbd2a8b Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2025-10-20 12:30:42 +02:00
Daniele Bariletti be64cedfc3 EgtGeomKernel :
- piccola correzione.
2025-10-20 12:30:35 +02:00
Dario Sassi 2a6b35d658 EgtGeomKernel 2.7j3 :
- ricompilazione con cambio versione.
2025-10-20 12:25:08 +02:00
Daniele Bariletti f51c5c36d0 EgtGeomKernel :
- correzione tolleranza per l'interpolazione di punti con curve di bezier.
2025-10-20 10:39:32 +02:00
Daniele Bariletti 5599901185 EgtGeomKernel :
- correzione nel restituire i bordi di una surf di bezier chiusa.
2025-10-17 17:06:04 +02:00
Daniele Bariletti fb235bf985 EgtGeomKernel :
- aggiunta la funzione per l'approssimazione di una curva generica con una serie di bezier.
- piccole modifiche.
2025-10-17 15:36:32 +02:00
Daniele Bariletti 717d7a3fe3 EgtGeomKernel :
- piccola correzione.
2025-10-17 14:38:34 +02:00
Daniele Bariletti c91f468dce EgtGeomKernel :
- migliorata gestione input per l'interpolazione con curve di bezier.
2025-10-17 14:32:12 +02:00
Daniele Bariletti 1f36657efd EgtGeomKernel :
- correzione all'interpolazione tramite curve di bezier.
2025-10-16 17:40:14 +02:00
Daniele Bariletti b70ad5c808 EgtGeomKernel :
- migliorata gestione della validità delle curve di bezier.
2025-10-15 09:08:04 +02:00
SaraP da56ef91fd EgtGeomKernel :
- piccola correzione.
2025-10-15 08:30:20 +02:00
Daniele Bariletti 9bd7a152d7 EgtGeomKernel :
- piccola correzione.
2025-10-14 16:44:24 +02:00
Daniele Bariletti 5c287d49bb EgtGeomKernel :
- aggiornamento funzioni per recuperare i loop di una surf di bezier.
2025-10-14 16:30:45 +02:00
Daniele Bariletti 942f15b49d Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2025-10-13 15:21:19 +02:00
Daniele Bariletti 20b61cda42 EgtGeomKernel :
- correzione alla bezier ruled.
2025-10-13 15:21:13 +02:00
Dario Sassi b1b1d6d434 EgtGeomKernel :
- adattamento per modifiche nei puntatori a funzione.
2025-10-13 08:46:09 +02:00
Dario Sassi c7ad32ef30 EgtGeomKernel :
- in Dump di TriMesh e Zmap aggiunta info ShowEdges.
2025-10-11 12:30:46 +02:00
Daniele Bariletti 6016db837e EgtGeomKernel :
- correzione del merge.
2025-10-10 16:50:59 +02:00
Daniele Bariletti 2051e0b5d9 Merge branch 'FasterVMill' 2025-10-10 16:49:26 +02:00
Daniele Bariletti fddb3f5707 EgtGeomKernel :
- pulizia.
2025-10-10 16:46:50 +02:00
Daniele Bariletti 096dd84511 EgtGeomKernel :
- correzione e pulizia.
2025-10-10 16:42:13 +02:00
Dario Sassi e16a2078fc EgtGeomKernel 2.7j2 :
- ricompilazione con Eigen 3.4.1.
2025-10-10 15:55:54 +02:00
Daniele Bariletti e388ae34e3 Merge branch 'master' into FasterVMill 2025-10-10 12:55:34 +02:00
Daniele Bariletti b64c747082 EgtGeomKernel :
- aggiunto un tipo di interpolazione con bezier.
2025-10-10 12:11:56 +02:00
Daniele Bariletti 8afa3ae47d EgtGeomKernel :
- corretta la copia di un VolZmap.
2025-10-10 10:22:20 +02:00
Daniele Bariletti 1eba68e95b EgtGeomKernel :
- aggiunta controllo box con tratti sugli spilloni( direz generica tool).
2025-10-09 16:45:03 +02:00
Daniele Bariletti 047b339006 EgtGeomKernel :
- piccola correzione.
2025-10-09 14:56:24 +02:00
Daniele Bariletti acd7415835 EgtGeomKernel :
- aggiunta controllo box con tratti sugli spilloni.
2025-10-09 14:46:31 +02:00
Daniele Bariletti a48460ef76 EgtGeomKernel :
- pulizia codice.
2025-10-09 11:32:36 +02:00
Daniele Bariletti 8ab3896e3a Merge branch 'FasterVMill5Axis_Bez3x1' 2025-10-09 10:54:46 +02:00
73 changed files with 12578 additions and 2929 deletions
+40 -20
View File
@@ -1,12 +1,13 @@
//----------------------------------------------------------------------------
// EgalTech 2020-2024
// EgalTech 2020-2026
//----------------------------------------------------------------------------
// File : CDeClosedSurfTmClosedSurfTm.h Data : 24.03.24 Versione : 2.6c2
// File : CDeClosedSurfTmClosedSurfTm.h Data : 23.01.26 Versione : 3.1a3
// Contenuto : Implementazione funzione verifica collisione tra
// SurfTm e SurfTm.
//
// Modifiche : 13.11.20 LM Creazione modulo.
// 24.03.24 DS Aggiunta TestSurfTmSurfTm.
// 23.01.26 DS In TestSurfTmSurfTm aggiunto flag per collisione quando una delle due è chiusa e contiene l'altra.
//
//----------------------------------------------------------------------------
@@ -45,10 +46,10 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf
BBox3d b3BoxA, b3BoxB ;
pSrfA->GetLocalBBox( b3BoxA) ;
pSrfB->GetLocalBBox( b3BoxB) ;
// Se è necessario, espando il box di B di una costante additiva pari alla distanza di sicurezza.
// Se è necessario, espando il box di B di una costante additiva pari alla distanza di sicurezza.
if ( dSafeDist > EPS_SMALL)
b3BoxB.Expand( dSafeDist) ;
// Se i box non si sovrappongono, non c'è collisione. Ho finito.
// Se i box non si sovrappongono, non c'è collisione. Ho finito.
if ( ! b3BoxA.Overlaps( b3BoxB))
return false ;
// Recupero i triangoli di A che interferiscono col box di B
@@ -61,13 +62,13 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf
continue ;
BBox3d b3BoxTriaA ;
trTriaA.GetLocalBBox( b3BoxTriaA) ;
// Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza.
// Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza.
if ( dSafeDist > EPS_SMALL)
b3BoxTriaA.Expand( dSafeDist) ;
// Recupero i triangoli di B che interferiscono col box del triangolo di A
INTVECTOR vNearTria ;
pSrfB->GetAllTriaOverlapBox( b3BoxTriaA, vNearTria) ;
// Settare tutti i triangoli come già processati.
// Settare tutti i triangoli come già processati.
// Al termine della chiamata i TempInt dei triangoli valgono 0.
pSrfB->ResetTempInts() ;
// Ciclo sui triangoli della superficie B che cadono nel box del triangolo corrente della Superficie A.
@@ -84,14 +85,14 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf
// Ciclo sui vertici del triangolo.
for ( int nVB = 0 ; nVB < 3 ; ++ nVB) {
// Se il triangolo adiacente al triangolo corrente su questo edge
// non è stato processato, processo il vertice e l'edge.
// non è stato processato, processo il vertice e l'edge.
int nAdjTriaTempFlag ;
if ( ! ( pSrfB->GetTempInt( nAdjTriaId[nVB], nAdjTriaTempFlag) || nAdjTriaTempFlag == 0))
continue ;
// Processo il vertice: se c'è collisione fra triangolo A e sfera ho finito.
// Processo il vertice: se c'è collisione fra triangolo A e sfera ho finito.
if ( CDeSimpleSpheTria( trTriaB.GetP( nVB), dSafeDist, trTriaA))
return true ;
// Processo l'edge: se c'è collisione fra triangolo A e cilindro ho finito.
// Processo l'edge: se c'è collisione fra triangolo A e cilindro ho finito.
Vector3d vtEdgeV = trTriaB.GetP( ( nVB + 1) % 3) - trTriaB.GetP( nVB) ;
double dEdgeLen = vtEdgeV.Len() ;
vtEdgeV /= dEdgeLen ;
@@ -111,10 +112,10 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf
}
}
// Non ho trovato collisioni fra triangoli delle superfici.
// Se il BBox della prima superficie non è interno a quello della seconda e viceversa, non c'è collisione
// Se il BBox della prima superficie non è interno a quello della seconda e viceversa, non c'è collisione
if ( ! b3BoxA.Encloses( b3BoxB) && ! b3BoxB.Encloses( b3BoxA))
return false ;
// La collisione c'è se una superficie è dentro l'altra.
// La collisione c'è se una superficie è dentro l'altra.
Point3d ptPointA, ptPointB ;
pSrfA->GetFirstVertex( ptPointA) ;
pSrfB->GetFirstVertex( ptPointB) ;
@@ -127,7 +128,7 @@ CDeClosedSurfTmClosedSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& Surf
// Verifica l'interferenza tra le due superfici : restituisce true in caso di interferenza.
//----------------------------------------------------------------------------
bool
TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double dSafeDist)
TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double dSafeDist, bool bTestEnclosion)
{
// Recupero le superfici base
const SurfTriMesh* pSrfA = GetBasicSurfTriMesh( &SurfA) ;
@@ -140,10 +141,10 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d
BBox3d b3BoxA, b3BoxB ;
pSrfA->GetLocalBBox( b3BoxA) ;
pSrfB->GetLocalBBox( b3BoxB) ;
// Se è necessario, espando il box di B di una costante additiva pari alla distanza di sicurezza.
// Se è necessario, espando il box di B di una costante additiva pari alla distanza di sicurezza.
if ( dSafeDist > EPS_SMALL)
b3BoxB.Expand( dSafeDist) ;
// Se i box non si sovrappongono, non c'è collisione. Ho finito.
// Se i box non si sovrappongono, non c'è collisione. Ho finito.
if ( ! b3BoxA.Overlaps( b3BoxB))
return false ;
// Recupero i triangoli di A che interferiscono col box di B
@@ -156,13 +157,13 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d
continue ;
BBox3d b3BoxTriaA ;
trTriaA.GetLocalBBox( b3BoxTriaA) ;
// Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza.
// Se è necessario, espando il box di una costante additiva pari alla distanza di sicurezza.
if ( dSafeDist > EPS_SMALL)
b3BoxTriaA.Expand( dSafeDist) ;
// Recupero i triangoli di B che interferiscono col box del triangolo di A
INTVECTOR vNearTria ;
pSrfB->GetAllTriaOverlapBox( b3BoxTriaA, vNearTria) ;
// Settare tutti i triangoli come già processati.
// Settare tutti i triangoli come già processati.
// Al termine della chiamata i TempInt dei triangoli valgono 0.
pSrfB->ResetTempInts() ;
// Ciclo sui triangoli della superficie B che cadono nel box del triangolo corrente della Superficie A.
@@ -179,14 +180,14 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d
// Ciclo sui vertici del triangolo.
for ( int nVB = 0 ; nVB < 3 ; ++ nVB) {
// Se il triangolo adiacente al triangolo corrente su questo edge
// non è stato processato, processo il vertice e l'edge.
// non è stato processato, processo il vertice e l'edge.
int nAdjTriaTempFlag ;
if ( ! ( pSrfB->GetTempInt( nAdjTriaId[nVB], nAdjTriaTempFlag) || nAdjTriaTempFlag == 0))
continue ;
// Processo il vertice: se c'è collisione fra triangolo A e sfera ho finito.
// Processo il vertice: se c'è collisione fra triangolo A e sfera ho finito.
if ( CDeSimpleSpheTria( trTriaB.GetP( nVB), dSafeDist, trTriaA))
return true ;
// Processo l'edge: se c'è collisione fra triangolo A e cilindro ho finito.
// Processo l'edge: se c'è collisione fra triangolo A e cilindro ho finito.
Vector3d vtEdgeV = trTriaB.GetP( ( nVB + 1) % 3) - trTriaB.GetP( nVB) ;
double dEdgeLen = vtEdgeV.Len() ;
vtEdgeV /= dEdgeLen ;
@@ -205,6 +206,25 @@ TestSurfTmSurfTm( const ISurfTriMesh& SurfA, const ISurfTriMesh& SurfB, double d
pSrfB->SetTempInt( nTB, 1) ;
}
}
// Non c'è interferenza
// Se non richiesto test di inclusione, non c'è interferenza
if ( ! bTestEnclosion)
return false ;
// Se la prima superficie è chiusa, verifico se include totalmente la seconda
if ( pSrfA->IsClosed() && b3BoxA.Encloses( b3BoxB)) {
Point3d ptPointB ;
pSrfB->GetFirstVertex( ptPointB) ;
DistPointSurfTm DistPoinBSrfA( ptPointB, *pSrfA) ;
if ( DistPoinBSrfA.IsPointInside() || DistPoinBSrfA.IsEpsilon( dSafeDist))
return true ;
}
// Se la seconda superficie è chiusa, verifico se include totalmente la prima
if ( pSrfB->IsClosed() && b3BoxB.Encloses( b3BoxA)) {
Point3d ptPointA ;
pSrfA->GetFirstVertex( ptPointA) ;
DistPointSurfTm DistPoinASrfB( ptPointA, *pSrfB) ;
if ( DistPoinASrfB.IsPointInside() || DistPoinASrfB.IsEpsilon( dSafeDist))
return true ;
}
// Non c'è interferenza
return false ;
}
+233
View File
@@ -0,0 +1,233 @@
//----------------------------------------------------------------------------
// EgalTech 2026
//----------------------------------------------------------------------------
// File : CalcDerivate.cpp Data : 03.02.26 Versione : 1.5h1
// Contenuto : Funzioni per calcolo derivate secondo Bessel e Akima.
//
//
//
// Modifiche : 03.02.26 DB Creazione modulo.
//
//
//----------------------------------------------------------------------------
#pragma once
#include "stdafx.h"
#include "CalcDerivate.h"
#include "/EgtDev/Include/EGkPoint3d.h"
#include "/EgtDev/Include/EgtNumCollection.h"
#include "/EgtDev/Include/EGkGeoCollection.h"
//----------------------------------------------------------------------------
bool
ComputeAkimaTangents( bool bDetectCorner, const DBLVECTOR& vPar, const PNTVECTOR& vPnt, VCT3DVECTOR& vPrevDer, VCT3DVECTOR& vNextDer)
{
// pulisco i vettori dei parametri e delle tangenti
vPrevDer.clear() ;
vNextDer.clear() ;
// numero di punti
int nSize = int( vPnt.size()) ;
// sono necessari almeno due punti
if ( nSize < 2)
return false ;
// calcolo le derivate
vPrevDer.reserve( nSize) ;
vNextDer.reserve( nSize) ;
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
if ( nSize == 2) {
// non esiste derivata prima del primo punto
vPrevDer.emplace_back( 0, 0, 0) ;
vNextDer.push_back( ( vPnt[1] - vPnt[0]) / ( vPar[1] - vPar[0])) ;
vPrevDer.push_back( vNextDer[0]) ;
// non esiste derivata dopo il secondo e ultimo punto
vNextDer.emplace_back( 0, 0, 0) ;
return true ;
}
// verifico se curva chiusa (primo e ultimo punto coincidono)
bool bClosed = AreSamePointApprox( vPnt.front(), vPnt.back()) ;
// calcolo le derivate
for ( int i = 0 ; i < nSize ; ++ i) {
Vector3d vtPrevDer ;
Vector3d vtNextDer ;
// primo punto
if ( i == 0) {
// se curva chiusa, come precedente uso il penultimo punto
if ( bClosed) {
// se non ci sono almeno 5 punti
if ( nSize < 5) {
if ( ! CalcCircleMidDer( vPar[nSize-2] - vPar[nSize-1], vPnt[nSize-2], vPar[i], vPnt[i],
vPar[i+1], vPnt[i+1], vtNextDer))
return false ;
vtPrevDer = vtNextDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( vPar[nSize-3] - vPar[nSize-1], vPnt[nSize-3], vPar[nSize-2] - vPar[nSize-1], vPnt[nSize-2],
vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
vPar[i+2], vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// altrimenti, uso arco sui primi tre punti
else {
if ( ! CalcCircleStartDer( vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
vPar[i+2], vPnt[i+2], vtNextDer))
return false ;
vtPrevDer = Vector3d( 0, 0, 0) ;
}
}
// ultimo punto
else if ( i == nSize - 1) {
// se curva chiusa, le tg devono coincidere con quelle del primo
if ( bClosed) {
vtPrevDer = vPrevDer[0] ;
vtNextDer = vNextDer[0] ;
}
// altrimenti, uso arco sugli ultimi tre punti
else {
if ( ! CalcCircleEndDer( vPar[i-2], vPnt[i-2], vPar[i-1], vPnt[i-1],
vPar[i], vPnt[i], vtPrevDer))
return false ;
vtNextDer = Vector3d( 0, 0, 0) ;
}
}
// punti intermedi
else {
// se secondo punto
if ( i == 1) {
// se curva aperta o non ci sono almeno 5 punti
if ( ! bClosed || nSize < 5) {
if ( ! CalcCircleMidDer( vPar[i-1], vPnt[i-1], vPar[i], vPnt[i],
vPar[i+1], vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( vPar[nSize-2] - vPar[nSize-1], vPnt[nSize-2], vPar[i-1], vPnt[i-1],
vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
vPar[i+2], vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// se penultimo punto
else if ( i == nSize - 2) {
// se curva aperta o non ci sono almeno 5 punti
if ( ! bClosed || nSize < 5) {
if ( ! CalcCircleMidDer( vPar[i-1], vPnt[i-1], vPar[i], vPnt[i],
vPar[i+1], vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( vPar[i-2], vPnt[i-2], vPar[i-1], vPnt[i-1],
vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
vPar[1] + vPar[i+1], vPnt[1], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( vPar[i-2], vPnt[i-2], vPar[i-1], vPnt[i-1],
vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
vPar[i+2], vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// salvo la derivata
vPrevDer.push_back( vtPrevDer) ;
vNextDer.push_back( vtNextDer) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
ComputeBesselTangents( const DBLVECTOR& vPar, const PNTVECTOR& vPnt, VCT3DVECTOR& vPrevDer, VCT3DVECTOR& vNextDer)
{
// pulisco i vettori dei parametri e delle tangenti
vPrevDer.clear() ;
vNextDer.clear() ;
// numero di punti
int nSize = int( vPnt.size()) ;
// sono necessari almeno due punti
if ( nSize < 2)
return false ;
// calcolo le derivate
vPrevDer.reserve( nSize) ;
vNextDer.reserve( nSize) ;
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
if ( nSize == 2) {
// non esiste derivata prima del primo punto
vPrevDer.emplace_back( 0, 0, 0) ;
vNextDer.push_back( ( vPnt[1] - vPnt[0]) / ( vPar[1] - vPar[0])) ;
vPrevDer.push_back( vNextDer[0]) ;
// non esiste derivata dopo il secondo e ultimo punto
vNextDer.emplace_back( 0, 0, 0) ;
return true ;
}
// verifico se curva chiusa (primo e ultimo punto coincidono)
bool bClosed = AreSamePointApprox( vPnt.front(), vPnt.back()) ;
// calcolo le derivate
for ( int i = 0 ; i < nSize ; ++ i) {
Vector3d vtPrevDer ;
Vector3d vtNextDer ;
// primo punto
if ( i == 0) {
// se curva chiusa, come precedente uso il penultimo punto
if ( bClosed) {
if ( ! CalcBesselMidDer( vPar[nSize-2] - vPar[nSize-1], vPnt[nSize-2], vPar[i], vPnt[i],
vPar[i+1], vPnt[i+1], vtNextDer))
return false ;
vtPrevDer = vtNextDer ;
}
// altrimenti, uso i primi tre punti
else {
if ( ! CalcBesselStartDer( vPar[i], vPnt[i], vPar[i+1], vPnt[i+1],
vPar[i+2], vPnt[i+2], vtNextDer))
return false ;
vtPrevDer = Vector3d( 0, 0, 0) ;
}
}
// ultimo punto
else if ( i == nSize - 1) {
// se curva chiusa, le tg devono coincidere con quelle del primo
if ( bClosed) {
vtPrevDer = vPrevDer[0] ;
vtNextDer = vNextDer[0] ;
}
// altrimenti, uso gli ultimi tre punti
else {
if ( ! CalcBesselEndDer( vPar[i-2], vPnt[i-2], vPar[i-1], vPnt[i-1],
vPar[i], vPnt[i], vtPrevDer))
return false ;
vtNextDer = Vector3d( 0, 0, 0) ;
}
}
// punti intermedi
else {
if ( ! CalcBesselMidDer( vPar[i-1], vPnt[i-1], vPar[i], vPnt[i],
vPar[i+1], vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// salvo la derivata
vPrevDer.push_back( vtPrevDer) ;
vNextDer.push_back( vtNextDer) ;
}
return true ;
}
+5
View File
@@ -14,6 +14,8 @@
#pragma once
#include "/EgtDev/Include/EGkPoint3d.h"
#include "/EgtDev/Include/EgtNumCollection.h"
#include "/EgtDev/Include/EGkGeoCollection.h"
//----------------------------------------------------------------------------
@@ -179,3 +181,6 @@ CalcAkimaMidDer( double dU0, const Point3d& ptP0, double dU1, const Point3d& ptP
}
return ( ! vtPrevDer.IsZero() && ! vtNextDer.IsZero()) ;
}
bool ComputeAkimaTangents( bool bDetectCorner, const DBLVECTOR& vPar, const PNTVECTOR& vPnt, VCT3DVECTOR& vPrevDer, VCT3DVECTOR& vNextDer) ;
bool ComputeBesselTangents( const DBLVECTOR& vPar, const PNTVECTOR& vPnt, VCT3DVECTOR& vPrevDer, VCT3DVECTOR& vNextDer) ;
+436 -117
View File
@@ -722,7 +722,7 @@ AssignFeedSpiral( ICurveComposite* pCrv, const ISurfFlatRegion* pSrfRemoved, boo
//----------------------------------------------------------------------------
static bool
AssignFeedSpiralOpt( const int nOptType, const PocketParams& PockParams, ICurveComposite* pCrv )
AssignFeedSpiralOpt( int nOptType, const PocketParams& PockParams, ICurveComposite* pCrv )
{
// controllo della curva corrente
if ( pCrv == nullptr || ! pCrv->IsValid() || pCrv->GetCurveCount() == 0)
@@ -732,24 +732,24 @@ AssignFeedSpiralOpt( const int nOptType, const PocketParams& PockParams, ICurveC
if ( ! PockParams.bCalcFeed)
return AssignMaxFeed( pCrv, PockParams) ;
switch ( PockParams.nType) {
case POCKET_SPIRALIN :
if ( nOptType == 0) { // Spirale dall'Esterno
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
if ( u == 0) // prima circonferenza
pCrv->SetCurveTempParam( 0, GetMinFeed( PockParams), 0) ;
else // semi cerchi in tangenza
pCrv->SetCurveTempParam( u, GetMaxFeed( PockParams), 0) ;
}
if ( PockParams.nType == POCKET_SPIRALIN || PockParams.nType == POCKET_CONFORMAL_ZIGZAG ||
PockParams.nType == POCKET_CONFORMAL_ONEWAY) {
if ( nOptType == 0) { // Spirale dall'Esterno
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
if ( u == 0) // prima circonferenza
pCrv->SetCurveTempParam( 0, GetMinFeed( PockParams), 0) ;
else // semi cerchi in tangenza
pCrv->SetCurveTempParam( u, GetMaxFeed( PockParams), 0) ;
}
else if ( nOptType == 1) { // Trapezoidi
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ;
}
break ;
}
else if ( nOptType == 1) { // Trapezoidi
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ;
}
}
/* NB. Essendo la funzione CalcSpiral richiamata sia per lo SpiralIN che per lo SpiralOUT le curve sono sempre
orientate nello stesso modo, solamente alla fine viene invertita la curva finale per la svuotatura... */
case POCKET_SPIRALOUT :
else {
if ( nOptType == 0) { // Spiral verso l'esterno
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u) {
if ( u > pCrv->GetCurveCount() - 3) // prime semi circonferenze
@@ -762,9 +762,6 @@ AssignFeedSpiralOpt( const int nOptType, const PocketParams& PockParams, ICurveC
for ( int u = 0 ; u < pCrv->GetCurveCount() ; ++ u)
pCrv->SetCurveTempParam( u, GetMinFeed( PockParams), 0) ;
}
break ;
default :
break ;
}
return true ;
@@ -1047,13 +1044,12 @@ ExtendPath( ICurveComposite* pCompo, const ISurfFlatRegion* pSfr, const PocketPa
}
// angoli di rotazione ( potrebbero servirne altri)
double dAng45 = ANG_RIGHT / 2. ;
static DBLVECTOR vAngles = { 0., ANG_RIGHT, 3 * ANG_RIGHT,
dAng45, 3 * dAng45, 5 * dAng45, 7 * dAng45 } ;
const double ANG_45 = ANG_RIGHT / 2. ;
const array vAngles{ 0., ANG_RIGHT, 3 * ANG_RIGHT, ANG_45, 3 * ANG_45, 5 * ANG_45, 7 * ANG_45} ;
// ruoto il versore di uscita cercando un'entrata valida
double dMinDist = PockParams.dRad + PockParams.dRadialOffset ;
for ( int i = 0 ; i < int( vAngles.size()) ; ++ i) {
for ( int i = 0 ; i < ssize( vAngles) ; ++ i) {
// ruoto il versore d'uscita
Vector3d vtRotOut = GetRotate( vtFirstOut, Z_AX, - vAngles[i]) ;
// calcolo il punto di caduta dell'utensile
@@ -1062,9 +1058,9 @@ ExtendPath( ICurveComposite* pCompo, const ISurfFlatRegion* pSfr, const PocketPa
bool bInside = true ;
bool bOkOut = true ;
if ( PockParams.SfrLimit.IsValid()) {
bOkOut = ( IsPointInsideSurfFr( ptFall, &PockParams.SfrLimit, dMinDist, bInside) && ! bInside) ;
bOkOut = ( IsPointInsideSurfFr( ptFall, &PockParams.SfrLimit, dMinDist - 10. * EPS_SMALL, bInside) && ! bInside) ;
if ( bOkOut)
bOkOut = ( IsPointInsideSurfFr( Media( ptFall, pt), &PockParams.SfrLimit, dMinDist, bInside) && ! bInside) ;
bOkOut = ( IsPointInsideSurfFr( Media( ptFall, pt), &PockParams.SfrLimit, dMinDist - 10. * EPS_SMALL, bInside) && ! bInside) ;
}
if ( bOkOut)
bOkOut = ( IsPointInsideSurfFr( ptFall, pSfr, dMinDist, bInside) && ! bInside) ;
@@ -2639,6 +2635,87 @@ PreparareTrapezoidTwoBases( const ICurveComposite* pCrvCompo, const double dDiam
return true ;
}
//----------------------------------------------------------------------------
static bool
IsForcedStepTrapezoid( const ICurveComposite* pCrvTrap, const PocketParams& PockParam,
int nBase, int nSecondBase, bool& bForced)
{
bForced = false ;
// se la curva non è valida, allora non può essere forzato
if ( pCrvTrap == nullptr || ! pCrvTrap->IsValid())
return false ;
// scorro la curva e ricavo le TempProps
array<int, 4> vnProps ;
int nClose = 0 ;
for ( int i = 0 ; i < 4 ; ++ i) {
if ( ! pCrvTrap->GetCurveTempProp( i, vnProps[i], 0))
return false ;
if ( vnProps[i] == TEMP_PROP_CLOSE_EDGE)
++ nClose ;
}
double dDiam = 2. * PockParam.dRad ;
switch ( nClose) {
// se trapezio tutto aperto, allora non è forzato
case 0 :
bForced = false ;
break ;
// se ho un lato chiuso, non è forzato
case 1 :
bForced = false ;
break ;
// se ho due lati chiusi
case 2 : {
if ( nBase < 0 || nBase > 4 || nSecondBase < 0 || nSecondBase > 4)
return false ;
// se entrambe le basi sono chiuse, è forzato
if ( vnProps[nBase] == TEMP_PROP_CLOSE_EDGE && vnProps[nSecondBase] == TEMP_PROP_CLOSE_EDGE)
bForced = true ;
// se entrambe le basi sono aperte
else if ( vnProps[nBase] == TEMP_PROP_OPEN_EDGE && vnProps[nSecondBase] == TEMP_PROP_OPEN_EDGE) {
const ICurve* pCrvOpenBase = pCrvTrap->GetCurve( nBase) ;
const ICurve* pCrvOpenSecondBase = pCrvTrap->GetCurve( nSecondBase) ;
if ( pCrvOpenBase == nullptr || ! pCrvOpenBase->IsValid() ||
pCrvOpenSecondBase == nullptr || ! pCrvOpenSecondBase->IsValid())
return false ;
double dLenOpenBase ; pCrvOpenBase->GetLength( dLenOpenBase) ;
double dLenSecondOpenBase ; pCrvOpenSecondBase->GetLength( dLenSecondOpenBase) ;
bForced = ( dLenOpenBase < dDiam + 10. * EPS_SMALL &&
dLenSecondOpenBase < dDiam + 10. * EPS_SMALL) ;
}
// se alternate, non forzo
else
bForced = false ;
}
break ;
// se ho tre lati chiusi
case 3 : {
// diventa forzato se il lato aperto non è grande
double dLenOpen = 0. ;
for ( int i = 0 ; i < 4 ; ++ i) {
if ( vnProps[i] == TEMP_PROP_OPEN_EDGE) {
const ICurve* pCrvOpen = pCrvTrap->GetCurve( i) ;
if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid())
return false ;
pCrvOpen->GetLength( dLenOpen) ;
break ;
}
}
bForced = ( dLenOpen < dDiam + 10. * EPS_SMALL) ;
}
break ;
// se tutto chiuso, è forzato
case 4 :
bForced = true ;
break ;
default :
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
static bool
GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTrap,
@@ -2700,7 +2777,7 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr
double dLen0, dLen2 ;
pCrvTrap->GetCurve( 0)->GetLength( dLen0) ;
pCrvTrap->GetCurve( 2)->GetLength( dLen2) ;
if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL)
if ( dLen0 < dDiam - EPS_SMALL || dLen2 < dDiam - EPS_SMALL)
pCrvTrap->Clear() ;
}
@@ -2981,38 +3058,38 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr
// se non ho trovato delle basi, allora cerco in maniera generale un trapezoide ( se esiste)
if ( nBase == -1) {
bool bOK = false ;
for ( int u = 0 ; u < pCrvCompo->GetCurveCount() && !bOK ; ++ u) {
for ( int nU = 0 ; nU < pCrvCompo->GetCurveCount() && ! bOK ; ++ nU) {
// cerco un lato chiuso ( esiste per forza)
if ( pCrvCompo->GetCurve( u)->GetTempProp( 0) == 0) {
if ( pCrvCompo->GetCurve( nU)->GetTempProp( 0) == 0) {
// controllo se il lato corrente può essere una base
int nType = -1 ;
if ( ! GetBoxCrvOptTrap( u, pCrvCompo, dDiam, nType, pCrvTrap))
if ( ! GetBoxCrvOptTrap( nU, pCrvCompo, dDiam, nType, pCrvTrap))
return false ;
// se è una base valida
if ( nType != -1) {
// ricavo la dimensione di svuotatura
pCrvTrap->GetCurve( 1)->GetLength( dPocketSize) ;
// ricavo la sua direzione iniziale
Vector3d vtBaseDir ; pCrvCompo->GetCurve( u)->GetStartDir( vtBaseDir) ;
Vector3d vtBaseDir ; pCrvCompo->GetCurve( nU)->GetStartDir( vtBaseDir) ;
// ricavo il suo punto iniziale
Point3d ptBaseStart ; pCrvCompo->GetCurve( u)->GetStartPoint( ptBaseStart) ;
Point3d ptBaseStart ; pCrvCompo->GetCurve( nU)->GetStartPoint( ptBaseStart) ;
// ricavo il suo punto finale
Point3d ptBaseEnd ; pCrvCompo->GetCurve( u)->GetEndPoint( ptBaseEnd) ;
Point3d ptBaseEnd ; pCrvCompo->GetCurve( nU)->GetEndPoint( ptBaseEnd) ;
// cerco il lato chiuso lineare parallelo ad esso e distante circa dPocketSize
for ( int uu = 0 ; uu < pCrvCompo->GetCurveCount() && !bOK ; ++ uu) {
if ( uu == u ||
pCrvCompo->GetCurve( uu)->GetType() != CRV_LINE ||
pCrvCompo->GetCurve( uu)->GetTempProp() != 0)
for ( int nOtherU = 0 ; nOtherU < pCrvCompo->GetCurveCount() && ! bOK ; ++ nOtherU) {
if ( nOtherU == nU ||
pCrvCompo->GetCurve( nOtherU)->GetType() != CRV_LINE ||
pCrvCompo->GetCurve( nOtherU)->GetTempProp() != 0)
continue ;
Vector3d vtSecondBaseDir ; pCrvCompo->GetCurve( uu)->GetStartDir( vtSecondBaseDir) ;
Vector3d vtSecondBaseDir ; pCrvCompo->GetCurve( nOtherU)->GetStartDir( vtSecondBaseDir) ;
if ( ! AreOppositeVectorEpsilon( vtBaseDir, vtSecondBaseDir, 5 * EPS_SMALL))
continue ;
Point3d ptSecondBaseStart ; pCrvCompo->GetCurve( uu)->GetStartPoint( ptSecondBaseStart) ;
Point3d ptSecondBaseStart ; pCrvCompo->GetCurve( nOtherU)->GetStartPoint( ptSecondBaseStart) ;
double dDist = 0. ;
DistPointCurve DPL( ptBaseStart, *pCrvCompo->GetCurve( uu), false) ;
DistPointCurve DPL( ptBaseStart, *pCrvCompo->GetCurve( nOtherU), false) ;
if ( DPL.GetDist( dDist) && abs( dDist - dDiam) < TOL_TRAPEZOID) {
nBase = u ;
nSecondBase = uu ;
nBase = nU ;
nSecondBase = nOtherU ;
if ( ! PreparareTrapezoidTwoBases( pCrvCompo, dDiam, nType, nBase, nSecondBase, bOK, pCrvTrap))
return false ;
}
@@ -3041,8 +3118,12 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr
return false ;
// se parametro MaxOptSize non compatibile => non è ottimizzato
if ( PockParams.dMaxOptSize > EPS_SMALL && dPocketSize > PockParams.dMaxOptSize)
pCrvTrap->Clear() ;
bool bForced = false ;
IsForcedStepTrapezoid( pCrvTrap, PockParams, nBase, nSecondBase, bForced) ;
if ( ! bForced) {
if ( PockParams.dMaxOptSize > EPS_SMALL && dPocketSize > PockParams.dMaxOptSize)
pCrvTrap->Clear() ;
}
return true ;
}
@@ -3050,7 +3131,8 @@ GetTrapezoidFromShape( const ICurveComposite* pCrvCompo, ICurveComposite* pCrvTr
//----------------------------------------------------
static bool
SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenClosed,
const ICurveComposite* pCrvPocket, const PocketParams& PockParams)
const ICurveComposite* pCrvPocket, const PocketParams& PockParams,
const Point3d& ptRef)
{
// parametri
double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ;
@@ -3060,10 +3142,18 @@ SpecialAdjustTrapezoidSpiralForAngles( ICurveComposite* pMCrv, const bool bEvenC
// calcolo gli offset dei lati obliqui
PtrOwner<ICurveLine> pLineS( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 0 : 3)->Clone())) ;
pLineS->SimpleOffset( - dRad) ;
pLineS->Invert() ;
PtrOwner<ICurveLine> pLineE( GetCurveLine( pCrvPocket->GetCurve( bEvenClosed ? 2 : 1)->Clone())) ;
pLineE->SimpleOffset( - dRad) ;
pLineE->Invert() ;
// verifico orientamento delle curve in base al punto di riferimento ( se valido)
double dSqDistS = 0., dSqDistE = 0. ;
if ( ! ptRef.IsValid() ||
( ( DistPointCurve( ptRef, *pCrvPocket->GetCurve( bEvenClosed ? 3 : 0)).GetSqDist( dSqDistS)) &&
( DistPointCurve( ptRef, *pCrvPocket->GetCurve( bEvenClosed ? 1 : 2)).GetSqDist( dSqDistE)) &&
dSqDistS < dSqDistE)) {
pLineS->Invert() ;
pLineE->Invert() ;
}
Point3d ptS, ptE ;
pLineS->GetEndPoint( ptS) ;
@@ -3134,10 +3224,10 @@ CalcTrapezoidSpiralXCoord( const ICurveComposite* pCrvPocket, int nBase, int nSe
double dDiam = PockParams.dRad_prec > 0 ? 2 * PockParams.dRad_prec : 2 * PockParams.dRad ;
double dOffsR = PockParams.dRad_prec > 0 ? PockParams.dRadialOffset_prec : PockParams.dRadialOffset ;
double dRad = 0.5 * dDiam + dOffsR ;
// recupero la curva di interesse
int nCrvId = ( bStart ? nSecondBase : nBase) + 1 ;
int nProp = - 1 ;
int nProp = -1 ;
if ( ! pCrvPocket->GetCurveTempProp( nCrvId, nProp))
return false ;
// se Open
@@ -3417,6 +3507,9 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
// passo in un sistema di riferimento locale avente asse X allineato con uno dei due lati paralleli
// (possibilmente aperto) e centro nel punto iniziale del lato
pCrvPocket->ToLoc( frTrap) ;
Point3d ptRef = P_INVALID ;
if ( PockParams.ptStart.IsValid())
ptRef = GetToLoc( PockParams.ptStart, frTrap) ;
// calcolo la larghezza massima della svuotatura (riferimento con X parallelo a primo lato chiuso)
double dLen0, dLen1, dLen2, dLen3, dMaxLarg = 0. ;
@@ -3433,16 +3526,19 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
Vector3d vtX ; pCrvPocket->GetCurve( 1)->GetStartDir( vtX) ;
Frame3d frDim ; frDim.Set( ptOrig, Z_AX, vtX) ; frDim.Invert() ;
BBox3d b3Dim ; pCrvPocket->GetBBox( frDim, b3Dim, BBF_EXACT) ;
dMaxLarg = ( vnProp[0] != 0 ? b3Dim.GetDimY() : dPocketSize) ;
dMaxLarg = ( vnProp[0] != TEMP_PROP_CLOSE_EDGE ? b3Dim.GetDimY() : dPocketSize) ;
}
// calcolo percorso di svuotatura
// se lati obliqui sono entrambi chiusi e dimensione svuotatura è maggiore di diametro fresa e minore del doppio gestione speciale
if (( bRealTrap && dMaxLarg > PockParams.dRad * 2 + 10 * EPS_SMALL) &&
((( vnProp[0] != 0 && vnProp[2] != 0) && ( vnProp[3] == 0 && vnProp[1] == 0) && ( max( dLen0, dLen2) < 2 * dDiam + EPS_SMALL)) ||
(( vnProp[1] != 0 && vnProp[3] != 0) && ( vnProp[0] == 0 && vnProp[2] == 0) && ( max( dLen1, dLen3) < 2 * dDiam + EPS_SMALL)))) {
if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, vnProp[0] == 0, pCrvPocket, PockParams)) {
if ( ( bRealTrap && dMaxLarg > dDiam + 10. * EPS_SMALL) &&
( ( ( vnProp[0] != TEMP_PROP_CLOSE_EDGE && vnProp[2] != TEMP_PROP_CLOSE_EDGE) &&
( vnProp[3] == TEMP_PROP_CLOSE_EDGE && vnProp[1] == TEMP_PROP_CLOSE_EDGE) &&
( max( dLen0, dLen2) < 2. * dDiam + EPS_SMALL)) ||
( ( vnProp[1] != TEMP_PROP_CLOSE_EDGE && vnProp[3] != TEMP_PROP_CLOSE_EDGE) &&
( vnProp[0] == TEMP_PROP_CLOSE_EDGE && vnProp[2] == TEMP_PROP_CLOSE_EDGE) &&
( max( dLen0, dLen2) < 2. * dDiam + EPS_SMALL)))) {
if ( ! SpecialAdjustTrapezoidSpiralForAngles( pMCrv, ( vnProp[0] == TEMP_PROP_CLOSE_EDGE), pCrvPocket, PockParams, ptRef)) {
pMCrv->Clear() ;
return false ;
}
@@ -3452,7 +3548,7 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
double dYCoord ;
// se base principale chiusa
if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE)
dYCoord = 0.5 * dDiam + dOffsR ;
dYCoord = 0.5 * dDiam + dOffsR ;
// se base principale aperta e secondaria chiusa
else if ( pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE)
dYCoord = dPocketSize - 0.5 * dDiam - dOffsR ;
@@ -3463,15 +3559,32 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
// determino le quote coordinate in X inziale e finale
double dXCoordStart = -INFINITO ;
double dXCoordEnd = INFINITO ;
if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, true, dYCoord, dXCoordStart,
dPocketSize, PockParams) || dXCoordStart < - INFINITO + 1)
if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, true, dYCoord, dXCoordStart, dPocketSize, PockParams) ||
dXCoordStart < - INFINITO + 1)
return false ;
if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, false, dYCoord, dXCoordEnd,
dPocketSize, PockParams) || dXCoordEnd > INFINITO - 1)
if ( ! CalcTrapezoidSpiralXCoord( pCrvPocket, nBase, nSecondBase, false, dYCoord, dXCoordEnd, dPocketSize, PockParams) ||
dXCoordEnd > INFINITO - 1)
return false ;
if ( dXCoordStart > dXCoordEnd + 500 * EPS_SMALL)
return false ;
// determino se devo invertire la curva dato il punto di riferimento
bool bInvertByRef = false ;
if ( ptRef.IsValid()) {
PtrOwner<ICurve> pCrvRight( pCrvPocket->CopyParamRange( nBase + 1, nSecondBase)) ;
PtrOwner<ICurve> pCrvLeft( pCrvPocket->CopyParamRange( nSecondBase + 1, nBase)) ;
if ( IsNull( pCrvRight) || IsNull( pCrvLeft) ||
! pCrvRight->IsValid() || ! pCrvLeft->IsValid())
return false ;
double dSqDistBase = INFINITO, dSqDistSecondBase = INFINITO, dSqDistLeft = INFINITO, dSqDistRight = INFINITO ;
DistPointCurve( ptRef, *pCrvPocket->GetCurve( nBase)).GetSqDist( dSqDistBase) ;
DistPointCurve( ptRef, *pCrvPocket->GetCurve( nSecondBase)).GetSqDist( dSqDistSecondBase) ;
DistPointCurve( ptRef, *pCrvRight).GetSqDist( dSqDistRight) ;
DistPointCurve( ptRef, *pCrvLeft).GetSqDist( dSqDistLeft) ;
bInvertByRef = ( dSqDistSecondBase < min( {dSqDistBase, dSqDistLeft, dSqDistRight}) ||
dSqDistRight < min( {dSqDistBase, dSqDistSecondBase, dSqDistLeft})) ;
}
// determino gli estremi del segmento di svuotatura
Point3d ptStart( dXCoordStart, dYCoord) ;
Point3d ptEnd( dXCoordEnd, dYCoord) ;
@@ -3491,7 +3604,6 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
if ( ! pLine1->SimpleOffset( - PockParams.dRad - PockParams.dRadialOffset) ||
! pLine3->SimpleOffset( - PockParams.dRad - PockParams.dRadialOffset))
return false ;
Point3d ptS, ptE ;
if ( vtDir3 * X_AX > EPS_SMALL) {
pLine1->GetStartPoint( ptS) ;
@@ -3501,7 +3613,6 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
pLine1->GetEndPoint( ptE) ;
pLine3->GetEndPoint( ptS) ;
}
if ( vnProp[0] != TEMP_PROP_CLOSE_EDGE) {
pMCrv->AddPoint( ptS) ;
if ( vnProp[2] != TEMP_PROP_CLOSE_EDGE)
@@ -3517,34 +3628,37 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
pMCrv->AddLine( ptStart) ;
pMCrv->Invert() ;
}
pMCrv->SetCurveTempProp( 0, TEMP_PROP_OPEN_EDGE) ;
// verifico se invertirla nel caso di un punto di riferimento
if ( bInvertByRef &&
vnProp[0] != TEMP_PROP_CLOSE_EDGE && vnProp[2] != TEMP_PROP_CLOSE_EDGE)
pMCrv->Invert() ;
}
}
// se estremi del segmento differenti, allora il percorso è definito
else {
// creo la linea
if ( ! pMCrv->AddPoint( ptStart))
return true ;
if ( ! pMCrv->AddLine( ptEnd))
return true ;
// aggiustamenti al percorso per rimuovere materiale residuo negli angoli
if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE ||
pCrvPocket->GetCurve( nSecondBase)->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) {
Frame3d frOpen ;
bool bSwitch = false ;
// Base principale chiusa e base Secondaria aperta
if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE) {
// Base Principale chiusa e Base Secondaria aperta o inversione per punto di riferimento
if ( pCrvPocket->GetCurve( nBase)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE ||
bInvertByRef) {
pCrvPocket->ChangeStartPoint( nSecondBase) ;
// oriento il Frame ( ho sempre l'origine nell'estremo superiore del lato aperto)
Vector3d vtDir ; pCrvPocket->GetStartDir( vtDir) ;
Point3d ptORIG ;
Point3d ptOpen ;
if ( vtDir.y > 0)
pCrvPocket->GetCurve( nBase)->GetEndPoint( ptORIG) ;
pCrvPocket->GetFirstCurve()->GetEndPoint( ptOpen) ;
else
pCrvPocket->GetCurve( nBase)->GetStartPoint( ptORIG) ;
frOpen.Set( ptORIG, Z_AX, -X_AX) ;
pCrvPocket->GetFirstCurve()->GetStartPoint( ptOpen) ;
frOpen.Set( ptOpen, Z_AX, -X_AX) ;
if ( ! frOpen.IsValid())
return false ;
pCrvPocket->ToLoc( frOpen) ;
@@ -3552,7 +3666,7 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
pMCrv->Invert() ;
bSwitch = true ;
}
// la Base principale è sempre aperta
if ( pCrvPocket->GetCurve( 3)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE &&
! AdjustTrapezoidSpiralForAngles( pMCrv, pCrvPocket, PockParams, true)) {
pMCrv->Clear() ;
@@ -3576,14 +3690,8 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
if ( pMCrv->GetCurveCount() == 0)
return true ;
pMCrv->ToGlob( frTrap) ;
if ( PockParams.bInvert) {
pMCrv->Invert() ;
// inverto le proprietà in modo che nProp3 sia sempre legata al punto iniziale e nProp1 a quello finale
swap( vnProp[1], vnProp[3]) ;
}
// segno i lati aperti come temp prop della curva
int nOpenEdges = vnProp[0] + vnProp[1] * 2 + vnProp[2] * 4 + vnProp[3] * 8 ;
pMCrv->SetTempProp( nOpenEdges, 0) ;
@@ -3593,6 +3701,112 @@ CalcTrapezoidSpiral( ICurveComposite* pCrvPocket, const Frame3d& frTrap, double
return true ;
}
//----------------------------------------------------------------------------
static bool
AdjustTrapeziodLeadIn( ICurveComposite* pCrvRes, const PocketParams& PockParam,
const ISurfFlatRegion* pSfrChunk)
{
// recupero la TempProp
int nTmpProp = pCrvRes->GetTempProp( 0) ;
// se esiste almeno un aperto
if ( nTmpProp > 0) {
// se solo lato3 aperto
bool bCheckHead = ( nTmpProp != 8 && nTmpProp != 2) ;
if ( nTmpProp == 2)
pCrvRes->Invert() ; // entro dall'unico aperto
if ( bCheckHead) {
// recupero gli estremi della curva corrente e la inverto in base alla Testa
Point3d ptS ; pCrvRes->GetStartPoint( ptS) ;
Point3d ptE ; pCrvRes->GetEndPoint( ptE) ;
Point3d ptSGlob = GetToGlob( ptS, PockParam.frLocXY) ;
Point3d ptEGlob = GetToGlob( ptE, PockParam.frLocXY) ;
if ( ( PockParam.bAboveHead && ptEGlob.z > ptSGlob.z) ||
( ! PockParam.bAboveHead && ptEGlob.z < ptSGlob.z))
pCrvRes->Invert() ;
}
}
// Assegno la Feed
AssignFeedSpiralOpt( 1, PockParam, pCrvRes) ;
// Se curva da invertire, inverto
if ( PockParam.bInvert)
pCrvRes->Invert() ;
// se esiste almeno un aperto, provo ad estendere il percorso
if ( nTmpProp > 0) {
// Calcolo eventuale entrata da fuori
Vector3d vtRef ; pCrvRes->GetStartDir( vtRef) ;
vtRef.Invert() ;
bool bIsStartExtended = false ;
if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, false, PockParam.dRad + PockParam.dOpenMinSafe, bIsStartExtended))
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
static bool
GetZigZagOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& PockParam,
ICurveComposite* pCrvRes)
{
// controllo dei parametri
if ( pSfrChunk == nullptr || ! pSfrChunk->IsValid())
return false ;
pCrvRes->Clear() ;
// ricavo la curva di bordo del chunk corrente
PtrOwner<ICurveComposite> pCrvBorder( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ;
if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid())
return false ;
pCrvBorder->MergeCurves( 10. * EPS_SMALL, 10. * EPS_ANG_SMALL, true, true) ;
pCrvBorder->SetExtrusion( pSfrChunk->GetNormVersor()) ;
/* TRAPEZI
- E' richiesto che una dimensione del box della curva sia compatibile con il primo Offset, il
quale sarebbe una singola curva aperta
*/
PtrOwner<ICurveComposite> pCrvTrap( CreateCurveComposite()) ;
if ( IsNull( pCrvTrap))
return false ;
Frame3d frTrap ;
double dPocketSize ;
int nBase, nSecondBase ;
bool bOkTrap = GetTrapezoidFromShape( pCrvBorder, pCrvTrap, frTrap, PockParam, dPocketSize, nBase, nSecondBase) ;
if ( bOkTrap && pCrvTrap->IsValid()) {
// verifico se il trapezio ottenuto deve o meno rispettare il SideStep
bool bForcedTrap = false ;
IsForcedStepTrapezoid( pCrvTrap, PockParam, nBase, nSecondBase, bForcedTrap) ;
if ( ! bForcedTrap)
bOkTrap = ( dPocketSize < PockParam.dMaxOptSize + 10. * EPS_SMALL) ;
}
if ( bOkTrap && pCrvTrap->IsValid()) {
pCrvTrap->SetExtrusion( Z_AX) ;
CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParam, pCrvRes, bOkTrap) ;
if ( bOkTrap) {
// verifico che tale curva non interferisca con la regione limite
if ( PockParam.SfrLimit.IsValid()) {
double dOffsCheck = PockParam.dRad + PockParam.dRadialOffset - 50. * EPS_SMALL ; // restrittivo per sicurezza
PtrOwner<ISurfFlatRegion> pSfrToolShape( GetSurfFlatRegionFromFatCurve( pCrvRes->Clone(), dOffsCheck, false, false)) ;
bOkTrap = ( ! IsNull( pSfrToolShape) && pSfrToolShape->IsValid()) ;
if ( bOkTrap) {
bOkTrap = ( pSfrToolShape->Intersect( PockParam.SfrLimit) &&
! pSfrToolShape->IsValid()) ;
if ( ! bOkTrap)
pCrvRes->Clear() ;
}
}
if ( bOkTrap) {
AdjustTrapeziodLeadIn( pCrvRes, PockParam, pSfrChunk) ;
// imposto il flag di curva singola
pCrvRes->SetTempProp( TEMP_PROP_OPT_TRAPEZOID, 0) ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
static bool
GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams& PockParam,
@@ -3607,7 +3821,7 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams&
PtrOwner<ICurveComposite> pCrvBorder( ConvertCurveToComposite( pSfrChunk->GetLoop( 0, 0))) ;
if ( IsNull( pCrvBorder) || ! pCrvBorder->IsValid())
return false ;
pCrvBorder->MergeCurves( 10 * EPS_SMALL, 10 * EPS_ANG_SMALL, true, true) ;
pCrvBorder->MergeCurves( 10. * EPS_SMALL, 10. * EPS_ANG_SMALL, true, true) ;
pCrvBorder->SetExtrusion( pSfrChunk->GetNormVersor()) ;
/* SPIRALE EUCLIDEA
@@ -3620,17 +3834,35 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams&
if ( bOkSpiral) {
// controllo che sia una circonferenza
Point3d ptCen ; double dRad ;
if ( ! OptimizedSpiralCircle( pCrvBorder, 50 * EPS_SMALL, dRad, ptCen, bOkSpiral))
if ( ! OptimizedSpiralCircle( pCrvBorder, 50. * EPS_SMALL, dRad, ptCen, bOkSpiral))
return false ;
// se è una circonferenza
if ( bOkSpiral) {
double dOffs = PockParam.dRad + PockParam.dRadialOffset ;
// se curva tutta Open, allora ingrandisco il raggio
if ( nTempPropRef == TEMP_PROP_OPEN_EDGE)
// se curva tutta Open
if ( nTempPropRef == TEMP_PROP_OPEN_EDGE) {
// ingrandisco il raggio
dRad += 1.05 * PockParam.dRad + PockParam.dRadialOffset ;
// verifico che l'utensile ora non interferisca con la regione limite
if ( PockParam.SfrLimit.IsValid()) {
// definisco il nuovo bordo
PtrOwner<ICurveArc> pCrvArc( CreateCurveArc()) ;
bOkSpiral = ( ! IsNull( pCrvArc) &&
pCrvArc->Set( ptCen, Z_AX, dRad + PockParam.dRad)) ;
if ( bOkSpiral) {
CRVCVECTOR ccClass ;
bOkSpiral = ( PockParam.SfrLimit.GetCurveClassification( *pCrvArc, EPS_SMALL, ccClass) &&
ssize( ccClass) == 1 && ccClass[0].nClass == CRVC_OUT) ;
// NB. una versione più complessa dovrebbe verificare se la sottrazione tra la
// superficie dell'utensile e la regione limite non genera un'altra circonferenza...
// In questo caso la sottrazione potrebbe essere trattata come una circonferenza
// chiusa ed essere ancora svotata a spirale...
}
}
}
// se curva chiusa, controllo che il raggio sia compatibile con il primo Offset
else
bOkSpiral = ( dRad - dOffs > 10 * EPS_SMALL) ;
bOkSpiral = ( dRad - dOffs > 10. * EPS_SMALL) ;
if ( bOkSpiral) {
double dIntRad = 0 ;
if ( PockParam.nType == POCKET_SPIRALOUT && PockParam.nLiType == LEAD_IN_HELIX)
@@ -3664,25 +3896,34 @@ GetSpiralOptimizedCurves( const ISurfFlatRegion* pSfrChunk, const PocketParams&
Frame3d frTrap ;
double dPocketSize ;
int nBase, nSecondBase ;
bool bOkTrap = ( GetTrapezoidFromShape( pCrvBorder, pCrvTrap, frTrap, PockParam, dPocketSize, nBase, nSecondBase) &&
dPocketSize < PockParam.dMaxOptSize + 10 * EPS_SMALL) ;
bool bOkTrap = GetTrapezoidFromShape( pCrvBorder, pCrvTrap, frTrap, PockParam, dPocketSize, nBase, nSecondBase) ;
if ( bOkTrap && pCrvTrap->IsValid()) {
// verifico se il trapezio ottenuto deve o meno rispettare il SideStep
bool bForcedTrap = false ;
IsForcedStepTrapezoid( pCrvTrap, PockParam, nBase, nSecondBase, bForcedTrap) ;
if ( ! bForcedTrap)
bOkTrap = ( dPocketSize < PockParam.dMaxOptSize + 10. * EPS_SMALL) ;
}
if ( bOkTrap && pCrvTrap->IsValid()) {
pCrvTrap->SetExtrusion( Z_AX) ;
CalcTrapezoidSpiral( pCrvTrap, frTrap, dPocketSize, nBase, nSecondBase, PockParam, pCrvRes, bOkTrap) ;
if ( bOkTrap) {
// calcolo eventuali uscite e ingressi
if ( pCrvRes->GetTempProp( 0) > 0) {
Vector3d vtRef ; pCrvRes->GetStartDir( vtRef) ;
vtRef.Invert() ;
bool bIsStartExtended = false ;
if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, false, PockParam.dRad + PockParam.dOpenMinSafe, bIsStartExtended))
return false ;
pCrvRes->GetEndDir( vtRef) ;
bool bIsEndExtended = false ;
if ( ! ExtendPath( pCrvRes, pSfrChunk, PockParam, vtRef, true, PockParam.dRad + PockParam.dOpenMinSafe, bIsEndExtended))
return false ;
if ( bIsEndExtended && ! bIsStartExtended)
pCrvRes->Invert() ;
// verifico che tale curva non interferisca con la regione limite
if ( PockParam.SfrLimit.IsValid()) {
double dOffsCheck = PockParam.dRad + PockParam.dRadialOffset - 50. * EPS_SMALL ; // restrittivo per sicurezza
PtrOwner<ISurfFlatRegion> pSfrToolShape( GetSurfFlatRegionFromFatCurve( pCrvRes->Clone(), dOffsCheck, false, false)) ;
bOkTrap = ( ! IsNull( pSfrToolShape) && pSfrToolShape->IsValid()) ;
if ( bOkTrap) {
bOkTrap = ( pSfrToolShape->Intersect( PockParam.SfrLimit) &&
! pSfrToolShape->IsValid()) ;
if ( ! bOkTrap)
pCrvRes->Clear() ;
}
}
if ( bOkTrap) {
AdjustTrapeziodLeadIn( pCrvRes, PockParam, pSfrChunk) ;
// imposto il flag di curva singola
pCrvRes->SetTempProp( TEMP_PROP_OPT_TRAPEZOID, 0) ;
}
}
}
@@ -3725,23 +3966,31 @@ GetPocketingOptimizedCurves( ISurfFlatRegion* pSfr, const PocketParams& PockPara
PockParam.nType == POCKET_CONFORMAL_ZIGZAG || PockParam.nType == POCKET_CONFORMAL_ONEWAY) {
// curva da resituire
PtrOwner<ICurveComposite> pCrvOptSpiral( CreateCurveComposite()) ;
if ( IsNull( pCrvOptSpiral) ||
! GetSpiralOptimizedCurves( pSfrChunk, PockParam, pCrvOptSpiral))
if ( IsNull( pCrvOptSpiral) ||
! GetSpiralOptimizedCurves( pSfrChunk, PockParam, pCrvOptSpiral))
return false ;
// se ho ricavato una curva ottimizzata
if ( ! IsNull( pCrvOptSpiral) && pCrvOptSpiral->IsValid() && pCrvOptSpiral->GetCurveCount() > 0) {
vCrvOptCurves.emplace_back( Release( pCrvOptSpiral)) ;
vCrvOptCurves.emplace_back( Release( pCrvOptSpiral)) ;
pSfr->EraseChunk( nCurrChunk) ;
}
else
++ nCurrChunk ;
}
else if ( PockParam.nType == POCKET_ZIGZAG || PockParam.nType == POCKET_ONEWAY) {
// curva da restituire
PtrOwner<ICurveComposite> pCrvOptZigZag( CreateCurveComposite()) ;
if ( IsNull( pCrvOptZigZag) ||
! GetZigZagOptimizedCurves( pSfrChunk, PockParam, pCrvOptZigZag))
return false ;
// se ho ricavato una curva ottimizzata
if ( ! IsNull( pCrvOptZigZag) && pCrvOptZigZag->IsValid() && pCrvOptZigZag->GetCurveCount() > 0) {
vCrvOptCurves.emplace_back( Release( pCrvOptZigZag)) ;
pSfr->EraseChunk( nCurrChunk) ;
}
else
++ nCurrChunk ;
}
// else if ( PockParam.nType == POCKET_ZIGZAG)
// ;
// else if ( PockParam.nType == POCKET_ONEWAY)
// ;
// else if ( PockParam.nType == POCKET_CONFORMAL_ONEWAY || PockParam.nType == POCKET_CONFORMAL_ZIGZAG)
// ;
}
return true ;
@@ -3849,7 +4098,7 @@ GetParamOnOpenCurve( const ICurveComposite* pCompo, const PocketParams& PockPara
//----------------------------------------------------------------------------
static bool
GetPtStartOnOpenEdgeByOrigCurve( const ICurveComposite* pCrvOrig, const PocketParams& PockParams,
GetPtStartOnOpenEdgeByOrigCurve( const Point3d& ptRef, const ICurveComposite* pCrvOrig, const PocketParams& PockParams,
const ICurveComposite* pCrvCompo, Point3d& ptStart, Vector3d& vtMidOut,
bool& bMidOut)
{
@@ -3859,8 +4108,71 @@ GetPtStartOnOpenEdgeByOrigCurve( const ICurveComposite* pCrvOrig, const PocketPa
return false ;
bMidOut = false ;
// cerco il lato aperto più lungo ( sufficientemente lungo)
double dLenRef = ( 2 * PockParams.dRad + 2 * PockParams.dRadialOffset) - 50 * EPS_SMALL ;
// se ho un punto di riferimento, cerco il lato aperto sull'originale più vicino ad essa ( sufficientemente lungo)
if ( ptRef.IsValid()) {
double dSqMinDist = INFINITO ;
int nIndCrv = -1 ;
for ( int i = 0 ; i < pCrvOrig->GetCurveCount() ; ++ i) {
// escludo le sottocurve chiuse
if ( pCrvOrig->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE)
continue ;
// recupero la curva i-esima aperta dalla curva originale
const ICurve* pCrvOpen = pCrvOrig->GetCurve( i) ;
if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid())
return false ;
// ricavo la lunghezza di tale curva
double dLen = 0. ;
pCrvOpen->GetLength( dLen) ;
// se lunghezza accettabile o maggiore della massima trovata
if ( dLen > dLenRef - 10. * EPS_SMALL) {
// verifico la distanza con il punto di riferimento
double dCurrSqDist = 0. ;
if ( DistPointCurve( ptRef, *pCrvOpen).GetSqDist( dCurrSqDist) && dCurrSqDist < dSqMinDist) {
dSqMinDist = dCurrSqDist ;
nIndCrv = i ;
}
}
}
// se ho un indice di curva valido, allora ricavo i valori
if ( nIndCrv != -1) {
// recupero la curva
const ICurve* pCrvOpen = pCrvOrig->GetCurve( nIndCrv) ;
if ( pCrvOpen == nullptr || ! pCrvOpen->IsValid())
return false ;
Point3d ptSTmp ;
Vector3d vtMidOutTmp ;
// ricavo il punto medio e il vettore tangente ad esso associato
if ( pCrvOpen->GetPointD1D2( 0.5, ICurve::FROM_MINUS, ptSTmp, &vtMidOutTmp)) {
// versore d'uscita
vtMidOutTmp.Normalize() ;
vtMidOutTmp.Rotate( Z_AX, 0, -1) ;
ptSTmp += vtMidOutTmp * max( PockParams.dRad - PockParams.dSideStep, 0.) ;
// cerco la sottocurva più vicina a ptSTmp
int nFlag ;
double dMyPar ;
if ( DistPointCurve( ptSTmp, *pCrvCompo).GetParamAtMinDistPoint( 0, dMyPar, nFlag)) {
int nCrv = int( floor( dMyPar)) ;
// recupero tale sottocurva e controllo che anche essa sia OPEN
const ICurve* pMyCrv = pCrvCompo->GetCurve( nCrv) ;
if ( pMyCrv != nullptr && pMyCrv->IsValid() && pMyCrv->GetTempProp( 0) == TEMP_PROP_OPEN_EDGE) {
// recupero ptStart
pMyCrv->GetMidPoint( ptStart) ;
// assegno direzione fuori
vtMidOut = vtMidOutTmp ;
// flag per possibile entrata da fuori
bMidOut = true ;
}
}
}
// esco
return true ;
}
}
// se non ho un punto di riferimento valido, o avendolo non si riesce ad entrare dal lato aperto più vicino
// cerco il lato aperto più lungo ( sufficientemente lungo)
for ( int i = 0 ; i < pCrvOrig->GetCurveCount() ; ++ i) {
// escludo le sottocurve chiuse
if ( pCrvOrig->GetCurve( i)->GetTempProp( 0) == TEMP_PROP_CLOSE_EDGE)
@@ -3944,7 +4256,7 @@ GetPtStartOnOpenEdgeByPtRef( const Point3d& ptRef, const PocketParams& PockParam
// se non ho trovato nulla, allora cerco un punto iniziale valido su una sottocurva OPEN
if ( nStartCrv == -1 && pCrvOrig != nullptr && pCrvOrig->IsValid()) {
return GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvCompo, ptStart, vtMidOut, bMidOut) ;
return GetPtStartOnOpenEdgeByOrigCurve( ptRef, pCrvOrig, PockParams, pCrvCompo, ptStart, vtMidOut, bMidOut) ;
}
// se ho trovato la curva più vicina, cerco un punto iniziale valido
else {
@@ -4233,7 +4545,7 @@ SetPtStartForPath( ICurveComposite* pCrvOffs, const PocketParams& PockParams, co
if ( pCrvOrig != nullptr && pCrvOrig->IsValid()) {
// ... e non ho un punto di riferimento, lo cerco sulla curva originale
if ( ! ptEndPrec.IsValid()) {
if ( ! GetPtStartOnOpenEdgeByOrigCurve( pCrvOrig, PockParams, pCrvOffs, ptStart, vtMidOut, bMidOut))
if ( ! GetPtStartOnOpenEdgeByOrigCurve( P_INVALID, pCrvOrig, PockParams, pCrvOffs, ptStart, vtMidOut, bMidOut))
return false ;
}
// ... e ho un punto di riferimento
@@ -4828,7 +5140,7 @@ CalcBoundedSmoothedLink( const Point3d& ptStart, const Vector3d& vtStart, const
return false ;
// controllo se la distanza lineare tra i due punti è maggiore della tolleranza...
static double dSqTol = 4 * PockParams.dRad * PockParams.dRad + PockParams.dSideStep * PockParams.dSideStep ;
const double dSqTol = 4 * PockParams.dRad * PockParams.dRad + PockParams.dSideStep * PockParams.dSideStep ;
if ( SqDist( ptStart, ptEnd) > dSqTol)
bSpecial = ( CalcSpecialBoundedSmoothedLink( ptStart, vtStart, ptEnd, vtEnd, PockParams, pMyCrvLink)) ;
if ( ! pMyCrvLink->IsValid() || pMyCrvLink->GetCurveCount() == 0) {
@@ -5917,6 +6229,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co
// ricavo le regioni progressive
double dOffsPrec = 0. ;
int nCrvFirstOffs = 0 ;
bool bLastNotValid = false ;
while ( nIter < MAX_ITER) {
// Offset della regione attuale
PtrOwner<ISurfFlatRegion> pSfrOffsVR( pSrfAct->CreateOffsetSurf( - dOffs, ICurve::OFF_FILLET)) ;
@@ -5927,6 +6240,7 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co
pSfrOffsVR.Set( pSrfAct->CreateOffsetSurf( - dOffs + 5 * EPS_SMALL, ICurve::OFF_FILLET)) ;
if ( IsNull( pSfrOffsVR))
return false ;
bLastNotValid = true ;
}
// se primo Offset
@@ -5958,6 +6272,10 @@ CalcSpiral( const ISurfFlatRegion* pSfrPock, const ISurfFlatRegion* pSfrOrig, co
bool bInsert = true ;
if ( ! CheckIfOffsetIsNecessary( pSrfAct, pCrvCompoBorder, dOffs, dOffsPrec, nIter, PockParams, bInsert))
return false ;
// per evitare di allacciare una curva di regione non svuotata alla prima curva di Offset
// ( quindi avere un entrata nel pieno del grezzo) controllo di non eliminare il secondo Offset
if ( ! bInsert && nChunks == 1 && bLastNotValid)
bInsert = true ;
if ( bInsert) {
// imposto come secondo TempParam il Side di classificazione
pCrvCompoBorder->SetTempParam( j == 0 ? MDS_RIGHT : MDS_LEFT, 1) ;
@@ -8774,14 +9092,14 @@ CalcSpiralPocketing( const ISurfFlatRegion* pSfr, int nType, const PocketParams&
// il tipo può essere solo SpiralIn o SpiralOut
if ( nType != POCKET_SPIRALIN && nType != POCKET_SPIRALOUT)
return false ;
PtrOwner<ISurfFlatRegion> pSfrLimit( PockParams.SfrLimit.IsValid() ? PockParams.SfrLimit.Clone() : CreateSurfFlatRegion()) ;
// calcolo il percorso di svuotatura spiral
return ( CalcPocketing( pSfr, PockParams.dRad, PockParams.dRadialOffset, PockParams.dSideStep,
PockParams.dAngle, PockParams.dOpenMinSafe, nType, PockParams.bSmooth,
PockParams.bCalcUnclearedRegs, PockParams.bInvert, PockParams.bAvoidOpt,
PockParams.bAllowZigZagOneWayBorders, PockParams.bCalcFeed, PockParams.ptStart,
PockParams.SfrLimit.IsValid() ? PockParams.SfrLimit.Clone() : CreateSurfFlatRegion(),
PockParams.bAvoidOpt, PockParams.dMaxOptSize, PockParams.dLiTang, PockParams.nLiType,
vCrvCompoRes)) ;
pSfrLimit, PockParams.bAvoidOpt, PockParams.dMaxOptSize, PockParams.dLiTang,
PockParams.nLiType, vCrvCompoRes)) ;
}
//----------------------------------------------------------------------------
@@ -9076,9 +9394,10 @@ SmoothExtensionLinesByIntersection( ICRVCOMPOPOVECTOR& vCrvPaths, const PocketPa
//----------------------------------------------------------------------------
bool
CalcPocketing( const ISurfFlatRegion* pSfr, double dRad, double dRadOffs, double dStep, double dAngle,
double dOpenMinSafe, int nType, bool bSmooth, bool bCalcUnclReg, bool bInvert, bool bAvoidOpt, bool bAllowZigZagOneWayBorders,
bool bCalcFeed, const Point3d& ptEndPrec, const ISurfFlatRegion* pSfrLimit, bool bAllOffs,
double dMaxOptSize, double dLiTang, int nLiType, ICRVCOMPOPOVECTOR& vCrvCompoRes)
double dOpenMinSafe, int nType, bool bSmooth, bool bCalcUnclReg, bool bInvert, bool bAvoidOpt,
bool bAllowZigZagOneWayBorders, bool bCalcFeed, const Point3d& ptEndPrec,
const ISurfFlatRegion* pSfrLimit, bool bAllOffs, double dMaxOptSize, double dLiTang,
int nLiType, ICRVCOMPOPOVECTOR& vCrvCompoRes)
{
// controllo dei parametri
if ( pSfr == nullptr || ! pSfr->IsValid() ||
+1
View File
@@ -16,6 +16,7 @@
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Include/EGkGeomDB.h"
#include "/EgtDev/Include/EGkCurve.h"
#include "/EgtDev/Include/EGkCurveComposite.h"
#include <algorithm>
using namespace std ;
+1 -1
View File
@@ -127,7 +127,7 @@ GetHSVFromColor( const Color& cCol)
hsv.dSat = dDelta / dMax ;
if ( cCol.GetRed() >= dMax) // tra giallo e magenta
hsv.dHue = ( cCol.GetGreen() - cCol.GetBlue()) / dDelta ;
else if( cCol.GetGreen() >= dMax) // tra ciano e giallo
else if ( cCol.GetGreen() >= dMax) // tra ciano e giallo
hsv.dHue = 2.0 + ( cCol.GetBlue() - cCol.GetRed()) / dDelta ;
else // tra magenta e ciano
hsv.dHue = 4.0 + ( cCol.GetRed() - cCol.GetGreen()) / dDelta ;
+2 -2
View File
@@ -1294,7 +1294,7 @@ CurveArc::Invert( void)
//----------------------------------------------------------------------------
bool
CurveArc::SimpleOffset( double dDist, int nType)
CurveArc::SimpleOffset( double dDist, int nType, double dMaxAngExt)
{
// la curva deve essere validata
if ( m_nStatus != OK)
@@ -1329,7 +1329,7 @@ CurveArc::SimpleOffset( double dDist, int nType)
//----------------------------------------------------------------------------
bool
CurveArc::MyExtendedOffset( double dDist, bool bAll, int nType)
CurveArc::MyExtendedOffset( double dDist, bool bAll)
{
// bAll == true fa accettare raggi nulli ==> da usare solo internamente
// quando si è sicuri di aumentare subito il raggio o di cancellare
+4 -4
View File
@@ -116,7 +116,7 @@ class CurveArc : public ICurveArc, public IGeoObjRW
{ return ApproxWithArcs( dLinTol, dAngTolDeg, PA) ; }
ICurve* CopyParamRange( double dUStart, double dUEnd) const override ;
bool Invert( void) override ;
bool SimpleOffset( double dDist, int nType = OFF_FILLET) override ;
bool SimpleOffset( double dDist, int nType = OFF_FILLET, double dMaxAngExt = ANG_RIGHT) override ;
bool ModifyStart( const Point3d& ptNewStart) override ;
bool ModifyEnd( const Point3d& ptNewEnd) override ;
bool SetExtrusion( const Vector3d& vtExtr) override
@@ -178,8 +178,8 @@ class CurveArc : public ICurveArc, public IGeoObjRW
bool ChangeDeltaN( double dNewDeltaN) override ;
bool ChangeAngCenter( double dNewAngCenDeg) override ;
bool ChangeStartPoint( double dU) override ;
bool ExtendedOffset( double dDist, int nType = OFF_FILLET) override
{ return MyExtendedOffset( dDist, false, nType) ; }
bool ExtendedOffset( double dDist) override
{ return MyExtendedOffset( dDist, false) ; }
bool ToExplementary( void) override ;
bool Flip( void) override ;
@@ -200,7 +200,7 @@ class CurveArc : public ICurveArc, public IGeoObjRW
{ if ( ! CopyFrom( caSrc))
LOG_ERROR( GetEGkLogger(), "CurveArc : copy error")
return *this ; }
bool MyExtendedOffset( double dDist, bool bAll, int nType = OFF_FILLET) ;
bool MyExtendedOffset( double dDist, bool bAll) ;
bool MyCalcPointParamPosiz( const Point3d& ptP, double& dU, int& nPos, double dLinTol) const ;
Voronoi* GetVoronoiObject( void) const ;
void ResetVoronoiObject( void) const ;
+592 -109
View File
@@ -13,6 +13,8 @@
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "CalcDerivate.h"
#include "Bernstein.h"
#include "CurveAux.h"
#include "GeoConst.h"
#include "CurveLine.h"
@@ -23,14 +25,26 @@
#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/EGkCurveByInterp.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#define EIGEN_NO_IO
#include "/EgtDev/Extern/Eigen/Dense"
#define SAVEAPPROX 0
#define SAVECURVEPASSED 0
#define SAVELINEARAPPROX 0
#if SAVEAPPROX || SAVECURVEPASSED || SAVELINEARAPPROX
static int nCrvPassed = 0 ;
#include "/EgtDev/Include/EGkGeoObjSave.h"
#endif
using namespace std ;
static bool FindSpan( double dU, int nDeg, const DBLVECTOR& vKnots, int& nSpan) ;
static bool CalcBasisFunc( double dU, int nDeg, const DBLVECTOR& vKnots, DBLVECTOR& vBasis) ;
static bool CalcBasisFunc( double dU, int nSpan, int nDeg, const DBLVECTOR& vKnots, DBLVECTOR& vBasis) ;
//----------------------------------------------------------------------------
bool
@@ -520,9 +534,9 @@ LineToBezierCurve( const ICurveLine* pCrvLine, int nDeg, bool bMakeRatOrNot)
return nullptr ;
PtrOwner<ICurveBezier> pCrvBezier( CreateCurveBezier()) ;
// rendo tutte le curve di grado 2 e razionali così posso convertire anche archi e avere tutte curve dello stesso grado e razionali
pCrvBezier->Init( nDeg, true) ;
pCrvBezier->FromLine( *pCrvLine) ;
pCrvBezier->Init( nDeg, false) ;
if ( ! pCrvBezier->FromLine( *pCrvLine))
return nullptr ;
if ( bMakeRatOrNot)
pCrvBezier->MakeRational() ;
return Release( pCrvBezier) ;
@@ -575,6 +589,13 @@ ArcToBezierCurve( const ICurveArc* pArc, int nDeg, bool bMakeRatOrNot)
PtrOwner<ICurveBezier> pCrvBez( CreateBasicCurveBezier()) ;
if ( IsNull( pCrvBez) || ! pCrvBez->FromArc( cArc))
return nullptr ;
if ( ! bMakeRatOrNot) {
Point3d ptCen = pArc->GetCenter() ;
Vector3d vtN = pArc->GetNormVersor() ;
pCrvBez.Set( ApproxArcCurveBezierWithSingleCubic( pCrvBez, ptCen, vtN)) ;
}
if ( IsNull( pCrvBez))
return nullptr ;
// aumento il grado della curva come richiesto
while ( pCrvBez->GetDegree() < nDeg)
pCrvBez.Set( BezierIncreaseDegree( pCrvBez)) ;
@@ -685,7 +706,7 @@ EditBezierCurve( const ICurveBezier* pCrvBezier, int nDeg, bool bMakeRatOrNot, d
// adatto ogni sottocurva cubica
PtrOwner<ICurveComposite> pCCEdited( CreateCurveComposite()) ;
for ( int i = 0 ; i < pBezCubics->GetCurveCount() ; ++i) {
if( ! pCCEdited->AddCurve( EditBezierCurve( GetCurveBezier( pBezCubics->GetCurve( i)), nDeg, bMakeRatOrNot, dTol)) )
if ( ! pCCEdited->AddCurve( EditBezierCurve( GetCurveBezier( pBezCubics->GetCurve( i)), nDeg, bMakeRatOrNot, dTol)) )
return nullptr ;
}
return Release( pCCEdited) ;
@@ -897,7 +918,7 @@ BezierDecreaseDegree(const ICurveBezier* pCrvBezier, double dTol)
}
// se l'approssimazione dà un errore troppo alto allora annullo tutto
// ricalcolo l'errore a mano, per avere un valore più attendibile
CalcBezierApproxError( pCrvBezier, pNewBezier, dErr) ;
CalcApproxError( pCrvBezier, pNewBezier, dErr) ;
if ( dErr > dTol)
return nullptr ;
@@ -1003,7 +1024,7 @@ ApproxBezierWithCubics(const ICurve* pCrv, double dTol)
pCrvCubic.Set( ApproxCurveBezierWithSingleCubic( pCrvPart)) ;
}
}
CalcBezierApproxError( pCrvPart, pCrvCubic, dErr) ;
CalcApproxError( pCrvPart, pCrvCubic, dErr) ;
if ( dErr > dTol && ! bOneIsEnough)
nParts += 2 ;
else {
@@ -1123,76 +1144,147 @@ ApproxArcCurveBezierWithSingleCubic( const ICurve* pCrv, const Point3d& ptCen, c
}
//----------------------------------------------------------------------------
ICurve*
ApproxCurveWithBezier( const ICurve*, double dTol)
static bool
FindSpan( double dU, int nDeg, const DBLVECTOR& vKnots, int& nSpan)
{
// campiono punti lungo la curva e poi li interpolo
if ( dU < 0)
return false ;
else if ( dU < EPS_ZERO) {
nSpan = nDeg - 1 ;
return true ;
}
// trovo a quale span appartiene il parametro dU
int nKnots = ssize( vKnots) ;
if ( abs( dU - vKnots[nKnots-1]) < EPS_SMALL) {
nSpan = nKnots - 1 - nDeg ;
return true ;
}
int nLow = nDeg - 1 ;
int nHigh = nKnots - 1 ;
int nMid = ( nLow + nHigh) / 2 ;
while ( dU < vKnots[nMid] || dU >= vKnots[nMid + 1] ) {
if ( dU < vKnots[nMid])
nHigh = nMid ;
else
nLow = nMid ;
nMid = ( nLow + nHigh) / 2 ;
if ( nMid == nDeg - 1)
break ;
}
nSpan = nMid ;
return true ;
}
// oppure faccio la fat curve e poi calcolo una bezier che stia all'interno di quella regione
//----------------------------------------------------------------------------
static bool
CalcBasisFunc( double dU, int nSpan, int nDeg, const DBLVECTOR& vKnots, DBLVECTOR& vBasis)
{
// mi aspetto che il vettore vBasis sia di lunghezza nDeg + 1
if ( ssize( vBasis) != nDeg + 1)
return false ;
PtrOwner<ICurveComposite> pCC( CreateBasicCurveComposite()) ;
return Release( pCC) ;
vBasis[0] = 1 ;
DBLVECTOR vLeft ; vLeft.resize( nDeg + 1) ;
DBLVECTOR vRight ; vRight.resize( nDeg + 1) ;
for ( int j = 1 ; j <= nDeg ; ++j) {
vLeft[j] = dU - vKnots[nSpan + 1 -j] ;
vRight[j] = vKnots[nSpan + j] - dU ;
double dSaved = 0 ;
for ( int r = 0 ; r < j ; ++r) {
double dSum = vRight[r+1] + vLeft[j-r] ;
double dTemp = 0 ;
if ( dSum > EPS_ZERO)
dTemp = vBasis[r] / dSum ;
vBasis[r] = dSaved + vRight[r+1] * dTemp ;
dSaved = vLeft[j-r] * dTemp ;
}
vBasis[j] = dSaved ;
}
return true ;
}
//----------------------------------------------------------------------------
ICurve*
InterpolatePointSetWithBezier( const PNTVECTOR& vPnt, double dTol)
InterpolatePointSetWithBezierNoIntermedLines( const PNTVECTOR& vPnt, int nStart, int nEnd, int nDeg, const DBLVECTOR& vLen, double dLenTot,
const Vector3d& vtStartDir = V_NULL, const Vector3d& vtEndDir = V_NULL)
{
PtrOwner<ICurve> pCrvInt ;
// pag 364 del Piegl
// scelgo il parametro associato ad ogni punto in modo che rispecchi la distanza tra i punti
int nPoints = vPnt.size() ;
if ( nPoints < 4)
int nPoints = nEnd - nStart + 1 ;
if ( nPoints < 2)
return nullptr ;
int nDeg = 3 ;
DBLVECTOR vLen ;
double dLenTot = 0 ;
for ( int i = 0 ; i < int( nPoints -1) ; ++i) {
double dLen = Dist(vPnt[i], vPnt[i+1]) ;
vLen.push_back( dLen) ;
dLenTot += dLen ;
else if ( nPoints == 2) {
// se ho solo due punti restituisco una linea
CurveLine cl ; cl.Set( vPnt[nStart], vPnt[nEnd]) ;
pCrvInt.Set( LineToBezierCurve( &cl, nDeg, false)) ;
if ( ! IsNull( pCrvInt) && pCrvInt->IsValid())
return Release( pCrvInt) ;
else
return nullptr ;
}
else if (nPoints == 3) {
// se ho solo tre punti uso un altro algoritmo
CurveByInterp cbi ;
for ( int i = nStart ; i <= nEnd ; ++i)
cbi.AddPoint( vPnt[i]) ;
pCrvInt.Set( cbi.GetCurve( CurveByInterp::AKIMA_CORNER, CurveByInterp::CUBIC_BEZIERS)) ;
if ( ! IsNull( pCrvInt) && pCrvInt->IsValid())
return Release( pCrvInt) ;
else
return nullptr ;
}
bool bUseStartEndDir = vtStartDir.IsValid() && vtEndDir.IsValid() ;
DBLVECTOR vPntParam ;
vPntParam.resize( nPoints) ;
vPntParam[0] = 0 ;
vPntParam.back() = 1 ;
for ( int i = 1 ; i < int( nPoints - 1) ; ++i)
for ( int i = 1 ; i < nPoints - 1 ; ++i)
vPntParam[i] = vPntParam[i-1] + vLen[i-1] / dLenTot ;
DBLVECTOR vKnots ;
vKnots.resize( nPoints + nDeg - 1) ;
int nKnots = bUseStartEndDir ? nPoints + nDeg - 1 + 2 : nPoints + nDeg - 1 ;
vKnots.resize( nKnots) ;
for ( int i = 0 ; i < nDeg ; ++i) {
vKnots[i] = 0 ;
vKnots.end()[-i-1] = 1 ;
}
for ( int i = nDeg ; i < nPoints - 1 ; ++i) {
int nKnotsToEdit = bUseStartEndDir ? nPoints + 1 : nPoints - 1 ;
for ( int i = nDeg ; i < nKnotsToEdit ; ++i) {
double dKnot = 0 ;
for ( int j = i ; j < i + nDeg ; ++j)
for ( int j = i + 1 ; j < i + nDeg + 1 ; ++j)
dKnot += vPntParam[j - nDeg] ;
dKnot /= nDeg ;
vKnots[i] = dKnot ;
}
Eigen::MatrixXd mA( nPoints, nPoints) ;
int nEq = bUseStartEndDir ? nPoints + 2 : nPoints ;
Eigen::MatrixXd mA( nEq, nEq) ;
mA.fill( 0) ;
for ( int i = 0 ; i < nPoints ; ++i) {
int nSpan = 0 ; FindSpan(vPntParam[i], nDeg, vKnots, nSpan) ;
for ( int i = 0 ; i < nEq ; ++i) {
if ( i == 0)
mA.row(0).col(0) << 1 ;
else if ( i == nPoints - 1)
mA.row(i).col(nPoints - 1) << 1 ;
else if ( i == nEq - 1)
mA.row(i).col( nEq - 1) << 1 ;
else {
int nSpan = 0 ; FindSpan( vPntParam[i], nDeg, vKnots, nSpan) ;
DBLVECTOR vBasis ; vBasis.resize( nDeg + 1) ;
CalcBasisFunc( vPntParam[i], nDeg, vKnots, vBasis) ;
for( int j = nSpan - nDeg ; j < nSpan ; ++j)
mA.row(i).col(j) << vBasis[j - nSpan + nDeg] ;
CalcBasisFunc( vPntParam[i], nSpan, nDeg, vKnots, vBasis) ;
for ( int j = nSpan - nDeg + 1 ; j <= nSpan + 1 ; ++j)
mA.row(i).col(j) << vBasis[j - nSpan + nDeg - 1] ;
}
}
int nDim = 3 ;
Eigen::MatrixXd mb ; mb.resize( nPoints, nDim) ;
for ( int i = 0 ; i < nPoints ; ++i) {
mb.row(i).col(0) << vPnt[nStart + i].x ;
mb.row(i).col(1) << vPnt[nStart + i].y ;
mb.row(i).col(2) << vPnt[nStart + i].z ;
}
Eigen::MatrixXd mX = mA.fullPivLu().solve(mb) ;
PNTVECTOR vPntCtrl ;
@@ -1206,76 +1298,423 @@ InterpolatePointSetWithBezier( const PNTVECTOR& vPnt, double dTol)
pCrvInt.Set( NurbsToBezierCurve( cNurbs)) ;
return Release( pCrvInt) ;
if ( ! IsNull(pCrvInt) && pCrvInt->IsValid())
return Release( pCrvInt) ;
else
return nullptr ;
}
//----------------------------------------------------------------------------
static bool
FindSpan( double dU, int nDeg, const DBLVECTOR& vKnots, int& nSpan)
ICurve*
InterpolatePointSetWithBezier( const PNTVECTOR& vPnt, double dLinTol, double dMaxLen)
{
if ( dU < 0)
return false ;
else if ( dU < EPS_ZERO) {
nSpan = nDeg ;
return true ;
}
// trovo a quale span appartiene il parametro dU
int nKnots = int( vKnots.size()) ;
if ( abs( dU - vKnots[nKnots-1]) < EPS_SMALL) {
nSpan = nKnots - 1 ;
return true ;
}
int nLow = nDeg ;
int nHigh = nKnots ;
int nMid = ( nLow + nHigh) / 2 ;
while ( dU < vKnots[nMid] || dU > vKnots[nMid + 1] ) {
if ( dU < vKnots[nMid])
nHigh = nMid ;
else
nLow = nMid ;
nMid = ( nLow + nHigh) / 2 ;
if( nMid == nDeg)
break ;
}
nSpan = nMid ;
return true ;
}
PolyLine pl ; pl.FromPointVector( vPnt) ;
PtrOwner<ICurveComposite> pCrvOri( CreateCurveComposite()) ;
pCrvOri->FromPolyLine( pl) ;
//----------------------------------------------------------------------------
static bool
CalcBasisFunc( double dU, int nDeg, const DBLVECTOR& vKnots, DBLVECTOR& vBasis)
{
// mi aspetto che il vettore vBasis sia di lunghezza nDeg + 1
if ( vBasis.size() != nDeg + 1)
return false ;
int nSpan = 0 ;
FindSpan( dU, nDeg, vKnots, nSpan) ;
vBasis[0] = 1 ;
DBLVECTOR vLeft ; vLeft.resize( nDeg + 1) ;
DBLVECTOR vRight ; vRight.resize( nDeg + 1) ;
for ( int j = 1 ; j <= nDeg ; ++j) {
vLeft[j] = dU - vKnots[nSpan + 1 -j] ;
vRight[j] = vKnots[nSpan + j] - dU ;
double dSaved = 0 ;
for ( int r = 0 ; r < j ; ++r) {
double dTemp = vBasis[r] / ( vRight[r+1] + vLeft[j-r]) ;
vBasis[r] = dSaved + vRight[r+1] * dTemp ;
dSaved = vLeft[j-r] * dTemp ;
PtrOwner<ICurveComposite> pCrvInt( CreateCurveComposite()) ;
// pag 364 del Piegl
// scelgo il parametro associato ad ogni punto in modo che rispecchi la distanza tra i punti
double dErr = INFINITO ;
int nItCount = 0 ;
while ( dErr > dLinTol && nItCount < 10) {
pCrvInt->Clear() ;
int nPoints = ssize( vPnt) ;
int nDeg = 3 ;
if ( nPoints < 2)
return nullptr ;
else if ( nPoints == 2) {
// se ho solo due punti restituisco una linea
CurveLine cl ; cl.Set( vPnt[0], vPnt[1]) ;
pCrvInt->AddCurve( LineToBezierCurve( &cl, nDeg, false)) ;
if ( ! IsNull( pCrvInt) && pCrvInt->IsValid())
return Release( pCrvInt) ;
else
return nullptr ;
}
vBasis[j] = dSaved ;
else if ( nPoints == 3) {
// se ho solo tre punti uso un altro algoritmo
CurveByInterp cbi ;
for ( int i = 0 ; i < ssize( vPnt) ; ++i)
cbi.AddPoint( vPnt[i]) ;
pCrvInt->AddCurve( cbi.GetCurve( CurveByInterp::AKIMA_CORNER, CurveByInterp::CUBIC_BEZIERS)) ;
if ( ! IsNull( pCrvInt) && pCrvInt->IsValid())
return Release( pCrvInt) ;
else
return nullptr ;
}
// scorro il vettore di punti passato in input e interpolo separatamente gruppi di punti se incontro
// tratti più lunghi della distanza dMaxLen
int nStart = 0, nEnd = 0 ;
bool bOk = true ;
bool bFoundLine = false ;
while ( nStart < nPoints - 1 && bOk) {
bFoundLine = false ;
nEnd = 0 ;
DBLVECTOR vLen ;
double dLenTot = 0 ;
for ( int i = nStart ; i < nPoints - 1 ; ++i) {
double dLen = Dist( vPnt[i], vPnt[i+1]) ;
if ( dLen < dMaxLen) {
vLen.push_back( dLen) ;
dLenTot += dLen ;
}
else {
nEnd = i ;
bFoundLine = true ;
break ;
}
}
if ( ! vLen.empty()) {
if ( nEnd == 0)
nEnd = nPoints - 1 ;
Vector3d vtStartDir = V_INVALID ;
Vector3d vtEndDir = V_INVALID ;
//if ( nStart != 0 && nEnd != nPoints - 1) {
// pCrvInt->GetEndDir( vtStartDir) ;
// vtEndDir =
//}
pCrvInt->AddCurve( InterpolatePointSetWithBezierNoIntermedLines( vPnt, nStart, nEnd, nDeg, vLen, dLenTot, vtStartDir, vtEndDir)) ;
}
if ( bFoundLine) {
CurveLine cl ; cl.Set( vPnt[nEnd], vPnt[nEnd+1]) ;
pCrvInt->AddCurve( LineToBezierCurve( &cl, nDeg, false)) ;
++ nEnd ;
}
bOk = pCrvInt->IsValid() ;
nStart = nEnd ;
}
//dErr = 0 ;
CalcApproxError( pCrvOri, pCrvInt, dErr) ;
if ( dErr > dLinTol && dMaxLen > 200 * EPS_SMALL)
dMaxLen /= 2 ;
++ nItCount ;
}
if ( ! IsNull( pCrvInt) && pCrvInt->IsValid() && dErr < dLinTol)
return Release( pCrvInt) ;
else
return nullptr ;
}
//----------------------------------------------------------------------------
static bool
ParamByLen( const PNTVECTOR& vPnt, DBLVECTOR& vParam, int nFirst, int nLast)
{
int nPoints = nLast - nFirst + 1 ;
if ( nPoints < 2)
return false ;
if ( vParam.empty())
vParam.resize( nPoints) ;
if ( vParam[nFirst] == 0 && vParam[nLast] == 1)
return true ;
vParam[nFirst] = 0 ;
for ( int i = nFirst + 1 ; i <= nLast ; ++i) {
double dDist = Dist( vPnt[i], vPnt[i-1]) ;
vParam[i] = vParam[i- 1] + dDist ;
}
for ( int i = nFirst + 1 ; i < nLast ; ++i)
vParam[i] /= vParam[nLast] ;
vParam[nLast] = 1 ;
return true ;
}
//----------------------------------------------------------------------------
ICurveBezier*
ApproxPointSetWithSingleBezier( const PNTVECTOR& vPnt, int nFirst, int nLast,
const Vector3d& vtStartDir, const Vector3d& vtEndDir, const DBLVECTOR& vParam)
{
// cerco di approssimare un set di punti con una sola bezier cubica non razionale
int nPoints = nLast - nFirst + 1 ;
// se ho solo quattro punti allora costruisco direttamente la curva
PtrOwner<ICurveBezier> pCrvBez( CreateCurveBezier()) ;
int nDeg = 3 ;
bool bRat = false ;
pCrvBez->Init( nDeg, bRat) ;
const Point3d& pt0 = vPnt[nFirst] ;
const Point3d& pt3 = vPnt[nLast] ;
pCrvBez->SetControlPoint( 0, pt0) ;
pCrvBez->SetControlPoint( 3, pt3) ;
Eigen::Vector2d mA ;
if ( nPoints > 4) {
// risoluzione sistema
Eigen::Matrix2d mC ; mC.setZero() ;
Eigen::Vector2d mX ; mX.setZero() ;
for ( int i = nFirst ; i <= nLast ; ++i) {
double dU = vParam[i] ;
DBLVECTOR vBern(4) ;
GetAllBernstein( dU, 3, vBern) ;
Vector3d A1 = vtStartDir * vBern[1] ;
Vector3d A2 = vtEndDir * vBern[2] ;
Vector3d tmp = vPnt[i] - ( pt0 * ( vBern[0] + vBern[1])) - (( pt3 * ( vBern[2] + vBern[3])) - ORIG) ; // ORIG serve solo per trasformare l'ultimo termine in un vettore
mC(0,0) += A1 * A1 ;
mC(0,1) += A1 * A2 ;
mC(1,0) += A1 * A2 ;
mC(1,1) += A2 * A2 ;
mX(0) += A1 * tmp ;
mX(1) += A2 * tmp ;
}
mA = mC.fullPivLu().solve(mX) ;
}
// l'algoritmo è fatto in modo che alpha1 e alpha2 siano positivi ( se tutto va bene)
// io invece ho tenuto le tangenti con la direzione originale, quindi il primo dovrebbe essere positivo e il secondo negativo
if ( mA(0) < 0 || mA(1) > 0 || nPoints < 4) {
if ( mA(0) < 0 || mA(1) > 0)
LOG_DBG_ERR( GetEGkLogger(), "valori di alfa sballati, potrebbe essere la spaziatura dismogenea tra punti")
double dDistCorr = Dist( pt3, pt0) / 3 ;
mA(0) = dDistCorr ;
mA(1) = - dDistCorr ;
}
Point3d pt1 = pt0 + vtStartDir * mA(0) ;
Point3d pt2 = pt3 + vtEndDir * mA(1) ;
pCrvBez->SetControlPoint( 1, pt1) ;
pCrvBez->SetControlPoint( 2, pt2) ;
return Release( pCrvBez) ;
}
//----------------------------------------------------------------------------
bool
CalcBezierApproxError( const ICurveBezier* pCrvOri, const ICurveBezier* pCrvNew, double& dErr, int nPoints)
CalcPointSetApproxError( const PNTVECTOR& vPntOrig, const DBLVECTOR& vParam,
int nFirst, int nLast, const ICurve* pCrvNew, double& dErr, int& nPointMaxErr)
{
if ( pCrvOri->GetType() != CRV_BEZIER || pCrvNew->GetType() != CRV_BEZIER)
return false ;
dErr = 0 ;
// calcolo l'errore di approssimazione
for ( int i = nFirst ; i <= nLast ; ++i) {
Point3d ptBez ; pCrvNew->GetPointD1D2( vParam[i], ICurve::Side::FROM_MINUS, ptBez) ;
double dErrTemp = Dist( vPntOrig[i], ptBez) ;
if ( dErrTemp > dErr) {
dErr = dErrTemp ;
nPointMaxErr = i ;
}
}
return true ;
}
//----------------------------------------------------------------------------
ICurve*
FitWithBezier( const ICurve* pCrvOrig, const PNTVECTOR& vPnt, DBLVECTOR& vParam,
int nFirst, int nLast, const VCT3DVECTOR& vPrevDer, const VCT3DVECTOR& vNextDer, double dTol, bool bLimitSplit = false)
{
ParamByLen( vPnt, vParam, nFirst, nLast) ;
PtrOwner<ICurveComposite> pCrvFit( CreateCurveComposite()) ;
PtrOwner<ICurveBezier> pCrvBez( CreateCurveBezier()) ;
double dErr = INFINITO ;
double dErrPrec = INFINITO ;
double dErrSplit = dTol * 25 ;
int nIter = 0 ;
while ( dErr > dTol && nIter < 10) {
if ( dErr < INFINITO) {
// riparametrizzo i punti
for ( int i = nFirst + 1 ; i < nLast ; ++i) {
// questo potrebbe diventare un while appena capisco di quanto si aggiusta il parametro ad ogni iterazione
double dCorr = 1 ;
do {
Vector3d vtDer1, vtDer2 ;
Point3d ptBez ; pCrvBez->GetPointD1D2( vParam[i], ICurve::Side::FROM_MINUS, ptBez, &vtDer1, &vtDer2) ;
Vector3d vtLink = ptBez - vPnt[i] ;
double dNum = vtLink * vtDer1 ;
double dDen = vtLink * vtDer2 + vtDer1 * vtDer1 ;
dCorr = dDen > EPS_ZERO ? dNum / dDen : 0 ;
vParam[i] = vParam[i] - dCorr ;
} while ( abs( dCorr) > EPS_ZERO) ;
Clamp( vParam[i], 0., 1.) ;
}
}
// fit della curva
Vector3d vtStartDir, vtEndDir ;
if ( bLimitSplit) {
vtStartDir = vNextDer[nFirst / 3] ;
vtEndDir = vPrevDer[nLast / 3] ;
}
else {
vtStartDir = vNextDer[nFirst] ;
vtEndDir = vPrevDer[nLast] ;
}
pCrvBez.Set( ApproxPointSetWithSingleBezier( vPnt, nFirst, nLast, vtStartDir, vtEndDir, vParam)) ;
if ( IsNull( pCrvBez) || ! pCrvBez->IsValid())
return nullptr ;
#if SAVEAPPROX
SaveGeoObj( pCrvBez->Clone(), "D:\\Temp\\bezier\\approxWithBezier\\"+ToString(nCrvPassed) + "first_approx.nge") ;
#endif
int nPointMaxErr = 0 ;
CalcPointSetApproxError( vPnt, vParam, nFirst, nLast, pCrvBez, dErr, nPointMaxErr) ;
// se sto unendo due punti consecutivi e l'errore è oltre quello richiesto allora restituisco un segmento che unisce i punti
if ( ((nLast - nFirst == 1) || ( bLimitSplit && nLast - nFirst == 3)) && dErr > dTol) {
CurveLine CL ; CL.Set( vPnt[nFirst], vPnt[nLast]) ;
pCrvBez.Set( GetCurveBezier( CurveToBezierCurve( &CL))) ;
dErr = 0 ;
}
if ( bLimitSplit && nPointMaxErr % 3 != 0) {
nPointMaxErr = 3 * int( round( nPointMaxErr / 3.)) ;
if ( nPointMaxErr == nFirst)
nPointMaxErr += 3 ;
else if( nPointMaxErr == nLast)
nPointMaxErr -= 3 ;
}
++nIter ;
bool bSplit = false ;
if ( ( nIter == 10 && dErr > dTol) || dErr > dErrPrec || dErrPrec - dErr < dErrPrec / 20)
bSplit = true ;
dErrPrec = dErr ;
// se la curva di approssimazione è ancora molto lontana dalla curva originale allora divido il set di punti in due
if ( dErr > dErrSplit || bSplit) {
if ( nLast - nFirst > 1 && nPointMaxErr - nFirst > 1 && nLast - nPointMaxErr > 1) {
if ( ! pCrvFit->AddCurve( FitWithBezier( pCrvOrig, vPnt, vParam, nFirst, nPointMaxErr, vPrevDer, vNextDer,dTol, bLimitSplit)) ||
! pCrvFit->AddCurve( FitWithBezier( pCrvOrig, vPnt, vParam, nPointMaxErr, nLast, vPrevDer, vNextDer, dTol, bLimitSplit)))
return nullptr ;
break ;
}
else
return nullptr ;
}
}
if ( pCrvFit->GetCurveCount() > 0)
return Release( pCrvFit) ;
else if ( dErr < dTol && ! IsNull( pCrvBez) && pCrvBez->IsValid())
return Release( pCrvBez) ;
else
return nullptr ;
}
//----------------------------------------------------------------------------
ICurve*
ApproxCurveWithBezier( const ICurve* pCrv , double dTol)
{
#if SAVECURVEPASSED
SaveGeoObj( pCrv->Clone(), "D:\\Temp\\bezier\\approxWithBezier\\CurveDaApprossimare\\"+ToString(nCrvPassed) + ".nge") ;
++nCrvPassed ;
#endif
//// uso l'algoritmo di Schneider in Grafic Gems I
// mi aspetto che non ci siano angoli ( discontinuità della derivata prima) nel risultato desiderato
PolyLine plApprox ;
double dAngTolFine = 1 ;
double dLinTolFine = 0.05 ;
pCrv->ApproxWithLines( dLinTolFine, dAngTolFine, ICurve::APL_STD, plApprox) ;
#if SAVELINEARAPPROX
CurveComposite CC ; CC.FromPolyLine(plApprox) ;
SaveGeoObj( CC.Clone(), "D:\\Temp\\bezier\\approxWithBezier\\approssimazione_lineare.nge") ;
#endif
PNTVECTOR vPnt ;
PNTVECTOR vPntOverSampling ;
Point3d pt ; plApprox.GetFirstPoint( pt) ;
do {
if ( ! vPntOverSampling.empty()) {
vPntOverSampling.push_back( Media( vPnt.back(), pt,1./3.)) ;
vPntOverSampling.push_back( Media( vPnt.back(), pt,2./3.)) ;
}
vPntOverSampling.push_back( pt) ;
vPnt.push_back( pt) ;
} while ( plApprox.GetNextPoint( pt)) ;
// calcolo la curvatura nei vari punti per identificare zone a curvatura costante
DBLVECTOR vRad ( ssize( vPnt)) ;
for ( int i = 1 ; i < ssize( vPnt) - 1 ; ++i) {
Vector3d vtA = vPnt[i] - vPnt[i-1] ;
Vector3d vtB = vPnt[i+1] - vPnt[i-1] ;
double dR = ( vtA.Len() * vtB.Len() * ( vtA - vtB).Len()) / ( 2 * ( vtA ^ vtB).Len()) ;
vRad[i] = dR ;
}
vRad[0] = vRad[1] ;
vRad.back() = vRad.end()[-2] ;
// identifico le zone a curvatura costante // primo e ultimo punto degli intervalli non devono avere curvatura uguale agli altri perché sono di frontiera
INTINTVECTOR vConstCurv ;
double dRadPrec = vRad[0] ;
int nStart = 0 ;
int nEnd = 1 ;
double dRatio = 1.5 ;
while ( nStart < ssize( vPnt) - 1) {
double dRadTol = max( max( vRad[nEnd], dRadPrec) / 10 , 1.) ;
if ( dRadPrec > dRatio * vRad[nEnd] || dRatio * dRadPrec < vRad[nEnd])
dRadTol = 0 ;
while ( nEnd < ssize( vPnt) - 1 && abs( vRad[nEnd] - dRadPrec) < dRadTol) {
dRadPrec = vRad[nEnd] ;
++nEnd ;
}
vConstCurv.emplace_back( nStart * 3, nEnd * 3) ;
nStart = nEnd ;
dRadPrec = vRad[nEnd] ;
++nEnd ;
}
if ( vConstCurv.empty())
vConstCurv.emplace_back( 0, ssize( vPnt) - 1) ;
int nPoints = ssize( vPnt) ;
DBLVECTOR vParam( nPoints) ;
int nFirst = 0 ;
int nLast = ssize( vPnt) - 1 ;
ParamByLen( vPnt, vParam, nFirst, nLast) ;
VCT3DVECTOR vPrevDer ;
VCT3DVECTOR vNextDer ;
ComputeAkimaTangents( false, vParam, vPnt, vPrevDer, vNextDer) ;
int nOverSampling = ssize( vPntOverSampling) ;
vParam.resize( nOverSampling) ;
nFirst = 0 ;
nLast = nOverSampling - 1 ;
ParamByLen( vPntOverSampling, vParam, nFirst, nLast) ;
//normalizzo tutte le derivate
for ( int i = 0 ; i < ssize( vPrevDer) ; ++i) {
vPrevDer[i].Normalize() ;
vNextDer[i].Normalize() ;
}
// potrei verificare prima se un tratto è retto e aggiustare le tangenti del tratto precedente e successivo prima di approssimare
PtrOwner<ICurveComposite> pCCApproxTot( CreateCurveComposite()) ;
for ( INTINT iiSE : vConstCurv) {
nFirst = iiSE.first ;
nLast = iiSE.second ;
// riconosco se ho un tratto retto
int nPnt = nFirst / 3 ;
if ( nLast - nFirst == 3 && ( nPnt > 0 && vRad[nPnt] > dRatio * vRad[nPnt - 1]) && ( nPnt < ssize( vRad) && vRad[nPnt]> dRatio * vRad[nPnt + 1])) {
CurveLine CL ; CL.Set( vPntOverSampling[nFirst], vPntOverSampling[nLast]) ;
PtrOwner<ICurveBezier> pCApprox( LineToBezierCurve( &CL, 3, false)) ;
if ( ! pCCApproxTot->AddCurve( Release( pCApprox)))
return nullptr ;
}
else {
//definisco la bezier che vado a raffinare iterativamente
PtrOwner<ICurve> pCApprox( FitWithBezier( pCrv, vPntOverSampling, vParam, nFirst, nLast, vPrevDer, vNextDer, dTol, true)) ;
if ( IsNull( pCApprox) || ! pCApprox->IsValid())
return nullptr ;
if ( ! pCCApproxTot->AddCurve( Release( pCApprox)))
return nullptr ;
}
}
return Release( pCCApproxTot) ;
}
//----------------------------------------------------------------------------
bool
CalcApproxError( const ICurve* pCrvOri, const ICurve* pCrvNew, double& dErr, int nPoints)
{
if ( pCrvOri == nullptr || ! pCrvOri->IsValid() || pCrvNew == nullptr || ! pCrvNew->IsValid()){
dErr = INFINITO ;
return false ;
}
// controllo l'errore effettivo campionando più finemente
double dLenOri = 0 ; pCrvOri->GetLength( dLenOri) ;
double dLenNew = 0 ; pCrvNew->GetLength( dLenNew) ;
@@ -1357,7 +1796,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData)
{
// se con nodi extra
if ( cnData.bExtraKnotes) {
int nKnotesNbr = int( cnData.vU.size()) ;
int nKnotesNbr = ssize( cnData.vU) ;
if ( nKnotesNbr < 4)
return false ;
cnData.bExtraKnotes = false ;
@@ -1371,7 +1810,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData)
bool bAlreadyChecked = false ;
// se la curva è peridica verifco che effettivamente ci sia un numero di punti ripetituti uguale al grado della curva
// wrap della curva su se stessa
if ( cnData.bPeriodic && (int(cnData.vU.size()) > int(cnData.vCP.size()) + cnData.nDeg - 1)) {
if ( cnData.bPeriodic && ( ssize( cnData.vU) > ssize( cnData.vCP) + cnData.nDeg - 1)) {
bool bRepeated = true ;
for ( int i = 0 ; i < cnData.nDeg ; ++i) {
if ( ! AreSamePointApprox( cnData.vCP[i], cnData.vCP.end()[-cnData.nDeg + i]) ) {
@@ -1380,11 +1819,11 @@ NurbsCurveCanonicalize( CNurbsData& cnData)
}
}
bool bFirstAddedAtEnd = false ;
if ( ! bRepeated || (bRepeated && AreSamePointApprox( cnData.vCP[0],cnData.vCP[cnData.nDeg]))){
if ( ! bRepeated || ( bRepeated && AreSamePointApprox( cnData.vCP[0], cnData.vCP[cnData.nDeg]))) {
// salvo il vettore dei nodi in caso mi accorga di avere tra le mani una curva unclamped
DBLVECTOR vU = cnData.vU ;
// se effettivamente ho dei nodi in più da togliere allora li tolgo ed eventualmente aggiungo punti di controllo
if ( int(cnData.vU.size()) > int(cnData.vCP.size()) + cnData.nDeg - 1 ) {
if ( ssize( cnData.vU) > ssize( cnData.vCP) + cnData.nDeg - 1 ) {
// se il primo e l'ultimo punto non coincidono allora aggiungo il primo punto in fondo al vettore dei punti di controllo
if ( ! AreSamePointApprox( cnData.vCP[0], cnData.vCP.back())) {
bFirstAddedAtEnd = true ;
@@ -1396,11 +1835,11 @@ NurbsCurveCanonicalize( CNurbsData& cnData)
cnData.vU = DBLVECTOR( cnData.vU.begin(), cnData.vU.end() - cnData.nDeg) ;
// controllo eventualmente anche i nodi extra
// se ne ho due in più ne tolgo uno in cima e uno in fondo
if ( cnData.vU.size() == int( cnData.vCP.size()) + cnData.nDeg + 1 ) { // significa che ci sono due nodi extra, uno all'inizio e uno alla fine, da togliere
if ( ssize( cnData.vU) == ssize( cnData.vCP) + cnData.nDeg + 1) { // significa che ci sono due nodi extra, uno all'inizio e uno alla fine, da togliere
cnData.vU = vector<double>( cnData.vU.begin() + 1, cnData.vU.end() - 1) ;
}
// se ne ho solo uno in più lo tolgo in cima
else if ( cnData.vU.size() == int( cnData.vCP.size()) + cnData.nDeg) {
else if ( ssize( cnData.vU) == ssize( cnData.vCP) + cnData.nDeg) {
cnData.vU = vector<double>( cnData.vU.begin() + 1, cnData.vU.end()) ;
}
}
@@ -1427,7 +1866,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData)
// recupero il vettore dei nodi
cnData.vU = vU ;
// verifico se ho nodi extra
if ( cnData.vU.size() == int( cnData.vCP.size()) + cnData.nDeg + 1 ) {
if ( ssize( cnData.vU) == ssize( cnData.vCP) + cnData.nDeg + 1 ) {
// significa che ci sono due nodi extra:
// se la curva ha grado maggiore di 1 e i primi due nodi sono uguali allora tolgo quelli
if ( cnData.nDeg > 1 && abs(cnData.vU[1] - cnData.vU[0]) < EPS_SMALL) {
@@ -1438,7 +1877,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData)
cnData.vU = vector<double>( cnData.vU.begin() + 1, cnData.vU.end() - 1) ;
}
// se ne ho solo uno in più lo tolgo in cima
else if ( cnData.vU.size() == int( cnData.vCP.size()) + cnData.nDeg)
else if ( ssize( cnData.vU) == ssize( cnData.vCP) + cnData.nDeg)
cnData.vU = vector<double>( cnData.vU.begin() + 1, cnData.vU.end()) ;
}
bAlreadyChecked = true ;
@@ -1463,7 +1902,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData)
// qui aggiungo un controllo se la curva è collassata in un punto ( ho un polo), lascio stare
bool bCollapsed = true ;
Point3d ptFirst = cnData.vCP.front() ;
for ( int i = 1 ; i < int( cnData.vCP.size()) ; ++i) {
for ( int i = 1 ; i < ssize( cnData.vCP) ; ++i) {
if ( ! AreSamePointApprox( ptFirst, cnData.vCP[i])) {
bCollapsed = false ;
break ;
@@ -1480,7 +1919,7 @@ NurbsCurveCanonicalize( CNurbsData& cnData)
// agli indici perché uso u_p-1 e u_(m-p+1), anziché u_p e u_m-p
// comincio ad aumentare la molteplictià del nodo u_m-p+1
int nCP = int( cnData.vCP.size()) ;
int nCP = ssize( cnData.vCP) ;
int nU = nCP + cnData.nDeg - 1 ;
int nDeg = cnData.nDeg ;
PNTVECTOR vBC ;
@@ -1676,9 +2115,9 @@ NurbsToBezierCurve( const CNurbsData& cnData)
if ( cnData.bPeriodic || cnData.bExtraKnotes)
return nullptr ;
// numero dei nodi
int nU = int( cnData.vCP.size()) + cnData.nDeg - 1 ;
int nU = ssize( cnData.vCP) + cnData.nDeg - 1 ;
// controllo relazione nodi - punti di controllo
if ( nU != int( cnData.vU.size()))
if ( nU != ssize( cnData.vU))
return nullptr ;
// numero degli intervalli
int nInt = nU - 2 * cnData.nDeg + 1 ;
@@ -2048,7 +2487,7 @@ CalcCurvesVoronoiDiagram( const CICURVEPVECTOR& vCrvC, ICURVEPOVECTOR& vCrvs, in
PtrOwner<Voronoi> pVoronoiObj( new( std::nothrow) Voronoi()) ;
if ( pVoronoiObj == nullptr)
return false ;
for ( int i = 0 ; i < int( vCrvC.size()) ; i ++) {
for ( int i = 0 ; i < ssize( vCrvC) ; i ++) {
if ( ! pVoronoiObj->AddCurve( vCrvC[i]))
return false ;
}
@@ -2075,7 +2514,7 @@ CalcCurvesMedialAxis( const CICURVEPVECTOR& vCrvC, ICURVEPOVECTOR& vCrvs, int nS
PtrOwner<Voronoi> pVoronoiObj( new( std::nothrow) Voronoi()) ;
if ( pVoronoiObj == nullptr)
return false ;
for ( int i = 0 ; i < int( vCrvC.size()) ; i ++) {
for ( int i = 0 ; i < ssize( vCrvC) ; i ++) {
if ( ! pVoronoiObj->AddCurve( vCrvC[i]))
return false ;
}
@@ -2136,7 +2575,7 @@ bool CalcOffsetCurves( const ICURVEPVECTOR& vpCrvs, ICURVEPOVECTOR& vCrvs, doubl
PtrOwner<Voronoi> pVoronoiObj( new( std::nothrow) Voronoi()) ;
if ( pVoronoiObj == nullptr)
return false ;
for ( int i = 0 ; i < int( vpCrvs.size()) ; i ++) {
for ( int i = 0 ; i < ssize( vpCrvs) ; i ++) {
if ( ! pVoronoiObj->AddCurve( vpCrvs[i]))
return false ;
}
@@ -2166,7 +2605,7 @@ bool CalcFatOffsetCurves( const ICURVEPVECTOR& vpCrvs, ICURVEPOVECTOR& vCrvs, do
PtrOwner<Voronoi> pVoronoiObj( new( std::nothrow) Voronoi()) ;
if ( pVoronoiObj == nullptr)
return false ;
for ( int i = 0 ; i < int( vpCrvs.size()) ; i ++) {
for ( int i = 0 ; i < ssize( vpCrvs) ; i ++) {
if ( ! pVoronoiObj->AddCurve( vpCrvs[i]))
return false ;
}
@@ -2195,3 +2634,47 @@ ResetCurveVoronoi( const ICurve& crvC)
break ;
}
}
//----------------------------------------------------------------------------
bool
GetChainedCurves( ICRVCOMPOPOVECTOR& vCrv, double dChainTol, bool bAllowInvert)
{
if ( ssize( vCrv) == 1)
return true ;
ChainCurves chainCrv ;
// modifico direttamente le curve passate in input
chainCrv.Init( bAllowInvert, dChainTol, ssize( vCrv)) ;
for ( int c = 0 ; c < ssize( vCrv) ; ++c) {
Point3d ptStart, ptEnd ;
Vector3d vtStart, vtEnd ;
vCrv[c]->GetStartPoint( ptStart) ;
vCrv[c]->GetEndPoint( ptEnd) ;
vCrv[c]->GetStartDir( vtStart) ;
vCrv[c]->GetEndDir( vtEnd) ;
chainCrv.AddCurve( 1 + c, ptStart, vtStart, ptEnd, vtEnd) ;
}
INTVECTOR vIds ;
Point3d ptStart = ORIG ;
while ( chainCrv.GetChainFromNear( ptStart, false, vIds)) {
ICurveComposite* pFirstCrv = vCrv[abs(vIds[0]) - 1] ;
for ( int nId : vIds) {
bool bInvert = false ;
if ( nId < 0)
bInvert = true ;
nId = abs( nId) - 1 ;
if ( bInvert)
vCrv[nId]->Invert() ;
if ( ! pFirstCrv->AddCurve( Release( vCrv[nId]), true, dChainTol))
return false ;
}
pFirstCrv->GetEndPoint( ptStart) ;
}
// elimino gli elementi del vettore che non contengono più curve
int c = ssize( vCrv) ;
while ( c > -1) {
if ( IsNull( vCrv[c]))
vCrv.erase( vCrv.begin() + c) ;
--c ;
}
return true ;
}
+1
View File
@@ -35,3 +35,4 @@ 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) ;
+115 -35
View File
@@ -93,8 +93,11 @@ CurveBezier::Init( int nDeg, bool bIsRational)
bool
CurveBezier::SetControlPoint( int nInd, const Point3d& ptCtrl)
{
// verifico validità indice
if ( m_nStatus != OK || m_bRat || nInd < 0 || nInd > m_nDeg)
// verifico validità indice e punto
if ( m_nStatus != OK || m_bRat || nInd < 0 || nInd > m_nDeg || ! ptCtrl.IsValid())
return false ;
if ( abs( ptCtrl.x) > INFINITO || abs( ptCtrl.y) > INFINITO || abs( ptCtrl.z) > INFINITO)
return false ;
// assegno il valore
@@ -123,8 +126,11 @@ CurveBezier::SetControlPoint( int nInd, const Point3d& ptCtrl, double dW)
if ( m_nStatus != OK || ! m_bRat || nInd < 0 || nInd > m_nDeg)
return false ;
// verifico che il peso non sia nullo o negativo
if ( dW < EPS_SMALL)
// verifico che il punto sia valido e il peso non sia nullo o negativo
if ( ! ptCtrl.IsValid() || dW < EPS_SMALL || ! isfinite( dW) || dW > INFINITO)
return false ;
if ( abs( ptCtrl.x) > INFINITO || abs( ptCtrl.y) > INFINITO || abs( ptCtrl.z) > INFINITO)
return false ;
// assegno il valore e il peso
@@ -151,7 +157,7 @@ CurveBezier::SetControlWeight( int nInd, double dW)
return false ;
// verifico che il peso non sia nullo o negativo
if ( dW < EPS_SMALL)
if ( dW < EPS_SMALL || ! isfinite( dW) || dW > INFINITO)
return false ;
// assegno il valore e il peso
@@ -267,22 +273,21 @@ CurveBezier::FromArc( const ICurveArc& crArc)
bool
CurveBezier::FromLine( const ICurveLine& crLine)
{
if ( ! crLine.IsValid())
if ( m_nStatus != OK || ! crLine.IsValid())
return false ;
double dWeight = 1 ;
int nCount = 0 ;
Point3d ptStart ; crLine.GetStartPoint( ptStart) ;
SetControlPoint( nCount, ptStart, dWeight) ;
SetControlPoint( nCount, ptStart) ;
++nCount ;
double dPart = 1. / m_nDeg ;
for ( int i = 1 ; i < m_nDeg ; ++i) {
double dU = i * dPart ;
Point3d ptMid ; crLine.GetPointD1D2( dU, ICurve::FROM_MINUS, ptMid) ;
SetControlPoint( nCount, ptMid, dWeight) ;
SetControlPoint( nCount, ptMid) ;
++nCount ;
}
Point3d ptEnd ; crLine.GetEndPoint( ptEnd) ;
SetControlPoint( nCount, ptEnd, dWeight) ;
SetControlPoint( nCount, ptEnd) ;
++nCount ;
return true ;
}
@@ -367,6 +372,8 @@ CurveBezier::CopyFrom( const CurveBezier& cbSrc)
{
if ( &cbSrc == this)
return true ;
if ( ! cbSrc.IsValid())
return false ;
if ( ! Init( cbSrc.m_nDeg, cbSrc.m_bRat))
return false ;
m_dParSing = cbSrc.m_dParSing ;
@@ -517,21 +524,21 @@ bool
CurveBezier::Validate( void)
{
if ( m_nStatus == TO_VERIFY) {
for ( const auto& ptP : m_vPtCtrl) {
if ( ! ptP.IsValid()) {
m_nStatus = ERR ;
break ;
for ( const auto& ptP : m_vPtCtrl) {
if ( ! ptP.IsValid()) {
m_nStatus = ERR ;
break ;
}
}
}
}
if ( m_nStatus == TO_VERIFY) {
for ( const auto& dWe : m_vWeCtrl) {
if ( ! isfinite( dWe)) {
m_nStatus = ERR ;
break ;
for ( const auto& dWe : m_vWeCtrl) {
if ( ! isfinite( dWe)) {
m_nStatus = ERR ;
break ;
}
}
}
}
if ( m_nStatus == TO_VERIFY)
m_nStatus = ( ( m_nDeg >= 1 && m_vPtCtrl.size() >= 2) ? OK : ERR) ;
@@ -1658,6 +1665,10 @@ CurveBezier::BiArcOrSplit( int nLev, PolyLine& PL, double dLinTol, double dAngTo
ICurve*
CurveBezier::CopyParamRange( double dUStart, double dUEnd) const
{
// la curva deve essere valida
if ( m_nStatus != OK)
return nullptr ;
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
if ( dUStart < - EPS_PARAM || dUStart > 1 + EPS_PARAM ||
dUEnd < - EPS_PARAM || dUEnd > 1 + EPS_PARAM)
@@ -1800,6 +1811,10 @@ CurveBezier::TrimEndAtParam( double dUTrim)
bool
CurveBezier::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// i parametri start ed end devono essere compresi nel dominio parametrico della curva
if ( dUStartTrim < - EPS_PARAM || dUStartTrim > 1 + EPS_PARAM ||
dUEndTrim < - EPS_PARAM || dUEndTrim > 1 + EPS_PARAM)
@@ -1809,19 +1824,19 @@ CurveBezier::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim)
return false ;
// se razionale devo trovare il punto di trim iniziale per ricalcolare il parametro di trim
Point3d ptStart ;
if( m_bRat)
if ( m_bRat)
GetPointD1D2( dUStartTrim, ptStart) ;
// trim finale
if ( ! TrimEndAtParam( dUEndTrim))
return false ;
// trim iniziale con il parametro opportunamente ricalcolato
double dNewUStartTrim ;
if( m_bRat)
if ( m_bRat)
GetParamAtPoint( ptStart, dNewUStartTrim) ;
else
dNewUStartTrim = dUStartTrim / dUEndTrim ;
//trim iniziale
if( ! TrimStartAtParam( dNewUStartTrim))
if ( ! TrimStartAtParam( dNewUStartTrim))
return false ;
return true ;
@@ -1831,6 +1846,10 @@ CurveBezier::TrimStartEndAtParam( double dUStartTrim, double dUEndTrim)
bool
CurveBezier::TrimStartAtLen( double dLenTrim)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// lunghezze negative vengono considerate nulle
dLenTrim = max( dLenTrim, 0.) ;
@@ -1840,7 +1859,7 @@ CurveBezier::TrimStartAtLen( double dLenTrim)
return false ;
// utilizzo il trim sui parametri
if( ! TrimStartAtParam( dUTrim))
if ( ! TrimStartAtParam( dUTrim))
return false ;
return true ;
@@ -1850,6 +1869,10 @@ CurveBezier::TrimStartAtLen( double dLenTrim)
bool
CurveBezier::TrimEndAtLen( double dLenTrim)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// lunghezze negative vengono considerate nulle
dLenTrim = max( dLenTrim, 0.) ;
@@ -1859,7 +1882,7 @@ CurveBezier::TrimEndAtLen( double dLenTrim)
return false ;
// utilizzo il trim sui parametri
if( ! TrimEndAtParam( dUTrim))
if ( ! TrimEndAtParam( dUTrim))
return false ;
return true ;
@@ -1869,6 +1892,10 @@ CurveBezier::TrimEndAtLen( double dLenTrim)
bool
CurveBezier::ExtendStartByLen( double dLenExt)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// la lunghezza deve essere positiva
if ( dLenExt < - EPS_ZERO)
return false ;
@@ -1920,6 +1947,10 @@ CurveBezier::ExtendStartByLen( double dLenExt)
bool
CurveBezier::ExtendEndByLen( double dLenExt)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
// la lunghezza deve essere positiva
if ( dLenExt < - EPS_ZERO)
return false ;
@@ -2259,6 +2290,10 @@ CurveBezier::ResetVoronoiObject() const
bool
CurveBezier::MakeRational( void)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
if ( m_bRat)
return true ;
// creo il vettore dei pesi e li setto tutti a 1
@@ -2273,6 +2308,10 @@ CurveBezier::MakeRational( void)
bool
CurveBezier::MakeRationalStandardForm( void)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
if ( ! m_bRat)
return false ;
double dW0 = m_vWeCtrl.front() ;
@@ -2294,6 +2333,10 @@ CurveBezier::MakeRationalStandardForm( void)
bool
CurveBezier::MakeNonRational( double dTol)
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
if ( ! m_bRat)
return true ;
@@ -2308,15 +2351,44 @@ CurveBezier::MakeNonRational( double dTol)
bool bOk = true ;
if ( ! bIsActualRat) {
PtrOwner<CurveBezier> pNewBez( CreateBasicCurveBezier()) ;
for ( int p = 0 ; p < m_nDeg ; ++p) {
Point3d pt = GetControlPoint( p) ;
pNewBez->SetControlPoint( p, pt) ;
}
// semplicemente tolgo il booleano della razionalità e i punti restano gli stessi
m_bRat = false ;
}
else {
// provo ad approssimare la curva di bezier con una controparte non razionale
int nDeg = m_nDeg ;
// se ho una curva razionale di grado 2 verifico se è un arco, in quel caso la converto in una curva di grado 3 non razionale con la funzione dedicata
if ( nDeg == 2 && m_bRat) {
// prendo due punti sulla curva e calcolo l'intersezione dei due assi dei segmenti formati da pt2-pt0 e pt3-pt1
Point3d pt0 ; GetStartPoint( pt0) ;
Point3d pt1 ; GetPointD1D2( 0.3, pt1) ;
Point3d pt2 ; GetPointD1D2( 0.6, pt2) ;
Point3d pt3 ; GetEndPoint( pt3) ;
Vector3d vtDir1 = pt2 - pt0 ;
Vector3d vtDir2 = pt3 - pt1 ;
Vector3d vtN = vtDir2 ^ vtDir1 ;
CurveLine cl1 ; cl1.Set( pt1, pt1 + (vtDir1 ^ vtN) * 5) ;
CurveLine cl2 ; cl1.Set( pt2, pt2 + (vtDir2 ^ vtN) * 5) ;
IntersLineLine ill( cl1, cl2, false) ;
IntCrvCrvInfo iccInfo ; ill.GetIntCrvCrvInfo( iccInfo) ;
Point3d ptCen = iccInfo.IciA[0].ptI ;
// se sia l'inizio che la fine della curva distano uguale dal punto di intersezione tra i due assi trovati allora la curva è un arco di circonferenza
if ( abs(Dist( pt0, ptCen) - Dist( pt3, ptCen)) < EPS_SMALL) {
PtrOwner<ICurveBezier> pNew ( ApproxArcCurveBezierWithSingleCubic( this, ptCen, vtN)) ;
if ( IsNull( pNew) || ! pNew->IsValid())
return false ;
Init( 3, false) ;
for ( int i = 0 ; i < 3 ; ++i)
SetControlPoint( i, pNew->GetControlPoint(i)) ;
return true ;
}
}
// punto di rientro in caso fallisca il primo tentativo
retry :
nDeg += 2 ;
@@ -2339,7 +2411,7 @@ CurveBezier::MakeNonRational( double dTol)
Point3d pt ; pNewBez->GetPointD1D2( double( p) / nDeg, pt) ;
Vector3d vDiff = vPntSampling[p] - pt ;
double dErrLoc = vDiff.Len() ;
if( dErrLoc > dErrMax)
if ( dErrLoc > dErrMax)
dErrMax = dErrLoc ;
// aggiorno il vettore dei punti di controllo della nuova curva
vPntCtrl[p] += vDiff ;
@@ -2352,7 +2424,7 @@ CurveBezier::MakeNonRational( double dTol)
}
// calcolo l'errore di approssimazione sulla curva
CalcBezierApproxError( this, pNewBez, dErr) ;
CalcApproxError( this, pNewBez, dErr) ;
bOk = dErr < dTol ;
if ( bOk) {
// aggiorno la curva di bezier originale con quella approssimata
@@ -2373,13 +2445,17 @@ CurveBezier::MakeNonRational( double dTol)
bool
CurveBezier::IsALine( void) const
{
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
Point3d ptStart ; GetStartPoint( ptStart) ;
Point3d ptEnd ; GetEndPoint( ptEnd) ;
for ( int i = 1 ; i < m_nDeg ; ++i) {
Point3d ptCtrl = GetControlPoint( i) ;
DistPointLine dpl( ptCtrl, ptStart, ptEnd) ;
double dDist = 0 ; dpl.GetDist( dDist) ;
if( dDist > EPS_SMALL)
if ( dDist > EPS_SMALL)
return false ;
}
return true ;
@@ -2389,6 +2465,10 @@ CurveBezier::IsALine( void) const
PNTVECTOR
CurveBezier::GetAllControlPoints( void) const
{
PNTVECTOR vPntCtrl = m_vPtCtrl ;
return vPntCtrl ;
PNTVECTOR vPntCtrl ;
// la curva deve essere valida
if ( m_nStatus != OK)
return vPntCtrl ;
return m_vPtCtrl ;
}
+1 -1
View File
@@ -116,7 +116,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW
{ return ApproxWithArcs( dLinTol, dAngTolDeg, PA) ; }
ICurve* CopyParamRange( double dUStart, double dUEnd) const override ;
bool Invert( void) override ;
bool SimpleOffset( double dDist, int nType = OFF_FILLET) override
bool SimpleOffset( double dDist, int nType = OFF_FILLET, double dMaxAngExt = ANG_RIGHT) override
{ return false ; } // l'offset di crvBezier non è crvBezier tranne in casi molto particolari
bool ModifyStart( const Point3d& ptNewStart) override ;
bool ModifyEnd( const Point3d& ptNewEnd) override ;
+2 -201
View File
@@ -202,213 +202,14 @@ CurveByApprox::CalcParameterization( void)
bool
CurveByApprox::CalcAkimaTangents( bool bDetectCorner)
{
// pulisco i vettori delle tangenti
m_vPrevDer.clear() ;
m_vNextDer.clear() ;
// numero di punti
int nSize = int( m_vPnt.size()) ;
// sono necessari almeno due punti
if ( nSize < 2)
return false ;
// calcolo le derivate
m_vPrevDer.reserve( nSize) ;
m_vNextDer.reserve( nSize) ;
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
if ( nSize == 2) {
// non esiste derivata prima del primo punto
m_vPrevDer.emplace_back( 0, 0, 0) ;
m_vNextDer.push_back( ( m_vPnt[1] - m_vPnt[0]) / ( m_vPar[1] - m_vPar[0])) ;
m_vPrevDer.push_back( m_vNextDer[0]) ;
// non esiste derivata dopo il secondo e ultimo punto
m_vNextDer.emplace_back( 0, 0, 0) ;
return true ;
}
// verifico se curva chiusa (primo e ultimo punto coincidono)
bool bClosed = AreSamePointApprox( m_vPnt.front(), m_vPnt.back()) ;
// calcolo le derivate
for ( int i = 0 ; i < nSize ; ++ i) {
Vector3d vtPrevDer ;
Vector3d vtNextDer ;
// primo punto
if ( i == 0) {
// se curva chiusa, come precedente uso il penultimo punto
if ( bClosed) {
// se non ci sono almeno 5 punti
if ( nSize < 5) {
if ( ! CalcCircleMidDer( m_vPar[nSize-2] - m_vPar[nSize-1], m_vPnt[nSize-2], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtNextDer))
return false ;
vtPrevDer = vtNextDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( m_vPar[nSize-3] - m_vPar[nSize-1], m_vPnt[nSize-3], m_vPar[nSize-2] - m_vPar[nSize-1], m_vPnt[nSize-2],
m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// altrimenti, uso arco sui primi tre punti
else {
if ( ! CalcCircleStartDer( m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], vtNextDer))
return false ;
vtPrevDer = Vector3d( 0, 0, 0) ;
}
}
// ultimo punto
else if ( i == nSize - 1) {
// se curva chiusa, le tg devono coincidere con quelle del primo
if ( bClosed) {
vtPrevDer = m_vPrevDer[0] ;
vtNextDer = m_vNextDer[0] ;
}
// altrimenti, uso arco sugli ultimi tre punti
else {
if ( ! CalcCircleEndDer( m_vPar[i-2], m_vPnt[i-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], vtPrevDer))
return false ;
vtNextDer = Vector3d( 0, 0, 0) ;
}
}
// punti intermedi
else {
// se secondo punto
if ( i == 1) {
// se curva aperta o non ci sono almeno 5 punti
if ( ! bClosed || nSize < 5) {
if ( ! CalcCircleMidDer( m_vPar[i-1], m_vPnt[i-1], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( m_vPar[nSize-2] - m_vPar[nSize-1], m_vPnt[nSize-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// se penultimo punto
else if ( i == nSize - 2) {
// se curva aperta o non ci sono almeno 5 punti
if ( ! bClosed || nSize < 5) {
if ( ! CalcCircleMidDer( m_vPar[i-1], m_vPnt[i-1], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( m_vPar[i-2], m_vPnt[i-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[1] + m_vPar[i+1], m_vPnt[1], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( m_vPar[i-2], m_vPnt[i-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// salvo la derivata
m_vPrevDer.push_back( vtPrevDer) ;
m_vNextDer.push_back( vtNextDer) ;
}
return true ;
return ComputeAkimaTangents( bDetectCorner, m_vPar, m_vPnt, m_vPrevDer, m_vNextDer) ;
}
//----------------------------------------------------------------------------
bool
CurveByApprox::CalcBesselTangents( void)
{
// pulisco i vettori delle tangenti
m_vPrevDer.clear() ;
m_vNextDer.clear() ;
// numero di punti
int nSize = int( m_vPnt.size()) ;
// sono necessari almeno due punti
if ( nSize < 2)
return false ;
// calcolo le derivate
m_vPrevDer.reserve( nSize) ;
m_vNextDer.reserve( nSize) ;
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
if ( nSize == 2) {
// non esiste derivata prima del primo punto
m_vPrevDer.emplace_back( 0, 0, 0) ;
m_vNextDer.push_back( ( m_vPnt[1] - m_vPnt[0]) / ( m_vPar[1] - m_vPar[0])) ;
m_vPrevDer.push_back( m_vNextDer[0]) ;
// non esiste derivata dopo il secondo e ultimo punto
m_vNextDer.emplace_back( 0, 0, 0) ;
return true ;
}
// verifico se curva chiusa (primo e ultimo punto coincidono)
bool bClosed = AreSamePointApprox( m_vPnt.front(), m_vPnt.back()) ;
// calcolo le derivate
for ( int i = 0 ; i < nSize ; ++ i) {
Vector3d vtPrevDer ;
Vector3d vtNextDer ;
// primo punto
if ( i == 0) {
// se curva chiusa, come precedente uso il penultimo punto
if ( bClosed) {
if ( ! CalcBesselMidDer( m_vPar[nSize-2] - m_vPar[nSize-1], m_vPnt[nSize-2], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtNextDer))
return false ;
vtPrevDer = vtNextDer ;
}
// altrimenti, uso i primi tre punti
else {
if ( ! CalcBesselStartDer( m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], vtNextDer))
return false ;
vtPrevDer = Vector3d( 0, 0, 0) ;
}
}
// ultimo punto
else if ( i == nSize - 1) {
// se curva chiusa, le tg devono coincidere con quelle del primo
if ( bClosed) {
vtPrevDer = m_vPrevDer[0] ;
vtNextDer = m_vNextDer[0] ;
}
// altrimenti, uso gli ultimi tre punti
else {
if ( ! CalcBesselEndDer( m_vPar[i-2], m_vPnt[i-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], vtPrevDer))
return false ;
vtNextDer = Vector3d( 0, 0, 0) ;
}
}
// punti intermedi
else {
if ( ! CalcBesselMidDer( m_vPar[i-1], m_vPnt[i-1], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// salvo la derivata
m_vPrevDer.push_back( vtPrevDer) ;
m_vNextDer.push_back( vtNextDer) ;
}
return true ;
return ComputeBesselTangents( m_vPar, m_vPnt, m_vPrevDer, m_vNextDer) ;
}
//----------------------------------------------------------------------------
+34 -225
View File
@@ -50,7 +50,37 @@ CurveByInterp::AddPoint( const Point3d& ptP)
ICurve*
CurveByInterp::GetCurve( int nMethod, int nType)
{
// calcolo le tangenti
// se richieste curve di Bezier cubiche (ottenute da interpolazione con Nurbs)
if ( nType == CUBIC_BEZIERS_LONG) {
// creo la curva composita
PtrOwner<ICurve> pCrv ;
//pCrv.Set( InterpolatePointSetWithBezier( m_vPnt, 50 * EPS_SMALL, 50)) ;
//debug
pCrv.Set( InterpolatePointSetWithBezier( m_vPnt, 0.1, 100)) ;
if ( IsNull(pCrv) || ! pCrv->IsValid())
return nullptr ;
return Release( pCrv) ;
}
// numero di punti
int nSize = int( m_vPnt.size()) ;
// sono necessari almeno due punti
if ( nSize < 2)
return nullptr ;
// calcolo le distanze tra i punti per derivarne i parametri
m_vPar.reserve( nSize) ;
double dPar = 0 ;
m_vPar.push_back( dPar) ;
for ( int i = 1 ; i < nSize ; ++ i) {
double dDist = Dist( m_vPnt[i-1], m_vPnt[i]) ;
dPar += dDist ;
m_vPar.push_back( dPar) ;
}
// calcolo le tangenti
if ( nMethod == BESSEL) {
if ( ! CalcBesselTangents())
return nullptr ;
@@ -110,233 +140,12 @@ CurveByInterp::GetCurve( int nMethod, int nType)
bool
CurveByInterp::CalcAkimaTangents( bool bDetectCorner)
{
// pulisco i vettori dei parametri e delle tangenti
m_vPar.clear() ;
m_vPrevDer.clear() ;
m_vNextDer.clear() ;
// numero di punti
int nSize = int( m_vPnt.size()) ;
// sono necessari almeno due punti
if ( nSize < 2)
return false ;
// calcolo le distanze tra i punti per derivarne i parametri
m_vPar.reserve( nSize) ;
double dPar = 0 ;
m_vPar.push_back( dPar) ;
for ( int i = 1 ; i < nSize ; ++ i) {
double dDist = Dist( m_vPnt[i-1], m_vPnt[i]) ;
dPar += dDist ;
m_vPar.push_back( dPar) ;
}
// calcolo le derivate
m_vPrevDer.reserve( nSize) ;
m_vNextDer.reserve( nSize) ;
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
if ( nSize == 2) {
// non esiste derivata prima del primo punto
m_vPrevDer.emplace_back( 0, 0, 0) ;
m_vNextDer.push_back( ( m_vPnt[1] - m_vPnt[0]) / ( m_vPar[1] - m_vPar[0])) ;
m_vPrevDer.push_back( m_vNextDer[0]) ;
// non esiste derivata dopo il secondo e ultimo punto
m_vNextDer.emplace_back( 0, 0, 0) ;
return true ;
}
// verifico se curva chiusa (primo e ultimo punto coincidono)
bool bClosed = AreSamePointApprox( m_vPnt.front(), m_vPnt.back()) ;
// calcolo le derivate
for ( int i = 0 ; i < nSize ; ++ i) {
Vector3d vtPrevDer ;
Vector3d vtNextDer ;
// primo punto
if ( i == 0) {
// se curva chiusa, come precedente uso il penultimo punto
if ( bClosed) {
// se non ci sono almeno 5 punti
if ( nSize < 5) {
if ( ! CalcCircleMidDer( m_vPar[nSize-2] - m_vPar[nSize-1], m_vPnt[nSize-2], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtNextDer))
return false ;
vtPrevDer = vtNextDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( m_vPar[nSize-3] - m_vPar[nSize-1], m_vPnt[nSize-3], m_vPar[nSize-2] - m_vPar[nSize-1], m_vPnt[nSize-2],
m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// altrimenti, uso arco sui primi tre punti
else {
if ( ! CalcCircleStartDer( m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], vtNextDer))
return false ;
vtPrevDer = Vector3d( 0, 0, 0) ;
}
}
// ultimo punto
else if ( i == nSize - 1) {
// se curva chiusa, le tg devono coincidere con quelle del primo
if ( bClosed) {
vtPrevDer = m_vPrevDer[0] ;
vtNextDer = m_vNextDer[0] ;
}
// altrimenti, uso arco sugli ultimi tre punti
else {
if ( ! CalcCircleEndDer( m_vPar[i-2], m_vPnt[i-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], vtPrevDer))
return false ;
vtNextDer = Vector3d( 0, 0, 0) ;
}
}
// punti intermedi
else {
// se secondo punto
if ( i == 1) {
// se curva aperta o non ci sono almeno 5 punti
if ( ! bClosed || nSize < 5) {
if ( ! CalcCircleMidDer( m_vPar[i-1], m_vPnt[i-1], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( m_vPar[nSize-2] - m_vPar[nSize-1], m_vPnt[nSize-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// se penultimo punto
else if ( i == nSize - 2) {
// se curva aperta o non ci sono almeno 5 punti
if ( ! bClosed || nSize < 5) {
if ( ! CalcCircleMidDer( m_vPar[i-1], m_vPnt[i-1], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( m_vPar[i-2], m_vPnt[i-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[1] + m_vPar[i+1], m_vPnt[1], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// altrimenti
else {
if ( ! CalcAkimaMidDer( m_vPar[i-2], m_vPnt[i-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], bDetectCorner,
vtPrevDer, vtNextDer))
return false ;
}
}
// salvo la derivata
m_vPrevDer.push_back( vtPrevDer) ;
m_vNextDer.push_back( vtNextDer) ;
}
return true ;
return ComputeAkimaTangents( bDetectCorner, m_vPar, m_vPnt, m_vPrevDer, m_vNextDer) ;
}
//----------------------------------------------------------------------------
bool
CurveByInterp::CalcBesselTangents( void)
{
// pulisco i vettori dei parametri e delle tangenti
m_vPar.clear() ;
m_vPrevDer.clear() ;
m_vNextDer.clear() ;
// numero di punti
int nSize = int( m_vPnt.size()) ;
// sono necessari almeno due punti
if ( nSize < 2)
return false ;
// calcolo le distanze tra i punti per derivarne i parametri
m_vPar.reserve( nSize) ;
double dPar = 0 ;
m_vPar.push_back( dPar) ;
for ( int i = 1 ; i < nSize ; ++ i) {
double dDist = Dist( m_vPnt[i-1], m_vPnt[i]) ;
dPar += dDist ;
m_vPar.push_back( dPar) ;
}
// calcolo le derivate
m_vPrevDer.reserve( nSize) ;
m_vNextDer.reserve( nSize) ;
// se ci sono solo 2 punti, le tangenti devono essere dirette lungo la linea che li unisce
if ( nSize == 2) {
// non esiste derivata prima del primo punto
m_vPrevDer.emplace_back( 0, 0, 0) ;
m_vNextDer.push_back( ( m_vPnt[1] - m_vPnt[0]) / ( m_vPar[1] - m_vPar[0])) ;
m_vPrevDer.push_back( m_vNextDer[0]) ;
// non esiste derivata dopo il secondo e ultimo punto
m_vNextDer.emplace_back( 0, 0, 0) ;
return true ;
}
// verifico se curva chiusa (primo e ultimo punto coincidono)
bool bClosed = AreSamePointApprox( m_vPnt.front(), m_vPnt.back()) ;
// calcolo le derivate
for ( int i = 0 ; i < nSize ; ++ i) {
Vector3d vtPrevDer ;
Vector3d vtNextDer ;
// primo punto
if ( i == 0) {
// se curva chiusa, come precedente uso il penultimo punto
if ( bClosed) {
if ( ! CalcBesselMidDer( m_vPar[nSize-2] - m_vPar[nSize-1], m_vPnt[nSize-2], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtNextDer))
return false ;
vtPrevDer = vtNextDer ;
}
// altrimenti, uso i primi tre punti
else {
if ( ! CalcBesselStartDer( m_vPar[i], m_vPnt[i], m_vPar[i+1], m_vPnt[i+1],
m_vPar[i+2], m_vPnt[i+2], vtNextDer))
return false ;
vtPrevDer = Vector3d( 0, 0, 0) ;
}
}
// ultimo punto
else if ( i == nSize - 1) {
// se curva chiusa, le tg devono coincidere con quelle del primo
if ( bClosed) {
vtPrevDer = m_vPrevDer[0] ;
vtNextDer = m_vNextDer[0] ;
}
// altrimenti, uso gli ultimi tre punti
else {
if ( ! CalcBesselEndDer( m_vPar[i-2], m_vPnt[i-2], m_vPar[i-1], m_vPnt[i-1],
m_vPar[i], m_vPnt[i], vtPrevDer))
return false ;
vtNextDer = Vector3d( 0, 0, 0) ;
}
}
// punti intermedi
else {
if ( ! CalcBesselMidDer( m_vPar[i-1], m_vPnt[i-1], m_vPar[i], m_vPnt[i],
m_vPar[i+1], m_vPnt[i+1], vtPrevDer))
return false ;
vtNextDer = vtPrevDer ;
}
// salvo la derivata
m_vPrevDer.push_back( vtPrevDer) ;
m_vNextDer.push_back( vtNextDer) ;
}
return true ;
}
return ComputeBesselTangents( m_vPar, m_vPnt, m_vPrevDer, m_vNextDer) ;
}
+14 -7
View File
@@ -889,14 +889,21 @@ CurveComposite::Validate( void)
//----------------------------------------------------------------------------
bool
CurveComposite::TestClosure( void)
CurveComposite::TestClosure( double dLinTol)
{
// se non è chiusa, esco subito
if ( ! IsClosed())
// se non valida o vuota, esco subito
if ( m_nStatus != OK || m_CrvSmplS.empty())
return true ;
// se non è chiusa entro la tolleranza, esco subito
Point3d ptStart, ptEnd ;
if ( ! m_CrvSmplS.front()->GetStartPoint( ptStart) ||
! m_CrvSmplS.back()->GetEndPoint( ptEnd) ||
! AreSamePointEpsilon( ptStart, ptEnd, dLinTol))
return true ;
// se singola retta, esco subito
if ( m_CrvSmplS.size() == 1 && m_CrvSmplS.front()->GetType() == CRV_LINE)
return true ;
// verifico ed eventualmente aggiusto coincidenza punti estremi
Point3d ptStart ; m_CrvSmplS.front()->GetStartPoint( ptStart) ;
Point3d ptEnd ; m_CrvSmplS.back()->GetEndPoint( ptEnd) ;
// se distanza superiore al limite ridotto forzo i punti a coincidere
if ( ! AreSamePointEpsilon( ptStart, ptEnd, EPS_CONNECT)) {
// se un solo arco
@@ -1707,7 +1714,7 @@ CurveComposite::Invert( void)
//----------------------------------------------------------------------------
bool
CurveComposite::SimpleOffset( double dDist, int nType)
CurveComposite::SimpleOffset( double dDist, int nType, double dMaxAngExt)
{
// se distanza di offset nulla, non devo fare alcunché
if ( abs( dDist) < EPS_SMALL)
@@ -1729,7 +1736,7 @@ CurveComposite::SimpleOffset( double dDist, int nType)
}
// eseguo l'offset nel piano XY
bool bOk = SimpleOffsetXY( dDist, nType) ;
bool bOk = SimpleOffsetXY( dDist, nType, dMaxAngExt) ;
// riporto la curva nel riferimento originale
if ( bNeedRef)
+3 -3
View File
@@ -113,7 +113,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW
bool ApproxWithArcsEx( double dLinTol, double dAngTolDeg, double dLinFea, PolyArc& PA) const override ;
ICurve* CopyParamRange( double dUStart, double dUEnd) const override ;
bool Invert( void) override ;
bool SimpleOffset( double dDist, int nType = OFF_FILLET) override ;
bool SimpleOffset( double dDist, int nType = OFF_FILLET, double dMaxAngExt = ANG_RIGHT) override ;
bool ModifyStart( const Point3d& ptNewStart) override ;
bool ModifyEnd( const Point3d& ptNewEnd) override ;
bool SetExtrusion( const Vector3d& vtExtr) override
@@ -198,17 +198,17 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW
return *this ; }
bool RelocateFrom( CurveComposite& ccSrc) ;
bool GetApproxLength( double& dLen) const ;
bool TestClosure( double dLinTol = EPS_SMALL) ;
Voronoi* GetVoronoiObject( void) const ;
void ResetVoronoiObject( void) const ;
private :
bool CopyFrom( const CurveComposite& ccSrc) ;
bool Validate( void) ;
bool TestClosure( void) ;
bool AddCurveByRelocate( CurveComposite& ccSrc, bool bEndOrStart = true, double dLinTol = EPS_SMALL) ;
bool AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart = true, double dLinTol = EPS_SMALL) ;
bool GetIndSCurveAndLocPar( double dU, Side nS, int& nSCrv, double& dLocU) const ;
bool SimpleOffsetXY( double dDist, int nType = OFF_FILLET) ;
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 ;
+14 -10
View File
@@ -19,6 +19,7 @@
#include "GeoConst.h"
#include "/EgtDev/Include/EGkCurve.h"
#include "/EgtDev/Include/EGkIntersCurves.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
@@ -30,14 +31,14 @@ static const int TP_IS_VERT_LINE = 1 ;
static bool IsVerticalLine( const ICurve* pCrv, double* pdLenZ) ;
static bool VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2, CurveComposite& ccAux) ;
static bool VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2, CurveComposite& ccAux) ;
static bool VerifyAndAdjustExternalAngle( ICurve* pCrv1, ICurve* pCrv2, double dDist, int nType,
static bool VerifyAndAdjustExternalAngle( ICurve* pCrv1, ICurve* pCrv2, double dDist, int nType, double dMaxAngExt,
CurveComposite& ccAux) ;
static bool AddFirstLastVerticalLines( CurveComposite& ccOffs, double dLenVertFirst, double dLenVertLast) ;
static bool MediaInternalAngleDeltaZ( CurveComposite& ccOffs) ;
//----------------------------------------------------------------------------
bool
CurveComposite::SimpleOffsetXY( double dDist, int nType)
CurveComposite::SimpleOffsetXY( double dDist, int nType, double dMaxAngExt)
{
// creo una copia formata solo da rette e archi che giacciono nel piano XY (VtExtr è Z+)
CurveComposite ccCopy ;
@@ -98,7 +99,7 @@ CurveComposite::SimpleOffsetXY( double dDist, int nType)
CurveComposite ccTemp ;
if ( VerifyAndAdjustSamePoint( pCrvPrev, pCrv2, ccTemp) ||
VerifyAndAdjustInternalAngle( pCrvPrev, pCrv2, ccTemp) ||
VerifyAndAdjustExternalAngle( pCrvPrev, pCrv2, dDist, nType, ccTemp)) {
VerifyAndAdjustExternalAngle( pCrvPrev, pCrv2, dDist, nType, dMaxAngExt, ccTemp)) {
if ( ccTemp.GetCurveCount() > 0 && ! ccOffs.AddCurveByRelocate( ccTemp))
return false ;
}
@@ -122,7 +123,7 @@ CurveComposite::SimpleOffsetXY( double dDist, int nType)
CurveComposite ccTemp ;
if ( VerifyAndAdjustSamePoint( pCrvPrev, pCrvNext, ccTemp) ||
VerifyAndAdjustInternalAngle( pCrvPrev, pCrvNext, ccTemp) ||
VerifyAndAdjustExternalAngle( pCrvPrev, pCrvNext, dDist, nType, ccTemp)) {
VerifyAndAdjustExternalAngle( pCrvPrev, pCrvNext, dDist, nType, dMaxAngExt, ccTemp)) {
int nCrvCount = ccTemp.GetCurveCount() ;
if ( nCrvCount > 0 && ! ccOffs.AddCurveByRelocate( ccTemp))
return false ;
@@ -174,7 +175,7 @@ bool
VerifyAndAdjustSamePoint( ICurve* pCrv1, ICurve* pCrv2, CurveComposite& ccAux)
{
// verifica dei puntatori
if ( pCrv1 == nullptr || pCrv2 == nullptr || &ccAux == nullptr)
if ( pCrv1 == nullptr || pCrv2 == nullptr)
return false ;
// pulisco la curva ausiliaria
@@ -218,7 +219,7 @@ bool
VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2, CurveComposite& ccAux)
{
// verifica dei puntatori
if ( pCrv1 == nullptr || pCrv2 == nullptr || &ccAux == nullptr)
if ( pCrv1 == nullptr || pCrv2 == nullptr)
return false ;
// pulisco la curva ausiliaria
@@ -259,11 +260,11 @@ VerifyAndAdjustInternalAngle( ICurve* pCrv1, ICurve* pCrv2, CurveComposite& ccAu
//----------------------------------------------------------------------------
bool
VerifyAndAdjustExternalAngle( ICurve* pCrv1, ICurve* pCrv2, double dDist, int nType,
VerifyAndAdjustExternalAngle( ICurve* pCrv1, ICurve* pCrv2, double dDist, int nType, double dMaxAngExt,
CurveComposite& ccAux)
{
// verifica dei puntatori
if ( pCrv1 == nullptr || pCrv2 == nullptr || &ccAux == nullptr)
if ( pCrv1 == nullptr || pCrv2 == nullptr)
return false ;
// pulisco la curva ausiliaria
@@ -272,6 +273,9 @@ VerifyAndAdjustExternalAngle( ICurve* pCrv1, ICurve* pCrv2, double dDist, int nT
// elimino dal tipo le parti estranee all'angolo esterno
nType &= ( ICurve::OFF_FILLET | ICurve::OFF_CHAMFER | ICurve::OFF_EXTEND) ;
// porto il massimo angolo per tipo Extend in limiti accettabili (90° - 150°)
dMaxAngExt = Clamp( dMaxAngExt, ANG_RIGHT, 1.667 * ANG_RIGHT) ;
// calcolo direzioni tangenti sull'estremo in comune
Vector3d vtDir1, vtDir2 ;
if ( ! pCrv1->GetEndDir( vtDir1) || ! pCrv2->GetStartDir( vtDir2))
@@ -319,8 +323,8 @@ VerifyAndAdjustExternalAngle( ICurve* pCrv1, ICurve* pCrv2, double dDist, int nT
( dDist > 0 && dAngDeg < 0)))
return false ;
// se l'angolo esterno supera il retto, offset extend diventa offset chamfer
if ( nType == ICurve::OFF_EXTEND && abs( dAngDeg) > ANG_RIGHT + EPS_ANG_SMALL)
// se l'angolo esterno supera il limite, offset extend diventa offset chamfer
if ( nType == ICurve::OFF_EXTEND && abs( dAngDeg) > dMaxAngExt + EPS_ANG_SMALL)
nType = ICurve::OFF_CHAMFER ;
// se angolo esterno molto piccolo, semplifico tutto
+1 -1
View File
@@ -577,7 +577,7 @@ CurveLine::Invert( void)
//----------------------------------------------------------------------------
bool
CurveLine::SimpleOffset( double dDist, int nType)
CurveLine::SimpleOffset( double dDist, int nType, double dMaxAngExt)
{
// verifico lo stato
if ( m_nStatus != OK)
+1 -1
View File
@@ -117,7 +117,7 @@ class CurveLine : public ICurveLine, public IGeoObjRW
{ return ApproxWithArcs( dLinTol, dAngTolDeg, PA) ; }
ICurve* CopyParamRange( double dUStart, double dUEnd) const override ;
bool Invert( void) override ;
bool SimpleOffset( double dDist, int nType = OFF_FILLET) override ;
bool SimpleOffset( double dDist, int nType = OFF_FILLET, double dMaxAngExt = ANG_RIGHT) override ;
bool ModifyStart( const Point3d& ptNewStart) override ;
bool ModifyEnd( const Point3d& ptNewEnd) override ;
bool SetExtrusion( const Vector3d& vtExtr) override
+15 -2
View File
@@ -116,6 +116,7 @@ PolishMinDistPointCurve( const Point3d& ptP, const ICurve& cCurve,
vtDiff = ptQ - ptP ;
// angolo tra vettore e tangente
dTemp = vtDer1 * vtDiff ;
bool bEquiverse = dTemp > 0 ;
if ( abs( dTemp) > EPS_ZERO)
dSqCosA = dTemp * dTemp / ( vtDer1.SqLen() * vtDiff.SqLen()) ;
else
@@ -123,8 +124,20 @@ PolishMinDistPointCurve( const Point3d& ptP, const ICurve& cCurve,
// stima prossimo valore del parametro (Newton : Unext = U - F(U) / F'(U))
dPrevPar = dPar ;
dTemp = vtDer2 * vtDiff + vtDer1.SqLen() ;
if ( abs( dTemp) > EPS_ZERO)
dPar = dPrevPar - ( vtDer1 * vtDiff) / dTemp ;
// se il coseno tra questi due vettori è troppo grande potrei aver avuto una cattiva stima iniziale
// provo quindi ad aggiustare a mano, anziché usare il segno suggerito da newton, che con queste premesse potrebbe divergere
double dCos75 = 0.2588 ;
if ( abs( dTemp) > EPS_ZERO) {
double dDelta = ( vtDer1 * vtDiff) / dTemp ;
if ( dSqCosA > dCos75) {
if ( ( bEquiverse && dDelta > 0) || ( ! bEquiverse && dDelta < 0))
dDelta *= -1 ;
dPar = dPrevPar + dDelta ;
}
else
dPar = dPrevPar - dDelta ;
}
// clipping parametro
if ( dPar < approxMin.dParMin) {
if ( approxMin.bParMinSing && ! bClampedFromSing) {
+12 -1
View File
@@ -26,7 +26,7 @@ DistPointCrvBezier::DistPointCrvBezier( const Point3d& ptP, const ICurveBezier&
// distanza non calcolata
m_dDist = - 1 ;
if ( &CrvBez == nullptr || ! CrvBez.IsValid())
if ( ! CrvBez.IsValid())
return ;
// determino tolleranza di approssimazione in base a ingombro curva
@@ -42,6 +42,17 @@ DistPointCrvBezier::DistPointCrvBezier( const Point3d& ptP, const ICurveBezier&
if ( ! CrvBez.ApproxWithLines( dLinTol, ANG_TOL_APPROX_DEG, ICurve::APL_STD, PL))
return ;
int nDeg = CrvBez.GetDegree() ;
if ( PL.GetPointNbr() < nDeg + 1) {
// costruisco una polilinea con un numero di curve scelto in base al grado della curva
PL.Clear() ;
for ( int i = 0 ; i <= nDeg + 1 ; ++i) {
double dU = double(i) / (nDeg + 1) ;
Point3d ptBez ;
CrvBez.GetPointD1D2( dU, ICurve::Side::FROM_MINUS, ptBez) ;
PL.AddUPoint( dU, ptBez) ;
}
}
// cerco la minima distanza per la polilinea
MDCVECTOR vApproxMin ;
if ( ! CalcMinDistPointPolyLine( ptP, PL, dLinTol, vApproxMin))
+120
View File
@@ -0,0 +1,120 @@
//----------------------------------------------------------------------------
// EgalTech 2025
//----------------------------------------------------------------------------
// File : DistPointSurfBz.cpp Data : 29.10.25 Versione : 2.7j3
// Contenuto : Implementazione della classe distanza Punto da superficie Bezier.
//
//
//
// Modifiche : 29.10.25 DB Creazione modulo.
//
//
//----------------------------------------------------------------------------
#include "stdafx.h"
#include "SurfTriMesh.h"
#include "SurfBezier.h"
#include "/EgtDev/Include/EGkDistPointTria.h"
#include "/EgtDev/Include/EGkDistPointSurfTm.h"
#include "/EgtDev/Include/EGkDistPointSurfBz.h"
#include "/EgtDev/Include/EGkIntersLineTria.h"
using namespace std ;
//----------------------------------------------------------------------------
DistPointSurfBz::DistPointSurfBz( const Point3d& ptP, const ISurfBezier& pSrfBz)
: m_dDist( -1), m_bIsInside( false), m_bIsSurfClosed( false)
{
// Bezier non valida
if ( ! pSrfBz.IsValid())
return ;
// Calcolo la distanza
Calculate( ptP, pSrfBz) ;
}
//----------------------------------------------------------------------------
void
DistPointSurfBz::Calculate( const Point3d& ptP, const ISurfBezier& srfBz)
{
// Inizializzo distanza non calcolata
m_dDist = -1 ;
// Controllo se la superficie è chiusa
m_bIsSurfClosed = srfBz.IsClosed() ;
// Lavoro con l'oggetto superficie trimesh di base
const ISurfTriMesh* pStmRef = srfBz.GetAuxSurfRefined() ;
if ( pStmRef == nullptr)
return ;
DistPointSurfTm dpst( ptP, *pStmRef) ;
// recupero il punto a distanza minima sulla trimesh e lo raffino, prima di restituire distanza e punto minimo
Point3d ptMinTm ; dpst.GetMinDistPoint( ptMinTm) ;
int nT ; dpst.GetMinDistTriaIndex( nT) ;
// salvo il punto corrispondente nel parametrico
srfBz.UnprojectPointFromStm( nT, ptMinTm, m_ptParam) ;
// salvo il punto a minima distanza sulla superficie e la normale alla superficie in quel punto
srfBz.GetPointNrmD1D2( m_ptParam.x, m_ptParam.y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, m_ptMinDistPoint, m_vtN) ;
// salvo la distanza minima
m_dDist = Dist( ptP, m_ptMinDistPoint) ;
// se il punto è sulla superficie
if ( m_dDist < EPS_SMALL) {
m_bIsInside = false ;
return ;
}
else {
m_bIsInside = ( ( ptP - m_ptMinDistPoint) * m_vtN < - EPS_SMALL) ;
return ;
}
}
//----------------------------------------------------------------------------
bool
DistPointSurfBz::GetDist( double& dDist) const
{
// Distanza non valida
if ( m_dDist < -EPS_ZERO)
return false ;
// Distanza valida
dDist = m_dDist ;
return true ;
}
//----------------------------------------------------------------------------
bool
DistPointSurfBz::GetMinDistPoint( Point3d& ptMinDistPoint) const
{
// Distanza non valida
if ( m_dDist < -EPS_ZERO)
return false ;
// Distanza valida
ptMinDistPoint = m_ptMinDistPoint ;
return true ;
}
//----------------------------------------------------------------------------
bool
DistPointSurfBz::GetParamsAtMinDistPoint( double& dU, double& dV) const
{
// Distanza non valida
if ( m_dDist < -EPS_ZERO)
return false ;
// Distanza valida
dU = m_ptParam.x ;
dV = m_ptParam.y ;
return true ;
}
//----------------------------------------------------------------------------
bool
DistPointSurfBz::GetNorm( Vector3d& vtN) const
{
// Distanza non valida
if ( m_dDist < -EPS_ZERO)
return false ;
// Distanza valida
vtN = m_vtN ;
return true ;
}
+2 -2
View File
@@ -194,11 +194,11 @@ GetDefaultFont( void)
}
//-----------------------------------------------------------------------------
static pfProcEvents s_pFunProcEvents = nullptr ;
static psfProcEvents s_pFunProcEvents = nullptr ;
//-----------------------------------------------------------------------------
bool
SetEGkProcessEvents( pfProcEvents pFun)
SetEGkProcessEvents( psfProcEvents pFun)
{
s_pFunProcEvents = pFun ;
return ( pFun != nullptr) ;
BIN
View File
Binary file not shown.
+8 -4
View File
@@ -116,7 +116,7 @@
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<EnablePREfast>false</EnablePREfast>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -151,7 +151,7 @@ copy $(TargetPath) \EgtProg\DllD32</Command>
<MinimalRebuild>false</MinimalRebuild>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalOptions>-Wno-tautological-undefined-compare</AdditionalOptions>
</ClCompile>
<Link>
@@ -199,7 +199,7 @@ copy $(TargetPath) \EgtProg\DllD64</Command>
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
<WholeProgramOptimization>false</WholeProgramOptimization>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -245,7 +245,7 @@ copy $(TargetPath) \EgtProg\Dll32</Command>
<EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations>
<WholeProgramOptimization>false</WholeProgramOptimization>
<DebugInformationFormat>None</DebugInformationFormat>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard>stdcpp20</LanguageStandard>
<AdditionalOptions>-Wno-tautological-undefined-compare</AdditionalOptions>
<IntelJCCErratum>true</IntelJCCErratum>
</ClCompile>
@@ -281,6 +281,7 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClCompile Include="BBox3d.cpp" />
<ClCompile Include="BiArcs.cpp" />
<ClCompile Include="CalcPocketing.cpp" />
<ClCompile Include="CalcDerivate.cpp" />
<ClCompile Include="CAvSilhouetteSurfTm.cpp" />
<ClCompile Include="CAvSimpleSurfFrMove.cpp" />
<ClCompile Include="CAvToolSurfTm.cpp" />
@@ -310,7 +311,9 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClCompile Include="CurveByApprox.cpp" />
<ClCompile Include="CurveByInterp.cpp" />
<ClCompile Include="CurveCompositeOffset.cpp" />
<ClCompile Include="DistPointSurfBz.cpp" />
<ClCompile Include="DistPointSurfFr.cpp" />
<ClCompile Include="IntersCurvePlane.cpp" />
<ClCompile Include="IntersCurveSurfTm.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</ExcludedFromBuild>
@@ -320,6 +323,7 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClCompile Include="IntersLineVolZmap.cpp" />
<ClCompile Include="IntersPlaneVolZmap.cpp" />
<ClCompile Include="IntersLineSurfBez.cpp" />
<ClCompile Include="Trimming.cpp" />
<ClCompile Include="MultiGeomDB.cpp" />
<ClCompile Include="SurfTriMeshOffset.cpp" />
<ClCompile Include="VolZmapOffset.cpp" />
+15
View File
@@ -55,6 +55,9 @@
<Filter Include="File di origine\GeoCollisionDetection">
<UniqueIdentifier>{865b76ee-b10d-41fc-861c-b48ce52fa277}</UniqueIdentifier>
</Filter>
<Filter Include="File di origine\GeoStriping">
<UniqueIdentifier>{54901321-08f6-4428-80c7-a1f859136a32}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Vector3d.cpp">
@@ -555,6 +558,18 @@
<ClCompile Include="MultiGeomDB.cpp">
<Filter>File di origine\Gdb</Filter>
</ClCompile>
<ClCompile Include="DistPointSurfBz.cpp">
<Filter>File di origine\GeoDist</Filter>
</ClCompile>
<ClCompile Include="IntersCurvePlane.cpp">
<Filter>File di origine\GeoInters</Filter>
</ClCompile>
<ClCompile Include="Trimming.cpp">
<Filter>File di origine\GeoStriping</Filter>
</ClCompile>
<ClCompile Include="CalcDerivate.cpp">
<Filter>File di origine\Geo</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
+1 -1
View File
@@ -1087,7 +1087,7 @@ ExtDimension::Update( void) const
if ( m_nType == DT_RADIAL)
sVal = "R " + sVal ;
else if ( m_nType == DT_DIAMETRAL)
sVal = u8"\u00D8 " + sVal ;
sVal = reinterpret_cast<const char *>( u8"\u00D8") + sVal ;
ReplaceString( m_sCalcText, IS_MEASURE, sVal) ;
}
// punto di inserimento del testo
+35 -35
View File
@@ -28,41 +28,6 @@
#define GEOOBJ_NGEIDTOTYPE( nNgeId) GeoObjFactory::NgeIdToType( nNgeId)
#define GEOOBJ_CREATE( nKey) GeoObjFactory::Create( nKey)
//----------------------------------------------------------------------------
template <class T>
class GeoObjRegister
{
public :
static bool DoRegister( int nKey, int nNgeId)
{ if ( ! GeoObjFactory::Register( nKey, NgeAscKeyW[nNgeId], nNgeId, Create))
return false ;
GetTypePrivate() = nKey ;
GetKeyPrivate() = NgeAscKeyW[nNgeId] ;
GetNgeIdPrivate() = nNgeId ;
return true ; }
static IGeoObj* Create( void)
{ return new( std::nothrow) T ; }
static int GetType( void)
{ return GetTypePrivate() ; }
static const std::string& GetKey( void)
{ return GetKeyPrivate() ; }
static int GetNgeId( void)
{ return GetNgeIdPrivate() ; }
private :
GeoObjRegister( void) {}
~GeoObjRegister( void) {}
static int& GetTypePrivate( void)
{ static int s_nType ;
return s_nType ; }
static std::string& GetKeyPrivate( void)
{ static std::string s_sKey ;
return s_sKey ; }
static int& GetNgeIdPrivate( void)
{ static int s_nNgeId ;
return s_nNgeId ; }
} ;
//----------------------------------------------------------------------------
class GeoObjFactory
{
@@ -117,3 +82,38 @@ class GeoObjFactory
{ static CreatorMap s_CreatorMap ;
return s_CreatorMap ; }
} ;
//----------------------------------------------------------------------------
template <class T>
class GeoObjRegister
{
public :
static bool DoRegister( int nKey, int nNgeId)
{ if ( ! GeoObjFactory::Register( nKey, NgeAscKeyW[nNgeId], nNgeId, Create))
return false ;
GetTypePrivate() = nKey ;
GetKeyPrivate() = NgeAscKeyW[nNgeId] ;
GetNgeIdPrivate() = nNgeId ;
return true ; }
static IGeoObj* Create( void)
{ return new( std::nothrow) T ; }
static int GetType( void)
{ return GetTypePrivate() ; }
static const std::string& GetKey( void)
{ return GetKeyPrivate() ; }
static int GetNgeId( void)
{ return GetNgeIdPrivate() ; }
private :
GeoObjRegister( void) {}
~GeoObjRegister( void) {}
static int& GetTypePrivate( void)
{ static int s_nType ;
return s_nType ; }
static std::string& GetKeyPrivate( void)
{ static std::string s_sKey ;
return s_sKey ; }
static int& GetNgeIdPrivate( void)
{ static int s_nNgeId ;
return s_nNgeId ; }
} ;
+8 -6
View File
@@ -38,16 +38,18 @@ using namespace std ;
class LockAddErase
{
public :
LockAddErase( atomic_flag& bAddEraseOn, bool bUse = true): m_bAddEraseOn( bAddEraseOn), m_bUse( bUse)
LockAddErase( atomic_flag& bAddEraseOn, bool bUse = true)
: m_bAddEraseOn( bAddEraseOn), m_bUse( bUse)
{ if ( ! m_bUse) return ;
while ( m_bAddEraseOn.test_and_set()) {
this_thread::sleep_for( chrono::nanoseconds{ 1}) ;
while ( m_bAddEraseOn.test_and_set( memory_order_acquire)) {
m_bAddEraseOn.wait( true, memory_order_relaxed) ;
}
} ;
~LockAddErase( void)
{ if ( ! m_bUse) return ;
m_bAddEraseOn.clear() ;
m_bAddEraseOn.clear( memory_order_release) ;
m_bAddEraseOn.notify_one() ;
} ;
private :
@@ -611,7 +613,7 @@ GeomDB::GetGdbObj( int nId) const
// radice
else if ( nId == GDB_ID_ROOT)
return &m_GrpRadix ;
// un nodo qualubque
// un nodo qualunque
else
return m_IdManager.FindObj( nId) ;
}
@@ -658,7 +660,7 @@ GeomDB::InsertInGeomDB( GdbObj* pGObj, int nRefId, int nSonBeforeAfter, bool bLo
return false ;
}
// inserisco come figlio, in testa alla lista del padre
else if ( nSonBeforeAfter == GDB_FIRST_SON){
else if ( nSonBeforeAfter == GDB_FIRST_SON) {
GdbGroup* pGroup = ::GetGdbGroup( pGRef) ;
if ( pGroup == nullptr)
return false ;
+2
View File
@@ -31,6 +31,8 @@ class GeomDB : public IGeomDB
friend class GdbGeo ;
friend int CopyGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob) ;
friend int CopyGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob) ;
friend int DuplicateGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId) ;
friend int DuplicateGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, bool bSkipTemp) ;
public :
~GeomDB( void) override ;
+234 -99
View File
@@ -34,6 +34,7 @@ static bool CalcATypeFromDisk( const ICurve& CurveA, double dUA, ICurve::Side nS
const ICurve& CurveB, double dUB, int& nType) ;
static bool CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA,
const ICurve& CurveB, double dUB1, double dUB2, int& nType) ;
static bool CalcSide( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2, const ICurve* pThisCrv, const ICurve* pOtherCrv, bool bCrvAOrB, int& nType) ;
//----------------------------------------------------------------------------
IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
@@ -197,7 +198,7 @@ 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
// 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) ;
@@ -264,7 +265,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
EraseOtherInfo( i, j) ;
EraseCurrentInfo( i, j) ;
}
// caso DET-NULL -> NULL-DET per prima curva
// caso DET-(NULL) -> (NULL)-DET per prima curva
else if ( m_Info[j].IciA[kj].nPrevTy != ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL &&
m_Info[i].IciA[ki].nPrevTy == ICCT_NULL && m_Info[i].IciA[ki].nNextTy != ICCT_NULL) {
// per la prima curva tengo i determinati
@@ -272,16 +273,22 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ;
// se overlap equiverso
if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) {
// per la seconda curva ogni sottotipo è il duale di quello della prima
// per la seconda curva ogni sottotipo è il duale di quello della prima
m_Info[i].IciB[ki].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ;
m_Info[i].IciB[ki].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ;
}
// se altrimenti overlap controverso
else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) {
// per la seconda curva ogni sottotipo è come quello della prima ma in posizione invertita
// per la seconda curva ogni sottotipo è come quello della prima ma in posizione invertita
m_Info[i].IciB[ki].nPrevTy = m_Info[i].IciA[ki].nNextTy ;
m_Info[i].IciB[ki].nNextTy = m_Info[i].IciA[ki].nPrevTy ;
}
else {
if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL)
m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ;
if ( m_Info[i].IciB[ki].nNextTy == ICCT_NULL)
m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ;
}
// se overlap equiverso
if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) {
m_Info[j].IciB[kj].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ;
@@ -292,6 +299,13 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciA[ki].nNextTy ;
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciA[ki].nPrevTy ;
}
else {
if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL)
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ;
if ( m_Info[j].IciB[kj].nNextTy == ICCT_NULL)
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ;
}
// medio parametri e punti separatamente per le due curve
MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj], CCompoA) ;
MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj], CCompoB) ;
@@ -306,7 +320,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
EraseCurrentInfo( i, j) ;
}
}
// caso NULL-DET -> DET-NULL per prima curva (possibile su inizio/fine di curva chiusa)
// caso (NULL)-DET -> DET-(NULL) per prima curva (possibile su inizio/fine di curva chiusa)
else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy != ICCT_NULL &&
m_Info[i].IciA[ki].nPrevTy != ICCT_NULL && m_Info[i].IciA[ki].nNextTy == ICCT_NULL) {
// per la prima curva tengo i determinati
@@ -314,28 +328,41 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciA[ki].nPrevTy ;
// se overlap equiverso
if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) {
// per la seconda curva ogni sottotipo è il duale di quello della prima
// per la seconda curva ogni sottotipo è il duale di quello della prima
m_Info[i].IciB[ki].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ;
m_Info[i].IciB[ki].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ;
}
// se altrimenti overlap controverso
else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) {
// per la seconda curva ogni sottotipo è come quello della prima ma in posizione scambiata
// per la seconda curva ogni sottotipo è come quello della prima ma in posizione scambiata
m_Info[i].IciB[ki].nPrevTy = m_Info[i].IciA[ki].nNextTy ;
m_Info[i].IciB[ki].nNextTy = m_Info[i].IciA[ki].nPrevTy ;
}
else {
if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL)
m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ;
if ( m_Info[i].IciB[ki].nNextTy == ICCT_NULL)
m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ;
}
// se overlap equiverso
if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) {
// per la seconda curva ogni sottotipo è il duale di quello della prima
// per la seconda curva ogni sottotipo è il duale di quello della prima
m_Info[j].IciB[kj].nPrevTy = GetDualIcct( m_Info[i].IciA[ki].nPrevTy) ;
m_Info[j].IciB[kj].nNextTy = GetDualIcct( m_Info[i].IciA[ki].nNextTy) ;
}
// se altrimenti overlap controverso
else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) {
// per la seconda curva ogni sottotipo è come quello della prima ma in posizione scambiata
// per la seconda curva ogni sottotipo è come quello della prima ma in posizione scambiata
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciA[ki].nNextTy ;
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciA[ki].nPrevTy ;
}
else {
if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL)
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ;
if ( m_Info[j].IciB[kj].nNextTy == ICCT_NULL)
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ;
}
// medio parametri e punti separatamente per le due curve
MediaParamPoints( m_Info[i].IciA[ki], m_Info[j].IciA[kj], CCompoA) ;
MediaParamPoints( m_Info[i].IciB[ki], m_Info[j].IciB[kj], CCompoB) ;
@@ -370,13 +397,21 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
}
// caso NULL-NULL per corrente di prima curva
else if ( m_Info[i].IciA[ki].nPrevTy == ICCT_NULL && m_Info[i].IciA[ki].nNextTy == ICCT_NULL) {
m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ;
m_Info[j].IciA[kj].nNextTy = ICCT_NULL ;
if ( m_Info[j].IciB[kj].nNextTy == ICCT_NULL)
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ;
if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL)
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ;
// cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente)
EraseCurrentInfo( i, j) ;
}
// caso NULL-NULL per precedente di prima curva
else if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL && m_Info[j].IciA[kj].nNextTy == ICCT_NULL) {
m_Info[i].IciA[0].nPrevTy = m_Info[j].IciA[0].nPrevTy ;
m_Info[i].IciA[ki].nPrevTy = ICCT_NULL ;
if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL)
m_Info[i].IciB[ki].nPrevTy = m_Info[j].IciB[kj].nPrevTy ;
if ( m_Info[i].IciB[ki].nNextTy == ICCT_NULL)
m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[kj].nNextTy ;
// cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente)
EraseOtherInfo( i, j) ;
}
@@ -410,7 +445,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
EraseOtherInfo( i, j) ;
EraseCurrentInfo( i, j) ;
}
// caso DET-NULL -> NULL-DET per seconda curva
// caso DET-(NULL) -> (NULL)-DET per seconda curva
else if ( m_Info[j].IciB[kj].nPrevTy != ICCT_NULL && m_Info[j].IciB[kj].nNextTy == ICCT_NULL &&
m_Info[i].IciB[ki].nPrevTy == ICCT_NULL && m_Info[i].IciB[ki].nNextTy != ICCT_NULL) {
// per la seconda curva tengo i determinati
@@ -418,25 +453,25 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ;
// se overlap equiverso
if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) {
// per la prima curva ogni sottotipo è il duale di quello della seconda
// per la prima curva ogni sottotipo è il duale di quello della seconda
m_Info[i].IciA[ki].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ;
m_Info[i].IciA[ki].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ;
}
// se altrimenti overlap controverso
else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) {
// per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata
// per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata
m_Info[i].IciA[ki].nPrevTy = m_Info[i].IciB[ki].nNextTy ;
m_Info[i].IciA[ki].nNextTy = m_Info[i].IciB[ki].nPrevTy ;
}
// se overlap equiverso
if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) {
// per la prima curva ogni sottotipo è il duale di quello della seconda
// per la prima curva ogni sottotipo è il duale di quello della seconda
m_Info[j].IciA[kj].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ;
m_Info[j].IciA[kj].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ;
}
// se altrimenti overlap controverso
else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) {
// per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata
// per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata
m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciB[ki].nNextTy ;
m_Info[j].IciA[kj].nNextTy = m_Info[i].IciB[ki].nPrevTy ;
}
@@ -454,7 +489,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
EraseCurrentInfo( i, j) ;
}
}
// caso NULL-DET -> DET-NULL per seconda curva (possibile su inizio/fine di curva chiusa)
// caso (NULL)-DET -> DET-(NULL) per seconda curva (possibile su inizio/fine di curva chiusa)
else if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL && m_Info[j].IciB[kj].nNextTy != ICCT_NULL &&
m_Info[i].IciB[ki].nPrevTy != ICCT_NULL && m_Info[i].IciB[ki].nNextTy == ICCT_NULL) {
// per la seconda curva tengo i determinati
@@ -462,25 +497,25 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
m_Info[j].IciB[kj].nPrevTy = m_Info[i].IciB[ki].nPrevTy ;
// se overlap equiverso
if ( m_Info[i].bOverlap && m_Info[i].bCBOverEq) {
// per la prima curva ogni sottotipo è il duale di quello della seconda
// per la prima curva ogni sottotipo è il duale di quello della seconda
m_Info[i].IciA[ki].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ;
m_Info[i].IciA[ki].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ;
}
// se altrimenti overlap controverso
else if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) {
// per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata
// per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata
m_Info[i].IciA[ki].nPrevTy = m_Info[i].IciB[ki].nNextTy ;
m_Info[i].IciA[ki].nNextTy = m_Info[i].IciB[ki].nPrevTy ;
}
// se overlap equiverso
if ( m_Info[j].bOverlap && m_Info[j].bCBOverEq) {
// per la prima curva ogni sottotipo è il duale di quello della seconda
// per la prima curva ogni sottotipo è il duale di quello della seconda
m_Info[j].IciA[kj].nPrevTy = GetDualIcct( m_Info[i].IciB[ki].nPrevTy) ;
m_Info[j].IciA[kj].nNextTy = GetDualIcct( m_Info[i].IciB[ki].nNextTy) ;
}
// se altrimenti overlap controverso
else if ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq) {
// per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata
// per la prima curva ogni sottotipo è come quello della seconda ma in posizione scambiata
m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciB[ki].nNextTy ;
m_Info[j].IciA[kj].nNextTy = m_Info[i].IciB[ki].nPrevTy ;
}
@@ -518,17 +553,21 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
}
// caso NULL-NULL per corrente di seconda curva
else if ( m_Info[i].IciB[ki].nPrevTy == ICCT_NULL && m_Info[i].IciB[ki].nNextTy == ICCT_NULL) {
m_Info[j].IciB[kj].nNextTy = m_Info[i].IciB[ki].nNextTy ;
if ( m_Info[i].IciA[ki].dU > m_Info[j].IciA[kj].dU + EPS_PARAM)
m_Info[j].IciB[kj].nNextTy = ICCT_NULL ;
if ( m_Info[j].IciA[kj].nNextTy == ICCT_NULL)
m_Info[j].IciA[kj].nNextTy = m_Info[i].IciA[ki].nNextTy ;
if ( m_Info[j].IciA[kj].nPrevTy == ICCT_NULL)
m_Info[j].IciA[kj].nPrevTy = m_Info[i].IciA[ki].nPrevTy ;
// cancello l'intersezione corrente (non aggiunge nulla rispetto alla precedente)
EraseCurrentInfo( i, j) ;
}
// caso NULL-NULL per precedente di seconda curva
else if ( m_Info[j].IciB[kj].nPrevTy == ICCT_NULL && m_Info[j].IciB[kj].nNextTy == ICCT_NULL) {
m_Info[i].IciB[0].nPrevTy = m_Info[j].IciB[0].nPrevTy ;
if ( m_Info[j].IciA[0].dU < m_Info[i].IciA[0].dU - EPS_PARAM)
m_Info[i].IciA[0].nPrevTy = m_Info[j].IciA[0].nPrevTy ;
m_Info[i].IciB[ki].nPrevTy = ICCT_NULL ;
if ( m_Info[i].IciA[ki].nPrevTy == ICCT_NULL)
m_Info[i].IciA[ki].nPrevTy = m_Info[j].IciA[kj].nPrevTy ;
if ( m_Info[i].IciA[ki].nNextTy == ICCT_NULL)
m_Info[i].IciA[ki].nNextTy = m_Info[j].IciA[kj].nNextTy ;
// cancello l'intersezione precedente (non aggiunge nulla rispetto alla corrente)
EraseOtherInfo( i, j) ;
}
@@ -537,16 +576,16 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
// ripristino ordinamento su prima curva
stable_sort( m_Info.begin(), m_Info.end(), SortGreaterA) ;
// verifico se sono rimaste delle intersezioni di tipo non definito sulla curva A e cerco di risolverle per continuità
// verifico se sono rimaste delle intersezioni di tipo non definito sulla curva A e cerco di risolverle per continuità
for ( int i = 0 ; i < m_nNumInters ; ++ i) {
// se il tipo di accostamento per la curva A non è definito
// se il tipo di accostamento per la curva A non è definito
if ( m_Info[i].IciA[0].nPrevTy == ICCT_NULL) {
if ( i > 0 || ( bCrvAClosed && ! bAutoInters)) {
int j = ( i > 0 ? i - 1 : m_nNumInters - 1) ;
m_Info[i].IciA[0].nPrevTy = ( m_Info[j].bOverlap ? m_Info[j].IciA[1].nNextTy : m_Info[j].IciA[0].nNextTy) ;
}
}
// se il tipo di allontanamento per la curva A non è definito
// se il tipo di allontanamento per la curva A non è definito
int ki = ( m_Info[i].bOverlap ? 1 : 0) ;
if ( m_Info[i].IciA[ki].nNextTy == ICCT_NULL) {
if ( i < m_nNumInters - 1 || ( bCrvAClosed && ! bAutoInters)) {
@@ -556,21 +595,22 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
}
}
// verifico se sono rimaste delle intersezioni di tipo non definito sulla curva B e cerco di risolverle per continuità
// verifico se sono rimaste delle intersezioni di tipo non definito sulla curva B e cerco di risolverle per continuità
stable_sort( m_Info.begin(), m_Info.end(), SortGreaterB) ;
for ( int i = 0 ; i < m_nNumInters ; ++ i) {
// se il tipo di accostamento per la curva B non è definito
// se il tipo di accostamento per la curva B non è definito
if ( m_Info[i].IciB[0].nPrevTy == ICCT_NULL) {
if ( i > 0 || ( bCrvBClosed && ! bAutoInters)) {
int j = ( i > 0 ? i - 1 : m_nNumInters - 1) ;
m_Info[i].IciB[0].nPrevTy = ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq ? m_Info[j].IciB[1].nNextTy : m_Info[j].IciB[0].nNextTy) ;
m_Info[i].IciB[0].nPrevTy = ( m_Info[j].bOverlap ? m_Info[j].IciB[1].nNextTy : m_Info[j].IciB[0].nNextTy) ;
}
}
// se il tipo di allontanamento per la curva B non è definito
if ( m_Info[i].IciB[0].nNextTy == ICCT_NULL) {
// se il tipo di allontanamento per la curva B non è definito
int ki = ( m_Info[i].bOverlap ? 1 : 0) ;
if ( m_Info[i].IciB[ki].nNextTy == ICCT_NULL) {
if ( i < m_nNumInters - 1 || ( bCrvBClosed && ! bAutoInters)) {
int j = ( i < m_nNumInters - 1 ? i + 1 : 0) ;
m_Info[i].IciB[0].nNextTy = ( m_Info[j].bOverlap && ! m_Info[j].bCBOverEq ? m_Info[j].IciB[1].nPrevTy : m_Info[j].IciB[0].nPrevTy) ;
m_Info[i].IciB[ki].nNextTy = m_Info[j].IciB[0].nPrevTy ;
}
}
}
@@ -581,7 +621,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
for ( int i = 0 ; i < m_nNumInters ; ++ i) {
// in assenza di overlap
if ( ! m_Info[i].bOverlap) {
// se il tipo di accostamento per la curva A non è definito
// se il tipo di accostamento per la curva A non è definito
if ( m_Info[i].IciA[0].nPrevTy == ICCT_NULL) {
// devo studiare un intorno dell'intersezione
int nType ;
@@ -590,7 +630,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
// aggiorno il tipo di accostamento della curva A alla curva B
m_Info[i].IciA[0].nPrevTy = nType ;
}
// se il tipo di accostamento per la curva B non è definito
// se il tipo di accostamento per la curva B non è definito
if ( m_Info[i].IciB[0].nPrevTy == ICCT_NULL) {
// devo studiare un intorno dell'intersezione
int nType ;
@@ -599,7 +639,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
// aggiorno il tipo di accostamento della curva B alla curva A
m_Info[i].IciB[0].nPrevTy = nType ;
}
// se il tipo di allontanamento per la curva A non è definito
// se il tipo di allontanamento per la curva A non è definito
if ( m_Info[i].IciA[0].nNextTy == ICCT_NULL) {
// devo studiare un intorno dell'intersezione
int nType ;
@@ -608,7 +648,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
// aggiorno il tipo di allontanamento della curva A dalla curva B
m_Info[i].IciA[0].nNextTy = nType ;
}
// se il tipo di allontanamento per la curva B non è definito
// se il tipo di allontanamento per la curva B non è definito
if ( m_Info[i].IciB[0].nNextTy == ICCT_NULL) {
// devo studiare un intorno dell'intersezione
int nType ;
@@ -620,66 +660,68 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
}
// in presenza di overlap
else {
// se il tipo di accostamento è non definito per la curva A
// se il tipo di accostamento è non definito per la curva A
if ( m_Info[i].IciA[0].nPrevTy == ICCT_NULL) {
// se autointersezione con spike
double dDeltaU = abs( m_Info[i].IciA[0].dU - m_Info[i].IciB[0].dU) ;
if ( bAutoInters && ( dDeltaU < EPS_PARAM || ( bCrvAClosed && abs( dDeltaU - dCrvASpan) < EPS_PARAM))) {
// è punta di spike
int nType = ICCT_SPK ;
// aggiorno il tipo di allontanamento della curva A dalla curva B
// devo studiare un intorno dell'intersezione
int nType ;
if ( CalcATypeFromDisk( CCompoA, m_Info[i].IciA[0].dU, ICurve::FROM_MINUS,
CCompoB, m_Info[i].IciB[0].dU, nType)) {
// aggiorno il tipo di accostamento della curva A alla curva B
m_Info[i].IciA[0].nPrevTy = nType ;
// aggiorno anche il corrispondente tipo sulla curva B
// aggiorno anche il corrispondente tipo sulla curva B
if ( m_Info[i].bCBOverEq)
m_Info[i].IciB[0].nPrevTy = GetDualIcct( nType) ;
else
m_Info[i].IciB[0].nNextTy = nType ;
}
// caso standard
else {
// devo studiare un intorno dell'intersezione
int nType ;
if ( CalcATypeFromDisk( CCompoA, m_Info[i].IciA[0].dU, ICurve::FROM_MINUS,
CCompoB, m_Info[i].IciB[0].dU, nType)) {
// aggiorno il tipo di accostamento della curva A alla curva B
m_Info[i].IciA[0].nPrevTy = nType ;
// aggiorno anche il corrispondente tipo sulla curva B
if ( m_Info[i].bCBOverEq)
m_Info[i].IciB[0].nPrevTy = GetDualIcct( nType) ;
else
m_Info[i].IciB[0].nNextTy = nType ;
}
}
}
// se il tipo di allontanamento è non definito per la curva A
// se il tipo di allontanamento è non definito per la curva A
if ( m_Info[i].IciA[1].nNextTy == ICCT_NULL) {
// se autointersezione con spike
double dDeltaU = abs( m_Info[i].IciA[1].dU - m_Info[i].IciB[1].dU) ;
if ( bAutoInters && ( dDeltaU < EPS_PARAM || ( bCrvAClosed && abs( dDeltaU - dCrvASpan) < EPS_PARAM))) {
// è punta di spike
int nType = ICCT_SPK ;
// aggiorno il tipo di allontanamento della curva A dalla curva B
// devo studiare un intorno dell'intersezione
int nType ;
if ( CalcATypeFromDisk( CCompoA, m_Info[i].IciA[1].dU, ICurve::FROM_PLUS,
CCompoB, m_Info[i].IciB[1].dU, nType)) {
// aggiorno il tipo di allontanamento della curva A dalla curva B
m_Info[i].IciA[1].nNextTy = nType ;
// aggiorno anche il corrispondente tipo sulla curva B
// aggiorno anche il corrispondente tipo sulla curva B
if ( m_Info[i].bCBOverEq)
m_Info[i].IciB[1].nNextTy = GetDualIcct( nType) ;
else
m_Info[i].IciB[1].nPrevTy = nType ;
}
// caso standard
else {
// devo studiare un intorno dell'intersezione
int nType ;
if ( CalcATypeFromDisk( CCompoA, m_Info[i].IciA[1].dU, ICurve::FROM_PLUS,
CCompoB, m_Info[i].IciB[1].dU, nType)) {
// aggiorno il tipo di allontanamento della curva A dalla curva B
m_Info[i].IciA[1].nNextTy = nType ;
// aggiorno anche il corrispondente tipo sulla curva B
if ( m_Info[i].bCBOverEq)
m_Info[i].IciB[1].nNextTy = GetDualIcct( nType) ;
else
m_Info[i].IciB[1].nPrevTy = nType ;
}
}
}
}
if ( bAutoInters) {
// controllo l'eventuale presenza di spike
for ( int i = 0 ; i < m_nNumInters ; ++ i) {
if ( m_Info[i].bOverlap && ! m_Info[i].bCBOverEq) {
// se secondo tratto dello spike
double dDeltaU = abs( m_Info[i].IciA[0].dU - m_Info[i].IciB[0].dU) ;
if ( dDeltaU < EPS_PARAM || ( bCrvAClosed && abs( dDeltaU - dCrvASpan) < EPS_PARAM)) {
// è punta di spike
int nType = ICCT_SPK ;
// aggiorno il tipo di allontanamento della curva A dalla curva B
m_Info[i].IciA[0].nPrevTy = nType ;
// aggiorno anche il corrispondente tipo sulla curva B
if ( m_Info[i].bCBOverEq)
m_Info[i].IciB[0].nPrevTy = GetDualIcct( nType) ;
else
m_Info[i].IciB[0].nNextTy = nType ;
}
// se primo tratto dello spike
dDeltaU = abs( m_Info[i].IciA[1].dU - m_Info[i].IciB[1].dU) ;
if ( dDeltaU < EPS_PARAM || ( bCrvAClosed && abs( dDeltaU - dCrvASpan) < EPS_PARAM)) {
// è punta di spike
int nType = ICCT_SPK ;
// aggiorno il tipo di allontanamento della curva A dalla curva B
m_Info[i].IciA[1].nNextTy = nType ;
// aggiorno anche il corrispondente tipo sulla curva B
if ( m_Info[i].bCBOverEq)
m_Info[i].IciB[1].nNextTy = GetDualIcct( nType) ;
else
m_Info[i].IciB[1].nPrevTy = nType ;
}
}
}
@@ -693,10 +735,10 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
// se prima curva aperta, salto alla prossima
if ( ! CCompoA.IsClosed())
continue ;
// è chiusa quindi prendo l'ultima
// è chiusa quindi prendo l'ultima
j = m_nNumInters - 1 ;
}
// se i due indici coincidono, c'è una sola intersezione e posso uscire
// se i due indici coincidono, c'è una sola intersezione e posso uscire
if ( i == j)
break ;
// assegno sottoindici (considero solo intersezioni overlap)
@@ -724,7 +766,7 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
}
}
// se è rimasta una sola intersezione con overlap anche ad entrambi gli estremi e le curve sono chiuse
// se è rimasta una sola intersezione con overlap anche ad entrambi gli estremi e le curve sono chiuse
if ( m_nNumInters == 1 && CCompoA.IsClosed() && CCompoB.IsClosed() &&
m_Info[0].IciA[0].nPrevTy == ICCT_ON && m_Info[0].IciA[1].nNextTy == ICCT_ON &&
GetCrvBDirANext( m_Info[0]) == ICCT_ON && GetCrvBDirAPrev( m_Info[0]) == ICCT_ON) {
@@ -738,10 +780,103 @@ IntersCrvCompoCrvCompo::IntersCrvCompoCrvCompo( const ICurveComposite& CCompoA,
m_Info[0].IciB[1].dU = ( m_Info[0].bCBOverEq ? dEnd : dStart) ;
}
// verifico se una curva ha tutte le info e queste info sono coerenti
if ( m_nNumInters > 1) {
bool bCoherent = true ;
INTVECTOR vIncoherenceWithPrev ;
// salvo eventuali incoerenze col precedente
for ( int i = bCrvAClosed ? 0 : 1 ; i < m_nNumInters ; ++i) {
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
int kj = m_Info[j].bOverlap ? 1 : 0 ;
if ( m_Info[j].IciA[kj].nNextTy != m_Info[i].IciA[0].nPrevTy &&
m_Info[j].IciA[kj].nNextTy != ICCT_SPK && m_Info[i].IciA[0].nPrevTy != ICCT_SPK) {
vIncoherenceWithPrev.push_back( i) ;
bCoherent = false ;
}
}
// incoerenze sulla curva A
if ( ! bCoherent) {
for ( int i : vIncoherenceWithPrev) {
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
int kj = m_Info[j].bOverlap ? 1 : 0 ;
int nType = 0 ;
CalcSide( m_Info[j], m_Info[i], &CCompoA, &CCompoB, true, nType) ;
if ( nType == MDS_LEFT)
nType = ICCT_IN ;
else if ( nType == MDS_RIGHT)
nType = ICCT_OUT ;
m_Info[i].IciA[0].nPrevTy = nType ;
m_Info[j].IciA[kj].nNextTy = nType ;
}
}
stable_sort( m_Info.begin(), m_Info.end(), SortGreaterB) ;
bCoherent = true ;
vIncoherenceWithPrev.clear() ;
// salvo eventuali incoerenze col precedente
for ( int i = bCrvBClosed ? 0 : 1 ; i < m_nNumInters ; ++i) {
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
int kj = m_Info[j].bOverlap ? 1 : 0 ;
if ( m_Info[j].IciB[kj].nNextTy != m_Info[i].IciB[0].nPrevTy &&
m_Info[j].IciB[kj].nNextTy != ICCT_SPK && m_Info[i].IciB[0].nPrevTy != ICCT_SPK) {
vIncoherenceWithPrev.push_back( i) ;
bCoherent = false ;
}
}
// incoerenze sulla curva B
if ( ! bCoherent) {
for ( int i : vIncoherenceWithPrev) {
int j = i == 0 ? m_nNumInters - 1 : i - 1 ;
int kj = m_Info[j].bOverlap ? 1 : 0 ;
int nType = 0 ;
CalcSide( m_Info[j], m_Info[i], &CCompoB, &CCompoA, false, nType) ;
if ( nType == MDS_LEFT)
nType = ICCT_IN ;
else if ( nType == MDS_RIGHT)
nType = ICCT_OUT ;
m_Info[i].IciB[0].nPrevTy = nType ;
m_Info[j].IciB[kj].nNextTy = nType ;
}
}
}
else {
// posso completare A guardando B e viceversa
}
stable_sort( m_Info.begin(), m_Info.end(), SortGreaterA) ;
// verifiche su intersezioni in zone non-manifold
OrderNonManifoldInters( m_Info, CCompoA, CCompoB) ;
}
//----------------------------------------------------------------------------
static bool
CalcSide( const IntCrvCrvInfo& Icci1, const IntCrvCrvInfo& Icci2,const ICurve* pThisCrv, const ICurve* pOtherCrv, bool bCrvAOrB, int& nType)
{
// calcolo tra l'intersezione 1 e 2 se la curva sta dentro o fuori
int kj = Icci1.bOverlap ? 1 : 0 ;
double dU = 0 ;
if ( bCrvAOrB) {
// se precedente minore del successivo faccio la media
if ( Icci1.IciA[kj].dU < Icci2.IciA[0].dU)
dU = (Icci2.IciA[0].dU + Icci1.IciA[kj].dU) / 2 ;
// altrimenti guardo tra lo start e il successivo
else
dU = (Icci2.IciA[0].dU + 0.) / 2 ;
}
else {
// se precedente minore del successivo faccio la media
if ( Icci1.IciB[kj].dU < Icci2.IciB[0].dU)
dU = (Icci2.IciB[0].dU + Icci1.IciB[kj].dU) / 2 ;
// altrimenti guardi tra lo start e il successivo
else
dU = (Icci2.IciB[0].dU + 0.) / 2 ;
}
Point3d ptTest ; pThisCrv->GetPointD1D2( dU, ICurve::FROM_MINUS, ptTest) ;
DistPointCurve dpc( ptTest, *pOtherCrv) ;
dpc.GetSideAtMinDistPoint( 0, Z_AX, nType) ;
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCrvCompoCrvCompo::IntersSimpleCurves( const ICurve& CurveA, int nA, const ICurve& CurveB, int nB,
@@ -879,7 +1014,7 @@ SortGreaterB( const IntCrvCrvInfo& aInfo1, const IntCrvCrvInfo& aInfo2)
bool
OrderNonManifoldInters( ICCIVECTOR& Info, const ICurve& CurveA, const ICurve& CurveB)
{
// questi controlli sono validi solo se la curva B è chiusa
// questi controlli sono validi solo se la curva B è chiusa
if ( ! CurveB.IsClosed())
return false ;
@@ -908,7 +1043,7 @@ OrderNonManifoldInters( ICCIVECTOR& Info, const ICurve& CurveA, const ICurve& Cu
// se prima curva aperta, salto alla prossima
if ( ! CurveA.IsClosed())
continue ;
// è chiusa quindi prendo l'ultima
// è chiusa quindi prendo l'ultima
j = nNumInters - 1 ;
}
// se i due indici coincidono, salto
@@ -998,7 +1133,7 @@ MediaParamPoints( IntCrvInfo& Ici1, IntCrvInfo& Ici2, const ICurveComposite& crv
//Point3d ptMed ;
//if ( ! crvCompo.GetPointD1D2( dUmed, ICurve::FROM_MINUS, ptMed))
// return ;
// verifico che non sia più lontano dei punti originali dal loro medio
// verifico che non sia più lontano dei punti originali dal loro medio
//if ( SqDist( Ici1.ptI, ptMed) > dSqDist / 4)
// return ;
// medio i parametri
@@ -1012,13 +1147,13 @@ MediaParamPoints( IntCrvInfo& Ici1, IntCrvInfo& Ici2, const ICurveComposite& crv
static int
GetCrvBDirAPrev( IntCrvCrvInfo& Icci)
{
// non è overlap, è il prev del primo punto
// non è overlap, è il prev del primo punto
if ( ! Icci.bOverlap)
return Icci.IciB[0].nPrevTy ;
// è overlap equiverso, è il prev del primo punto
// è overlap equiverso, è il prev del primo punto
if ( Icci.bCBOverEq)
return Icci.IciB[0].nPrevTy ;
// è overlap controverso, è il next del primo punto
// è overlap controverso, è il next del primo punto
return Icci.IciB[0].nNextTy ;
}
@@ -1028,13 +1163,13 @@ GetCrvBDirAPrev( IntCrvCrvInfo& Icci)
static int
GetCrvBDirANext( IntCrvCrvInfo& Icci)
{
// non è overlap, è il next del primo punto
// non è overlap, è il next del primo punto
if ( ! Icci.bOverlap)
return Icci.IciB[0].nNextTy ;
// è overlap equiverso, è il next del secondo punto
// è overlap equiverso, è il next del secondo punto
if ( Icci.bCBOverEq)
return Icci.IciB[1].nNextTy ;
// è overlap controverso, è il prev del secondo punto
// è overlap controverso, è il prev del secondo punto
return Icci.IciB[1].nPrevTy ;
}
@@ -1078,7 +1213,7 @@ CalcATypeFromDisk( const ICurve& CurveA, double dUA, ICurve::Side nSideA,
return false ;
if ( dAngBpDeg < 0)
dAngBpDeg += ANG_FULL ;
// se l'angolo di DirA è compreso tra DirBn e DirBp (muovendosi in senso CCW) allora è IN, altrimenti OUT
// se l'angolo di DirA è compreso tra DirBn e DirBp (muovendosi in senso CCW) allora è IN, altrimenti OUT
if ( dAngADeg > 0 && dAngADeg < dAngBpDeg)
nType = ICCT_IN ;
else
@@ -1151,12 +1286,12 @@ CalcATypeFromDisk2( const ICurve& CurveA, double dUA, ICurve::Side nSideA,
// li ordino in senso crescente
if ( dAngB1pDeg > dAngB2pDeg)
swap( dAngB1pDeg, dAngB2pDeg) ;
// se non ci sono variazioni angolari significative, non posso decidere alcunché
// se non ci sono variazioni angolari significative, non posso decidere alcunché
const double MIN_DEV_ANG = 2 ;
if ( abs( DiffAngle( dAngB1pDeg + ANG_STRAIGHT, 0)) < MIN_DEV_ANG &&
abs( DiffAngle( dAngB2pDeg + ANG_STRAIGHT, dAngB2nDeg)) < MIN_DEV_ANG)
return false ;
// IN è tra 0 e dAngB1pDeg e tra dAngB2nDeg e dAngB2pDeg
// IN è tra 0 e dAngB1pDeg e tra dAngB2nDeg e dAngB2pDeg
if ( ( dAngADeg > 0 && dAngADeg < dAngB1pDeg) ||
( dAngADeg > dAngB2nDeg && dAngADeg < dAngB2pDeg))
nType = ICCT_IN ;
+81 -15
View File
@@ -47,7 +47,7 @@ IntersCurveCurve::IntersCurveCurve( const ICurve& CurveA, const ICurve& CurveB,
// ciclo sulle curve per verificare se da approssimare
for ( int i = 0 ; i < 2 ; ++ i) {
// se curva è arco da approssimare oppure è curva di Bezier
// se curva è arco da approssimare oppure è curva di Bezier
if ( ( m_pCurve[i]->GetType() == CRV_ARC && IsArcToApprox( *m_pCurve[i])) ||
m_pCurve[i]->GetType() == CRV_BEZIER) {
// approssimo con rette
@@ -127,7 +127,7 @@ IntersCurveCurve::IsArcToApprox( const ICurve& Curve)
const CurveArc* pArc = GetBasicCurveArc( &Curve) ;
if ( pArc == nullptr)
return false ;
// verifico se non è nel piano XY o ha più di un giro al centro
// verifico se non è nel piano XY o ha più di un giro al centro
return ( ( ! pArc->GetNormVersor().IsZplus() && ! pArc->GetNormVersor().IsZminus()) ||
abs( pArc->GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) ;
}
@@ -252,10 +252,10 @@ IntersCurveCurve::CrvCompoCrvCompoCalculate( const ICurve& CurveA, const ICurve&
bool
IntersCurveCurve::AdjustIntersParams( bool bAdjCrvA, bool bAdjCrvB)
{
// se non ci sono intersezioni, non va fatto alcunché
// se non ci sono intersezioni, non va fatto alcunché
if ( m_Info.empty())
return true ;
// se le curve originali non sono state approssimate, non va fatto alcunché
// se le curve originali non sono state approssimate, non va fatto alcunché
if ( ! bAdjCrvA && ! bAdjCrvB)
return true ;
// procedo ad aggiustare
@@ -291,6 +291,24 @@ IntersCurveCurve::GetIntersCount( void)
return m_nIntersCount ;
}
//----------------------------------------------------------------------------
int
IntersCurveCurve::GetInters3DCount( void)
{
int nCount = 0 ;
for ( int i = 0 ; i < m_nIntersCount ; ++i) {
if ( ! m_Info[i].bOverlap || ( m_Info[i].bOverlap && m_Info[i].bCBOverEq)) {
if ( abs( m_Info[i].IciA[0].ptI.z - m_Info[i].IciB[0].ptI.z) < EPS_SMALL)
++nCount ;
}
else {
if ( abs( m_Info[i].IciA[0].ptI.z - m_Info[i].IciB[1].ptI.z) < EPS_SMALL)
++nCount ;
}
}
return nCount ;
}
//----------------------------------------------------------------------------
int
IntersCurveCurve::GetCrossIntersCount( void)
@@ -340,6 +358,30 @@ IntersCurveCurve::GetIntCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo)
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetInt3DCrvCrvInfo( int nInd, IntCrvCrvInfo& aInfo)
{
if ( nInd < 0 || nInd >= GetInters3DCount())
return false ;
int nCount = - 1 ;
for ( int i = 0 ; i < m_nIntersCount ; ++i) {
if ( ! m_Info[i].bOverlap || ( m_Info[i].bOverlap && m_Info[i].bCBOverEq)) {
if ( abs( m_Info[i].IciA[0].ptI.z - m_Info[i].IciB[0].ptI.z) < EPS_SMALL)
++nCount ;
}
else {
if ( abs( m_Info[i].IciA[0].ptI.z - m_Info[i].IciB[1].ptI.z) < EPS_SMALL)
++nCount ;
}
if ( nCount == nInd) {
aInfo = m_Info[nInd] ;
return true ;
}
}
return false ;
}
//----------------------------------------------------------------------------
bool
IntersCurveCurve::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d& ptI)
@@ -347,11 +389,11 @@ IntersCurveCurve::GetIntersPointNearTo( int nCrv, const Point3d& ptNear, Point3d
if ( m_nIntersCount == 0 || nCrv < 0 || nCrv > 1)
return false ;
// ricerca del punto più vicino tra le intersezioni singole
// ricerca del punto più vicino tra le intersezioni singole
bool bFound = false ;
double dMinSqDist = SQ_INFINITO ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i) {
// se è un'intersezione singola
// se è un'intersezione singola
if ( ! m_Info[i].bOverlap) {
// faccio la verifica sul punto
Point3d ptP = ( nCrv == 0 ? m_Info[i].IciA[0].ptI : m_Info[i].IciB[0].ptI) ;
@@ -416,7 +458,7 @@ IntersCurveCurve::GetCurveClassification( int nCrv, double dLenMin, CRVCVECTOR&
// se esiste almeno una intersezione
if ( m_nIntersCount >= 1)
return CalcCurveClassification( m_pCurve[0], m_Info, dLenMin, ccClass) ;
// altrimenti la curva è completamente interna oppure completamente esterna
// altrimenti la curva è completamente interna oppure completamente esterna
else
return CalcCurveInOrOut( m_pCurve[0], m_pCurve[1], ccClass) ;
}
@@ -433,7 +475,7 @@ IntersCurveCurve::GetCurveClassification( int nCrv, double dLenMin, CRVCVECTOR&
// se esiste almeno una intersezione
if ( m_nIntersCount >= 1)
return CalcCurveClassification( m_pCurve[1], InfoTmp, dLenMin, ccClass) ;
// altrimenti la curva è completamente interna oppure completamente esterna
// altrimenti la curva è completamente interna oppure completamente esterna
else
return CalcCurveInOrOut( m_pCurve[1], m_pCurve[0], ccClass) ;
}
@@ -498,7 +540,7 @@ IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTO
double dU2 = Info[j].IciA[1].dU ;
if ( dU2 < dU1 && pCurve->IsClosed())
dU2 += dEndPar ;
// se cade nell'intervallo è da saltare
// se cade nell'intervallo è da saltare
if ( Info[i].IciA[0].dU >= dU1 && Info[i].IciA[0].dU <= dU2) {
bToSkip = true ;
break ;
@@ -517,7 +559,7 @@ IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTO
double dCurrPar = dStartPar ;
double dCurrLen = 0 ;
double dEndLen ; pCurve->GetLength( dEndLen) ;
// se è chiusa, recupero come finisce
// se è chiusa, recupero come finisce
if ( pCurve->IsClosed()) {
if ( ! InfoCorr[nNumInters-1].bOverlap)
nLastTy = InfoCorr[nNumInters-1].IciA[0].nNextTy ;
@@ -535,7 +577,7 @@ IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTO
}
// costruisco il vettore delle classificazioni
for ( int i = 0 ; i < nNumInters ; ++ i) {
// se è definito un tratto precedente
// se è definito un tratto precedente
double dLenU ; pCurve->GetLengthAtParam( InfoCorr[i].IciA[0].dU, dLenU) ;
if ( InfoCorr[i].IciA[0].dU > dCurrPar + EPS_PARAM && dLenU - dCurrLen > dLenMin) {
// verifico che la definizione sul tratto sia omogenea e valida
@@ -557,7 +599,7 @@ IntersCurveCurve::CalcCurveClassification( const ICurve* pCurve, const ICCIVECTO
// altrimenti, salvo il tipo
else
nLastTy = InfoCorr[i].IciA[0].nNextTy ;
// se è definito un tratto in sovrapposizione
// se è definito un tratto in sovrapposizione
if ( InfoCorr[i].bOverlap) {
// assegno i dati
CrvClass segClass ;
@@ -597,7 +639,7 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB
double dStartParB, dEndParB ;
if ( ! pCurveB->GetDomain( dStartParB, dEndParB))
return false ;
// se almeno un punto di ciascuna curva è esterno al box dell'altra, sono sicuramente esterne
// se almeno un punto di ciascuna curva è esterno al box dell'altra, sono sicuramente esterne
BBox3d boxCrvA, boxCrvB ;
if ( ! pCurveA->GetLocalBBox( boxCrvA) ||
! pCurveB->GetLocalBBox( boxCrvB))
@@ -640,13 +682,37 @@ IntersCurveCurve::CalcCurveInOrOut( const ICurve* pCurveA, const ICurve* pCurveB
IntersCurveCurve iCC( clLine, *pCurveB) ;
// dichiaro la classe della curva per default
int nClass = CRVC_OUT ;
// se c'è almeno una intersezione
// se c'è almeno una intersezione
if ( iCC.GetIntersCount() > 0) {
// se quanto precede la prima intersezione è interno, allora la curva è interna
// se quanto precede la prima intersezione è interno, allora la curva è interna
IntCrvCrvInfo aInfo ;
iCC.GetIntCrvCrvInfo( 0, aInfo) ;
if ( aInfo.IciA[0].nPrevTy == ICCT_IN)
nClass = CRVC_IN ;
else if ( aInfo.IciA[0].nPrevTy == ICCT_OUT)
nClass = CRVC_OUT ;
else if ( aInfo.IciA[0].nPrevTy == ICCT_NULL) {
// se il primo punto scelto non va bene allora ne cerco uno che mi dia informazioni sull'essere interno o esterno
CurveLine clLine ;
Point3d ptNewChoice ; pCurveA->GetPointD1D2( 0.25, ICurve::FROM_MINUS, ptNewChoice) ;
if ( ! clLine.SetPDL( ptNewChoice, 0, dLen))
return false ;
// calcolo l'intersezione
IntersCurveCurve iCC( clLine, *pCurveB) ;
if ( iCC.GetIntersCount() > 0) {
// se quanto precede la prima intersezione è interno, allora la curva è interna
IntCrvCrvInfo aInfo ;
iCC.GetIntCrvCrvInfo( 0, aInfo) ;
if ( aInfo.IciA[0].nPrevTy == ICCT_IN)
nClass = CRVC_IN ;
else if ( aInfo.IciA[0].nPrevTy == ICCT_OUT)
nClass = CRVC_OUT ;
else
return false ; // se arrivo qui potrei ritentare la ricerca
}
else
return false ;
}
}
// altrimenti sono esterni tra loro
else {
+449
View File
@@ -0,0 +1,449 @@
//----------------------------------------------------------------------------
// EgalTech 2025
//----------------------------------------------------------------------------
// File : IntersCurvePlane.cpp Data : 07.11.25 Versione : 2.7k1
// Contenuto : Implementazione della classe intersezione curva-piano.
//
//
//
// Modifiche : 07.11.25 DB Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "GeoConst.h"
#include "CurveLine.h"
#include "CurveComposite.h"
#include "IntersLineLine.h"
#include "IntersLineArc.h"
#include "IntersArcArc.h"
#include "IntersCrvCompoCrvCompo.h"
#include "/EgtDev/Include/EGkIntersCurves.h"
#include "/EgtDev/Include/EGkIntersLinePlane.h"
#include "/EgtDev/Include/EGkIntersCurvePlane.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkPlane3d.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include <algorithm>
using namespace std ;
//----------------------------------------------------------------------------
IntersCurvePlane::IntersCurvePlane( const ICurve& Curve, const Point3d& ptOrig, const Vector3d& vtN)
{
// Le intersezioni sono calcolate nel piano XY locale.
// Il flag bAreSegments vale solo per intersezione tra due linee e riguarda entrambe.
// inizializzazioni
m_nIntersCount = 0 ;
m_pCurve = &Curve ;
m_plPlane.Set( ptOrig, vtN) ;
// puntatore alla curva usata nei calcoli (originali o temporanee)
const ICurve* pCalcCrv ;
// per eventuale esplosione temporanea delle curve
PtrOwner<ICurve> pTmpCrv ;
// se curva è arco da approssimare oppure è curva di Bezier
if ( m_pCurve->GetType() == CRV_ARC || m_pCurve->GetType() == CRV_BEZIER || m_pCurve->GetType() == CRV_COMPO) {
// approssimo con rette
PolyLine PL ;
if ( ! m_pCurve->ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL))
return ;
pTmpCrv.Set( CreateBasicCurveComposite()) ;
if ( IsNull( pTmpCrv))
return ;
if ( ! GetBasicCurveComposite( pTmpCrv)->FromPolyLine( PL))
return ;
pCalcCrv = pTmpCrv ;
}
else
pCalcCrv = m_pCurve ;
m_Info.clear() ;
if ( pCalcCrv->GetType() == CRV_LINE) {
CalcIntersLinePlane( m_plPlane, *pCalcCrv) ;
}
else if ( pCalcCrv->GetType() == CRV_COMPO){
for ( int i = 0 ; i < GetBasicCurveComposite( pCalcCrv)->GetCurveCount(); ++i) {
const ICurve& subCurve = *GetBasicCurveComposite( pCalcCrv)->GetCurve( i) ;
CalcIntersLinePlane( m_plPlane, subCurve, i) ;
}
OrderAndCompleteIntersections() ;
}
// per curve approssimate, sistemo...
AdjustIntersParams( pCalcCrv != m_pCurve) ;
}
//----------------------------------------------------------------------------
bool
IntersCurvePlane::CalcIntersLinePlane( const Plane3d& plPlane, const ICurve& Curve, int nCrv)
{
if ( Curve.GetType() != CRV_LINE)
return false ;
Point3d ptStart ; Curve.GetStartPoint( ptStart) ;
Point3d ptEnd ; Curve.GetEndPoint( ptEnd) ;
Point3d ptInt ;
double dLen = 0 ; Curve.GetLength( dLen) ;
int nIntersType = IntersLinePlane( ptStart, ptEnd, m_plPlane, ptInt, true) ;
// intersezione con attraversamento
if ( nIntersType == ILPT_YES) {
IntCrvPlnInfo icpi ;
icpi.Ici[0].ptI = ptInt ;
icpi.Ici[0].dU = Dist( ptInt, ptStart) / dLen + nCrv ;
Vector3d vtPos = ptStart - m_plPlane.GetPoint() ;
icpi.Ici[0].nPrevTy = vtPos * m_plPlane.GetVersN() > 0 ? ICPT_OUT : ICPT_IN ;
icpi.Ici[0].nNextTy = icpi.Ici[0].nPrevTy == ICPT_IN ? ICPT_OUT : ICPT_IN ;
m_Info.push_back( icpi) ;
}
// intersezione con tocco
else if ( nIntersType == ILPT_START || nIntersType == ILPT_END) {
IntCrvPlnInfo icpi ;
icpi.Ici[0].ptI = ptInt ;
icpi.Ici[0].dU = nIntersType == ILPT_START ? 0 : 1 + nCrv ;
if ( nIntersType == ILPT_START) {
Vector3d vtPos = ptEnd - m_plPlane.GetPoint() ;
icpi.Ici[0].nNextTy = vtPos * m_plPlane.GetVersN() > 0 ? ICPT_OUT : ICPT_IN ;
icpi.Ici[0].nPrevTy = ICPT_NULL ;
}
else {
Vector3d vtPos = ptStart - m_plPlane.GetPoint() ;
icpi.Ici[0].nPrevTy = vtPos * m_plPlane.GetVersN() > 0 ? ICPT_OUT : ICPT_IN ;
icpi.Ici[0].nNextTy = ICPT_NULL ;
}
m_Info.push_back( icpi) ;
}
// intersezione con sovrapposizione
else if ( nIntersType == ILPT_INPLANE) {
IntCrvPlnInfo icpi ;
icpi.bOverlap = true ;
icpi.Ici[0].ptI = ptStart ;
icpi.Ici[0].dU = 0 + nCrv;
icpi.Ici[1].ptI = ptEnd ;
icpi.Ici[1].dU = 1 + nCrv ;
icpi.Ici[0].nPrevTy = ICPT_NULL ;
icpi.Ici[0].nNextTy = ICPT_ON ;
icpi.Ici[1].nPrevTy = ICPT_ON ;
icpi.Ici[1].nNextTy = ICPT_NULL ;
m_Info.push_back( icpi) ;
}
return true ;
}
//----------------------------------------------------------------------------
void
IntersCurvePlane::OrderAndCompleteIntersections()
{
// cancello le interesezioni puntuali adiacenti a tratti di sovrapposizione
// riempio le info PrevTy e NexyTy
sort( m_Info.begin(), m_Info.end(), []( IntCrvPlnInfo& icpA, IntCrvPlnInfo& icpB) { return icpA.Ici[0].dU < icpA.Ici[0].dU ;}) ;
for ( int curr = m_Info.size() - 1 ; curr > - 1 ; --curr) {
int prev = curr == 0 ? m_Info.size() - 1 : curr - 1 ;
int next = curr == m_Info.size() - 1 ? 0 : curr + 1 ;
bool bErasedCurr = false ;
// solo le intersezioni di sovrapposizione o puntuali sullo start o end delle curve possono avere il PrevTy o NextTy non definito
if ( ! m_Info[curr].bOverlap) {
if ( m_Info[curr].Ici[0].nPrevTy == ICPT_NULL) {
if ( ! m_Info[prev].bOverlap) {
m_Info[curr].Ici[0].nPrevTy = m_Info[prev].Ici[0].nNextTy ;
// se ho due puntuali che coincidono cancello il successivo tra i due ( corrente)
if ( AreSamePointApprox( m_Info[curr].Ici[0].ptI, m_Info[prev].Ici[0].ptI)) {
m_Info.erase(m_Info.begin() + curr) ;
bErasedCurr = true ;
}
}
// se ho un'intersezione puntuale che in realtà è la fine di un tratto di sovrapposizione, la cancello
else {
m_Info[prev].Ici[1].nNextTy = m_Info[curr].Ici[0].nNextTy ;
m_Info.erase(m_Info.begin() + curr) ;
bErasedCurr = true ;
}
}
if ( ! bErasedCurr && m_Info[curr].Ici[0].nNextTy == ICPT_NULL){
if ( ! m_Info[prev].bOverlap)
m_Info[curr].Ici[0].nNextTy = m_Info[next].Ici[0].nPrevTy ;
// se ho un'intersezione puntuale che in realtà è la fine di un tratto di sovrapposizione, la cancello
else {
m_Info[next].Ici[0].nPrevTy = m_Info[curr].Ici[0].nPrevTy ;
m_Info.erase(m_Info.begin() + curr) ;
}
}
}
else {
if ( m_Info[curr].Ici[0].nPrevTy == ICPT_NULL) {
if ( ! m_Info[prev].bOverlap)
m_Info[curr].Ici[0].nPrevTy = m_Info[prev].Ici[0].nNextTy ;
else
m_Info[curr].Ici[0].nPrevTy = m_Info[prev].Ici[1].nNextTy ;
}
if ( m_Info[curr].Ici[1].nNextTy == ICPT_NULL) {
if ( ! m_Info[next].bOverlap)
m_Info[curr].Ici[0].nNextTy = m_Info[prev].Ici[0].nPrevTy ;
else
m_Info[curr].Ici[0].nNextTy = m_Info[prev].Ici[1].nPrevTy ;
}
}
}
m_nIntersCount = m_Info.size() ;
}
//----------------------------------------------------------------------------
bool
IntersCurvePlane::IsArcToApprox( const ICurve& Curve)
{
// recupero l'arco
const CurveArc* pArc = GetBasicCurveArc( &Curve) ;
if ( pArc == nullptr)
return false ;
// verifico se non è nel piano XY o ha più di un giro al centro
return ( ( ! pArc->GetNormVersor().IsZplus() && ! pArc->GetNormVersor().IsZminus()) ||
abs( pArc->GetAngCenter()) > ANG_FULL + EPS_ANG_ZERO) ;
}
//----------------------------------------------------------------------------
bool
IntersCurvePlane::AdjustIntersParams( bool bAdjCrv)
{
// se non ci sono intersezioni, non va fatto alcunché
if ( m_Info.empty())
return true ;
// se le curve originali non sono state approssimate, non va fatto alcunché
if ( ! bAdjCrv)
return true ;
// procedo ad aggiustare
for ( auto& aInfo : m_Info) {
// se curve originali approssimate, devo ricalcolare i parametri dei punti di intersezione
if ( bAdjCrv) {
if ( ! m_pCurve->GetParamAtPoint( aInfo.Ici[0].ptI, aInfo.Ici[0].dU, 10 * EPS_SMALL))
return false ;
if ( aInfo.bOverlap && ! m_pCurve->GetParamAtPoint( aInfo.Ici[1].ptI, aInfo.Ici[1].dU, 10 * EPS_SMALL))
return false ;
}
}
return true ;
}
//----------------------------------------------------------------------------
int
IntersCurvePlane::GetIntersCount( void)
{
return m_nIntersCount ;
}
//----------------------------------------------------------------------------
bool
IntersCurvePlane::GetIntersPointNearTo( const Point3d& ptNear, Point3d& ptI, double& dParam)
{
if ( m_nIntersCount == 0)
return false ;
// ricerca del punto più vicino tra le intersezioni singole
bool bFound = false ;
double dMinSqDist = SQ_INFINITO ;
for ( int i = 0 ; i < m_nIntersCount ; ++ i) {
// se è un'intersezione singola
if ( ! m_Info[i].bOverlap) {
// faccio la verifica sul punto
Point3d ptP = m_Info[i].Ici[0].ptI ;
double dSqDist = SqDist( ptNear, ptP) ;
if ( dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
ptI = ptP ;
dParam = m_Info[i].Ici[0].dU ;
bFound = true ;
}
}
// altrimenti
else {
// recupero il tratto di sovrapposizione
double dUStartTrim, dUEndTrim ;
dUStartTrim = m_Info[i].Ici[0].dU ;
dUEndTrim = m_Info[i].Ici[1].dU ;
PtrOwner<ICurve> pCrv( m_pCurve->CopyParamRange( dUStartTrim, dUEndTrim)) ;
if ( IsNull( pCrv))
continue ;
// cerco il punto
int nFlag ;
Point3d ptP ;
if ( DistPointCurve( ptNear, *pCrv).GetMinDistPoint( 0.5, ptP, nFlag)) {
// faccio la verifica
double dSqDist = SqDist( ptNear, ptP) ;
if ( dSqDist < dMinSqDist) {
dMinSqDist = dSqDist ;
ptI = ptP ;
m_pCurve->GetParamAtPoint( ptP, dParam) ;
bFound = true ;
}
}
}
}
return bFound ;
}
//----------------------------------------------------------------------------
bool
IntersCurvePlane::GetCurveClassification( double dLenMin, CRVPLNCVECTOR& ccClass)
{
// pulisco vettore classificazioni
ccClass.clear() ;
// verifico definizione della curva
if ( m_pCurve == nullptr)
return false ;
// se esiste almeno una intersezione
if ( m_nIntersCount >= 1)
return CalcCurveClassification( m_pCurve, m_Info, dLenMin, ccClass) ;
// altrimenti la curva è completamente interna oppure completamente esterna
else
return CalcCurveInOrOut( m_pCurve, ccClass) ;
}
//----------------------------------------------------------------------------
bool
IntersCurvePlane::CalcCurveClassification( const ICurve* pCurve, const ICPIVECTOR& Info, double dLenMin, CRVPLNCVECTOR& ccClass)
{
// numero intersezioni
int nNumInters = int( Info.size()) ;
if ( nNumInters < 1)
return false ;
// recupero il dominio parametrico della curva in esame
double dStartPar, dEndPar ;
if ( pCurve == nullptr || ! pCurve->GetDomain( dStartPar, dEndPar))
return false ;
// limito lunghezza minima
dLenMin = max( dLenMin, EPS_ZERO) ;
// elimino intersezioni senza attraversamento che giacciono in intervalli di sovrapposizione
ICPIVECTOR InfoCorr ;
InfoCorr.reserve( Info.size()) ;
for ( size_t i = 0 ; i < Info.size() ; ++ i) {
// se intersezione puntuale senza attraversamento
if ( ! Info[i].bOverlap && Info[i].Ici[0].nPrevTy == Info[i].Ici[0].nNextTy) {
// confronto con le intersezioni con sovrapposizione
bool bToSkip = false ;
for ( size_t j = 0 ; j < Info.size() ; ++ j) {
// se coincide o puntuale
if ( j == i || ! Info[j].bOverlap)
continue ;
// determino l'intervallo parametrico tenendo conto di eventuale avvolgimento attorno all'inizio
double dU1 = Info[j].Ici[0].dU ;
double dU2 = Info[j].Ici[1].dU ;
if ( dU2 < dU1 && pCurve->IsClosed())
dU2 += dEndPar ;
// se cade nell'intervallo è da saltare
if ( Info[i].Ici[0].dU >= dU1 && Info[i].Ici[0].dU <= dU2) {
bToSkip = true ;
break ;
}
}
if ( bToSkip)
continue ;
}
// salvo dati intersezione
InfoCorr.emplace_back( Info[i]) ;
}
// aggiorno numero di intersezioni da considerare
nNumInters = int( InfoCorr.size()) ;
// recupero la classificazione all'inizio della curva
int nLastTy = ICCT_NULL ;
double dCurrPar = dStartPar ;
double dCurrLen = 0 ;
double dEndLen ; pCurve->GetLength( dEndLen) ;
// se è chiusa, recupero come finisce
if ( pCurve->IsClosed()) {
if ( ! InfoCorr[nNumInters-1].bOverlap)
nLastTy = InfoCorr[nNumInters-1].Ici[0].nNextTy ;
else {
nLastTy = InfoCorr[nNumInters-1].Ici[1].nNextTy ;
// se attraversa il punto di giunzione (parametro di fine minore di quello di inizio)
if ( InfoCorr[nNumInters-1].Ici[1].dU < InfoCorr[nNumInters-1].Ici[0].dU) {
dCurrPar = InfoCorr[nNumInters-1].Ici[1].dU ;
double dTmpLen ; pCurve->GetLengthAtParam( dCurrPar, dTmpLen) ;
dCurrLen = dTmpLen - dEndLen ;
dEndPar = dCurrPar ;
dEndLen = dTmpLen ;
}
}
}
// costruisco il vettore delle classificazioni
for ( int i = 0 ; i < nNumInters ; ++ i) {
// se è definito un tratto precedente
double dLenU ; pCurve->GetLengthAtParam( InfoCorr[i].Ici[0].dU, dLenU) ;
if ( InfoCorr[i].Ici[0].dU > dCurrPar + EPS_PARAM && dLenU - dCurrLen > dLenMin) {
// verifico che la definizione sul tratto sia omogenea e valida
int nPrevTy = InfoCorr[i].Ici[0].nPrevTy ;
if ( ( nLastTy != ICCT_NULL && nPrevTy != nLastTy) ||
nPrevTy == ICCT_NULL || nPrevTy == ICCT_ON)
return false ;
// assegno i dati
CrvPlaneClass segClass ;
segClass.dParS = dCurrPar ;
segClass.dParE = InfoCorr[i].Ici[0].dU ;
segClass.nClass = (( nPrevTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ;
ccClass.push_back( segClass) ;
// salvo dati correnti
dCurrPar = InfoCorr[i].Ici[0].dU ;
dCurrLen = dLenU ;
nLastTy = InfoCorr[i].Ici[0].nNextTy ;
}
// altrimenti, salvo il tipo
else
nLastTy = InfoCorr[i].Ici[0].nNextTy ;
// se è definito un tratto in sovrapposizione
if ( InfoCorr[i].bOverlap) {
// assegno i dati
CrvPlaneClass segClass ;
segClass.dParS = dCurrPar ;
segClass.dParE = InfoCorr[i].Ici[1].dU ;
segClass.nClass = CRVPLN_ON ;
ccClass.push_back( segClass) ;
// salvo dati correnti
dCurrPar = InfoCorr[i].Ici[1].dU ;
dCurrLen = dLenU ;
nLastTy = InfoCorr[i].Ici[1].nNextTy ;
}
}
// eventuale tratto finale rimasto
if ( dCurrPar < dEndPar - EPS_PARAM && dEndLen - dCurrLen > dLenMin) {
// verifico che la definizione sul tratto sia valida
if ( nLastTy == ICCT_NULL || nLastTy == ICCT_ON)
return false ;
// assegno i dati
CrvPlaneClass segClass ;
segClass.dParS = dCurrPar ;
segClass.dParE = dEndPar ;
segClass.nClass = (( nLastTy == ICCT_IN) ? CRVC_IN : CRVC_OUT) ;
ccClass.push_back( segClass) ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
IntersCurvePlane::CalcCurveInOrOut( const ICurve* pCurve, CRVPLNCVECTOR& ccClass)
{
// controllo di non avere intersezioni
int nNumInters = int( m_Info.size()) ;
if ( nNumInters > 0)
return false ;
// se non ho intersezioni tra curva e piano devo solo capire da che parte del piano sta la curva
CrvPlaneClass cpClass ;
double dStartPar, dEndPar ;
if ( pCurve == nullptr || ! pCurve->GetDomain( dStartPar, dEndPar))
return false ;
Point3d ptStart ; pCurve->GetStartPoint( ptStart) ;
Vector3d vtCrv = ptStart - m_plPlane.GetPoint() ;
CrvPlaneClass segClass ;
segClass.dParS = dStartPar ;
segClass.dParE = dEndPar ;
segClass.nClass = ( (vtCrv * m_plPlane.GetVersN() < 0) ? CRVC_IN : CRVC_OUT) ;
ccClass.push_back( segClass) ;
return true ;
}
+17 -5
View File
@@ -113,7 +113,7 @@ IntersLineBox( const Point3d& ptL, const Vector3d& vtL, double dLen, const BBox3
double dU1, dU2 ;
bool bInters = IntersLineBox( ptL, vtL, b3Box.GetMin(), b3Box.GetMax(), dU1, dU2) ;
// Se non c'è intersezione
// Se non c'è intersezione
if ( ! bInters || ( bFinite && ( dU1 > dLen + EPS_SMALL || dU2 < -EPS_SMALL)))
return true ;
@@ -144,8 +144,14 @@ IntersLineBox( const Point3d& ptL, const Vector3d& vtL, double dLen, const BBox3
else if ( dU2 < EPS_SMALL)
vInters.emplace_back( ILBT_OUT, 0) ;
else {
vInters.emplace_back( ILBT_TG_INI, Clamp( dU1, 0., dLen)) ;
vInters.emplace_back( ILBT_TG_FIN, Clamp( dU2, 0., dLen)) ;
if ( dU1 < - EPS_SMALL)
vInters.emplace_back( ILBT_TG_INSIDE, 0.) ;
else
vInters.emplace_back( ILBT_TG_INI, Clamp( dU1, 0., dLen)) ;
if ( dU2 > dLen + EPS_SMALL)
vInters.emplace_back( ILBT_TG_INSIDE, dLen) ;
else
vInters.emplace_back( ILBT_TG_FIN, Clamp( dU2, 0., dLen)) ;
}
}
return true ;
@@ -162,8 +168,14 @@ IntersLineBox( const Point3d& ptL, const Vector3d& vtL, double dLen, const BBox3
else if ( dU2 < EPS_SMALL)
vInters.emplace_back( ILBT_OUT, 0) ;
else {
vInters.emplace_back( ILBT_IN, Clamp( dU1, 0., dLen)) ;
vInters.emplace_back( ILBT_OUT, Clamp( dU2, 0., dLen)) ;
if ( dU1 < - EPS_SMALL)
vInters.emplace_back( ILBT_INSIDE, 0.) ;
else
vInters.emplace_back( ILBT_IN, Clamp( dU1, 0., dLen)) ;
if ( dU2 > dLen + EPS_SMALL)
vInters.emplace_back( ILBT_INSIDE, dLen) ;
else
vInters.emplace_back( ILBT_OUT, Clamp( dU2, 0., dLen)) ;
}
}
return true ;
+30
View File
@@ -159,6 +159,36 @@ IntersLineLine::IntersFiniteLines( const CurveLine& Line1, const CurveLine& Line
// flag per segmenti che si allontanano significativamente
bool bFarEnds = ( nS1Side != 0 || nE1Side != 0 || nS2Side != 0 || nE2Side != 0) ;
// analisi casi speciali di quasi parallelismo
// segmento sovrapposto all'altro
double dDist1, dDist2 ;
if ( nS1Side == 0 || nE1Side == 0 || nS1Side == nE1Side) {
dDist1 = CrossXY( ptS1 - ptS2, vtDir2) ;
dDist2 = CrossXY( ptE1 - ptS2, vtDir2) ;
if ( abs( dDist1 - dDist2) < EPS_SMALL * dLen2XY) {
bParallel = true ;
bFarEnds = ! ( (nS1Side == 0 && nE1Side == 0) || (nS2Side == 0 && nE2Side == 0)) ;
}
}
else if ( nS2Side == 0 || nE2Side == 0 || nS2Side == nE2Side) {
dDist1 = CrossXY( ptS2 - ptS1, vtDir1) ;
dDist2 = CrossXY( ptE2 - ptS1, vtDir1) ;
if ( abs( dDist1 - dDist2) < EPS_SMALL * dLen1XY) {
bParallel = true ;
bFarEnds = ! ( (nS1Side == 0 && nE1Side == 0) || (nS2Side == 0 && nE2Side == 0)) ;
}
}
// estremità sovrapposte di poco
if ( ! bParallel && abs( dCrossXY) < ( 0.1 * DEGTORAD) * ( dLen1XY * dLen2XY)) {
if (( nS1Side == 0 && nS2Side == 0 && ScalarXY( vtDir1, vtDir2) < 0 && ! AreSamePointXYEpsilon( ptS1, ptS2, 2 * EPS_SMALL)) ||
( nS1Side == 0 && nE2Side == 0 && ScalarXY( vtDir1, vtDir2) > 0 && ! AreSamePointXYEpsilon( ptS1, ptE2, 2 * EPS_SMALL)) ||
( nE1Side == 0 && nS2Side == 0 && ScalarXY( vtDir1, vtDir2) > 0 && ! AreSamePointXYEpsilon( ptE1, ptS2, 2 * EPS_SMALL)) ||
( nE1Side == 0 && nE2Side == 0 && ScalarXY( vtDir1, vtDir2) < 0 && ! AreSamePointXYEpsilon( ptE1, ptE2, 2 * EPS_SMALL))) {
bParallel = true ;
bFarEnds = false ;
}
}
// se non sono paralleli e si allontanano tra loro abbastanza
if ( ! bParallel && bFarEnds) {
// posizioni parametriche dell'intersezione sulle linee
+35 -36
View File
@@ -34,7 +34,6 @@ RefineIntersNewton( const Point3d& ptL, const Vector3d& vtL, double dLen, bool b
const ISurfBezier* pSurfBz, Point3d& ptSP, Point3d& ptIBz)
{
// la funzione raffina la posisione del punto ptSP, minimizzando la distanza dalla retta e restituisce il punto di intersezione ptIBz
pSurfBz->GetPointD1D2( ptSP.x / SBZ_TREG_COEFF, ptSP.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBz) ;
// usando un algoritmo di newton cerco di avvicinarmi il più possibile alla retta
DistPointLine dpl( ptIBz, ptL, vtL, dLen, bFinite) ;
double dDistNew = 0, dDistPre = 0 ;
@@ -48,18 +47,18 @@ RefineIntersNewton( const Point3d& ptL, const Vector3d& vtL, double dLen, bool b
while ( dDistNew > EPS_SMALL && nCount < 100) {
dDistPre = dDistNew ;
Point3d ptIBzNew1 ;
pSurfBz->GetPointD1D2( ( ptSP.x + dh) / SBZ_TREG_COEFF, ptSP.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBzNew1) ;
pSurfBz->GetPointD1D2( ( ptSP.x + dh), ptSP.y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBzNew1) ;
DistPointLine dplNewU( ptIBzNew1, ptL, vtL, dLen, bFinite) ;
dplNewU.GetDist( dDistNew) ;
double dfdU = ( dDistNew - dDistPre) / dh ;
Point3d ptIBzNew2 ;
pSurfBz->GetPointD1D2( ptSP.x / SBZ_TREG_COEFF, ( ptSP.y + dh) / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBzNew2) ;
pSurfBz->GetPointD1D2( ptSP.x, ( ptSP.y + dh), ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBzNew2) ;
DistPointLine dplNewV( ptIBzNew2, ptL, vtL, dLen, bFinite) ;
dplNewV.GetDist( dDistNew) ;
double dfdV = ( dDistNew - dDistPre) / dh ;
// mi avvicino cercando di annullare la distanza in un colpo solo
double dr = - dDistPre / ( dfdU + dfdV) ;
pSurfBz->GetPointD1D2(( ptSP.x + dr * dfdU) / SBZ_TREG_COEFF, ( ptSP.y + dr * dfdV) / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBz) ;
pSurfBz->GetPointD1D2(( ptSP.x + dr * dfdU), ( ptSP.y + dr * dfdV), ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBz) ;
DistPointLine dplNew( ptIBz, ptL, vtL, dLen, bFinite) ;
dplNew.GetDist( dDistNew) ;
++ nCount ;
@@ -143,12 +142,12 @@ IntersLineSurfBz( const Point3d& ptL, const Vector3d& vtL, double dLen, const IS
pSurfTm->GetTriangle( InfoTm.nT, nVert) ;
double dU0, dV0 ;
pSurfTm->GetVertexParam( nVert[0], dU0, dV0) ;
ptSP = ptSP + Point3d(dU0, dV0, 0) ;
ptSP = ptSP + Point3d( dU0, dV0, 0) ;
if ( ! RefineIntersNewton( ptL,vtL, dLen, bFinite, pSurfBz, ptSP, ptIBz))
return false ;
}
Vector3d vtN ;
pSurfBz->GetPointNrmD1D2(ptSP.x / SBZ_TREG_COEFF, ptSP.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBz, vtN) ;
pSurfBz->GetPointNrmD1D2(ptSP.x, ptSP.y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBz, vtN) ;
double dCos = vtN * vtL ;
double dCos2 = 0 ;
// eventualmente ripeto tutto per ptI2 ( se ho un'intersezione con sovrapposizione)
@@ -163,7 +162,7 @@ IntersLineSurfBz( const Point3d& ptL, const Vector3d& vtL, double dLen, const IS
if ( ! RefineIntersNewton( ptL,vtL, dLen, bFinite, pSurfBz, ptSP, ptIBz))
return false ;
}
pSurfBz->GetPointNrmD1D2( ptSP2.x / SBZ_TREG_COEFF, ptSP2.y / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBz2, vtN) ;
pSurfBz->GetPointNrmD1D2( ptSP2.x, ptSP2.y, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, ptIBz2, vtN) ;
dCos2 = vtN * vtL ;
}
UpdateInfoIntersLineSurfBz( ptL, vtL, InfoTm.nILTT, InfoTm.nT, ptSP, ptIBz, dCos, ptSP2, ptIBz2, dCos2, vInfo) ;
@@ -251,13 +250,13 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
pSurfBz->GetInfo( nDegU, nDegV, nSpanU, nSpanV, bRat, bTrimmed) ;
// funzione pensata per funzionare solo con una monopatch bilineare
if( nDegU > 1 || nDegV > 1 || nSpanU > 1 || nSpanV > 1 || bRat)
if ( nDegU > 1 || nDegV > 1 || nSpanU > 1 || nSpanV > 1 || bRat)
return false ;
int nInters = int( vInfo.size()) ;
PNTVECTOR vPntCtrl ;
for( int p = 0 ; p < 4 ; ++p) {
for ( int p = 0 ; p < 4 ; ++p) {
bool bOk = false ;
vPntCtrl.push_back( pSurfBz->GetControlPoint( p, &bOk)) ;
}
@@ -281,14 +280,14 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
vdCoeff = { (B2 * D1 - B1 * D2), ( A2 * D1 - A1 * D2 + B2 * C1 - B1 * C2), ( A2 * C1 - A1 * C2)} ;
int nRoots = PolynomialRoots( 2, vdCoeff, vdRoots) ;
bool bFound = false ;
for( int w = 0 ; w < nRoots ; ++w) {
for ( int w = 0 ; w < nRoots ; ++w) {
if ( vdRoots[w] > 0 - EPS_ZERO && vdRoots[w] < 1 + EPS_ZERO ) {
double dU = 0, dV = vdRoots[w] ;
// verifico che non sia una soluzione con molteplicità > 1
bool bAlreadyFound = false ;
for ( int k = w - 1 ; k >= 0 && ! bAlreadyFound ; --k)
bAlreadyFound = abs( dV - vdRoots[k]) < EPS_PARAM ;
if( ! bAlreadyFound) {
if ( ! bAlreadyFound) {
dU = (dV * (C1 - C2) + ( D1 - D2)) / ( dV * ( A2 - A1) + ( B2 - B1)) ;
if ( dU > - EPS_ZERO && dU < 1 + EPS_ZERO) {
Point3d ptIBez, ptIBez2 ;
@@ -305,14 +304,14 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
// se tutti i coefficienti sono zero allora potrei avere una linea che giace sulla superficie
// per trovare i punti di inizio e fine sovrapposizione trovo i punti a minima distanza tra la linea e gli edge della superficie
if( ! bFound && abs( vdCoeff[0]) < EPS_ZERO && abs( vdCoeff[1]) < EPS_ZERO && abs( vdCoeff[2]) < EPS_ZERO) {
if ( ! bFound && abs( vdCoeff[0]) < EPS_ZERO && abs( vdCoeff[1]) < EPS_ZERO && abs( vdCoeff[2]) < EPS_ZERO) {
ICRVCOMPOPOVECTOR vCrvEdge( 4) ;
vCrvEdge[0].Set(pSurfBz->GetCurveOnU( 0)) ;
vCrvEdge[1].Set(pSurfBz->GetCurveOnV( 1)) ;
vCrvEdge[2].Set(pSurfBz->GetCurveOnU( 1)) ;
vCrvEdge[3].Set(pSurfBz->GetCurveOnV( 0)) ;
double dAngTolDeg = 5 ;
for( int i = 0 ; i < 4 ; ++i) {
for ( int i = 0 ; i < 4 ; ++i) {
PolyLine plApprox ; vCrvEdge[0]->ApproxWithLines( EPS_SMALL, dAngTolDeg, ICurve::ApprLineType::APL_STD, plApprox) ;
//CurveComposite cCC ;
//cCC.FromPolyLine( plApprox) ;
@@ -322,7 +321,7 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
Point3d ptClosest ;
int c = 0 ;
int nTot = plApprox.GetPointNbr() ;
for( int j = 0 ; j < nTot ; ++j) {
for ( int j = 0 ; j < nTot ; ++j) {
DistPointLine dpl( pt, ptL, vtL, dLen, bFinite) ;
double dDist = INFINITO ;
dpl.GetDist( dDist) ;
@@ -339,7 +338,7 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
// tra i due tratti dell'approssimazione che arrivano al punto selezionato come più vicino, devo trovare quale si avvicina di più
Point3d ptStart ; plApprox.GetFirstPoint( ptStart) ;
Point3d ptEnd ;
for( int z = 1 ; z < nClosestLine - 1 ; ++z)
for ( int z = 1 ; z < nClosestLine - 1 ; ++z)
plApprox.GetNextPoint( ptStart) ;
plApprox.GetNextPoint( ptEnd) ;
// linea precedente al punto
@@ -357,12 +356,12 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
double dDistCurr = INFINITO ;
dllCurr.GetDist( dDistCurr) ;
if( dDistPre < dDistCurr)
if ( dDistPre < dDistCurr)
dllPre.GetMinDistPoints( ptInt1, ptInt2) ;
else
dllCurr.GetMinDistPoints( ptInt1, ptInt2) ;
}
else if ( nClosestLine == 0){
else if ( nClosestLine == 0) {
// il punto più vicino è sulla prima linea
Point3d ptStart ; plApprox.GetFirstPoint( ptStart) ;
Point3d ptEnd ; plApprox.GetNextPoint( ptEnd) ;
@@ -375,7 +374,7 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
// il punto più vicino è sull'ultima linea
Point3d ptStart ; plApprox.GetFirstPoint( ptStart) ;
Point3d ptEnd ;
for( int z = 1 ; z < nClosestLine - 1 ; ++z)
for ( int z = 1 ; z < nClosestLine - 1 ; ++z)
plApprox.GetNextPoint( ptStart) ;
plApprox.GetNextPoint( ptEnd) ;
Vector3d vtLinePre = ptEnd - ptStart ;
@@ -386,23 +385,23 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
double dU1 = 0, dV1 = 0, dU2 = 0, dV2 = 0 ;
// se ho trovato due punti vuol dire che la linea coincide con un edge e ho trovato tutto quello che serve
if( ! AreSamePointExact( ptInt2, ORIG)) {
if( i == 0) {
if ( ! AreSamePointExact( ptInt2, ORIG)) {
if ( i == 0) {
//dV1 = 0 ; dV2 = 0 ;
vCrvEdge[0]->GetParamAtPoint( ptInt1, dU1) ;
vCrvEdge[0]->GetParamAtPoint( ptInt2, dU2) ;
}
else if( i == 1) {
else if ( i == 1) {
//dU1 = 1 ; dU2 = 1 ;
vCrvEdge[1]->GetParamAtPoint( ptInt1, dV1) ;
vCrvEdge[1]->GetParamAtPoint( ptInt2, dV2) ;
}
else if( i == 2){
else if ( i == 2){
//dV1 = 1 ; dV2 = 1 ;
vCrvEdge[2]->GetParamAtPoint( ptInt1, dU1) ;
vCrvEdge[2]->GetParamAtPoint( ptInt2, dU2) ;
}
else if( i == 3){
else if ( i == 3){
//dU1 = 0 ; dU2 = 0 ;
vCrvEdge[3]->GetParamAtPoint( ptInt1, dV1) ;
vCrvEdge[3]->GetParamAtPoint( ptInt2, dV2) ;
@@ -417,11 +416,11 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
double dCos2 = vtN2 * vtL ;
// se avevo già trovato un punto singolo che coincide col primo punto di questa intersezione sovrapposta, allora cancello l'intersezione singola che
// avevo salvato e aggiungo quella sovrapposto che ho trovato ora
if( bFound) {
if ( bFound) {
int nNewTot = int(vInfo.size()) ;
int nNewInters = nNewTot - nInters ;
bool bAlreadyFound = false ;
for( int i = 0 ; i < nNewInters ; ++i) {
for ( int i = 0 ; i < nNewInters ; ++i) {
bAlreadyFound = AreSamePointApprox(vInfo[nNewTot - i].ptUV, ptSP1) || AreSamePointApprox(vInfo[nNewTot - i].ptUV, ptSP2) ;
if ( bAlreadyFound) {
vInfo.erase( vInfo.begin() + nNewTot - i) ;
@@ -434,32 +433,32 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
break ;
}
// se ho trovato un punto a distanza zero dalla linea allora ho trovato l'intersezione
else if( dMinDist < EPS_SMALL) {
if( i == 0) {
else if ( dMinDist < EPS_SMALL) {
if ( i == 0) {
//dV1 = 0 ;
vCrvEdge[0]->GetParamAtPoint( ptInt1, dU1) ;
}
else if( i == 1) {
else if ( i == 1) {
//dU1 = 1 ;
vCrvEdge[1]->GetParamAtPoint( ptInt1, dV1) ;
}
else if( i == 2){
else if ( i == 2) {
//dV1 = 1 ;
vCrvEdge[2]->GetParamAtPoint( ptInt1, dU1) ;
}
else if( i == 3){
else if ( i == 3) {
//dU1 = 0 ;
vCrvEdge[3]->GetParamAtPoint( ptInt1, dV1) ;
}
Point3d ptSP1( dU1, dV1, 0), ptSP2 ;
// se avevo trovato già altri punti controllo di non essere esattamente su una diagonale ( e quindi avere un'intersezione con ogni edge, ma due sono doppie)
if( bFound) {
if ( bFound) {
int nNewTot = int(vInfo.size()) ;
int nNewInters = nNewTot - nInters ;
bool bAlreadyFound = false ;
for( int i = 0 ; i < nNewInters ; ++i)
for ( int i = 0 ; i < nNewInters ; ++i)
bAlreadyFound = AreSamePointApprox(vInfo[nNewTot - i].ptUV, ptSP1) ;
if( bAlreadyFound)
if ( bAlreadyFound)
continue ;
}
@@ -474,16 +473,16 @@ IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen,
}
// se la superficie è trimmed verifico che i punti trovati siano all'interno del parametrico trimmato
if( bTrimmed && bFound) {
if ( bTrimmed && bFound) {
int nNewTot = int(vInfo.size()) ;
int nNewInters = nNewTot - nInters ;
const ISurfFlatRegion* pFRTrim = pSurfBz->GetTrimRegion() ;
for( int i = 0 ; i < nNewInters ; ++i) {
for ( int i = 0 ; i < nNewInters ; ++i) {
Point3d ptTest = vInfo[nNewTot - i].ptUV * SBZ_TREG_COEFF ;
bool bInside = false ;
double dDist = INFINITO ;
IsPointInsideSurfFr( ptTest, pFRTrim, dDist, bInside) ;
if( ! bInside)
if ( ! bInside)
vInfo.erase( vInfo.begin() + nNewTot - i) ;
}
}
+1 -1
View File
@@ -1662,7 +1662,7 @@ LineTorus( const Point3d& ptLine, const Vector3d& vtLine,
// Riordino le soluzioni
for ( int ni = 0 ; ni < int( vdPar.size()) - 1 ; ++ ni) {
for ( int nj = ni ; nj < int( vdPar.size()) ; ++ nj) {
if( vdPar[ni] > vdPar[nj]) {
if ( vdPar[ni] > vdPar[nj]) {
swap( vdPar[ni], vdPar[nj]) ;
}
}
+1 -4
View File
@@ -19,7 +19,7 @@
using namespace std ;
//----------------------------------------------------------------------------
// Intersezione di unpiano con la superficie di un solido VolZmap
// Intersezione di un piano con la superficie di un solido VolZmap
//----------------------------------------------------------------------------
bool
IntersPlaneVolZmap( const Plane3d& plPlane, const IVolZmap& Vzm, ICURVEPOVECTOR& vpLoop)
@@ -28,9 +28,6 @@ IntersPlaneVolZmap( const Plane3d& plPlane, const IVolZmap& Vzm, ICURVEPOVECTOR&
const VolZmap* pVzm = GetBasicVolZmap( &Vzm) ;
if ( pVzm == nullptr)
return false ;
// verifico parametro di ritorno
if ( &vpLoop == nullptr)
return false ;
// eseguo intersezione
return pVzm->GetPlaneIntersection( plPlane, vpLoop) ;
+104 -7
View File
@@ -23,9 +23,6 @@ using namespace std ;
static int
CopyGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob)
{
// verifico i puntatori ai GeomDB
if ( pSouGDB == nullptr || pDstGDB == nullptr)
return GDB_ID_NULL ;
// recupero l'oggetto da copiare dal GeomDB sorgente
PtrOwner<IGeoObj> pGObj( pSouGDB->GetGeoObj( nSouId)->Clone()) ;
if ( IsNull( pGObj))
@@ -68,12 +65,11 @@ static int
CopyGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob)
{
// recupero il riferimento del gruppo
Frame3d frFrame ;
pSouGDB->GetGroupFrame( nSouId) ;
Frame3d frFrame = *( pSouGDB->GetGroupFrame( nSouId)) ;
// se in globale
if ( bGlob) {
// recupero il riferimento del gruppo in globale
if ( ! pSouGDB->GetGlobFrame( nSouId, frFrame))
if ( ! pSouGDB->GetGroupGlobFrame( nSouId, frFrame))
return GDB_ID_NULL ;
// recupero il riferimento del gruppo destinazione
Frame3d frDest ;
@@ -110,7 +106,7 @@ CopyGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, i
nSonNewId = CopyGeoObj( pSouGDB, nSonSouId, pDstGDB, GDB_ID_NULL, nNewId, GDB_LAST_SON, false) ;
// se altrimenti è un gruppo
else if ( nSonSouType == GDB_TY_GROUP)
nSonNewId = CopyGroupObj( pSouGDB, nSonSouId, pDstGDB, GDB_ID_NULL, nNewId, GDB_LAST_SON, false) ;
nSonNewId = CopyGroupObj( pSouGDB, nSonSouId, pDstGDB, GDB_ID_NULL, nNewId, GDB_LAST_SON, false) ;
// se copia non riuscita, esco con errore
if ( nSonNewId == GDB_ID_NULL)
return GDB_ID_NULL ;
@@ -130,6 +126,9 @@ Copy( IGeomDB* pSouGeomDB, int nSouId, IGeomDB* pDestGeomDB, int nDestId, int nR
GeomDB* pDstGDB = static_cast<GeomDB*>( pDestGeomDB) ;
if ( pSouGDB == nullptr || pDstGDB == nullptr)
return GDB_ID_NULL ;
// il sorgente non può essere il gruppo radice
if ( nSouId == GDB_ID_ROOT)
return GDB_ID_NULL ;
// nuovo identificativo oggetto destinazione
int nNewId = GDB_ID_NULL ;
// recupero il tipo di oggetto sorgente
@@ -159,3 +158,101 @@ CopyGlob( IGeomDB* pSouGeomDB, int nSouId, IGeomDB* pDestGeomDB, int nDestId, in
{
return Copy( pSouGeomDB, nSouId, pDestGeomDB, nDestId, nRefId, nSonBeforeAfter, true) ;
}
//----------------------------------------------------------------------------
static int
DuplicateGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId)
{
// recupero l'oggetto da copiare dal GeomDB sorgente
PtrOwner<IGeoObj> pGObj( pSouGDB->GetGeoObj( nSouId)->Clone()) ;
if ( IsNull( pGObj))
return GDB_ID_NULL ;
// lo inserisco nel GeomDB destinazione
int nNewId = pDstGDB->InsertGeoObj( nDestId, nRefId, GDB_LAST_SON, Release( pGObj)) ;
if ( nNewId != nDestId) {
pDstGDB->Erase( nNewId) ;
return GDB_ID_NULL ;
}
// copio le caratteristiche non geometriche
const GdbObj* pSouGdbObj = pSouGDB->GetGdbObj( nSouId) ;
GdbObj* pDstGdbObj = pDstGDB->GetGdbObj( nNewId) ;
if ( pSouGDB == nullptr || pDstGdbObj == nullptr ||
! pDstGdbObj->CopyAttribsFrom( pSouGdbObj) ||
! pDstGdbObj->CopyTextureDataFrom( pSouGdbObj) ||
! pDstGdbObj->CopyStippleDataFrom( pSouGdbObj) ||
! pDstGdbObj->CopyUserObjFrom( pSouGdbObj)) {
pDstGDB->Erase( nNewId) ;
return GDB_ID_NULL ;
}
return nNewId ;
}
//----------------------------------------------------------------------------
static int
DuplicateGroupObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, bool bSkipTemp)
{
int nNewId = GDB_ID_ROOT ;
if ( nSouId != GDB_ID_ROOT) {
// recupero il riferimento del gruppo
Frame3d frFrame = *( pSouGDB->GetGroupFrame( nSouId)) ;
// inserisco un nuovo gruppo nel GeomDB destinazione
nNewId = pDstGDB->InsertGroup( nDestId, nRefId, GDB_LAST_SON, frFrame) ;
if ( nNewId != nSouId) {
pDstGDB->Erase( nNewId) ;
return GDB_ID_NULL ;
}
// copio le caratteristiche non geometriche
const GdbObj* pSouGdbObj = pSouGDB->GetGdbObj( nSouId) ;
GdbObj* pDstGdbObj = pDstGDB->GetGdbObj( nNewId) ;
if ( pSouGDB == nullptr || pDstGdbObj == nullptr ||
! pDstGdbObj->CopyAttribsFrom( pSouGdbObj) ||
! pDstGdbObj->CopyTextureDataFrom( pSouGdbObj) ||
! pDstGdbObj->CopyStippleDataFrom( pSouGdbObj) ||
! pDstGdbObj->CopyUserObjFrom( pSouGdbObj)) {
pDstGDB->Erase( nNewId) ;
return GDB_ID_NULL ;
}
}
// copio gli eventuali figli
int nSonSouId = pSouGDB->GetFirstInGroup( nSouId) ;
while ( nSonSouId != GDB_ID_NULL) {
// verifico se non richiesto di saltare i temporanei oppure non lo è
int nLevel ;
if ( ! bSkipTemp || ! pSouGDB->GetLevel( nSonSouId, nLevel) || nLevel != GDB_LV_TEMP) {
// nuovo identificativo oggetto destinazione
int nSonNewId = GDB_ID_NULL ;
// recupero il tipo di oggetto sorgente
int nSonSouType = pSouGDB->GetGdbType( nSonSouId) ;
// se l'oggetto da copiare è geometrico
if ( nSonSouType == GDB_TY_GEO)
nSonNewId = DuplicateGeoObj( pSouGDB, nSonSouId, pDstGDB, nSonSouId, nNewId) ;
// se altrimenti è un gruppo
else if ( nSonSouType == GDB_TY_GROUP)
nSonNewId = DuplicateGroupObj( pSouGDB, nSonSouId, pDstGDB, nSonSouId, nNewId, bSkipTemp) ;
// se copia non riuscita, esco con errore
if ( nSonNewId != nSonSouId)
return GDB_ID_NULL ;
}
// passo al figlio successivo
nSonSouId = pSouGDB->GetNext( nSonSouId) ;
}
return nNewId ;
}
//----------------------------------------------------------------------------
bool
DuplicateGeomDB( IGeomDB* pSouGeomDB, IGeomDB* pDestGeomDB, bool bSkipTemp)
{
// adatto e verifico i GeomDB
const GeomDB* pSouGDB = static_cast<GeomDB*>( pSouGeomDB) ;
GeomDB* pDstGDB = static_cast<GeomDB*>( pDestGeomDB) ;
if ( pSouGDB == nullptr || pDstGDB == nullptr)
return false ;
// verifico che la destinazione sia vuota
if ( pDstGDB->GetFirstInGroup( GDB_ID_ROOT) != GDB_ID_NULL)
return false ;
// eseguo la copia di tutto (se richiesto salto gli oggetti temporanei)
return ( DuplicateGroupObj( pSouGDB, GDB_ID_ROOT, pDstGDB, GDB_ID_ROOT, GDB_ID_ROOT, bSkipTemp) != GDB_ID_NULL) ;
}
+63 -74
View File
@@ -17,6 +17,7 @@
#include "NgeKeyW.h"
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EgtStringConverter.h"
#include "/EgtDev/Extern/zlib/Include/zlib.h"
using namespace std ;
@@ -34,8 +35,12 @@ NgeReader::Init( const string& sFileIn)
break ;
case NGE_BINARY :
m_bBinary = true ;
m_InFile.open( stringtoW( sFileIn), ios::in | ios::binary, _SH_DENYWR) ;
return ( ! m_InFile.fail()) ;
m_InFile = gzopen_w( stringtoW( sFileIn), "rb") ;
if ( m_InFile == nullptr)
return false ;
const int DIM_BUFFER = 65536 ;
gzbuffer( m_InFile, DIM_BUFFER) ;
return true ;
break ;
}
return false ;
@@ -46,10 +51,12 @@ bool
NgeReader::Close( void)
{
if ( m_bBinary) {
bool bOk = ( m_InFile.good() && m_InFile.is_open()) ;
if ( m_InFile.is_open())
m_InFile.close() ;
return bOk ;
if ( m_InFile != nullptr) {
bool bOk = ( gzclose( m_InFile) == Z_OK) ;
m_InFile = nullptr ;
return bOk ;
}
return true ;
}
else
return m_Scan.Terminate() ;
@@ -59,31 +66,24 @@ NgeReader::Close( void)
int
NgeReader::NgeType( const string& sFile)
{
// apertura del file di ingresso
ifstream InFile ;
InFile.open( stringtoW( sFile), ios::in | ios::binary) ;
if ( InFile.fail())
// apertura file
gzFile_s* InFile = gzopen_w( stringtoW( sFile), "rb") ;
if ( InFile == nullptr)
return NGE_ERROR ;
// lettura dei primi 31 byte
char cBuff[32] ;
InFile.read( cBuff, 31) ;
cBuff[InFile.gcount()] = '\0' ;
// chiusura del file
InFile.close() ;
// verifico se file compresso (gz)
if ( cBuff[0] == '\x1F' && cBuff[1] == '\x8B')
return NGE_ASCII ;
// verifico se iniziano con "START"
string sBuff = cBuff ;
size_t nPos = sBuff.find( "START") ;
if ( nPos != string::npos && nPos < 10)
return NGE_ASCII ;
else
// lettura dei primi caratteri
char szBuff[9] = "\0\0\0\0\0\0\0\0" ;
int nLen = gzread( InFile, &szBuff, 8) ;
if ( gzclose( InFile) != Z_OK || nLen == Z_ERRNO)
return NGE_ERROR ;
// se binario
if ( szBuff[0] == '\x0F' && szBuff[1] == '\x0F')
return NGE_BINARY ;
// se testo
string sBuff{ szBuff} ;
if ( sBuff.find( "START") != string::npos)
return NGE_ASCII ;
// altrimenti errore
return NGE_ERROR ;
}
//----------------------------------------------------------------------------
@@ -91,7 +91,7 @@ int
NgeReader::GetCurrPos( void)
{
if ( m_bBinary)
return int( m_InFile.tellg()) ;
return int( gztell( m_InFile)) ;
else
return m_Scan.GetCurrLineNbr() ;
}
@@ -131,10 +131,9 @@ bool
NgeReader::ReadUchar( unsigned char& ucVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
m_InFile.read( (char*) &ucVal, sizeof( ucVal)) ;
return m_InFile.good() ;
return ( gzread( m_InFile, &ucVal, sizeof( ucVal)) != Z_ERRNO) ;
}
else {
// recupero il token
@@ -154,10 +153,9 @@ bool
NgeReader::ReadBool( bool& bVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
m_InFile.read( (char*) &bVal, sizeof( bVal)) ;
return m_InFile.good() ;
return ( gzread( m_InFile, &bVal, sizeof( bVal)) != Z_ERRNO) ;
}
else {
// recupero il token
@@ -173,10 +171,9 @@ bool
NgeReader::ReadInt( int& nVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
m_InFile.read( (char*) &nVal, sizeof( nVal)) ;
return m_InFile.good() ;
return ( gzread( m_InFile, &nVal, sizeof( nVal)) != Z_ERRNO) ;
}
else {
// recupero il token
@@ -203,10 +200,9 @@ bool
NgeReader::ReadDouble( double& dVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
m_InFile.read( (char*) &dVal, sizeof( dVal)) ;
return m_InFile.good() ;
return ( gzread( m_InFile, &dVal, sizeof( dVal)) != Z_ERRNO) ;
}
else {
// recupero il token
@@ -222,10 +218,9 @@ bool
NgeReader::ReadVector( Vector3d& vtV, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
m_InFile.read( (char*) &vtV.v, sizeof( vtV.v)) ;
return m_InFile.good() ;
return ( gzread( m_InFile, &vtV.v, sizeof( vtV.v)) != Z_ERRNO) ;
}
else {
// recupero il token
@@ -241,10 +236,9 @@ bool
NgeReader::ReadPoint( Point3d& ptP, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
m_InFile.read( (char*) &ptP.v, sizeof( ptP.v)) ;
return m_InFile.good() ;
return ( gzread( m_InFile, &ptP.v, sizeof( ptP.v)) != Z_ERRNO) ;
}
else {
// recupero il token
@@ -260,11 +254,10 @@ bool
NgeReader::ReadPointW( Point3d& ptP, double& dW, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
m_InFile.read( (char*) &ptP.v, sizeof( ptP.v)) ;
m_InFile.read( (char*) &dW, sizeof( dW)) ;
return m_InFile.good() ;
return ( gzread( m_InFile, &ptP.v, sizeof( ptP.v)) != Z_ERRNO &&
gzread( m_InFile, &dW, sizeof( dW)) != Z_ERRNO) ;
}
else {
// recupero il token
@@ -280,17 +273,13 @@ bool
NgeReader::ReadFrame( Frame3d& frF, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
Point3d ptOrig ;
m_InFile.read( (char*) &ptOrig.v, sizeof( ptOrig.v)) ;
Vector3d vtDirX ;
m_InFile.read( (char*) &vtDirX.v, sizeof( vtDirX.v)) ;
Vector3d vtDirY ;
m_InFile.read( (char*) &vtDirY.v, sizeof( vtDirY.v)) ;
Vector3d vtDirZ ;
m_InFile.read( (char*) &vtDirZ.v, sizeof( vtDirZ.v)) ;
if ( ! m_InFile.good())
Point3d ptOrig ; Vector3d vtDirX, vtDirY, vtDirZ ;
if ( gzread( m_InFile, &ptOrig.v, sizeof( ptOrig.v)) == Z_ERRNO ||
gzread( m_InFile, &vtDirX.v, sizeof( vtDirX.v)) == Z_ERRNO ||
gzread( m_InFile, &vtDirY.v, sizeof( vtDirY.v)) == Z_ERRNO ||
gzread( m_InFile, &vtDirZ.v, sizeof( vtDirZ.v)) == Z_ERRNO)
return false ;
return frF.Set( ptOrig, vtDirX, vtDirY, vtDirZ) ;
}
@@ -308,18 +297,20 @@ bool
NgeReader::ReadString( string& sVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( m_InFile == nullptr)
return false ;
const int MAX_STR_DIM = 65535 ;
if ( ! m_InFile.is_open())
return false ;
int nDim ;
m_InFile.read( (char*) &nDim, sizeof( nDim)) ;
if ( nDim > MAX_STR_DIM || ! m_InFile.good())
if ( gzread( m_InFile, &nDim, sizeof( nDim)) == Z_ERRNO || nDim > MAX_STR_DIM)
return false ;
if ( nDim == 0) {
sVal = "" ;
return true ;
}
char* szBuff = new( nothrow) char[ nDim + 1] ;
if ( szBuff == nullptr)
return false ;
m_InFile.read( szBuff, nDim) ;
if ( ! m_InFile.good()) {
if ( gzread( m_InFile, szBuff, nDim) == Z_ERRNO) {
delete[] szBuff ;
return false ;
}
@@ -348,12 +339,11 @@ NgeReader::ReadKey( int& nKey)
return true ;
}
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
// leggo il dato
int nVal ;
m_InFile.read( (char*) &nVal, sizeof( nVal)) ;
if ( ! m_InFile.good())
if ( gzread( m_InFile, &nVal, sizeof( nVal)) == Z_ERRNO)
return false ;
// ricavo l'indice
for ( int i = 0 ; i <= NGE_LAST_ID ; ++ i) {
@@ -386,11 +376,10 @@ bool
NgeReader::ReadCol( Color& cCol, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_InFile.is_open())
if ( m_InFile == nullptr)
return false ;
unsigned char ucCol[4] ;
m_InFile.read( (char*) &ucCol, sizeof( ucCol)) ;
if ( ! m_InFile.good())
if ( gzread( m_InFile, &ucCol, sizeof( ucCol)) == Z_ERRNO)
return false ;
cCol.Set( ucCol[0], ucCol[1], ucCol[2], ucCol[3]) ;
return true ;
+7 -5
View File
@@ -1,7 +1,7 @@
//----------------------------------------------------------------------------
// EgalTech 2014-2014
// EgalTech 2014-2025
//----------------------------------------------------------------------------
// File : NgeReader.h Data : 14.04.14 Versione : 1.5d5
// File : NgeReader.h Data : 29.12.25 Versione : 2.7l6
// Contenuto : Dichiarazione della classe NgeReader.
//
//
@@ -18,14 +18,16 @@
#include "/EgtDev/Include/EGkColor.h"
#include "/EgtDev/Include/EGnScanner.h"
#include "/EgtDev/Include/EgtStringBase.h"
#include <fstream>
struct gzFile_s ;
//----------------------------------------------------------------------------
class NgeReader
{
public :
NgeReader( void)
: m_iPosStart( std::string::npos), m_bUngetKey( false), m_nFileVer() {}
: m_bBinary( false), m_InFile( nullptr), m_iPosStart( std::string::npos),
m_bUngetKey( false), m_nLastKey(), m_nFileVer() {}
~NgeReader( void)
{ Close() ; }
bool Init( const std::string& sFileIn) ;
@@ -60,7 +62,7 @@ class NgeReader
private :
bool m_bBinary ;
// per file binari
std::ifstream m_InFile ;
gzFile_s* m_InFile ;
// per file ASCII
Scanner m_Scan ;
std::string::size_type m_iPosStart ;
+64 -86
View File
@@ -23,23 +23,23 @@
using namespace std ;
//----------------------------------------------------------------------------
inline bool
WriteStringOutTxt( gzFile OutTxtFile, const char* szVal, const char* szSep, bool bEndL)
static bool
WriteStringOutTxt( gzFile OutFile, const char* szVal, const char* szSep, bool bEndL)
{
// verifico apertura file
if ( OutTxtFile == nullptr)
if ( OutFile == nullptr)
return false ;
// scrivo stringa
if ( gzputs( OutTxtFile, szVal) == Z_ERRNO)
if ( gzputs( OutFile, szVal) == Z_ERRNO)
return false ;
// se fornito, scrivo separatore
if ( szSep != nullptr && szSep[0] != '\0') {
if ( gzputs( OutTxtFile, szSep) == Z_ERRNO)
if ( gzputs( OutFile, szSep) == Z_ERRNO)
return false ;
}
// se richiesto, scrivo fine linea
if ( bEndL) {
if ( gzputs( OutTxtFile, "\r\n") == Z_ERRNO)
if ( gzputs( OutFile, "\r\n") == Z_ERRNO)
return false ;
}
return true ;
@@ -50,27 +50,22 @@ bool
NgeWriter::Init( const string& sFileOut, int nFlag)
{
// salvo tipo file
m_bBinary = ( nFlag == GDB_SV_BIN) ;
m_bBinary = ( nFlag == GDB_SV_BIN || nFlag == GDB_SV_CMPBIN) ;
// apertura del file di uscita
if ( m_bBinary) {
ios_base::openmode nMode = ios::out | ( m_bBinary ? ios::binary : 0) ;
int nProt = _SH_DENYWR ;
m_OutBinFile.open( stringtoW( sFileOut), nMode, nProt) ;
return m_OutBinFile.good() ;
if ( nFlag == GDB_SV_TXT || nFlag == GDB_SV_BIN) {
m_OutFile = gzopen_w( stringtoW( sFileOut), "wbT") ;
return ( m_OutFile != nullptr) ;
}
else {
if ( nFlag == GDB_SV_TXT)
m_OutTxtFile = gzopen_w( stringtoW( sFileOut), "wbT") ;
else // GDB_SV_CMPTXT
m_OutTxtFile = gzopen_w( stringtoW( sFileOut), "wb") ;
if ( m_OutTxtFile == nullptr)
else { // GDB_SV_CMPTXT o GDB_SV_CMPBIN
m_OutFile = gzopen_w( stringtoW( sFileOut), "wb") ;
if ( m_OutFile == nullptr)
return false ;
const int DIM_BUFFER = 65536 ;
if ( gzbuffer( m_OutTxtFile, DIM_BUFFER) != Z_OK)
if ( gzbuffer( m_OutFile, DIM_BUFFER) != Z_OK)
return false ;
const int COMPR_LEVEL = 3 ; // 0 = no compression ... 9 = max compression
if ( gzsetparams( m_OutTxtFile, COMPR_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
if ( gzsetparams( m_OutFile, COMPR_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK)
return false ;
return true ;
}
@@ -80,20 +75,12 @@ NgeWriter::Init( const string& sFileOut, int nFlag)
bool
NgeWriter::Close( void)
{
if ( m_bBinary) {
bool bOk = ( m_OutBinFile.good() && m_OutBinFile.is_open()) ;
if ( m_OutBinFile.is_open())
m_OutBinFile.close() ;
if ( m_OutFile != nullptr) {
bool bOk = ( gzclose( m_OutFile) == Z_OK) ;
m_OutFile = nullptr ;
return bOk ;
}
else {
if ( m_OutTxtFile != nullptr) {
bool bOk = ( gzclose( m_OutTxtFile) == Z_OK) ;
m_OutTxtFile = nullptr ;
return bOk ;
}
return true ;
}
return true ;
}
//----------------------------------------------------------------------------
@@ -101,13 +88,12 @@ bool
NgeWriter::WriteUchar( unsigned char ucVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &ucVal, sizeof( ucVal)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &ucVal, sizeof( ucVal)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( ucVal).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( ucVal).c_str(), szSep, bEndL) ;
}
}
@@ -116,13 +102,12 @@ bool
NgeWriter::WriteBool( bool bVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &bVal, sizeof( bVal)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &bVal, sizeof( bVal)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( bVal).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( bVal).c_str(), szSep, bEndL) ;
}
}
@@ -131,13 +116,12 @@ bool
NgeWriter::WriteInt( int nVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &nVal, sizeof( nVal)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &nVal, sizeof( nVal)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( nVal).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( nVal).c_str(), szSep, bEndL) ;
}
}
@@ -146,13 +130,12 @@ bool
NgeWriter::WriteDouble( double dVal, const char* szSep, bool bEndL, int nPrec)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &dVal, sizeof( dVal)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &dVal, sizeof( dVal)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( dVal, nPrec).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( dVal, nPrec).c_str(), szSep, bEndL) ;
}
}
@@ -161,15 +144,14 @@ bool
NgeWriter::WriteString( const string& sVal, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
int nDim = int( sVal.size()) ;
m_OutBinFile.write( (char*) &nDim, sizeof( nDim)) ;
m_OutBinFile.write( sVal.c_str(), sVal.size()) ;
return m_OutBinFile.good() ;
int nDim = ssize( sVal) ;
return ( gzwrite( m_OutFile, &nDim, sizeof( nDim)) > 0 &&
( nDim == 0 || gzwrite( m_OutFile, sVal.c_str(), sVal.size()) > 0)) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, sVal.c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, sVal.c_str(), szSep, bEndL) ;
}
}
@@ -178,13 +160,12 @@ bool
NgeWriter::WriteVector( const Vector3d& vtV, const char* szSep, bool bEndL, int nPrec)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &vtV.v, sizeof( vtV.v)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &vtV.v, sizeof( vtV.v)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( vtV, nPrec).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( vtV, nPrec).c_str(), szSep, bEndL) ;
}
}
@@ -193,13 +174,12 @@ bool
NgeWriter::WritePoint( const Point3d& ptP, const char* szSep, bool bEndL, int nPrec)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &ptP.v, sizeof( ptP.v)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &ptP.v, sizeof( ptP.v)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( ptP, nPrec).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( ptP, nPrec).c_str(), szSep, bEndL) ;
}
}
@@ -208,14 +188,13 @@ bool
NgeWriter::WritePointW( const Point3d& ptP, double dW, const char* szSep, bool bEndL, int nPrecP, int nPrecW)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &ptP.v, sizeof( ptP.v)) ;
m_OutBinFile.write( (char*) &dW, sizeof( dW)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &ptP.v, sizeof( ptP.v)) > 0 &&
gzwrite( m_OutFile, &dW, sizeof( dW)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( ptP, dW, nPrecP, nPrecW).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( ptP, dW, nPrecP, nPrecW).c_str(), szSep, bEndL) ;
}
}
@@ -224,16 +203,15 @@ bool
NgeWriter::WriteFrame( const Frame3d& frF, const char* szSep, bool bEndL, int nPrecP, int nPrecV)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &frF.Orig().v, sizeof( frF.Orig().v)) ;
m_OutBinFile.write( (char*) &frF.VersX().v, sizeof( frF.VersX().v)) ;
m_OutBinFile.write( (char*) &frF.VersY().v, sizeof( frF.VersY().v)) ;
m_OutBinFile.write( (char*) &frF.VersZ().v, sizeof( frF.VersZ().v)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &frF.Orig().v, sizeof( frF.Orig().v)) > 0 &&
gzwrite( m_OutFile, &frF.VersX().v, sizeof( frF.VersX().v)) > 0 &&
gzwrite( m_OutFile, &frF.VersY().v, sizeof( frF.VersY().v)) > 0 &&
gzwrite( m_OutFile, &frF.VersZ().v, sizeof( frF.VersZ().v)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( frF, nPrecP, nPrecV).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( frF, nPrecP, nPrecV).c_str(), szSep, bEndL) ;
}
}
@@ -245,13 +223,12 @@ NgeWriter::WriteKey( int nKey)
return false ;
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
m_OutBinFile.write( (char*) &NgeBinKeyW[nKey], sizeof( int)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, &NgeBinKeyW[nKey], sizeof( int)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, NgeAscKeyW[nKey].c_str(), nullptr, true) ;
return WriteStringOutTxt( m_OutFile, NgeAscKeyW[nKey].c_str(), nullptr, true) ;
}
}
@@ -260,18 +237,17 @@ bool
NgeWriter::WriteCol( const Color& cCol, const char* szSep, bool bEndL)
{
if ( m_bBinary) {
if ( ! m_OutBinFile.is_open())
if ( m_OutFile == nullptr)
return false ;
unsigned char ucCol[4] ;
ucCol[0] = cCol.GetIntRed() ;
ucCol[1] = cCol.GetIntGreen() ;
ucCol[2] = cCol.GetIntBlue() ;
ucCol[3] = cCol.GetIntAlpha() ;
m_OutBinFile.write( (char*) ucCol, sizeof( ucCol)) ;
return m_OutBinFile.good() ;
return ( gzwrite( m_OutFile, ucCol, sizeof( ucCol)) > 0) ;
}
else {
return WriteStringOutTxt( m_OutTxtFile, ToString( cCol).c_str(), szSep, bEndL) ;
return WriteStringOutTxt( m_OutFile, ToString( cCol).c_str(), szSep, bEndL) ;
}
}
@@ -279,9 +255,11 @@ NgeWriter::WriteCol( const Color& cCol, const char* szSep, bool bEndL)
bool
NgeWriter::WriteRemark( const string& sVal)
{
if ( m_bBinary)
if ( m_bBinary) {
return true ;
else
return ( WriteStringOutTxt( m_OutTxtFile, "//", nullptr, false) &&
WriteStringOutTxt( m_OutTxtFile, sVal.c_str(), nullptr, true)) ;
}
else {
return ( WriteStringOutTxt( m_OutFile, "//", nullptr, false) &&
WriteStringOutTxt( m_OutFile, sVal.c_str(), nullptr, true)) ;
}
}
+5 -9
View File
@@ -1,7 +1,7 @@
//----------------------------------------------------------------------------
// EgalTech 2014-2014
// EgalTech 2014-2025
//----------------------------------------------------------------------------
// File : NgeWriter.h Data : 12.04.14 Versione : 1.5d5
// File : NgeWriter.h Data : 29.12.25 Versione : 2.7l6
// Contenuto : Dichiarazione della classe NgeWriter.
//
//
@@ -16,7 +16,6 @@
#include "NgeConst.h"
#include "/EgtDev/Include/EGkPoint3d.h"
#include "/EgtDev/Include/EGkColor.h"
#include <fstream>
struct gzFile_s ;
@@ -24,7 +23,7 @@ struct gzFile_s ;
class NgeWriter
{
public :
NgeWriter( void) : m_bBinary( false), m_OutTxtFile( nullptr) {}
NgeWriter( void) : m_bBinary( false), m_OutFile( nullptr) {}
~NgeWriter( void)
{ Close() ; }
bool Init( const std::string& sFileOut, int nFlag) ;
@@ -44,9 +43,6 @@ class NgeWriter
bool WriteRemark( const std::string& sVal /* bEndL = true*/) ;
private :
bool m_bBinary ;
// per file binari
std::ofstream m_OutBinFile ;
// per file ASCII
gzFile_s* m_OutTxtFile ;
bool m_bBinary ;
gzFile_s* m_OutFile ;
} ;
+4 -4
View File
@@ -243,11 +243,11 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType)
if ( IsNull( pCrv1))
return false ;
pCrv1->SetTempProp( nInd1) ;
if ( ! pCrv1->SimpleOffset( dDist, ICurve::OFF_FILLET)) {
if ( ! pCrv1->SimpleOffset( dDist)) {
CurveArc* pArc = GetBasicCurveArc( pCrv1) ;
if ( pArc == nullptr)
return false ;
if ( pArc->MyExtendedOffset( dDist, true, ICurve::OFF_FILLET))
if ( pArc->MyExtendedOffset( dDist, true))
pCrv1->SetTempProp( - nInd1) ;
}
// curve successive
@@ -255,11 +255,11 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType)
while ( ! IsNull( pCrv2)) {
// eseguo semplice offset
pCrv2->SetTempProp( nInd1 + 1) ;
if ( ! pCrv2->SimpleOffset( dDist, ICurve::OFF_FILLET)) {
if ( ! pCrv2->SimpleOffset( dDist)) {
CurveArc* pArc = GetBasicCurveArc( pCrv2) ;
if ( pArc == nullptr)
return false ;
if ( pArc->MyExtendedOffset( dDist, true, ICurve::OFF_FILLET))
if ( pArc->MyExtendedOffset( dDist, true))
pCrv2->SetTempProp( - ( nInd1 + 1)) ;
}
// verifico relazione con la curva precedente e aggiungo eventuali curve intermedie
+1
View File
@@ -14,6 +14,7 @@
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "PointsPCA.h"
#define EIGEN_NO_IO
#include "/EgtDev/Extern/Eigen/Dense"
+8 -4
View File
@@ -775,7 +775,7 @@ DouglasPeuckerSimplification( const PNTUVECTOR& vPtU, const double dSqTol, const
//----------------------------------------------------------------------------
bool
PolyLine::RemoveAlignedPoints( double dToler)
PolyLine::RemoveAlignedPoints( double dToler, bool bStartEnd)
{
// se non ci sono almeno 3 punti, esco subito
if ( m_lUPoints.size() < 3)
@@ -825,8 +825,8 @@ PolyLine::RemoveAlignedPoints( double dToler)
// ordino in senso crescente
sort( vInd.begin(), vInd.end()) ;
// se chiusa e almeno 4 punti rimasti, controllo allineamento dell'inizio con precedente e successivo rimasti
if ( IsClosed() && vInd.size() >= 4) {
// se richiesto e chiusa e almeno 4 punti rimasti, controllo allineamento dell'inizio con precedente e successivo rimasti
if ( bStartEnd && IsClosed() && vInd.size() >= 4) {
if ( DistPointLine( vPtU[vInd[0]].first, vPtU[vInd[1]].first, vPtU[vInd[int(vInd.size())-2]].first).IsEpsilon( dToler)) {
vInd.erase( vInd.begin()) ;
vInd.back() = vInd.front() ;
@@ -1531,6 +1531,10 @@ ChangePolyLineStart( PolyLine& plPoly, const Point3d& ptNewStart, double dToler)
return false ;
// Riferimento alla lista dei punti
PNTULIST& LoopList = const_cast<PolyLine&>( plPoly).GetUPointList() ;
// Se il punto inziale è già quello, non faccio nulla
if ( AreSamePointEpsilon( LoopList.begin()->first, ptNewStart, dToler))
return true ;
// Ciclo sui segmenti della polilinea per cercare il segmento più vicino al punto
double dMinSqDist = SQ_INFINITO ;
auto itMinDistEnd = LoopList.end() ;
@@ -1970,7 +1974,7 @@ MatchPolyLinesAddingPoints( const PolyLine& PL1, const PolyLine& PL2, int nType,
for ( int z = int( vbRep2.size()) - 1 ; z >= nCrv2 ; --z)
vbRep2[z] = true ;
}
if( nCrv1 < nPnt1) {
if ( nCrv1 < nPnt1) {
nRep1 += nPnt1 - nCrv1 ;
for ( int z = int( vbRep1.size()) - 1 ; z >= nCrv1 ; --z)
vbRep1[z] = true ;
+22 -14
View File
@@ -172,9 +172,9 @@ PolygonElevationInClosedSurfTm( const Polygon3d& pgFacet, const ISurfTriMesh& Cl
return true ;
}
}
else if ( ( Inters.nILTT == ILTT_VERT || Inters.nILTT == ILTT_EDGE || Inters.nILTT == ILTT_IN) && Inters.dCosDN > EPS_ZERO)
else if ( ( Inters.nILTT == ILTT_VERT || Inters.nILTT == ILTT_EDGE || Inters.nILTT == ILTT_IN) && Inters.dCosDN > EPS_ZERO)
dElev = max( dElev, Inters.dU) ;
else if ( Inters.nILTT == ILTT_SEGM || Inters.nILTT == ILTT_SEGM_ON_EDGE)
else if ( Inters.nILTT == ILTT_SEGM || Inters.nILTT == ILTT_SEGM_ON_EDGE)
dElev = max( dElev, Inters.dU2) ;
}
}
@@ -206,22 +206,30 @@ PolygonElevationInClosedSurfTm( const Polygon3d& pgFacet, const ISurfTriMesh& Cl
if ( vEdges[i].first.z < EPS_SMALL && vEdges[i].second.z < EPS_SMALL)
continue ;
// calcolo il segmento di linea
CurveLine clLine ;
CurveLine clLine ;
if ( ! clLine.Set( vEdges[i].first, vEdges[i].second))
return false ;
// l'elevazione va aggiornata con la massima Z delle eventuali intersezioni dell'edge con il loop
IntersCurveCurve intLL( clLine, ccLoop) ;
IntCrvCrvInfo aInfo ;
for ( int j = 0 ; intLL.GetIntCrvCrvInfo( j, aInfo) ; ++ j) {
dElev = max( dElev, aInfo.IciA[0].ptI.z) ;
if ( aInfo.bOverlap)
dElev = max( dElev, aInfo.IciA[1].ptI.z) ;
// se prima intersezione va da interno ad esterno allora devo considerare il punto iniziale del segmento (vertice)
if ( j == 0 && aInfo.IciA[0].nPrevTy == ICCT_IN)
dElev = max( dElev, vEdges[i].first.z) ;
// se ultima intersezione va da esterno a interno allora devo considerare il punto finale del segmento (vertice)
else if ( j == intLL.GetIntersCount() - 1 && aInfo.IciA[ aInfo.bOverlap ? 1 : 0].nNextTy == ICCT_IN)
dElev = max( dElev, vEdges[i].second.z) ;
if ( intLL.GetIntersCount() == 0) {
Point3d ptM = Media( vEdges[i].first, vEdges[i].second) ;
ptM.z = 0 ;
if ( IsPointInsidePolyLine( ptM, PL, -EPS_SMALL))
dElev = max( dElev, max( vEdges[i].first.z, vEdges[i].second.z)) ;
}
else {
IntCrvCrvInfo aInfo ;
for ( int j = 0 ; intLL.GetIntCrvCrvInfo( j, aInfo) ; ++ j) {
dElev = max( dElev, aInfo.IciA[0].ptI.z) ;
if ( aInfo.bOverlap)
dElev = max( dElev, aInfo.IciA[1].ptI.z) ;
// se prima intersezione va da interno ad esterno allora devo considerare il punto iniziale del segmento (vertice)
if ( j == 0 && aInfo.IciA[0].nPrevTy == ICCT_IN)
dElev = max( dElev, vEdges[i].first.z) ;
// se ultima intersezione va da esterno a interno allora devo considerare il punto finale del segmento (vertice)
else if ( j == intLL.GetIntersCount() - 1 && aInfo.IciA[ aInfo.bOverlap ? 1 : 0].nNextTy == ICCT_IN)
dElev = max( dElev, vEdges[i].second.z) ;
}
}
}
+275 -190
View File
@@ -1,7 +1,7 @@
//----------------------------------------------------------------------------
// EgalTech 2023-2025
// EgalTech 2023-2026
//----------------------------------------------------------------------------
// File : ProjectCurveSurfTm.cpp Data : 29.08.25 Versione : 2.7h2
// File : ProjectCurveSurfTm.cpp Data : 03.01.26 Versione : 3.1a1
// Contenuto : Implementazione funzioni proiezione curve su superficie Trimesh.
//
//
@@ -19,6 +19,7 @@
#include "/EgtDev/Include/EGkDistPointLine.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkDistPointSurfTm.h"
#include "/EgtDev/Include/EGkDistPointSurfBz.h"
#include "/EgtDev/Include/EGkIntersPlanePlane.h"
#include "/EgtDev/Include/EGkIntersLinePlane.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
@@ -59,6 +60,83 @@ PointsInTolerance( const PNT5AXVECTOR& vPt5ax, int nPrec, int nCurr, int nNext,
return true ;
}
//----------------------------------------------------------------------------
static bool
AddPointsOnCorners( PNT5AXVECTOR& vPt5ax)
{
for ( int i = 1 ; i < ssize( vPt5ax) ; ++ i) {
// precedente
int j = i - 1 ;
// se normali tra corrente e precedente oltre limite e punti abbastanza lontani
if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER &&
SqDist( vPt5ax[i].ptP, vPt5ax[j].ptP) > 25 * SQ_EPS_SMALL) {
// intersezione tra le due facce
Plane3d plPlane1 ; plPlane1.Set( vPt5ax[j].ptP, vPt5ax[j].vtDir1) ;
Plane3d plPlane2 ; plPlane2.Set( vPt5ax[i].ptP, vPt5ax[i].vtDir1) ;
Point3d ptEdge ; Vector3d vtEdge ;
if ( IntersPlanePlane( plPlane1, plPlane2, ptEdge, vtEdge) == IPPT_YES) {
Plane3d plPlane3 ; plPlane3.Set(vPt5ax[i].ptP, (vPt5ax[i].ptP - vPt5ax[j].ptP) ^ ( vPt5ax[i].vtDir1 + vPt5ax[j].vtDir1)) ;
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) ;
// 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) {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt - vtLine1 / dLen1 * 2 * EPS_SMALL ;
Pt5ax.vtDir1 = vPt5ax[j].vtDir1 ;
Pt5ax.vtDir2 = vPt5ax[j].vtDir2 ;
Pt5ax.vtDirU = vPt5ax[j].vtDirU ;
Pt5ax.vtDirV = vPt5ax[j].vtDirV ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CVEX ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
else
vPt5ax[j].nFlag = P5AX_CVEX ;
if ( dLen2 > 2 * EPS_SMALL) {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt + vtLine2 / dLen2 * 2 * EPS_SMALL ;
Pt5ax.vtDir1 = vPt5ax[i].vtDir1 ;
Pt5ax.vtDir2 = vPt5ax[i].vtDir2 ;
Pt5ax.vtDirU = vPt5ax[i].vtDirU ;
Pt5ax.vtDirV = vPt5ax[i].vtDirV ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CVEX ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
else
vPt5ax[i].nFlag = P5AX_CVEX ;
}
// altrimenti concavo, aggiungo un solo punto con la direzione media
else {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = Media( vPt5ax[i].vtDir1, vPt5ax[j].vtDir1) ; Pt5ax.vtDir1.Normalize() ;
Pt5ax.vtDir2 = Media( vPt5ax[i].vtDir2, vPt5ax[j].vtDir2) ; Pt5ax.vtDir2.Normalize() ;
Pt5ax.vtDirU = Media( vPt5ax[i].vtDirU, vPt5ax[j].vtDirU) ; Pt5ax.vtDirU.Normalize() ;
Pt5ax.vtDirV = Media( vPt5ax[i].vtDirV, vPt5ax[j].vtDirV) ; Pt5ax.vtDirV.Normalize() ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CONC ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
static bool
RemovePointsInExcess( PNT5AXVECTOR& vPt5ax, double dLinTol, double dMaxSegmLen, bool bTestDir)
@@ -70,7 +148,7 @@ RemovePointsInExcess( PNT5AXVECTOR& vPt5ax, double dLinTol, double dMaxSegmLen,
double dCosAngLim = 1 - dSqTol / ( 2 * LENREF * LENREF) ;
// Cerco gli angoli interni e marco opportunamente i punti nelle vicinanze fino ai limiti prima e dopo
int nInd = 0 ;
while ( nInd < int( vPt5ax.size())) {
while ( nInd < ssize( vPt5ax)) {
if ( vPt5ax[nInd].nFlag == P5AX_CONC) {
// analizzo i punti appena precedenti
int nIpv = nInd - 1 ;
@@ -86,7 +164,7 @@ RemovePointsInExcess( PNT5AXVECTOR& vPt5ax, double dLinTol, double dMaxSegmLen,
}
// analizzo i punti appena successivi
int nInx = nInd + 1 ;
while ( nInx < int( vPt5ax.size())) {
while ( nInx < ssize( vPt5ax)) {
double dSqLen = SqDist( vPt5ax[nInd].ptP, vPt5ax[nInx].ptP) ;
if ( dSqLen < dSqMaxLen)
vPt5ax[nInx].nFlag = P5AX_TO_DELETE ;
@@ -104,7 +182,7 @@ RemovePointsInExcess( PNT5AXVECTOR& vPt5ax, double dLinTol, double dMaxSegmLen,
int nPrec = 0 ;
int nCurr = 1 ;
int nNext = 2 ;
while ( nNext < int( vPt5ax.size())) {
while ( nNext < ssize( vPt5ax)) {
bool bRemove = false ;
// lunghezza del segmento che unisce gli adiacenti
double dSqLen = SqDist( vPt5ax[nPrec].ptP, vPt5ax[nNext].ptP) ;
@@ -161,6 +239,154 @@ RemovePointsInExcess( PNT5AXVECTOR& vPt5ax, double dLinTol, double dMaxSegmLen,
return true ;
}
//----------------------------------------------------------------------------
static const SurfTriMesh*
MyGetAuxSurf( const ISurf* pSrf)
{
if ( pSrf == nullptr)
return nullptr ;
switch ( pSrf->GetType()) {
case SRF_TRIMESH :
return GetBasicSurfTriMesh( pSrf) ;
case SRF_FLATRGN :
return GetBasicSurfFlatRegion( pSrf)->GetAuxSurf() ;
case SRF_BEZIER :
return GetBasicSurfBezier( pSrf)->GetAuxSurf() ;
default :
return nullptr ;
}
}
//----------------------------------------------------------------------------
static bool
ProjectPointOnSurf( const Point3d& ptP, const CISURFPVECTOR& vpSurf, double dPar, Point5ax& Pt5ax)
{
// punto sulle superfici a minima distanza
int nSurfMin = -1 ;
int nTriaMin = -1 ;
double dUMin = -1, dVMin = -1 ;
Point3d ptMin ;
double dMinDist = NAN ;
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
// punto sulla superficie a minima distanza
int nSrfType = ( vpSurf[i] != nullptr ? vpSurf[i]->GetType() : GEO_NONE) ;
if ( nSrfType == SRF_TRIMESH || nSrfType == SRF_FLATRGN) {
DistPointSurfTm dPS( ptP, *MyGetAuxSurf( vpSurf[i])) ;
double dDist ;
if ( dPS.GetDist( dDist) && ( nSurfMin == -1 || dDist < dMinDist)) {
nSurfMin = i ;
dPS.GetMinDistPoint( ptMin) ;
dPS.GetMinDistTriaIndex ( nTriaMin) ;
dMinDist = dDist ;
}
}
else if ( nSrfType == SRF_BEZIER) {
DistPointSurfBz dPS( ptP, *GetBasicSurfBezier( vpSurf[i])) ;
double dDist ;
if ( dPS.GetDist( dDist) && ( nSurfMin == -1 || dDist < dMinDist)) {
nSurfMin = i ;
dPS.GetMinDistPoint( ptMin) ;
dPS.GetParamsAtMinDistPoint( dUMin, dVMin) ;
dMinDist = dDist ;
}
}
}
// se trovato
if ( nSurfMin >= 0) {
// assegno il punto
Point3d ptInt = ptMin ;
// calcolo gli altri dati
int nSrfType = ( vpSurf[nSurfMin] != nullptr ? vpSurf[nSurfMin]->GetType() : GEO_NONE) ;
if ( nSrfType == SRF_TRIMESH || nSrfType == SRF_FLATRGN) {
// recupero superficie trimesh
const SurfTriMesh* pSurfTm = MyGetAuxSurf( vpSurf[nSurfMin]) ;
// calcolo la normale (si calcola smooth, in caso di errore si prende quella del triangolo)
Triangle3dEx trTria ;
if ( ! pSurfTm->GetTriangle( nTriaMin, trTria))
return false ;
Vector3d vtN ;
if ( ! CalcNormal( ptMin, trTria, vtN))
vtN = trTria.GetN() ;
// assegno valori al punto 5assi
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = vtN ;
Pt5ax.vtDir2 = vtN ;
Pt5ax.vtDirU = V_NULL ;
Pt5ax.vtDirV = V_NULL ;
Pt5ax.dPar = dPar ;
Pt5ax.nFlag = P5AX_STD ;
}
else if ( nSrfType == SRF_BEZIER) {
Point3d ptSB ;
Vector3d vtN, vtDerU, vtDerV ;
if ( ! GetBasicSurfBezier( vpSurf[nSurfMin])->GetPointNrmD1D2( dUMin, dVMin, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS,
ptSB, vtN, &vtDerU, &vtDerV))
return false ;
vtDerU.Normalize() ;
vtDerV.Normalize() ;
// assegno valori al punto 5assi
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = vtN ;
Pt5ax.vtDir2 = vtN ;
Pt5ax.vtDirU = vtDerU ;
Pt5ax.vtDirV = vtDerV ;
Pt5ax.dPar = dPar ;
Pt5ax.nFlag = P5AX_STD ;
}
// ritorno con successo
return true ;
}
return false ;
}
//----------------------------------------------------------------------------
bool
ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf,
double dLinTol, double dMaxSegmLen, bool bSharpEdges, PNT5AXVECTOR& vPt5ax)
{
// 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 ;
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
! PL.RemoveAlignedPoints( dLinTol, false) )
return false ;
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
return false ;
// 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 ;
Point3d ptP ;
bool bFound = PL.GetFirstUPoint( &dPar, &ptP) ;
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) ;
}
// se richiesto, inserimento punti intermedi in presenza di spigoli
if ( bSharpEdges)
AddPointsOnCorners( vPt5ax) ;
// rimozione punti in eccesso rispetto alle tolleranze
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
return true ;
}
//----------------------------------------------------------------------------
// --- vettore di oggetti intersezione massiva rette parallele SurfTM --------
typedef std::vector<IntersParLinesSurfTm*> INTPARLINESTMPVECTOR ;
@@ -173,11 +399,11 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const Frame
Point3d ptL = GetToLoc( ptP, frRefLine) ;
int nInd = -1 ;
IntLinStmInfo IntRes ;
for ( int i = 0 ; i < int( vpIntPLSTM.size()) ; ++ i) {
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 = int( vIntRes.size()) - 1 ;
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
@@ -216,6 +442,8 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const Frame
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = vtN ;
Pt5ax.vtDir2 = frRefLine.VersZ() ;
Pt5ax.vtDirU = V_NULL ;
Pt5ax.vtDirV = V_NULL ;
Pt5ax.dPar = dPar ;
Pt5ax.nFlag = P5AX_STD ;
// ritorno con successo
@@ -231,7 +459,7 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vect
{
// sistemazioni per tipo di superficie
CISRFTMPVECTOR vpSurfTm ;
for ( int i = 0 ; i < int( vpSurf.size()) ; ++ i) {
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
const SurfTriMesh* pSurfTm = nullptr ;
switch ( vpSurf[i]->GetType()) {
case SRF_TRIMESH :
@@ -257,9 +485,11 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vect
// controllo le tolleranze
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
// approssimo la curva con una polilinea alla massima risoluzione
// approssimo la curva con una polilinea entro la tolleranza
PolyLine PL ;
if ( ! crCrv.ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
! PL.RemoveAlignedPoints( dLinTol, false) )
return false ;
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
@@ -270,10 +500,10 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vect
if ( ! frRefLine.Set( ORIG, vtDir))
return false ;
INTPARLINESTMPVECTOR vpIntPLSTM ; vpIntPLSTM.reserve( vpSurfTm.size()) ;
for ( int i = 0 ; i < int( vpSurfTm.size()) ; ++ i) {
for ( int i = 0 ; i < ssize( vpSurfTm) ; ++ i) {
IntersParLinesSurfTm* pIntPLSTM = new IntersParLinesSurfTm( frRefLine, *vpSurfTm[i]) ;
if ( pIntPLSTM == nullptr) {
for ( int j = 0 ; j < int( vpIntPLSTM.size()) ; ++ j)
for ( int j = 0 ; j < ssize( vpIntPLSTM) ; ++ j)
delete vpIntPLSTM[j] ;
return false ;
}
@@ -298,72 +528,12 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const Vect
}
// Libero oggetti per calcolo massivo
for ( int i = 0 ; i < int( vpIntPLSTM.size()) ; ++ i)
for ( int i = 0 ; i < ssize( vpIntPLSTM) ; ++ i)
delete vpIntPLSTM[i] ;
// se richiesto, inserimento punti intermedi in presenza di spigoli
if ( bSharpEdges) {
for ( int i = 1 ; i < int( vPt5ax.size()) ; ++ i) {
// precedente
int j = i - 1 ;
// se normali tra corrente e precedente oltre limite e punti abbastanza lontani
if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER &&
SqDist( vPt5ax[i].ptP, vPt5ax[j].ptP) > 25 * SQ_EPS_SMALL) {
// intersezione tra le due facce
Plane3d plPlane1 ; plPlane1.Set( vPt5ax[j].ptP, vPt5ax[j].vtDir1) ;
Plane3d plPlane2 ; plPlane2.Set( vPt5ax[i].ptP, vPt5ax[i].vtDir1) ;
Point3d ptEdge ; Vector3d vtEdge ;
if ( IntersPlanePlane( plPlane1, plPlane2, ptEdge, vtEdge) == IPPT_YES) {
Plane3d plPlane3 ; plPlane3.Set( vPt5ax[i].ptP, ( vPt5ax[i].ptP - vPt5ax[j].ptP) ^ vtDir) ;
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) ;
// 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) {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt - vtLine1 / dLen1 * 2 * EPS_SMALL ;
Pt5ax.vtDir1 = vPt5ax[j].vtDir1 ;
Pt5ax.vtDir2 = vtDir ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CVEX ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
if ( dLen2 > 2 * EPS_SMALL) {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt + vtLine2 / dLen2 * 2 * EPS_SMALL ;
Pt5ax.vtDir1 = vPt5ax[i].vtDir1 ;
Pt5ax.vtDir2 = vtDir ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CVEX ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
}
// altrimenti concavo, aggiungo un solo punto con la direzione media
else {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = Media( vPt5ax[i].vtDir1, vPt5ax[j].vtDir1) ;
Pt5ax.vtDir2 = vtDir ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CONC ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
}
}
}
}
}
if ( bSharpEdges)
AddPointsOnCorners( vPt5ax) ;
// rimozione punti in eccesso rispetto alle tolleranze
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
@@ -385,11 +555,11 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const IGeoP
// conservo l'intersezione più alta
int nInd = -1 ;
IntLinStmInfo IntRes ;
for ( int i = 0 ; i < int( vpStm.size()) ; ++ i) {
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 = int( vIntRes.size()) - 1 ;
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
@@ -428,6 +598,8 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const IGeoP
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = vtN ;
Pt5ax.vtDir2 = vtLine ;
Pt5ax.vtDirU = V_NULL ;
Pt5ax.vtDirV = V_NULL ;
Pt5ax.dPar = dPar ;
Pt5ax.nFlag = P5AX_STD ;
// ritorno con successo
@@ -444,7 +616,7 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeo
{
// sistemazioni per tipo di superficie
CISRFTMPVECTOR vpSurfTm ;
for ( int i = 0 ; i < int( vpSurf.size()) ; ++ i) {
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
const SurfTriMesh* pSurfTm = nullptr ;
switch ( vpSurf[i]->GetType()) {
case SRF_TRIMESH :
@@ -471,9 +643,10 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeo
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
// approssimo la curva con una polilinea entro la metà della tolleranza
// approssimo la curva con una polilinea entro la tolleranza
PolyLine PL ;
if ( ! crCrv.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
! PL.RemoveAlignedPoints( dLinTol, false) )
return false ;
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
@@ -497,25 +670,8 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const IGeo
}
// se richiesto, inserimento punti intermedi in presenza di spigoli
if ( bSharpEdges) {
for ( int i = 1 ; i < int( vPt5ax.size()) ; ++ i) {
// precedente
int j = i - 1 ;
// se normali tra corrente e precedente oltre limite e punti abbastanza lontani
if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER &&
SqDist( vPt5ax[i].ptP, vPt5ax[j].ptP) > 25 * SQ_EPS_SMALL) {
// punto medio
Point3d ptMid = Media( vPt5ax[i].ptP, vPt5ax[j].ptP) ;
double dMid = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
// se trovo proiezione, la salvo
Point5ax Pt5ax ;
if ( ProjectPointOnSurf( ptMid, vpSurfTm, gpRef, dMid, Pt5ax)) {
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
-- i ;
}
}
}
}
if ( bSharpEdges)
AddPointsOnCorners( vPt5ax) ;
// rimozione punti in eccesso rispetto alle tolleranze
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
@@ -540,11 +696,11 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurv
// conservo l'intersezione più alta
int nInd = -1 ;
IntLinStmInfo IntRes ;
for ( int i = 0 ; i < int( vpStm.size()) ; ++ i) {
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 = int( vIntRes.size()) - 1 ;
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
@@ -583,6 +739,8 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const ICurv
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = vtN ;
Pt5ax.vtDir2 = vtLine ;
Pt5ax.vtDirU = V_NULL ;
Pt5ax.vtDirV = V_NULL ;
Pt5ax.dPar = dPar ;
Pt5ax.nFlag = P5AX_STD ;
// ritorno con successo
@@ -600,7 +758,7 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICur
{
// Sistemazioni per tipo di superficie
CISRFTMPVECTOR vpSurfTm ;
for ( int i = 0 ; i < int( vpSurf.size()) ; ++ i) {
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
const SurfTriMesh* pSurfTm = nullptr ;
switch ( vpSurf[i]->GetType()) {
case SRF_TRIMESH :
@@ -627,9 +785,10 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICur
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
// Approssimo la curva con una polilinea alla massima risoluzione
// Approssimo la curva con una polilinea entro la tolleranza
PolyLine PL ;
if ( ! crCrv.ApproxWithLines( EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
! PL.RemoveAlignedPoints( dLinTol, false) )
return false ;
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
@@ -653,68 +812,8 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ICur
}
// se richiesto, inserimento punti intermedi in presenza di spigoli
if ( bSharpEdges) {
for ( int i = 1 ; i < int( vPt5ax.size()) ; ++ i) {
// precedente
int j = i - 1 ;
// se normali tra corrente e precedente oltre limite e punti abbastanza lontani
if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER &&
SqDist( vPt5ax[i].ptP, vPt5ax[j].ptP) > 25 * SQ_EPS_SMALL) {
// intersezione tra le due facce
Plane3d plPlane1 ; plPlane1.Set( vPt5ax[j].ptP, vPt5ax[j].vtDir1) ;
Plane3d plPlane2 ; plPlane2.Set( vPt5ax[i].ptP, vPt5ax[i].vtDir1) ;
Point3d ptEdge ; Vector3d vtEdge ;
if ( IntersPlanePlane( plPlane1, plPlane2, ptEdge, vtEdge) == IPPT_YES) {
Plane3d plPlane3 ; plPlane3.Set( vPt5ax[i].ptP, vPt5ax[i].vtDir2 ^ vPt5ax[j].vtDir2) ;
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) ;
// 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) {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt - vtLine1 / dLen1 * 2 * EPS_SMALL ;
Pt5ax.vtDir1 = vPt5ax[j].vtDir1 ;
Pt5ax.vtDir2 = Media( vPt5ax[i].vtDir2, vPt5ax[j].vtDir2) ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CVEX ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
if ( dLen2 > 2 * EPS_SMALL) {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt + vtLine2 / dLen2 * 2 * EPS_SMALL ;
Pt5ax.vtDir1 = vPt5ax[i].vtDir1 ;
Pt5ax.vtDir2 = Media( vPt5ax[i].vtDir2, vPt5ax[j].vtDir2) ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CVEX ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
}
// altrimenti concavo, aggiungo un solo punto con la direzione media
else {
Point5ax Pt5ax ;
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = Media( vPt5ax[i].vtDir1, vPt5ax[j].vtDir1) ;
Pt5ax.vtDir2 = Media( vPt5ax[i].vtDir2, vPt5ax[j].vtDir2) ;
Pt5ax.dPar = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
Pt5ax.nFlag = P5AX_CONC ;
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
++ i ;
}
}
}
}
}
}
if ( bSharpEdges)
AddPointsOnCorners( vPt5ax) ;
// rimozione punti in eccesso rispetto alle tolleranze
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
@@ -748,11 +847,11 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const SurfT
// intersezione della retta con le superfici (conservo l'intersezione più alta)
int nInd = -1 ;
IntLinStmInfo IntRes ;
for ( int i = 0 ; i < int( vpStm.size()) ; ++ i) {
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 = int( vIntRes.size()) - 1 ;
int nI = ssize( vIntRes) - 1 ;
while ( nI >= 0 && abs( vIntRes[nI].dCosDN) < COS_ANG_LIM)
--nI ;
// se trovata
@@ -798,6 +897,8 @@ ProjectPointOnSurf( const Point3d& ptP, const CISRFTMPVECTOR& vpStm, const SurfT
Pt5ax.ptP = ptInt ;
Pt5ax.vtDir1 = vtN ;
Pt5ax.vtDir2 = vtN2 ;
Pt5ax.vtDirU = V_NULL ;
Pt5ax.vtDirV = V_NULL ;
Pt5ax.dPar = dPar ;
Pt5ax.nFlag = P5AX_STD ;
// ritorno con successo
@@ -814,7 +915,7 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISur
{
// sistemazioni per tipo di superficie
CISRFTMPVECTOR vpSurfTm ;
for ( int i = 0 ; i < int( vpSurf.size()) ; ++ i) {
for ( int i = 0 ; i < ssize( vpSurf) ; ++ i) {
const SurfTriMesh* pSurfTm = nullptr ;
switch ( vpSurf[i]->GetType()) {
case SRF_TRIMESH :
@@ -862,9 +963,10 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISur
dLinTol = max( dLinTol, LIN_TOL_MIN) ;
dMaxSegmLen = max( dMaxSegmLen, 10 * EPS_SMALL) ;
// approssimo la curva con una polilinea entro la metà della tolleranza
// approssimo la curva con una polilinea entro la tolleranza
PolyLine PL ;
if ( ! crCrv.ApproxWithLines( dLinTol, ANG_TOL_STD_DEG, ICurve::APL_STD, PL))
if ( ! crCrv.ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_SPECIAL, PL) ||
! PL.RemoveAlignedPoints( dLinTol, false) )
return false ;
const double MAX_SEG_LEN = min( dMaxSegmLen, 0.977) ;
if ( ! PL.AdjustForMaxSegmentLen( MAX_SEG_LEN))
@@ -888,25 +990,8 @@ ProjectCurveOnSurf( const ICurve& crCrv, const CISURFPVECTOR& vpSurf, const ISur
}
// se richiesto, inserimento punti intermedi in presenza di spigoli
if ( bSharpEdges) {
for ( int i = 1 ; i < int( vPt5ax.size()) ; ++ i) {
// precedente
int j = i - 1 ;
// se normali tra corrente e precedente oltre limite e punti abbastanza lontani
if ( vPt5ax[i].vtDir1 * vPt5ax[j].vtDir1 < COS_ANG_MAX_CORNER &&
SqDist( vPt5ax[i].ptP, vPt5ax[j].ptP) > 25 * SQ_EPS_SMALL) {
// punto medio
Point3d ptMid = Media( vPt5ax[i].ptP, vPt5ax[j].ptP) ;
double dMid = ( vPt5ax[i].dPar + vPt5ax[j].dPar) / 2 ;
// se trovo proiezione, la salvo
Point5ax Pt5ax ;
if ( ProjectPointOnSurf( ptMid, vpSurfTm, *pRefTm, dMid, Pt5ax)) {
vPt5ax.insert( vPt5ax.begin() + i, Pt5ax) ;
-- i ;
}
}
}
}
if ( bSharpEdges)
AddPointsOnCorners( vPt5ax) ;
// rimozione punti in eccesso rispetto alle tolleranze
RemovePointsInExcess( vPt5ax, dLinTol, dMaxSegmLen, bSharpEdges) ;
+58 -22
View File
@@ -78,7 +78,7 @@ GetSurfBezierByRegion( const CICURVEPVECTOR& vpCurve, double dLinTol)
for ( int i = 0 ; i < int( vnPLIndMat.size()) ; ++i) {
for ( int j = 0 ; j < int( vnPLIndMat[i].size()) ; ++j){
vPLOrd.push_back(vPL[vnPLIndMat[i][j]]) ;
if( vbInvert[vnPLIndMat[i][j]])
if ( vbInvert[vnPLIndMat[i][j]])
vPLOrd.back().Invert() ;
}
}
@@ -221,7 +221,7 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
const ICurveComposite* pCC = GetCurveComposite( pGuide) ;
for ( int i = 0 ; i < pCC->GetCurveCount() && bGuideIsPolyLine ; ++i) {
const ICurve* pCrv = pCC->GetCurve( i) ;
if( pCrv->GetType() != CRV_LINE) {
if ( pCrv->GetType() != CRV_LINE) {
if ( pCrv->GetType() == CRV_BEZIER) {
const ICurveBezier* pCrvBez = GetCurveBezier( pCrv) ;
bGuideIsPolyLine = pCrvBez->IsALine() ;
@@ -249,7 +249,7 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
int nSpanV = 0 ;
PtrOwner<ICurveComposite> pCrvV( CreateCurveComposite()) ;
if ( bGuideIsPolyLine ) {
if( pGuide->GetType() == CRV_LINE)
if ( pGuide->GetType() == CRV_LINE)
nSpanV = 1 ;
else if ( pGuide->GetType() == CRV_COMPO)
nSpanV = GetCurveComposite( pGuide)->GetCurveCount() ;
@@ -260,7 +260,7 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
pCrvV->AddCurve( CurveToBezierCurve( pGuide, 3, false)) ;
else {
const ICurveBezier* pGuideBez = GetCurveBezier( pGuide) ;
if( ! pGuideBez->IsRational())
if ( ! pGuideBez->IsRational())
pCrvV->AddCurve( pGuide->Clone()) ;
else
pCrvV->AddCurve( EditBezierCurve( pGuideBez, 3, false)) ;
@@ -297,7 +297,7 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
ICRVCOMPOPOVECTOR vCC ;
INTMATRIX mRep ; mRep.resize( nSpanU * nDegU + 1) ;
int nMaxSpanV = nSpanV ;
for( int i = 0 ; i < nSpanU ; ++i) {
for ( int i = 0 ; i < nSpanU ; ++i) {
const ICurveBezier* pSubCrv = GetCurveBezier( pCrvU->GetCurve( i)) ;
for ( int j = i==0 ? 0 : 1 ; j < nDegU + 1 ; ++j ) {
Point3d ptCtrl = pSubCrv->GetControlPoint( j) ;
@@ -327,7 +327,7 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
for ( int w = 0 ; w < int( vCC.size()) ; ++w) {
const ICurveComposite* pCCOther = vCC[w] ;
int nPropCheck = -1 ; pCCOther->GetCurveTempProp( z, nPropCheck) ;
if( nPropCheck != 0)
if ( nPropCheck != 0)
mRep[w][z] = 1 ;
}
}
@@ -337,11 +337,11 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
// conto in quante colonne di mRep la somma degli elementi è != 0
// questo numero va aggiunto all'attuale nSpanV
int nSpanPlus = 0 ;
for( int z = 0 ; z < nMaxSpanV ; ++z) {
for ( int z = 0 ; z < nMaxSpanV ; ++z) {
int nPosTot = 0 ;
for ( int k = 0 ; k < int( mRep.size()) ; ++k )
nPosTot += mRep[k][z] ;
if( nPosTot != 0)
if ( nPosTot != 0)
nSpanPlus += 1 ;
}
nMaxSpanV = max( nMaxSpanV, nSpanV + nSpanPlus) ;
@@ -349,14 +349,14 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
pSurfBez->Init( nDegU,nDegV, nSpanU, nSpanV, bRat) ;
//// aggiungo i punti di controllo alla superficie
//for( int i = 0 ; i < nSpanU ; ++i) {
//for ( int i = 0 ; i < nSpanU ; ++i) {
// for ( int j = i==0 ? 0 : 1 ; j < nDegU + 1 ; ++j ) {
// const ICurveComposite* pOffsetCrv = vCC[i*nDegU + j] ;
// for ( int z = 0 ; z < pOffsetCrv->GetCurveCount() ; ++z) {
// const ICurveLine* pCL = GetCurveLine( pOffsetCrv->GetCurve( z)) ;
// if( pCL == nullptr)
// if ( pCL == nullptr)
// return nullptr ;
// if( z == 0) {
// if ( z == 0) {
// Point3d ptSubStart ; pCL->GetStartPoint( ptSubStart) ;
// pSurfBez->SetControlPoint( i * nDegU + j, 0, ptSubStart) ;
// }
@@ -367,13 +367,13 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
//}
//// aggiungo i punti di controllo alla superficie /// DA CORREGGERE L'AGGIUNTA DEI PUNTI DI CONTROLLO
//for( int i = 0 ; i < int( vCC.size()) ; ++i) {
//for ( int i = 0 ; i < int( vCC.size()) ; ++i) {
// const ICurveComposite* pOffsetCrv = vCC[i] ;
// for ( int z = 0 ; z < pOffsetCrv->GetCurveCount() ; ++z) {
// const ICurveLine* pCL = GetCurveLine( pOffsetCrv->GetCurve( z)) ;
// if( pCL == nullptr)
// if ( pCL == nullptr)
// return nullptr ;
// if( z == 0) {
// if ( z == 0) {
// Point3d ptSubStart ; pCL->GetStartPoint( ptSubStart) ;
// pSurfBez->SetControlPoint( i * nDegU + j, 0, ptSubStart) ;
// }
@@ -422,7 +422,7 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
//frStart.Set( ptStart, -vtStart, vtStart ^ vtNorm) ;
//// porto la sezione nel sistema di riferimento del piano in cui giace
//pCrvU->ToLoc( frStart) ;
//for( int i = 0 ; i < nSpanU ; ++i) {
//for ( int i = 0 ; i < nSpanU ; ++i) {
// const ICurveBezier* pSubCrv = GetCurveBezier( pCrvU->GetCurve( i)) ;
// for ( int j = i==0 ? 0 : 1 ; j < nDegU + 1 ; ++j ) {
// Point3d ptCtrl = pSubCrv->GetControlPoint( j) ;
@@ -458,7 +458,7 @@ GetSurfBezierSweptInPlane( const ICurve* pSect, const ICurve* pGuide, const Vect
// // aggiungo i punti di controllo alla superficie
// for ( int z = 0 ; z < nSpanV ; ++z) {
// const ICurveBezier* pCrvBez = GetCurveBezier( pCrvV->GetCurve( z)) ;
// if( pCrvBez == nullptr)
// if ( pCrvBez == nullptr)
// return nullptr ;
// for ( int k = z == 0 ? 0 : 1 ; k < nDegV ; ++k) {
// Point3d ptCtrl = pCrvBez->GetControlPoint( k) ;
@@ -572,7 +572,7 @@ GetSurfBezierSwept3d( const ICurve* pSect, const ICurve* pGuide, const Vector3d&
pCrvU->AddCurve( CurveToBezierCurve( pSect, 3, false)) ;
else {
const ICurveBezier* pSectBez = GetCurveBezier( pSect) ;
if( ! pSectBez->IsRational())
if ( ! pSectBez->IsRational())
pCrvU->AddCurve( pSect->Clone()) ; ///// questa curva potrebbe non essere di grado 3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
else
pCrvU->AddCurve( EditBezierCurve( pSectBez, 3, false)) ;
@@ -709,7 +709,7 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou
// se la curva è già una bezier singola la tengo, sennò la converto
PtrOwner<ICurveComposite> pCC1( CreateCurveComposite()) ;
if ( pCurve1->GetType() != CRV_BEZIER)
pCC1->AddCurve( CurveToBezierCurve( pCurve1, true, false)) ;
pCC1->AddCurve( CurveToBezierCurve( pCurve1, 3, false)) ;
else
pCC1->AddCurve( pCurve1->Clone()) ;
if ( IsNull( pCC1) || ! pCC1->IsValid())
@@ -718,7 +718,7 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou
// se la curva è già una bezier singola la tengo, sennò la converto
PtrOwner<ICurveComposite> pCC2( CreateCurveComposite()) ;
if ( pCurve2->GetType() != CRV_BEZIER)
pCC2->AddCurve( CurveToBezierCurve( pCurve2, true, false)) ;
pCC2->AddCurve( CurveToBezierCurve( pCurve2, 3, false)) ;
else
pCC2->AddCurve( pCurve2->Clone()) ;
if ( IsNull( pCC2) || ! pCC2->IsValid())
@@ -733,18 +733,54 @@ GetSurfBezierRuled( const ICurve* pCurve1, const ICurve* pCurve2, int nType, dou
return Release( pSbz) ;
}
//-------------------------------------------------------------------------------
ISurfBezier*
GetSurfBezierRuledGuided( const ICurve* pCurve1, const ICurve* pCurve2, const BIPNTVECTOR& vCrv, double dLinTol)
{
// verifica parametri
if ( pCurve1 == nullptr || pCurve2 == nullptr)
return nullptr ;
// dLinTol servirà quando ci sarà la funzione ApproxWithCurveBezier
// se la curva è già una bezier singola la tengo, sennò la converto
PtrOwner<ICurveComposite> pCC1( CreateCurveComposite()) ;
if ( pCurve1->GetType() != CRV_BEZIER)
pCC1->AddCurve( CurveToBezierCurve( pCurve1, 3, false)) ;
else
pCC1->AddCurve( pCurve1->Clone()) ;
if ( IsNull( pCC1) || ! pCC1->IsValid())
return nullptr ;
// se la curva è già una bezier singola la tengo, sennò la converto
PtrOwner<ICurveComposite> pCC2( CreateCurveComposite()) ;
if ( pCurve2->GetType() != CRV_BEZIER)
pCC2->AddCurve( CurveToBezierCurve( pCurve2, 3, false)) ;
else
pCC2->AddCurve( pCurve2->Clone()) ;
if ( IsNull( pCC2) || ! pCC2->IsValid())
return nullptr ;
// creo e setto la superficie trimesh
PtrOwner<SurfBezier> pSbz( CreateBasicSurfBezier()) ;
if ( IsNull( pSbz) || ! pSbz->CreateByIsoParamSet( pCC1, pCC2, vCrv))
return nullptr ;
// restituisco la superficie
return Release( pSbz) ;
}
//-------------------------------------------------------------------------------
ISurfBezier*
GetSurfBezierSkinned( const CICURVEPVECTOR& vCrv, double dLinTol)
{
// verifico che le curve siano valide
for ( int i = 0 ; i < int( vCrv.size()) ; ++i) {
if( vCrv[i] == nullptr || ! vCrv[i]->IsValid())
if ( vCrv[i] == nullptr || ! vCrv[i]->IsValid())
return nullptr ;
}
// se ho solo due curve allora faccio la rigata
if( vCrv.size() == 2)
if ( vCrv.size() == 2)
return GetSurfBezierRuled( vCrv[0], vCrv[1], ISurfBezier::RLT_B_MINDIST_PLUS, dLinTol) ;
//trasformo le curve in curve di bezier, pareggio il numero di sottocurve e il grado
@@ -752,7 +788,7 @@ GetSurfBezierSkinned( const CICURVEPVECTOR& vCrv, double dLinTol)
// dLinTol servirà quando ci sarà la funzione ApproxWithCurveBezier
// se la curva è già una bezier singola la tengo, sennò la converto
ICURVEPOVECTOR vCrvBez ;
for( int c = 0 ; c < int( vCrv.size()) ; ++c){
for ( int c = 0 ; c < int( vCrv.size()) ; ++c){
PtrOwner<ICurveComposite> pCC( CreateCurveComposite()) ;
if ( vCrv[c]->GetType() != CRV_BEZIER )
pCC->AddCurve( CurveToBezierCurve( vCrv[c])) ;
+2 -2
View File
@@ -73,7 +73,7 @@ GetSurfTriMeshByRegion( const CICURVEPVECTOR& vpCurve, double dLinTol)
return nullptr ;
for ( int i = 0 ; i < int( vnPLIndMat.size()) ; ++i) {
for ( int j = 0 ; j < int( vnPLIndMat[i].size()) ; ++j){
if( vbInvert[vnPLIndMat[i][j]])
if ( vbInvert[vnPLIndMat[i][j]])
vPL[vnPLIndMat[i][j]].Invert() ;
}
}
@@ -165,7 +165,7 @@ GetSurfTriMeshByRegionExtrusion( const CICURVEPVECTOR& vpCurve, const Vector3d&
if ( ! CalcRegionPolyLines( vPL, vtN, vnPLIndMat, vbInvert))
return nullptr ;
for ( int i = 0 ; i < int( vPL.size()) ; ++i) {
if( vbInvert[i])
if ( vbInvert[i])
vPL[i].Invert() ;
}
// verifico la direzione di estrusione
+14 -7
View File
@@ -76,11 +76,18 @@ FromString( const string& sVal, Frame3d& frFrame)
bool
FromString( const string& sVal, Color& cCol)
{
// devono essere 4 parametri : Red, Green, Blue, Alpha
int vnVal[4] ;
if ( ! FromString( sVal, vnVal))
return false ;
// assegno il colore
cCol.Set( vnVal[0], vnVal[1], vnVal[2], vnVal[3]) ;
return true ;
// dovrebbero essere 4 parametri : Red, Green, Blue, Alpha
int vnRGBA[4] ;
if ( FromString( sVal, vnRGBA)) {
cCol.Set( vnRGBA[0], vnRGBA[1], vnRGBA[2], vnRGBA[3]) ;
return true ;
}
// riprovo con 3 parametri : Red, Green, Blue
int vnRGB[3] ;
if ( FromString( sVal, vnRGB)) {
cCol.Set( vnRGB[0], vnRGB[1], vnRGB[2]) ;
return true ;
}
// altrimenti errore
return false ;
}
+1 -1
View File
@@ -302,7 +302,7 @@ SetTmpPropByOverlap( ICurveComposite* pCrvCheck, const int nInd, const ICurveCom
// ultimo tratto di curva della Composita iniziale
PtrOwner<CurveComposite> pCrvB( GetBasicCurveComposite( pCrvCheck->CopyParamRange( nInd + 1, pCrvCheck->GetCurveCount()))) ;
if ( ! IsNull( pCrvB) && pCrvB->GetCurveCount() > 0 && pCrvB->IsValid())
if( ! pCrvToReturn->AddCurve( Release( pCrvB))) {
if ( ! pCrvToReturn->AddCurve( Release( pCrvB))) {
nStat = 2 ;
return true ;
}
+223 -65
View File
@@ -24,6 +24,13 @@
#include "/EgtDev/Include/EGkSurfAux.h"
#include "/EgtDev/Include/EGkSfrCreate.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#define SAVEMKUNIF_CRVS 0
#if SAVEMKUNIF_CRVS
#include "/EgtDev/Include/EGkGeoObjSave.h"
#endif
using namespace std ;
@@ -37,12 +44,12 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData)
bool bIsRational = snData.bRat ;
// vettore dei nodi
DBLVECTOR vU ;
int nKnot = (int) snData.vU.size() ;
int nKnot = ssize( snData.vU) ;
for ( int k = 0 ; k < nKnot ; ++k ) {
double dKnot = snData.vU[k] ;
vU.push_back( dKnot) ;
}
for( int j = 0 ; j < snData.nCPV ; ++j) {
for ( int j = 0 ; j < snData.nCPV ; ++j) {
CNurbsData nuCurve ;
nuCurve.bPeriodic = true ;
nuCurve.bRat = snData.bRat ;
@@ -66,12 +73,16 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData)
if ( NurbsCurveCanonicalize( nuCurve)) { // se NurbsCurveCanonicalize ha restituito false (la curva potrebbe esserre un punto di polo) allora non modifico i punti e il vettore dei nodi della superficie
if ( snData.mCP.size() != nuCurve.vCP.size() ) {
snData.mCP.resize( nuCurve.vCP.size()) ;
if( snData.bRat)
if ( snData.bRat)
snData.mW.resize( nuCurve.vW.size()) ;
}
for ( int i = 0 ; i < snData.nCPU ; ++i) {
for ( int i = 0 ; i < ssize( nuCurve.vCP) ; ++i) {
if ( snData.mCP[i].empty())
snData.mCP[i].resize( snData.nCPV) ;
snData.mCP[i][j] = nuCurve.vCP[i] ;
if( snData.bRat) {
if ( snData.bRat) {
if ( snData.mW[i].empty())
snData.mW[i].resize( snData.nCPV) ;
snData.mW[i][j] = nuCurve.vW[i] ;
snData.mCP[i][j] *= nuCurve.vW[i] ;
}
@@ -80,18 +91,18 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData)
}
}
snData.bPeriodicU = false ;
snData.nCPU = int( snData.mCP.size()) ;
snData.nCPU = ssize( snData.mCP) ;
}
if ( snData.bPeriodicV || ! snData.bClampedV) {
bool bIsRational = snData.bRat ;
// vettore dei nodi
DBLVECTOR vV ;
int nKnot = (int) snData.vV.size() ;
int nKnot = ssize( snData.vV) ;
for ( int k = 0 ; k < nKnot ; ++k ) {
double dKnot = snData.vV[k] ;
vV.push_back( dKnot) ;
}
for( int i = 0 ; i < snData.nCPU ; ++i) {
for ( int i = 0 ; i < snData.nCPU ; ++i) {
CNurbsData nuCurve ;
nuCurve.bPeriodic = true ;
nuCurve.bRat = snData.bRat ;
@@ -132,7 +143,7 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData)
}
}
snData.bPeriodicV = false ;
snData.nCPV = int( snData.mCP[0].size()) ;
snData.nCPV = ssize( snData.mCP[0]) ;
}
return true ;
}
@@ -526,6 +537,25 @@ NurbsToBezierSurface(const SNurbsSurfData& snData)
return Release( pSrfBz) ;
}
//----------------------------------------------------------------------------
ICurveComposite*
GetRectangleCurve( const Point3d& ptStart, double dWidth, double dHeight)
{
PolyLine PL ;
PL.AddUPoint( 0, ptStart) ;
PL.AddUPoint( 1, Point3d( ptStart.x + dWidth, ptStart.y)) ;
PL.AddUPoint( 2, Point3d( ptStart.x + dWidth, ptStart.y + dHeight, 0)) ;
PL.AddUPoint( 3, Point3d( ptStart.x , ptStart.y + dHeight, 0)) ;
PL.AddUPoint( 4, ptStart) ;
// creo la curva e la inserisco nel GDB
PtrOwner<ICurveComposite> pCrvCompo( CreateCurveComposite()) ;
bool bOk = true ;
bOk = bOk && ! IsNull( pCrvCompo) ;
// inserisco i segmenti che uniscono i punti
bOk = bOk && pCrvCompo->FromPolyLine( PL) ;
return Release( pCrvCompo) ;
}
//----------------------------------------------------------------------------
bool
MakeUniform( ISurfFlatRegion*& pSfr, bool& bRescaled, const DBLVECTOR& vU0, const DBLVECTOR& vV0,
@@ -535,36 +565,33 @@ MakeUniform( ISurfFlatRegion*& pSfr, bool& bRescaled, const DBLVECTOR& vU0, cons
bool bRescaledU = false ;
bool bRescaledV = false ;
int nSpanU = 1, nSpanV = 1 ;
PtrOwner<ISurfFlatRegion> pRescaledSfr( CreateSurfFlatRegion()) ;
ICRVCOMPOPOVECTOR vUniformedCurves ;
BOOLVECTOR vbUniform(2) ;
fill( vbUniform.begin(), vbUniform.end(), true) ;
DBLMATRIX mKnots(2) ;
for ( int nDir = 0 ; nDir <= 1 ; ++ nDir) {
// vettore dei nodi
DBLVECTOR vU ;
DBLVECTOR& vU = mKnots[nDir] ;
int nExtraKnots = 0 ;
// controllo in U
if ( nDir == 0) {
if ( nDegU > 1) {
nExtraKnots = nDegU - 1 ;
}
for ( int i = nExtraKnots ; i < int( vU0.size()) - nExtraKnots ; ++i ) {
for ( int i = nExtraKnots ; i < ssize( vU0) - nExtraKnots ; ++i ) {
double dKnot = vU0[i] * SBZ_TREG_COEFF ;
// lo aggiungo solo se è diverso dal precedente
if ( i == nExtraKnots || dKnot > vU.back() + EPS_SMALL || dKnot < vU.back() - EPS_SMALL)
if ( i == nExtraKnots || dKnot > vU.back() + EPS_SMALL)
vU.push_back( dKnot) ;
}
nSpanU = (int)vU.size() - 1 ;
nSpanU = ssize( vU) - 1 ;
}
// controllo in V
else if ( nDir == 1 ) {
if ( nDegV > 1) {
nExtraKnots = nDegV - 1 ;
}
for ( int i = nExtraKnots ; i < int( vV0.size()) - nExtraKnots ; ++i ) {
for ( int i = nExtraKnots ; i < ssize( vV0) - nExtraKnots ; ++i ) {
double dKnot = vV0[i] * SBZ_TREG_COEFF ;
// lo aggiungo solo se è diverso dal precedente
if ( i == nExtraKnots || dKnot > vU.back() + EPS_SMALL || dKnot < vU.back() - EPS_SMALL)
if ( i == nExtraKnots || dKnot > vU.back() + EPS_SMALL)
vU.push_back( dKnot) ;
}
nSpanV = (int)vU.size() - 1 ;
nSpanV = ssize( vU) - 1 ;
}
// controllo se il vettore dei nodi è uniforme
@@ -577,45 +604,97 @@ MakeUniform( ISurfFlatRegion*& pSfr, bool& bRescaled, const DBLVECTOR& vU0, cons
if ( b < (int)vU.size())
d1 = abs( vU[b] - vU[a]) ;
}
if ( b != (int)vU.size()) {
if ( b != (int)vU.size())
vbUniform[nDir] = false ;
}
// vettore delle curve di loop della regione di trim
ICRVCOMPOPOVECTOR vLoop ;
if ( ! vbUniform[0] || ! vbUniform[1]) {
for ( int c = 0 ; c < pSfr->GetChunkCount() ; ++c) {
for ( int l = 0 ; l < pSfr->GetLoopCount( c); ++l)
vLoop.emplace_back( ConvertCurveToComposite( pSfr->GetLoop( c, l))) ;
}
}
#if SAVEMKUNIF_CRVS
//debug
vector<IGeoObj*> vGeo ;
for( int i = 0 ; i < ssize( vLoop); ++i){
vGeo.push_back(vLoop[i]->Clone()) ;
}
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\import3dm\\trim_error\\failed_trim_crv_loops.nge") ;
//debug
#endif
for ( int nDir = 0 ; nDir <= 1 ; ++ nDir) {
DBLVECTOR& vU = mKnots[nDir] ;
if ( ! vbUniform[nDir]) {
nDir == 0 ? bRescaledU = true : bRescaledV = true ;
pRescaledSfr.Set( CreateSurfFlatRegion()) ;
if ( IsNull( pRescaledSfr))
return false ;
// creo il vettore delle curve all'interno di una striscia
ICRVCOMPOPOVECTOR vCrvStrip ;
for ( int p = 0 ; p < (int)vU.size() - 1 ; ++p) {
PtrOwner<ISurfFlatRegion> pSfr_copy( pSfr->Clone()) ;
if ( IsNull( pSfr_copy))
return false ;
double dLenStrip = abs( vU[p+1] - vU[p]) ;
if ( dLenStrip < EPS_SMALL)
continue ;
// creo la maschera per tagliare la superficie originale e ottenere una striscia
PtrOwner<ISurfFlatRegion> pSfrTrim( CreateSurfFlatRegion()) ;
PtrOwner<ICurveComposite> pTrimMask ;
// ricavo la maschera del trim, con cui poi farò l'intersezione con la sfr iniziale
Vector3d vtTrim ;
if ( nDir == 0) {
pSfrTrim.Set( GetSurfFlatRegionRectangle( dLenStrip, dScaleV + 2)) ;
vtTrim.Set( abs(vU[p] - vU.front()), - 1, 0) ;
Point3d ptStart( abs(vU[p] - vU.front()), - 1, 0) ;
pTrimMask.Set( GetRectangleCurve( ptStart, dLenStrip, dScaleV + 2)) ;
}
else{
pSfrTrim.Set( GetSurfFlatRegionRectangle( dScaleU + 2, dLenStrip)) ;
vtTrim.Set( - 1, abs(vU[p] - vU.front()), 0) ;
Point3d ptStart( - 1, abs(vU[p] - vU.front()), 0) ;
pTrimMask.Set( GetRectangleCurve( ptStart, dScaleU + 2, dLenStrip)) ;
}
pSfrTrim->Translate( vtTrim) ;
if ( ! pSfr_copy->Intersect( *pSfrTrim))
return false ;
// qui potrei decidere di eliminare tutti i tratti dei loop paralleli alla direzione del parametro che sto analizzando ( e di valore coincidente a quello di un nodo)
// aggiungo la nuova striscia solo se è valida
if ( pSfr_copy->IsValid() ) {
for ( int l = 0 ; l < ssize( vLoop); ++l) {
#if SAVEMKUNIF_CRVS
//debug
vector<IGeoObj*> vGeo ;
vGeo.push_back(pTrimMask->Clone()) ;
vGeo.push_back(vLoop[l]->Clone()) ;
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\import3dm\\trim_error\\failed_trim_crv_inters.nge") ;
//debug
#endif
IntersCurveCurve icc( *pTrimMask, *vLoop[l]) ;
CRVCVECTOR vCurveClass ;
icc.GetCurveClassification( 1, 10 * EPS_SMALL, vCurveClass) ;
for( int i = 0 ; i < ssize( vCurveClass); ++i) {
if( vCurveClass[i].nClass == CRVC_IN || vCurveClass[i].nClass == CRVC_ON_P)
vCrvStrip.emplace_back( ConvertCurveToComposite( vLoop[l]->CopyParamRange( vCurveClass[i].dParS, vCurveClass[i].dParE))) ;
}
}
#if SAVEMKUNIF_CRVS
//debug
vector<IGeoObj*> vGeo ;
for( int i = 0 ; i < ssize( vCrvStrip); ++i){
vGeo.push_back(vCrvStrip[i]->Clone()) ;
}
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\import3dm\\trim_error\\failed_trim_crv_strip.nge") ;
//debug
#endif
// riscalo le curve nella striscia
if ( ! vCrvStrip.empty()) {
double dCoeffX = 1, dCoeffY = 1 ;
if ( nDir == 0)
pSfr_copy->Scale( GLOB_FRM, SBZ_TREG_COEFF / dLenStrip, 1, 1) ;
else
pSfr_copy->Scale( GLOB_FRM, 1, SBZ_TREG_COEFF / dLenStrip, 1) ;
// prima di riunire la striscia al resto devo traslarla sul bordo destro della superificie che sto ricostruendo
dCoeffX = SBZ_TREG_COEFF / dLenStrip ;
else
dCoeffY = SBZ_TREG_COEFF / dLenStrip ;
for( int i = 0 ; i < ssize( vCrvStrip); ++i) {
if( ! IsNull( vCrvStrip[i]))
vCrvStrip[i]->Scale( GLOB_FRM, dCoeffX, dCoeffY, 1) ;
else
return false ;
}
// prima di riunire le curve al resto devo traslarle sul bordo destro della superificie che sto ricostruendo
Point3d pt ;
nDir == 0 ? pt.Set( abs(vU[p] - vU.front()), 0, 0) : pt.Set( 0,abs(vU[p] - vU.front()), 0) ;
if ( nDir == 0)
@@ -628,25 +707,78 @@ MakeUniform( ISurfFlatRegion*& pSfr, bool& bRescaled, const DBLVECTOR& vU0, cons
vtJoin.Set( p * SBZ_TREG_COEFF - pt.x, 0, 0) ;
else
vtJoin.Set( 0, p * SBZ_TREG_COEFF - pt.y, 0) ;
pSfr_copy->Translate( vtJoin) ;
// se sto ritentando MakeUniform, allora faccio anche OFFSET e controOFFSET
if ( bRetry)
pSfr_copy->Offset( 10 * EPS_SMALL, ICurve::OFF_CHAMFER) ; // OFFSET
if ( pRescaledSfr->IsValid()) {
if ( ! pRescaledSfr->Add( *pSfr_copy))
return false ;
for( int i = 0 ; i < ssize( vCrvStrip); ++i)
vCrvStrip[i]->Translate( vtJoin) ;
#if SAVEMKUNIF_CRVS
//debug
vector<IGeoObj*> vGeo ;
for( int i = 0 ; i < ssize( vCrvStrip); ++i){
vGeo.push_back(vCrvStrip[i]->Clone()) ;
}
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\import3dm\\trim_error\\failed_trim_crv_strip.nge") ;
//debug
#endif
// faccio la chain con le curve delle striscie precedenti
if ( ! vUniformedCurves.empty() || ! vCrvStrip.empty()) {
#if SAVEMKUNIF_CRVS
//debug
vector<IGeoObj*> vGeo ;
for( int i = 0 ; i < ssize( vUniformedCurves); ++i){
vGeo.push_back(vUniformedCurves[i]->Clone()) ;
}
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\import3dm\\trim_error\\failed_trim_crv_unif.nge") ;
//debug
#endif
ChainCurves chainCrv ;
double dChainTol = 5 * EPS_SMALL ;
chainCrv.Init( false, dChainTol, max(ssize( vUniformedCurves), ssize(vCrvStrip))) ;
for ( int c = 0 ; c < ssize( vUniformedCurves) ; ++c) {
Point3d ptStart, ptEnd ;
Vector3d vtStart, vtEnd ;
vUniformedCurves[c]->GetStartPoint( ptStart) ;
vUniformedCurves[c]->GetEndPoint( ptEnd) ;
vUniformedCurves[c]->GetStartDir( vtStart) ;
vUniformedCurves[c]->GetEndDir( vtEnd) ;
chainCrv.AddCurve( 1 + c, ptStart, vtStart, ptEnd, vtEnd) ;
}
for ( int c = 0 ; c < ssize( vCrvStrip); ++c) {
Point3d ptStart, ptEnd ;
Vector3d vtStart, vtEnd ;
vCrvStrip[c]->GetStartPoint( ptStart) ;
vCrvStrip[c]->GetEndPoint( ptEnd) ;
vCrvStrip[c]->GetStartDir( vtStart) ;
vCrvStrip[c]->GetEndDir( vtEnd) ;
chainCrv.AddCurve( 1 + ssize( vUniformedCurves) + c, ptStart, vtStart, ptEnd, vtEnd) ;
}
INTVECTOR vIds ;
ICRVCOMPOPOVECTOR vNewCrv ;
int nCrvPrec = ssize( vUniformedCurves) ;
while ( chainCrv.GetChainFromNear( ORIG, false, vIds)) {
vNewCrv.emplace_back( CreateBasicCurveComposite()) ;
for ( int nId : vIds) {
nId -= 1 ;
if ( nId < nCrvPrec)
vNewCrv.back()->AddCurve( Release( vUniformedCurves[nId]), true, dChainTol) ;
else
vNewCrv.back()->AddCurve( Release( vCrvStrip[nId - ssize( vUniformedCurves)]), true, dChainTol) ;
}
}
// aggiorno le curve
vUniformedCurves.clear() ;
vUniformedCurves.swap( vNewCrv) ;
}
else
pRescaledSfr.Set( pSfr_copy) ;
}
vCrvStrip.clear() ;
}
if ( nDir == 0) {
dScaleU = ((int)vU.size() - 1) * SBZ_TREG_COEFF ;
if ( pRescaledSfr->IsValid()) {
if ( bRetry)
pRescaledSfr->Offset( -10 * EPS_SMALL, ICurve::OFF_CHAMFER) ; //contro OFFSET
delete pSfr ;
pSfr = Release( pRescaledSfr) ;
if( ! vbUniform[1]) {
vLoop.swap( vUniformedCurves) ;
vUniformedCurves.clear() ;
}
}
else
@@ -654,12 +786,38 @@ MakeUniform( ISurfFlatRegion*& pSfr, bool& bRescaled, const DBLVECTOR& vU0, cons
}
}
if ( ! IsNull( pRescaledSfr) && pRescaledSfr->IsValid()) {
if ( bRetry)
pRescaledSfr->Offset( -10 * EPS_SMALL, ICurve::OFF_CHAMFER) ; // contro OFFSET
delete pSfr ;
pSfr = Release( pRescaledSfr) ;
if ( ! vUniformedCurves.empty()) {
#if SAVEMKUNIF_CRVS
//debug
vector<IGeoObj*> vGeo ;
for( int i = 0 ; i < ssize( vUniformedCurves); ++i){
vGeo.push_back(vUniformedCurves[i]->Clone()) ;
}
SaveGeoObj( vGeo, "D:\\Temp\\bezier\\import3dm\\trim_error\\failed_trim_crv_unif.nge") ;
//debug
#endif
// controllo che tutte le curve siano chiuse, sennò vuol dire che ho perso qualche pezzo durante le intersezioni
for ( int i = 0 ; i < ssize( vUniformedCurves); ++i) {
if ( ! vUniformedCurves[i]->IsClosed())
return false ;
}
// creo una regione dalle curve riscalate
SurfFlatRegionByContours sfrRescaled ;
for ( int i = 0 ; i < ssize( vUniformedCurves); ++i)
sfrRescaled.AddCurve( Release( vUniformedCurves[i])) ;
PtrOwner<ISurfFlatRegion> pRescaledSfr( sfrRescaled.GetSurf()) ;
if ( ! IsNull( pRescaledSfr) && pRescaledSfr->IsValid()) {
delete pSfr ;
pSfr = Release( pRescaledSfr) ;
}
else
return false ;
}
else if( ! vbUniform[0] || ! vbUniform[1])
return false ;
if ( ! bRescaledU && ! bRescaledV)
pSfr->Scale( GLOB_FRM, nSpanU / dScaleU * SBZ_TREG_COEFF, nSpanV / dScaleV * SBZ_TREG_COEFF, 1) ;
+1617 -454
View File
File diff suppressed because it is too large Load Diff
+16 -12
View File
@@ -20,6 +20,7 @@
#include "SurfTriMesh.h"
#include "SurfFlatRegion.h"
#include "/EgtDev/Include/EGkSurfBezier.h"
#include "/EgtDev/Include/EGkIntersLineTria.h"
#include "/EgtDev/Include/EGkGeoCollection.h"
//----------------------------------------------------------------------------
@@ -115,18 +116,17 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
bool GetControlCurveOnV( int nIndU, PolyLine& plCtrlV) const override ;
const SurfTriMesh* GetAuxSurf( void) const override ;
const SurfTriMesh* GetAuxSurfRefined( void) const override ;
SurfTriMesh* GetApproxSurf( double dTol, double dSideMin = 100 * EPS_SMALL) const override ;
SurfTriMesh* GetApproxSurf( double dTol, double dSideMin = 10 * EPS_SMALL, bool bUpdateEdges = false) const override ;
// funzione per ottenere la suddivisione dello spazio parametrico nelle celle utilizzate per la triangolazione.
bool GetLeaves( std::vector<std::tuple<int, Point3d, Point3d>>& vLeaves) const override ;
bool GetLeaves( std::vector<std::tuple<int, Point3d, Point3d>>& vLeaves, bool bRefined = false) const override ;
bool GetTriangles2D( std::vector<std::tuple<int,Point3d, Point3d, Point3d>>& vTria2D) const override ;
// funzioni che servono per ricavare l'immagine nel parametrico di un punto appartenente alla trimesh ausiliaria della superficie di Bezier
// a nIL si può passare 5 come valore di default
bool UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, int nIL = 5) const override ;
bool UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, int nIL = IntLineTriaType::ILTT_IN) const override ;
bool UnprojectPointFromStm( int nT, const Point3d& ptI, Point3d& ptSP, int nIL, const Point3d& ptIPrev, bool* bTroughEdge = nullptr) const override ;
// restituisce il corrispettivo parametrico di un punto qualunque della trimesh associata alla superficie
// ptIPrev è un punto addizionale che precede o segue il punto pt3D nel caso in cui il punto faccia parte di una curva 3d sulla superficie
// pPlCut è il piano di taglio su cui dovrebbe giacere il punto raffinato
bool UnprojectPoint( const Point3d& pt3D, Point3d& ptParam, const Point3d& ptIPrev, bool* bTroughEdge = nullptr, const Plane3d* plCut = nullptr) const override ;
bool UnprojectPoint( const Point3d& pt3D, Point3d& ptParam, const Point3d& ptIPrev = P_INVALID, bool* bTroughEdge = nullptr, const Plane3d* plCut = nullptr) const override ;
// pPlCut è il piano di taglio su cui giace la curva
bool UnprojectCurveFromStm( const ICurveComposite* pCC, ICRVCOMPOPVECTOR& vpCC, const Plane3d* pPlCut) const override ;
// funzione per tagliare una superficie di bezier con un piano ( cancello la parte dal lato positivo della normale del piano).
@@ -136,17 +136,23 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
bool IncreaseUV( double& dU, double dx, bool bUOrV, double* dUVCopy = nullptr, bool bModifyOrig = true) const override ;
bool IncreaseUV( Point3d& ptUV, Vector3d vtH , Point3d* ptUVCopy, bool bModifyOrig) const override ;
// funzione che restituisce gli edge della superficie o in forma di linea spezzata o in forma di curva di Bezier
// se la superficie è trimmata restituisce i loop dello spazio parametrico in forma di linee spezzate
bool GetLoops( ICRVCOMPOPOVECTOR& vCC, bool bLineOrBezier, int nEdge = -1) const override ; // se la superficie non è trimmata restituisce un vettore di 4 elementi. Se la superficie è chiusa lungo un parametro i lati algi estremi di quel parametro saranno null.
// restituisce un vettore con i loop della superficie ( più di uno solo se è trimmata con un parametrico con buchi o più di un chunk)
bool GetLoops( ICRVCOMPOPOVECTOR& vCC, bool bLineOrBezier) const override ;
// restituisce il singolo edge della superficie non trimmata
ICurveComposite* GetSingleEdge3D( bool bLineOrBezier, int nEdge) const override ;
bool IsPlanar( void) const override ;
bool CreateByFlatContour( const PolyLine& PL) override ;
bool CreateByRegion( const POLYLINEVECTOR& vPL) override ;
bool CreateByExtrusion( const ICurve* pCurve, const Vector3d& vtExtr, bool bDeg3OrDeg2 = false) override ;
bool CreateByExtrusion( const ICurve* pCurve, const Vector3d& vtExtr) override ;
bool CreateByScrewing( const ICurve* pCurve, const Point3d& ptAx, const Vector3d& vtAx, double dAngRotDeg, double dMove) override ;
bool CreateByPointCurve( const Point3d& pt, const ICurve* pCurve) override ;
bool CreateByTwoCurves( const ICurve* pCurve1, const ICurve* pCurve2, int nType) override ;
bool CreateBySetOfCurves( const ICURVEPOVECTOR& vCrvBez, bool bReduceToDeg3) override ;
PNTVECTOR GetAllControlPoints( void) const ;
bool GetAllPatchesIsocurves( bool bUorV, ICURVEPOVECTOR& vCrv) const ;
bool CreateByIsoParamSet( const ICurve* pCurve0, const ICurve* pCurve1, const BIPNTVECTOR& vCrv) ;
bool RemoveCollapsedSpans( void) override ;
bool SwapParameters( void) ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
@@ -200,8 +206,6 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
// funzione che proietta nello spazio parametrico un trim derivante da un taglio con un piano, categorizzandolo come aperto o chiuso ( nel parametrico)
bool AddCurveCompoToCuts( ICurveComposite* pCrvCompo, ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed, double dToler = EPS_SMALL, const Plane3d* pPlCut = nullptr) const ;
ISurfFlatRegion* CreateTrimRegionFromCuts( ICRVCOMPOPOVECTOR& vpCCOpen, ICRVCOMPOPOVECTOR& vpCCClosed) const ;
// restituisce il singolo edge della superficie non trimmata
ICurveComposite* GetSingleEdge3D( bool bLineOrBezier, int nEdge) const ;
// funzione che calcola se gli edge sono collassati in poli
bool CalcPoles( void) const ;
bool FindMatchByParam( const PolyLine& pl0, const PolyLine& pl1, INTVECTOR& vMatch, int& nLong) const ;
@@ -220,8 +224,8 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
int m_nSpanV ; // numero di pezze in V
bool m_bRat ; // flag di razionale/polinomiale
bool m_bTrimmed ; // flag per presenza regione di trim
mutable bool m_bClosedU ; // flag che indica se la superficie è chiusa lungo il parametro U
mutable bool m_bClosedV ; // flag che indica se la superficie è chiusa lungo il parametro V
mutable bool m_bClosedU ; // flag che indica se la superficie è chiusa lungo il parametro U ( gli edge a V=0 e V=1 coincidono)
mutable bool m_bClosedV ; // flag che indica se la superficie è chiusa lungo il parametro V ( gli edge a U=0 e U=1 coincidono)
mutable BOOLVECTOR m_vbPole ; // vettore di flag che indicano se i lati sono collassati in dei poli
PNTVECTOR m_vPtCtrl ; // vettore dei punti di controllo
DBLVECTOR m_vWeCtrl ; // vettore dei pesi di controllo
+85 -9
View File
@@ -517,9 +517,9 @@ SurfTriMesh::GetVertexParam( int nId, double& dU, double& dV) const
// verifico esistenza del vertice
if ( nId < 0 || nId >= GetVertexSize() || m_vVert[nId].nIdTria == SVT_DEL)
return false ;
// recupero i dati
dU = m_vVert[nId].dU ;
dV = m_vVert[nId].dV ;
// recupero i dati (verso l'esterno sempre in 0..1..2..3..)
dU = m_vVert[nId].dU / PREC_SCALE_COEFF ;
dV = m_vVert[nId].dV / PREC_SCALE_COEFF ;
return true ;
}
@@ -870,15 +870,21 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const
if ( nPos == -1)
return false ;
// medio le normali, finch non incontro degli spigoli
vtN = m_vTria[nT].vtN ;
// medio le normali, finchè non incontro degli spigoli
double dAngW = 1 ;
GetTriangleVertexAngle( nT, nV, dAngW) ;
vtN = dAngW * m_vTria[nT].vtN ;
// parto dal triangolo e vado in direzione positiva
int nLim = nPos ;
for ( int i = NextIndAroundVertex( nPos, nTria, bCirc) ;
i != nPos && i < int( vT.size()) ;
i = NextIndAroundVertex( i, nTria, bCirc)) {
if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng)
vtN += m_vTria[vT[i]].vtN ;
if ( m_vTria[nT].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng) {
int nK ; double dAngW = 1 ;
if ( FindVertexInTria( m_vTria[nT].nIdVert[nV], vT[i], nK) &&
GetTriangleVertexAngle( vT[i], nK, dAngW))
vtN += dAngW * m_vTria[vT[i]].vtN ;
}
else
break ;
nLim = i ;
@@ -887,8 +893,12 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const
for ( int i = PrevIndAroundVertex( nPos, nTria, bCirc) ;
i != nLim && i >= 0 ;
i = PrevIndAroundVertex( i, nTria, bCirc)) {
if ( m_vTria[vT[nPos]].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng)
vtN += m_vTria[vT[i]].vtN ;
if ( m_vTria[nT].vtN * m_vTria[vT[i]].vtN >= m_dCosSmAng) {
int nK ; double dAngW = 1 ;
if ( FindVertexInTria( m_vTria[nT].nIdVert[nV], vT[i], nK) &&
GetTriangleVertexAngle( vT[i], nK, dAngW))
vtN += dAngW * m_vTria[vT[i]].vtN ;
}
else
break ;
}
@@ -897,6 +907,23 @@ SurfTriMesh::GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetTriangleVertexAngle( int nT, int nV, double& dAng) const
{
// verifico esistenza del triangolo e validità vertice
if ( nT < 0 || nT >= GetTriangleSize() || m_vTria[nT].nIdVert[0] == SVT_DEL || nV < 0 || nV > 2)
return false ;
// determino i vettori dei due lati che partono dal vertice
Point3d ptVert = m_vVert[ m_vTria[nT].nIdVert[nV]].ptP ;
Point3d ptPrev = m_vVert[ m_vTria[nT].nIdVert[Prev( nV)]].ptP ;
Point3d ptNext = m_vVert[ m_vTria[nT].nIdVert[Next( nV)]].ptP ;
Vector3d vtPrev = ptPrev - ptVert ;
Vector3d vtNext = ptNext - ptVert ;
// determino l'angolo tra i due lati
return vtPrev.GetAngle( vtNext, dAng) ;
}
//----------------------------------------------------------------------------
SurfTriMesh*
SurfTriMesh::CloneTriangle( int nT) const
@@ -1340,6 +1367,8 @@ SurfTriMesh::GetTitle( void) const
bool
SurfTriMesh::Dump( string& sOut, bool bMM, const char* szNewLine) const
{
// visualizzazione spigoli
sOut += "ShowEdges=" + ToString( GetShowEdges()) + szNewLine ;
// area
double dArea ;
GetArea( dArea) ;
@@ -4386,6 +4415,35 @@ SurfTriMesh::ClonePart( int nPart) const
return Release( pSurfTM) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetPartAndShellFromFacet( int nFacet, int& nPart, int& nShell) const
{
// l'indice della faccia deve essere nei limiti
if ( nFacet < 0 || nFacet >= int( m_vFacet.size()))
return false ;
// mi assicuro che siano calcolate il numero di parti e di shell
int nParts = GetPartCount() ;
int nTria = m_vFacet[nFacet] ;
nShell = m_vTria[nTria].nShell ;
// scopro in quale part è la shell
int nPartTemp = 0 ;
nPart = - 1 ;
while ( nPartTemp < nParts && nPart == - 1) {
for ( int i : m_vPart[nPartTemp].vShell) {
if ( i == nShell) {
nPart = nPartTemp ;
break ;
}
}
++nPartTemp ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::ResetTFlags( void)
@@ -4512,3 +4570,21 @@ SurfTriMesh::AdjustTopologyFromZMap( void)
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetTriaFromFace( int nF, int& nT) const
{
// la superficie deve essere validata
if ( m_nStatus != OK)
return false ;
// verifico stato sfaccettatura
if ( ! VerifyFaceting())
return false ;
// l'indice della faccia deve essere nei limiti
if ( nF < 0 || nF >= int( m_vFacet.size()))
return false ;
// recupero la normale di un triangolo della faccetta
nT = m_vFacet[nF] ;
return true ;
}
+5
View File
@@ -322,6 +322,8 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool GetEdge( int nInd, int& nV1, int& nV2, int& nFl, int& nFr, double& dAng) const override ;
bool GetEdge( int nInd, Point3d& ptP1, Point3d& ptP2, double& dAng) const override ;
bool GetEdges( ICURVEPOVECTOR& vpCurve) const override ;
bool GetCurvature( int nV,
double& dMinK, Vector3d& vtMinK, double& dMaxK, Vector3d& vtMaxK, bool& bPlanar, Vector3d& vtNorm) const override ;
bool Cut( const Plane3d& plPlane, bool bSaveOnEq) override ;
bool GeneralizedCut( const ICurve& cvCurve, bool bSaveOnEq) override ;
bool Add( const ISurfTriMesh& Other) override ;
@@ -345,6 +347,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool GetPartVolume( int nPart, double& dVolume) const override ;
bool GetPartLoops( int nPart, POLYLINEVECTOR& vPL) const override ;
SurfTriMesh* ClonePart( int nPart) const override ;
bool GetPartAndShellFromFacet( int nFacet, int& nPart, int& nShell) const override ;
bool SetTFlag( int nId, int nTFlag) override ;
bool GetTFlag( int nId, int& nFlag) const override ;
int GetMaxTFlag( void) const override
@@ -378,6 +381,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool SetTempInt( int nId, int nTempInt) const ;
bool AddTriaFromZMap( const TRIA3DEXVECTOR& vTria, PointGrid3d& VertGrid, double dVertexTol = 2 * EPS_SMALL) ;
bool AdjustTopologyFromZMap( void) ;
bool GetTriaFromFace( int nF, int& nT) const ;
private :
typedef std::vector<StmVert> VERTVECTOR ;
@@ -411,6 +415,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
int NextIndAroundVertex( int nInd, int nSize, bool bCirc) const ;
int PrevIndAroundVertex( int nInd, int nSize, bool bCirc) const ;
bool GetTriangleSmoothNormal( int nT, int nV, Vector3d& vtN) const ;
bool GetTriangleVertexAngle( int nT, int nV, double& dAng) const ;
bool MarchAlongLoop( int nT, int nV, int nTimeStamp, PolyLine& PL) const ;
bool MarchOneTria( int& nT, int& nV, int nTimeStamp, PolyLine& PL, bool& bEnd) const ;
bool VerifyPolylinesForTwoCurves( const PolyLine& PL1, const PolyLine& PL2) const ;
+1 -1
View File
@@ -41,7 +41,7 @@
using namespace std ;
//----------------------------------------------------------------------------
const double BOOLEAN_SCALE = 1024 ;
const double BOOLEAN_SCALE = PREC_SCALE_COEFF ;
//----------------------------------------------------------------------------
bool
+1 -1
View File
@@ -26,7 +26,7 @@
using namespace std ;
//----------------------------------------------------------------------------
const double CUT_SCALE = 1024 ;
const double CUT_SCALE = PREC_SCALE_COEFF ;
//----------------------------------------------------------------------------
bool
+167 -19
View File
@@ -21,6 +21,8 @@
#include <array>
#include <set>
#include <unordered_map>
#define EIGEN_NO_IO
#include "/EgtDev/Extern/Eigen/Dense"
using namespace std ;
@@ -54,7 +56,7 @@ SurfTriMesh::UpdateFaceting( void)
bool bOk = true ;
for ( int j = 0 ; j < int( vOldFacet.size()) ; ++ j) {
int i = vOldFacet[j] ;
// salto triangoli inesistenti o già assegnati
// salto triangoli inesistenti o già assegnati
if ( i >= int( m_vTria.size()) ||
m_vTria[i].nIdVert[0] == SVT_DEL ||
m_vTria[i].nIdFacet != SVT_NULL)
@@ -69,7 +71,7 @@ SurfTriMesh::UpdateFaceting( void)
// ricostruisco le altre sfaccettature
for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) {
// salto triangoli cancellati o già assegnati
// salto triangoli cancellati o già assegnati
if ( m_vTria[i].nIdVert[0] == SVT_DEL ||
m_vTria[i].nIdFacet != SVT_NULL)
continue ;
@@ -103,7 +105,7 @@ SurfTriMesh::UpdateOneFace( int nFacet, int nT)
// set di triangoli da aggiornare
set<int> stTria ;
stTria.insert( nT) ;
// finchè set non vuoto
// finchè set non vuoto
bool bOk = true ;
while ( ! stTria.empty()) {
// tolgo un triangolo dal set
@@ -421,7 +423,7 @@ SurfTriMesh::GetFacetLoops( int nF, POLYLINEVECTOR& vPL) const
if ( ! MarchAlongFacetLoop( nF, nT, 1, m_nTimeStamp, vPL.back()))
return false ;
}
// se il lato 0 è di contorno
// se il lato 0 è di contorno
else if ( nAdjF[0] != nF) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
@@ -433,7 +435,7 @@ SurfTriMesh::GetFacetLoops( int nF, POLYLINEVECTOR& vPL) const
if ( ! MarchAlongFacetLoop( nF, nT, 1, m_nTimeStamp, vPL.back()))
return false ;
}
// se il lato 1 è di contorno
// se il lato 1 è di contorno
else if ( nAdjF[1] != nF) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
@@ -445,7 +447,7 @@ SurfTriMesh::GetFacetLoops( int nF, POLYLINEVECTOR& vPL) const
if ( ! MarchAlongFacetLoop( nF, nT, 2, m_nTimeStamp, vPL.back()))
return false ;
}
// se il lato 2 è di contorno
// se il lato 2 è di contorno
else if ( nAdjF[2] != nF) {
// ho trovato l'inizio di un loop
vPL.emplace_back() ;
@@ -457,7 +459,7 @@ SurfTriMesh::GetFacetLoops( int nF, POLYLINEVECTOR& vPL) const
if ( ! MarchAlongFacetLoop( nF, nT, 0, m_nTimeStamp, vPL.back()))
return false ;
}
// altrimenti non c'è contorno
// altrimenti non c'è contorno
else {
// marco il triangolo come verificato
m_vTria[nT].nTemp = m_nTimeStamp ;
@@ -476,7 +478,7 @@ SurfTriMesh::GetFacetLoops( int nF, POLYLINEVECTOR& vPL) const
return false ;
// se loop esterno
if ( vtN * plPlane.GetVersN() > 0) {
// se non c'è ancora loop esterno in prima posizione
// se non c'è ancora loop esterno in prima posizione
if ( ! bOutFirst) {
// lo sposto in prima posizione
if ( i != 0)
@@ -517,7 +519,7 @@ SurfTriMesh::MarchOneFacetTria( int nF, int& nT, int& nV, int nTimeStamp,
// verifico appartenga alla stessa faccia
if ( m_vTria[nAdjT].nIdFacet != nF)
return false ;
// recupero il suo lato di adiacenza (e verifico non abbia più adiacenze con il triangolo di partenza)
// recupero il suo lato di adiacenza (e verifico non abbia più adiacenze con il triangolo di partenza)
int nAdjS = SVT_NULL ;
for ( int i = 0 ; i < 3 ; ++ i) {
if ( m_vTria[nAdjT].nIdAdjac[i] == nT) {
@@ -531,11 +533,11 @@ SurfTriMesh::MarchOneFacetTria( int nF, int& nT, int& nV, int nTimeStamp,
return false ;
// vertice di fine adiacenza e indice del successivo lato
int nAdjV = Next( nAdjS) ;
// verifico se il lato successivo è un bordo
// verifico se il lato successivo è un bordo
int nNextT = m_vTria[nAdjT].nIdAdjac[nAdjV] ;
int nNextF = ( nNextT != SVT_NULL ? m_vTria[nNextT].nIdFacet : SVT_NULL) ;
if ( nNextF != nF) {
// se già recuperato
// se già recuperato
if ( m_vTria[nAdjT].nTemp == nTimeStamp) {
bEnd = true ;
return true ;
@@ -593,7 +595,7 @@ SurfTriMesh::GetFacetsContact( int nF1, int nF2, bool& bAdjac, Point3d& ptP1, Po
// verifico esistenza seconda faccia
if ( nF2 < 0 || nF2 >= int( m_vFacet.size()))
return false ;
// verifico se c'è un contatto con la seconda faccia e recupero i punti estremi della eventuale linea di contatto
// verifico se c'è un contatto con la seconda faccia e recupero i punti estremi della eventuale linea di contatto
bAdjac = false ;
for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
double dUs, dUe ;
@@ -606,7 +608,7 @@ SurfTriMesh::GetFacetsContact( int nF1, int nF2, bool& bAdjac, Point3d& ptP1, Po
ptP2 = ptPe ;
}
else {
// parametri del segmento già definito
// parametri del segmento già definito
Vector3d vtT ;
double dLen ;
DirDist( ptP1, ptP2, vtT, dLen) ;
@@ -646,7 +648,7 @@ SurfTriMesh::GetFacetCenter( int nF, Point3d& ptCen, Vector3d& vtN) const
POLYLINEVECTOR vPL ;
if ( ! GetFacetLoops( nF, vPL) || vPL.empty())
return false ;
// calcolo il centro del loop esterno (è il primo)
// calcolo il centro del loop esterno (è il primo)
PolygonPlane PolyPlane ;
Point3d ptP ;
for ( bool bFound = vPL[0].GetFirstPoint( ptP) ; bFound ; bFound = vPL[0].GetNextPoint( ptP))
@@ -730,7 +732,7 @@ SurfTriMesh::CloneFacet( int nF) const
// ciclo sui tre vertici
int nIdV[3] ;
for ( int j = 0 ; j < 3 ; ++ j) {
// verifico se vertice già presente
// verifico se vertice già presente
const auto it = PntMap.find( m_vTria[nT].nIdVert[j]) ;
if ( it == PntMap.end()) {
// aggiungo il vertice
@@ -773,7 +775,7 @@ SurfTriMesh::RemoveFacet( int nF)
if ( ! DoCompacting())
return false ;
// dichiaro necessità ricalcolo della grafica e di hashgrids3d
// dichiaro necessità ricalcolo della grafica e di hashgrids3d
m_OGrMgr.Reset() ;
ResetHashGrids3d() ;
@@ -878,7 +880,7 @@ SurfTriMesh::UpdateFacetEdging( void)
m_bFacEdged = false ;
m_vFacEdge.clear() ;
// verifico validità sfaccettatura
// verifico validità sfaccettatura
if ( ! VerifyFaceting())
return false ;
@@ -957,7 +959,7 @@ SurfTriMesh::GetEdge( int nInd, int& nV1, int& nV2, int& nFl, int& nFr, double&
// verifico stato bordi sfaccettatura
if ( ! VerifyFacetEdging())
return false ;
// verifico la validità dell'indice
// verifico la validità dell'indice
if ( nInd < 0 || nInd > int( m_vFacEdge.size()))
return SVT_NULL ;
// recupero i dati
@@ -980,7 +982,7 @@ SurfTriMesh::GetEdge( int nInd, Point3d& ptP1, Point3d& ptP2, double& dAng) cons
// verifico stato bordi sfaccettatura
if ( ! VerifyFacetEdging())
return false ;
// verifico la validità dell'indice
// verifico la validità dell'indice
if ( nInd < 0 || nInd > int( m_vFacEdge.size()))
return SVT_NULL ;
// recupero i dati
@@ -1015,3 +1017,149 @@ SurfTriMesh::GetEdges( ICURVEPOVECTOR& vpCurve) const
}
return true ;
}
//-----------------------------------------------------------------------------
// Funzione per il calcolo della curvatura massima e minima in un vertice della superficie TriMesh
// dMinK : curvatura minima
// vtMinK : versore direzione curvatura minima
// dMaxK : curvatura massima
// vtMaxK : versore direzione curvatura massima
// bPlanar : Flag per indicare le superficie localmente piana
// vtNorm : versore normale del piano tangente alla supericie nel vertice
bool
SurfTriMesh::GetCurvature( int nV,
double& dMinK, Vector3d& vtMinK, double& dMaxK, Vector3d& vtMaxK, bool& bPlanar, Vector3d& vtNorm) const
{
// Controllo la validità della TriMesh e del Vertice
if ( ! IsValid())
return false ;
Point3d ptCurr ;
if ( ! GetVertex( nV, ptCurr))
return false ;
bPlanar = false ;
// Recupero tutti i vertici attorno al vertice corrente ( se presenza di lato libero, allora errore)
INTVECTOR vT ;
bool bCirc ;
if ( ! GetAllTriaAroundVertex( nV, vT, bCirc) || ! bCirc)
return false ;
// Calcolo la normale del vertice pesata mediante angolo sotteso e distanza baricentrica
// ["Estimation Normal Vector of Triangular Mesh Vertex by Angle and Centroid Weights"]
// Controllo anche di non essere in presenza di uno spigolo vivo
INTSET setIndTriaNeightbors ;
bool bFirstTria = true ;
Vector3d vtNFirstTria = V_NULL ;
for ( const int& nT : vT) {
// Recupero il triangolo corrente
Triangle3d Tria ;
int nIdVert[3] ;
if ( ! GetTriangle( nT, Tria) || ! GetTriangle( nT, nIdVert))
return false ;
// Se il triangolo ha area troppo piccola, lo scarto
if ( Tria.GetArea() < EPS_SMALL)
continue ;
// Se primo triangolo salvo la sua normale di riferimento per successivi confronti
if ( bFirstTria) {
vtNFirstTria = Tria.GetN() ;
bFirstTria = false ;
}
else {
// Se spigolo vivo, la curvatura non può esistere
if ( Tria.GetN() * vtNFirstTria < m_dCosSmAng - EPS_SMALL)
return false ;
}
// Recupero le direzioni delle semirette per l'angolo al vertice corrente
Vector3d vtDir0 = V_NULL, vtDir1 = V_NULL ;
for ( int i = 0 ; i < 3 ; ++ i) {
if ( AreSamePointApprox( Tria.GetP( i), ptCurr)) {
vtDir0 = Tria.GetP( ( i + 1) % 3) - Tria.GetP( i) ;
vtDir0.Normalize() ;
vtDir1 = Tria.GetP( ( i + 2) % 3) - Tria.GetP( i) ;
vtDir1.Normalize() ;
break ;
}
}
for ( int i = 0 ; i < 3 ; ++ i) {
if ( nV == nIdVert[i]) {
setIndTriaNeightbors.insert( nIdVert[( i + 1) % 3]) ;
setIndTriaNeightbors.insert( nIdVert[( i + 2) % 3]) ;
break ;
}
}
// Calcolo l'angolo sotteso
double dCosTheta = max( -1., min( 1., ( vtDir0 * vtDir1))) ;
double dTheta = acos( dCosTheta) ;
// Calcolo la distanza baricentrica
double dSqBarDist = max( EPS_SMALL, ( ptCurr - Tria.GetCentroid()).SqLen()) ;
// Aggiorno il contributo della normale al vertice
vtNorm += ( ( dTheta / dSqBarDist) * Tria.GetN()) ;
}
vtNorm.Normalize() ;
// [ESTIMATING CURVATURE ON TRIANGULAR MESHES, cap. 2.1. Fitting Methods,
// par. 2.1.2. Quadric Fitting]
// [https://people.eecs.berkeley.edu/~jrs/meshpapers/GatzkeGrimm.pdf]
// Definisco il piano tangente al vertice corrente
Plane3d plTan ;
if ( ! plTan.Set( ptCurr, vtNorm))
return false ;
// Proietto i punti Neightbors(1) sul piano tangete ( senza ripeterli)
BIPNTVECTOR vPtPtProj ; vPtPtProj.reserve( setIndTriaNeightbors.size()) ;
for ( auto nIter = setIndTriaNeightbors.begin() ; nIter != setIndTriaNeightbors.end() ; ++ nIter) {
Point3d ptNeightbors ;
if ( ! GetVertex( *nIter, ptNeightbors))
return false ;
vPtPtProj.emplace_back( make_pair( ptNeightbors, ProjectPointOnPlane( ptNeightbors, plTan))) ;
}
// Recupero due versori perpendicolari nel piano definito
Vector3d vtTan1 = V_NULL ;
if ( abs( vtNorm.x) < 1./64. && abs( vtNorm.y) < 1./64.)
vtTan1 = Y_AX ^ vtNorm ;
else
vtTan1 = Z_AX ^ vtNorm ;
vtTan1.Normalize() ;
Vector3d vtTan2 = vtNorm ^ vtTan1 ;
vtTan2.Normalize() ;
// Sistema da risolvere mediante minimi quadrati : z(u,v) = Au^2 + Buv + Cv^2
// Questo sistema è molto più semplice e robusto rispetto a z(u,v) = Au^2 + Buv + Cv^2 + Du + Ev + F
// per il fatto che ora le coordinate sono in locale al piano tangente alla superficie ( mettendo
// quindi a 0 i coefficienti del primo ordine e il termine noto F)
// Definizione della matrice A(Nx3)
const int nPts = int( vPtPtProj.size()) ;
Eigen::MatrixXd mat_A( nPts, 3) ;
Eigen::VectorXd vec_b( nPts) ;
for ( int i = 0 ; i < nPts ; ++ i) {
Vector3d vtEdgeProj = vPtPtProj[i].second - ptCurr ;
Vector3d vtEdge = ( vPtPtProj[i].first - vPtPtProj[i].second) ;
double dU = vtEdgeProj * vtTan1 ;
double dV = vtEdgeProj * vtTan2 ;
double dW = vtEdge * vtNorm ;
mat_A( i, 0) = dU * dU ;
mat_A( i, 1) = dU * dV ;
mat_A( i, 2) = dV * dV ;
vec_b( i) = dW ;
}
// Risoluzione del sistema
Eigen::VectorXd vec_x = mat_A.colPivHouseholderQr().solve( vec_b) ;
// Costruzione della matrice hessiana
Eigen::Matrix2d mat_H {{ 2. * vec_x( 0), vec_x( 1)},
{ vec_x( 1), 2. * vec_x( 2)}} ;
// Calcolo gli autovalori ( quindi le curvature principali) e restituisco i risultati
Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> Solver( mat_H) ;
dMinK = Solver.eigenvalues()( 0) ;
dMaxK = Solver.eigenvalues()( 1) ;
Eigen::Vector2d dir_Min = Solver.eigenvectors().col( 0) ;
Eigen::Vector2d dir_Max = Solver.eigenvectors().col( 1) ;
vtMinK = dir_Min( 0) * vtTan1 + dir_Min( 1) * vtTan2 ;
vtMaxK = dir_Max( 0) * vtTan1 + dir_Max( 1) * vtTan2 ;
bPlanar = ( abs( dMinK) < EPS_SMALL && abs( dMaxK) < EPS_SMALL) ;
return true ;
}
+642 -93
View File
@@ -9,6 +9,7 @@
// Modifiche : 10.06.25 RE Creazione modulo.
// 10.06.25 RE Offset di superfici chiuse.
// 04.07.25 RE Thickening Offset di superfici generiche.
// 10.12.25 RE Creazione superfici Shell.
//
//----------------------------------------------------------------------------
@@ -16,11 +17,17 @@
#include "stdafx.h"
#include "VolZmap.h"
#include "SurfTriMesh.h"
#include "EgtDev/Include/EGkDistPointSurfTm.h"
#include "\EgtDev\Include\EGkSurfTriMeshAux.h"
#include "/EgtDev/Include/EGkDistPointSurfTm.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkDistPointTria.h"
#include "/EgtDev/Include/EGkSurfTriMeshAux.h"
#include "/EgtDev/Include/EGkStmFromCurves.h"
#include "/EgtDev/Include/EGkStmFromTriangleSoup.h"
#include <future>
#define DEBUG 0
#if DEBUG
#include "/EgtDev/Include/EGnStringUtils.h"
#include "/EgtDev/Include/EGkGeoObjSave.h"
#include "/EgtDev/Include/EGkGeoPoint3d.h"
#include "/EgtDev/Include/EGkGeoVector3d.h"
@@ -58,6 +65,255 @@ SumStm( const CISURFTMPVECTOR& vStm)
return ( Release( pStmAdd)) ;
}
//----------------------------------------------------------------------------
// Funzioni per la distanza tra punto e superficie TriMesh in parallelo
//----------------------------------------------------------------------------
static bool
BoundingBoxDifference( const BBox3d& boxA, const BBox3d& boxB, BOXVECTOR& vBoxDiff)
{
// svuoto il risultato
vBoxDiff.clear() ;
// se box A vuoto, risultato vuoto
if ( boxA.IsEmpty())
return false ;
// se box B vuoto o i box non si intersecano, risultato è ancora A
BBox3d boxInt ;
if ( boxB.IsSmall() || ! boxA.FindIntersection( boxB, boxInt)) {
vBoxDiff.emplace_back( boxA) ;
return true ;
}
// recupero i punti estremi dei box A e Intersezione
Point3d ptMinA, ptMaxA ; boxA.GetMinMax( ptMinA, ptMaxA) ;
Point3d ptMinInt, ptMaxInt ; boxInt.GetMinMax( ptMinInt, ptMaxInt) ;
// sotto
if ( ptMinInt.z - ptMinA.z > EPS_SMALL) {
BBox3d boxD( ptMinA, Point3d( ptMaxA.x, ptMaxA.y, ptMinInt.z)) ;
vBoxDiff.emplace_back( boxD) ;
}
// sopra
if ( ptMaxA.z - ptMaxInt.z > EPS_SMALL) {
BBox3d boxD( Point3d( ptMinA.x, ptMinA.y, ptMaxInt.z), ptMaxA) ;
vBoxDiff.emplace_back( boxD) ;
}
// davanti
if ( ptMinInt.y - ptMinA.y > EPS_SMALL) {
BBox3d boxD( Point3d( ptMinA.x, ptMinA.y, ptMinInt.z), Point3d( ptMaxA.x, ptMinInt.y, ptMaxInt.z)) ;
vBoxDiff.emplace_back( boxD) ;
}
// dietro
if ( ptMaxA.y - ptMaxInt.y > EPS_SMALL) {
BBox3d boxD( Point3d( ptMinA.x, ptMaxInt.y, ptMinInt.z), Point3d( ptMaxA.x, ptMaxA.y, ptMaxInt.z)) ;
vBoxDiff.emplace_back( boxD) ;
}
// sinistra
if ( ptMinInt.x - ptMinA.x > EPS_SMALL) {
BBox3d boxD( Point3d( ptMinA.x, ptMinInt.y, ptMinInt.z), Point3d( ptMinInt.x, ptMaxInt.y, ptMaxInt.z)) ;
vBoxDiff.emplace_back( boxD) ;
}
// destra
if ( ptMaxA.y - ptMaxInt.y > EPS_SMALL) {
BBox3d boxD( Point3d( ptMaxInt.x, ptMinInt.y, ptMinInt.z), Point3d( ptMaxA.x, ptMaxInt.y, ptMaxInt.z)) ;
vBoxDiff.emplace_back( boxD) ;
}
// risultato
return ( ! vBoxDiff.empty()) ;
}
//----------------------------------------------------------------------------
static bool
DistPointSurfTmMultiThread( const Point3d& ptP, const SurfTriMesh& SurfTm, double& dDist,
bool& bIsInside, INTVECTOR& vIndClosestTria)
{
// verifico che la supercicie sia valida
if ( ! SurfTm.IsValid())
return false ;
// inizializzo distanza non calcolata
dDist = - 1. ;
// vettore di indici dei triangoli più vicini inizialmente vuoto
vIndClosestTria.clear() ;
// vettore dei flag temporanei inizialmente tutto a 0
INTVECTOR vIntFlags( SurfTm.GetTriangleCount(), 0) ;
// recupero e verifico il box locale della superficie
BBox3d b3Stm = SurfTm.GetAllTriaBox() ;
if ( b3Stm.IsEmpty())
return false ;
// cerco triangoli in box centrati sul punto dato di ampiezza crescente ed escludendo le parti già verificate.
// termino quando non trovo più triangoli che possano soddisfare la richiesta.
Point3d ptMin, ptMax ; b3Stm.GetMinMax( ptMin, ptMax) ;
double dDeltaLen = max( min( min( b3Stm.GetDimX(), b3Stm.GetDimY()), b3Stm.GetDimZ()) / 40., 20.) ;
double dBoxHalfLenX = max( max( ptMin.x - ptP.x, ptP.x - ptMax.x), 0.) + dDeltaLen ;
double dBoxHalfLenY = max( max( ptMin.y - ptP.y, ptP.y - ptMax.y), 0.) + dDeltaLen ;
double dBoxHalfLenZ = max( max( ptMin.z - ptP.z, ptP.z - ptMax.z), 0.) + dDeltaLen ;
// considero anche il box precedente per poter analizzare solo il volume differenza tra i due
BBox3d boxPPrev( ptP) ;
BBox3d boxP( ptP, dBoxHalfLenX, dBoxHalfLenY, dBoxHalfLenZ) ;
// variabili distanza minima, indice del triangolo di distanza minima, punto di distanza minima
double dMinDist = DBL_MAX ;
int nMinDistTriaIndex = SVT_NULL ;
Point3d ptMinDistPoint ;
// finché non si verifica la condizione di terminazione ingrandisco il box.
bool bContinue = true ;
// creazione del vettore dei triangoli più vicini a ptP
vector<pair<int, Triangle3d>> vTria ; // <indice triangolo, Triangolo>
while ( bContinue) {
// calcolo il box differenza con il precedente per non esplorare parti già considerate
BOXVECTOR vBox ;
BoundingBoxDifference( boxP, boxPPrev, vBox) ;
// Ciclo sui box differenza
bool bCollide = false ;
for ( const auto& b3Box : vBox) {
// interseco il box con quello della superficie e ne verifico la distanza minima dal punto
BBox3d b3Int ;
if ( ! b3Box.FindIntersection( b3Stm, b3Int) || b3Int.DistFromPoint( ptP) > dMinDist)
continue ;
// ricerca sui triangoli nel box
bCollide = true ;
INTVECTOR vnIds ;
if ( SurfTm.GetAllTriaOverlapBox( b3Int, vnIds)) {
// ciclo sui triangoli del sotto-box corrente
for ( auto nT : vnIds) {
Triangle3d trCurTria ;
if ( vIntFlags[nT] == 0 && SurfTm.GetTriangle( nT, trCurTria)) {
vIntFlags[nT] = 1 ;
DistPointTriangle distPT( ptP, trCurTria) ;
double dCurrDist ;
// se la distanza del triangolo è valida e minore di quella attuale aggiorno
if ( distPT.GetDist( dCurrDist)) {
// se distanze uguali...
if ( abs( dCurrDist - dMinDist) < EPS_SMALL)
// aggiungo il triangolo
vTria.emplace_back( make_pair( nT, trCurTria)) ;
// se minore...
else if ( dCurrDist < dMinDist) {
// pulisco il vettore
vTria.clear() ;
dMinDist = dCurrDist ;
nMinDistTriaIndex = nT ;
distPT.GetMinDistPoint( ptMinDistPoint) ;
// aggiungo il triangolo
vTria.emplace_back( make_pair( nT, trCurTria)) ;
}
}
}
}
}
}
// se si verifica la condizione di terminazione arresto il ciclo altrimenti aggiorno i box
if ( ! bCollide || dMinDist < EPS_SMALL)
bContinue = false ;
else {
boxPPrev = boxP ;
boxP.Expand( dDeltaLen) ;
}
}
// se non ho trovato nessun triangolo, errore
if ( nMinDistTriaIndex == SVT_NULL)
return false ;
// riempio il vettore dei triangoli a minima distanza
for ( auto& Tria : vTria)
vIndClosestTria.emplace_back( Tria.first) ;
// salvo la distanza
dDist = dMinDist ;
// determino il Side
if ( dDist < EPS_SMALL) {
bIsInside = false ;
return true ;
}
// se ho solo un triangolo
else if ( int( vTria.size()) == 1) {
bIsInside = ( ( ptP - ptMinDistPoint) * vTria.back().second.GetN() < - EPS_SMALL) ;
return true ;
}
// controllo se tutti i triangoli a minima distanza forniscono la stessa informazione
// ( il punto potrebbe essere esterno a tutti, interno a tutti o indefinito )
bool bInside = false ;
bool bOutside = false ;
for ( int i = 0 ; i < int( vTria.size()) ; ++ i) {
if ( ( ptP - vTria[i].second.GetP( 0)) * vTria[i].second.GetN() < - EPS_SMALL)
bInside = true ;
else
bOutside = true ;
}
bIsInside = false ;
if ( bOutside == bInside) {
Point3d ptBar_tot ;
for ( const auto& Tria : vTria)
ptBar_tot += Tria.second.GetCentroid() ;
for ( const auto& Tria : vTria) {
Point3d ptInters1, ptInters2 ;
int nType = IntersLineTria( ptP, ptBar_tot, Tria.second, ptInters1, ptInters2) ;
if ( nType == ILTT_IN) {
DistPointTriangle( ptP, Tria.second).GetMinDistPoint( ptMinDistPoint) ;
bIsInside = ( ( ptP - ptMinDistPoint) * Tria.second.GetN() < - EPS_SMALL) ;
nMinDistTriaIndex = Tria.first ;
break ;
}
}
}
else
bIsInside = bInside ;
return true ;
}
//----------------------------------------------------------------------------
static bool
ClassifyTrianglesMultiThread( const TRIA3DEXVECTOR& vTria, int nIndS, int nIndE,
const SurfTriMesh& SurfTm, double dOffs, double dPrec,
bool bSaveInside, BOOLVECTOR& vbSafe)
{
// verifico che la superficie sia valida
if ( ! SurfTm.IsValid())
return false ;
// verifico la validità degli indici
if ( nIndS < 0 || nIndE >= int( vTria.size()))
return false ;
// verifico la dimensione dei vettori
if ( vTria.size() != vbSafe.size())
return false ;
// scorro gli indici dei triangoli da classificare
for ( int k = nIndS ; k <= nIndE ; ++ k) {
// recupero il triangolo corrente
const Triangle3dEx& Tria = vTria[k] ;
// preparo gli elementi di classificazione
DBLVECTOR vDists ; vDists.resize( 3) ;
INTMATRIX matIndClosestTria ; matIndClosestTria.resize( 3) ;
// verifico che i suoi punti siano distanti almeno |dOffs| - dTol dalla superficie
vbSafe[k] = true ;
for ( int i = 0 ; vbSafe[k] && i < 3 ; ++ i) {
bool bIsInside = false ;
DistPointSurfTmMultiThread( Tria.GetP( i), SurfTm, vDists[i], bIsInside, matIndClosestTria[i]) ;
vbSafe[k] = ( ( vDists[i] > abs( dOffs) - 0.25 * dPrec) &&
( vDists[i] < abs( dOffs) + 0.25 * dPrec) &&
( bIsInside == bSaveInside)) ;
}
// se tutti sufficientemente distanti
if ( vbSafe[k]) {
// i triangoli a minima distanza devono avere normale simile
bool bPerp = true ;
for ( int i = 0 ; bPerp && i < 3 ; ++ i) {
for ( int j = 0 ; bPerp && j < int( matIndClosestTria[i].size()) ; ++ j) {
Triangle3d TriaCloser ;
SurfTm.GetTriangle( matIndClosestTria[i][j], TriaCloser) ;
bPerp = ( abs( Tria.GetN() * TriaCloser.GetN()) < cos( 30. * DEGTORAD)) ;
}
}
vbSafe[k] = ( ! bPerp) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
// Funzione che crea l'Offset di una superficie TriMesh
//----------------------------------------------------------------------------
@@ -94,123 +350,138 @@ CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPr
return SumStm( vStm) ;
// creo lo Zmap associato alle superfici TriMesh
VolZmap OneVolZmap ;
if ( ! OneVolZmap.CreateFromTriMeshOffset( vStm, dOffs, dMyPrec, nType))
VolZmap myVolZmap ;
if ( ! myVolZmap.CreateFromTriMeshOffset( vStm, dOffs, dMyPrec, nType))
return nullptr ;
if ( ! OneVolZmap.IsValid())
if ( ! myVolZmap.IsValid())
return nullptr ;
// recupero le superfici aperte
CISURFTMPVECTOR vStmOpen ;
for ( const ISurfTriMesh* pStm : vStm) {
if ( pStm != nullptr && pStm->IsValid() && ! pStm->IsClosed())
if ( pStm != nullptr && pStm->IsValid() && ! pStm->IsClosed())
vStmOpen.emplace_back( pStm) ;
}
// --- se non ho superfici aperte
if ( vStmOpen.empty()) {
// restituisco la superficie TriMesh di Offset
return ( OneVolZmap.GetSurfTriMesh()) ;
return ( myVolZmap.GetSurfTriMesh()) ;
}
// --- se ho delle superfici aperte
// lo Zmap creato è orientato e definisce una superficie chiusa; devo rimuovere i triangoli in eccesso
// anzitutto controllo che lo Zmap sia valido
if ( ! OneVolZmap.IsValid())
return nullptr ;
// inzializzo la superficie TriMesh da restituire
PtrOwner<SurfTriMesh> pStm( CreateBasicSurfTriMesh()) ;
if ( IsNull( pStm) || ! pStm->Init( 3, 1))
return nullptr ;
PointGrid3d VertGrid ; VertGrid.Init( 50000) ;
// tolleranza di vicinanza alla superficie
double dTolDist = 30. * EPS_SMALL ;
#if DEBUG
VT.emplace_back( OneVolZmap.Clone()) ;
VC.emplace_back( BLACK) ;
#endif
// ciclo lungo i blocchi dello ZMap
for ( int nB = 0 ; nB < OneVolZmap.GetBlockCount() ; ++ nB) {
// recupero i triangoli
// --- se ho delle superfici chiuse
TRIA3DEXVECTOR vAllTria, vTriaOffs ;
for ( int nB = 0 ; nB < myVolZmap.GetBlockCount() ; ++ nB) {
TRIA3DEXVECTOR vTria, vTriaSafe ;
OneVolZmap.GetBlockTriangles( nB, vTria) ;
// un triangolo viene ritenuto valido se è non è troppo vicino ( dOffs) alle superfici aperte
myVolZmap.GetBlockTriangles( nB, vTria) ;
#if DEBUG
TRIA3DVECTOR vTriaUnsafe ;
#endif
for ( int nT = 0 ; nT < int( vTria.size()) ; ++ nT) {
// recupero il triangolo
Triangle3dEx& Tria = vTria[nT] ;
// scorro le superficie aperte
bool bInsert = true ;
for ( int nS = 0 ; bInsert && nS < int( vStm.size()) ; ++ nS) {
// controllo se posso inserirlo
vector<DistPointSurfTm> vDistPtStm ;
for ( int i = 0 ; i < 3 && bInsert ; ++ i) {
double dDist = 0. ;
vDistPtStm.emplace_back( DistPointSurfTm( Tria.GetP( i), *vStm[nS])) ;
bInsert = ( vDistPtStm.back().GetDist( dDist) && dDist > abs( dOffs) - dTolDist) ;
}
// se il triangolo è al più a distanza di |dOffs| - dTolDist
if ( bInsert) {
// recupero i triangoli a distanza minima dai vertici del triangolo corrente
bool bPerp = true ;
for ( int i = 0 ; i < 3 && bPerp ; ++ i) {
INTVECTOR vTria ;
vDistPtStm[i].GetMinDistTriaIndices( vTria) ;
for ( int j = 0 ; j < int( vTria.size()) && bPerp ; ++ j) {
Triangle3d TriaCloser ;
vStm[nS]->GetTriangle( vTria[j], TriaCloser) ;
bPerp = ( abs( Tria.GetN() * TriaCloser.GetN()) < dTolDist) ;
}
}
// se tutti i triangoli a distanza minima sono perpendicolari, allora non lo inserisco
bInsert = ( ! bPerp) ;
BBox3d BBoxTria ;
Tria.GetLocalBBox( BBoxTria) ;
// azzero flag di colore
vAllTria.push_back( Tria) ;
}
}
// classifico i triangoli
PtrOwner<const SurfTriMesh> pStmBasic( nullptr) ;
if ( int( vStmOpen.size() == 1))
pStmBasic.Set( GetBasicSurfTriMesh( CloneSurfTriMesh( vStmOpen[0]))) ;
else {
StmFromTriangleSoup AllOpenStmSoup ; AllOpenStmSoup.Start() ;
for ( const ISurfTriMesh* pStmOpen : vStmOpen) {
if ( pStmOpen != nullptr && pStmOpen->IsValid()) {
for ( int nT = 0 ; nT < pStmOpen->GetTriangleCount() ; ++ nT) {
Triangle3d Tria ;
if ( pStmOpen->GetTriangle( nT, Tria))
AllOpenStmSoup.AddTriangle( Tria) ;
}
}
// se triangolo da inserire
if ( bInsert)
vTriaSafe.emplace_back( Tria) ;
#if DEBUG
ICurveComposite* pCompo = CreateCurveComposite() ;
pCompo->AddPoint( Tria.GetP( 0)) ;
pCompo->AddLine( Tria.GetP( 1)) ;
pCompo->AddLine( Tria.GetP( 2)) ;
pCompo->Close() ;
Color myCol = ( bInsert ? Color( 0., 1., 0., .5) : Color( 1., 0., 0., .5)) ;
VT.emplace_back( CloneCurveComposite( pCompo)) ;
VC.emplace_back( myCol) ;
ISurfFlatRegion* pSfrTria = CreateSurfFlatRegion() ;
pSfrTria->AddExtLoop( pCompo) ;
VT.emplace_back( pSfrTria) ;
VC.emplace_back( myCol) ;
#endif
}
// inserisco tutti i triangoli validi
if ( ! pStm->AddTriaFromZMap( vTriaSafe, VertGrid))
return nullptr ;
AllOpenStmSoup.End() ;
pStmBasic.Set( GetBasicSurfTriMesh( AllOpenStmSoup.GetSurf())) ;
}
if ( pStmBasic == nullptr)
return nullptr ;
BBox3d b3Stm = pStmBasic->GetAllTriaBox() ;
if ( b3Stm.IsEmpty())
return nullptr ;
// numero di triangoli da analizzare
int nTriaCnt = int( vAllTria.size()) ;
// definisco un vettore di Flag per i triangoli già visitati
INTVECTOR vIntFlags( pStmBasic->GetTriangleCount()) ;
// numero massimo di thread concorrenti
int nThreadMax = thread::hardware_concurrency() ;
bool bOk = true ;
BOOLVECTOR vbSafeTria( vAllTria.size(), true) ;
if ( nThreadMax <= 1 || nTriaCnt < 50)
ClassifyTrianglesMultiThread( vAllTria, 0, nTriaCnt - 1, *pStmBasic, abs( dOffs), dPrec, ( dOffs < 0.), vbSafeTria) ;
else {
const int MAX_PARTS = 32 ;
INTINTVECTOR vFstLst( MAX_PARTS) ;
// calcolo le parti del vettore
int nPartCnt = min( nThreadMax, MAX_PARTS) ;
int nPartDim = nTriaCnt / nPartCnt + 1 ;
for ( int i = 0 ; i < nPartCnt ; ++ i) {
vFstLst[i].first = i * nPartDim ;
vFstLst[i].second = min( ( i + 1) * nPartDim, nTriaCnt) - 1 ;
}
// processo le parti
future<bool> vRes[MAX_PARTS] ;
for ( int i = 0 ; i < nPartCnt ; ++ i) {
vRes[i] = async( launch::async, &ClassifyTrianglesMultiThread, cref( vAllTria), vFstLst[i].first,
vFstLst[i].second, cref( *pStmBasic), abs( dOffs), dPrec, ( dOffs < 0.), ref( vbSafeTria)) ;
}
// attendo i risultati
int nFin = 0 ;
while ( nFin < nPartCnt) {
for ( int i = 0 ; i < nPartCnt ; ++ i) {
if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
bOk = vRes[i].get() && bOk ;
++ nFin ;
}
}
}
}
if ( ! bOk)
return nullptr ;
TRIA3DEXVECTOR vTriaSafe ; vTriaSafe.reserve( vAllTria.size()) ;
#if DEBUG
TRIA3DEXVECTOR vTriaUnSafe ; vTriaUnSafe.reserve( vAllTria.size()) ;
#endif
for ( int i = 0 ; i < int( vAllTria.size()) ; ++ i) {
if ( vbSafeTria[i])
vTriaSafe.emplace_back( vAllTria[i]) ;
#if DEBUG
if ( ! vbSafeTria[i])
vTriaUnSafe.emplace_back( vAllTria[i]) ;
#endif
}
// definisco la superficie con i soli triangoli validi
StmFromTriangleSoup TriaSoup ; TriaSoup.Start() ;
for ( const Triangle3d& SafeTria : vTriaSafe)
TriaSoup.AddTriangle( SafeTria) ;
TriaSoup.End() ;
PtrOwner<ISurfTriMesh> pStmOffs( TriaSoup.GetSurf()) ;
if ( IsNull( pStmOffs) || ! pStmOffs->IsValid() || pStmOffs->GetTriangleCount() == 0)
return nullptr ;
#if DEBUG
StmFromTriangleSoup _invalidSoup ; _invalidSoup.Start() ;
for ( const Triangle3d& _unsafeTria : vTriaUnSafe)
_invalidSoup.AddTriangle( _unsafeTria) ;
_invalidSoup.End() ;
VT.emplace_back( pStmOffs->Clone()) ;
VC.emplace_back( LIME) ;
VT.emplace_back( _invalidSoup.GetSurf()) ;
VC.emplace_back( RED) ;
SaveGeoObj( VT, VC, "C:\\Temp\\TriangleSelection.nge") ;
#endif
// sistemo la topologia
if ( ! pStm->AdjustTopologyFromZMap())
return nullptr ;
return ( Release( pStm)) ;
return ( Release( pStmOffs)) ;
}
//----------------------------------------------------------------------------
@@ -240,3 +511,281 @@ CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs,
// restituisco la superficie TriMesh
return ( OneVolZmap.GetSurfTriMesh()) ;
}
//----------------------------------------------------------------------------
// Funzione per creare la Superficie TriMesh Shell da una Trimesh aperta
//----------------------------------------------------------------------------
ISurfTriMesh*
CreateSurfTriMeshShell( const ISurfTriMesh* pStm, double dThick, double dPrec)
{
// verifico che la superficie sia valida ed aperta
if ( pStm == nullptr || ! pStm->IsValid() || pStm->IsClosed())
return nullptr ;
// lo spessore deve essere sempre positivo, il verso è sempre dato dalla normale dei triangoli
dThick = - max( 10. * EPS_SMALL, abs( dThick)) ;
// creo il suo Offset ( salvandomi lo Zmap per l'orientamento)
#if DEBUG
PerformanceCounter PC ; PC.Start() ;
#endif
VolZmap myVolZMap ;
if ( ! myVolZMap.CreateFromTriMeshOffset( { pStm}, dThick, dPrec))
return nullptr ;
if ( ! myVolZMap.IsValid())
return nullptr ;
#if DEBUG
LOG_INFO( GetEGkLogger(), ( string{ "Tria Time : "} + ToString( PC.Stop())).c_str()) ;
VT.clear() ; VC.clear() ;
VT.emplace_back( myVolZMap.Clone()) ;
VC.emplace_back( BLACK) ;
VT.emplace_back( pStm->Clone()) ;
VC.emplace_back( YELLOW) ;
SaveGeoObj( VT, VC, "C:\\Temp\\VolZMapOffs.nge") ;
#endif
#if DEBUG
VT.clear() ; VC.clear() ;
PC.Start() ;
#endif
// recupero i triangoli dallo ZMap creato
TRIA3DEXVECTOR vAllTria, vTriaOffs ;
for ( int nB = 0 ; nB < myVolZMap.GetBlockCount() ; ++ nB) {
TRIA3DEXVECTOR vTria, vTriaSafe ;
myVolZMap.GetBlockTriangles( nB, vTria) ;
#if DEBUG
TRIA3DVECTOR vTriaUnsafe ;
#endif
for ( int nT = 0 ; nT < int( vTria.size()) ; ++ nT) {
Triangle3dEx& Tria = vTria[nT] ;
BBox3d BBoxTria ;
Tria.GetLocalBBox( BBoxTria) ;
// azzero flag di colore
vAllTria.push_back( Tria) ;
}
}
// classifico i triangoli
const SurfTriMesh* pStmBasic = GetBasicSurfTriMesh( pStm) ;
if ( pStmBasic == nullptr)
return nullptr ;
BBox3d b3Stm = pStmBasic->GetAllTriaBox() ;
if ( b3Stm.IsEmpty())
return nullptr ;
// numero di triangoli da analizzare
int nTriaCnt = int( vAllTria.size()) ;
// definisco un vettore di Flag per i triangoli già visitati
INTVECTOR vIntFlags( pStmBasic->GetTriangleCount()) ;
// numero massimo di thread concorrenti
int nThreadMax = thread::hardware_concurrency() ;
bool bOk = true ;
BOOLVECTOR vbSafeTria( vAllTria.size(), true) ;
if ( nThreadMax <= 1 || nTriaCnt < 50)
ClassifyTrianglesMultiThread( vAllTria, 0, nTriaCnt - 1, *pStmBasic, dThick, dPrec, true, vbSafeTria) ;
else {
const int MAX_PARTS = 32 ;
INTINTVECTOR vFstLst( MAX_PARTS) ;
// calcolo le parti del vettore
int nPartCnt = min( nThreadMax, MAX_PARTS) ;
int nPartDim = nTriaCnt / nPartCnt + 1 ;
for ( int i = 0 ; i < nPartCnt ; ++ i) {
vFstLst[i].first = i * nPartDim ;
vFstLst[i].second = min( ( i + 1) * nPartDim, nTriaCnt) - 1 ;
}
// processo le parti
future<bool> vRes[MAX_PARTS] ;
for ( int i = 0 ; i < nPartCnt ; ++ i) {
vRes[i] = async( launch::async, &ClassifyTrianglesMultiThread, cref( vAllTria), vFstLst[i].first,
vFstLst[i].second, cref( *pStmBasic), dThick, dPrec, true, ref( vbSafeTria)) ;
}
// attendo i risultati
int nFin = 0 ;
while ( nFin < nPartCnt) {
for ( int i = 0 ; i < nPartCnt ; ++ i) {
if ( vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
bOk = vRes[i].get() && bOk ;
++ nFin ;
}
}
}
}
if ( ! bOk)
return nullptr ;
TRIA3DEXVECTOR vTriaSafe ; vTriaSafe.reserve( vAllTria.size()) ;
#if DEBUG
TRIA3DEXVECTOR vTriaUnSafe ; vTriaUnSafe.reserve( vAllTria.size()) ;
#endif
for ( int i = 0 ; i < int( vAllTria.size()) ; ++ i) {
if ( vbSafeTria[i])
vTriaSafe.emplace_back( vAllTria[i]) ;
#if DEBUG
if ( ! vbSafeTria[i])
vTriaUnSafe.emplace_back( vAllTria[i]) ;
#endif
}
// definisco la superficie con i soli triangoli validi
StmFromTriangleSoup TriaSoup ; TriaSoup.Start() ;
for ( const Triangle3d& SafeTria : vTriaSafe)
TriaSoup.AddTriangle( SafeTria) ;
TriaSoup.End() ;
PtrOwner<ISurfTriMesh> pStmOffs( TriaSoup.GetSurf()) ;
if ( IsNull( pStmOffs) || ! pStmOffs->IsValid() || pStmOffs->GetTriangleCount() == 0)
return nullptr ;
#if DEBUG
LOG_INFO( GetEGkLogger(), ( string{ "Tria Time ( exceed Approx) : "} + ToString( PC.Stop())).c_str()) ;
StmFromTriangleSoup _invalidSoup ; _invalidSoup.Start() ;
for ( const Triangle3d& _unsafeTria : vTriaUnSafe)
_invalidSoup.AddTriangle( _unsafeTria) ;
_invalidSoup.End() ;
VT.emplace_back( pStmOffs->Clone()) ;
VC.emplace_back( LIME) ;
VT.emplace_back( _invalidSoup.GetSurf()) ;
VC.emplace_back( RED) ;
SaveGeoObj( VT, VC, "C:\\Temp\\TriangleSelection.nge") ;
VT.clear() ; VC.clear() ;
PC.Start() ;
#endif
// recupero i loops della superficie originaria e del suo Offset orientato ( non devono essere diminuiti)
POLYLINEVECTOR vPL, vPLOffs ;
if ( ! pStm->GetLoops( vPL) || ! pStmOffs->GetLoops( vPLOffs))
return nullptr ;
// trasformo ogni loop in curve composite ( devono essere chiuse)
ICRVCOMPOPOVECTOR vCompoLoops ; vCompoLoops.reserve( vPL.size()) ;
for ( const PolyLine& PL : vPL) {
if ( PL.IsClosed()) {
if ( ! vCompoLoops.emplace_back( CreateCurveComposite()) ||
! vCompoLoops.back()->FromPolyLine( PL) ||
! vCompoLoops.back()->IsValid())
return nullptr ;
}
}
ICRVCOMPOPOVECTOR vCompoOffsLoops ; vCompoOffsLoops.reserve( vPLOffs.size()) ;
for ( const PolyLine& PLOffs : vPLOffs) {
if ( PLOffs.IsClosed()) {
if ( ! vCompoOffsLoops.emplace_back( CreateCurveComposite()) ||
! vCompoOffsLoops.back()->FromPolyLine( PLOffs) ||
! vCompoOffsLoops.back()->IsValid())
return nullptr ;
}
}
#if DEBUG
VT.emplace_back( pStmOffs->Clone()) ;
VC.emplace_back( YELLOW) ;
for ( ICurveComposite* pCompo : vCompoLoops) {
VT.emplace_back( pCompo->Clone()) ;
VC.emplace_back( AQUA) ;
}
for ( ICurveComposite* pCompoOffs : vCompoOffsLoops) {
VT.emplace_back( pCompoOffs->Clone()) ;
VC.emplace_back( ORANGE) ;
}
SaveGeoObj( VT, VC, "C:\\Temp\\myCurve.nge") ;
VT.clear() ; VC.clear() ;
#endif
// per ogni curva della superficie originale cerco la sua associata
// NB. per la creazione della superficie ruled la prima curva è quellla che determina il verso
// dei triangoli associati. Per un corretto ed automatico orientamento della superficie
// la prima curva deve essere sempre definita dalla superficie originale ed invertita ( le
// curve nella rigata devono seguire lo stesso orientamento
ISURFTMPOVECTOR vStmRuled ; vStmRuled.reserve( vCompoLoops.size()) ;
BOOLVECTOR vIndMatched( vCompoOffsLoops.size(), false) ;
for ( ICurveComposite* pCompoLoop : vCompoLoops) {
// sposto il punto iniziale della curva nel tratto più lungo
double dMaxLen = - INFINITO ;
int nIndCrv = 0 ;
for ( int nCrv = 0 ; nCrv < pCompoLoop->GetCurveCount() ; ++ nCrv) {
const ICurve* pCurve = pCompoLoop->GetCurve( nCrv) ;
if ( pCurve != nullptr && pCurve->IsValid()) {
double dCurrLen = 0. ;
pCurve->GetLength( dCurrLen) ;
if ( dCurrLen > dMaxLen) {
dMaxLen = dCurrLen ;
nIndCrv = nCrv ;
}
}
}
pCompoLoop->ChangeStartPoint( nIndCrv + 0.5) ;
Point3d ptStart ; pCompoLoop->GetStartPoint( ptStart) ;
// dalle altre curve derivanti dalla superficie di Offset cerco quella più vicina al punto inziale
double dMinSqDist = INFINITO ;
int nIndOffsCrv = -1 ;
Point3d ptMinDist ;
for ( int nOffsCrv = 0 ; nOffsCrv < int( vCompoOffsLoops.size()) ; ++ nOffsCrv) {
if ( vIndMatched[nOffsCrv])
continue ;
// recupero la curva e calcolo la distanza
const ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nOffsCrv] ;
int nFlag = 0 ;
Point3d ptCurrMinDist ;
if ( DistPointCurve( ptStart, *pCompoOffsLoop).GetMinDistPoint( 0., ptCurrMinDist, nFlag)) {
double dCurrSqDist = SqDist( ptStart, ptCurrMinDist) ;
if ( dCurrSqDist < dMinSqDist) {
dMinSqDist = dCurrSqDist ;
nIndOffsCrv = nOffsCrv ;
ptMinDist = ptCurrMinDist ;
}
}
}
if ( nIndOffsCrv == -1)
return nullptr ;
vIndMatched[ nIndOffsCrv] = true ;
// associo le due curve
ICurveComposite* pCompoOffsLoop = vCompoOffsLoops[nIndOffsCrv] ;
double dParMinDist = 0. ;
pCompoOffsLoop->GetParamAtPoint( ptMinDist, dParMinDist, 10. * EPS_SMALL) ;
pCompoOffsLoop->ChangeStartPoint( dParMinDist) ;
#if DEBUG
Color _cCol = Color( double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, double( rand()) / RAND_MAX, 1.) ;
VT.emplace_back( pCompoLoop->Clone()) ;
VC.emplace_back( _cCol) ;
VT.emplace_back( pCompoOffsLoop->Clone()) ;
VC.emplace_back( _cCol) ;
#endif
// creo la superficie tra queste due curve e la oriento in modo da definire un volume
pCompoLoop->Invert() ;
PtrOwner<ISurfTriMesh> pStmRuled( GetSurfTriMeshRuled( pCompoLoop, pCompoOffsLoop, ISurfTriMesh::RuledType::RLT_MINDIST)) ;
if ( IsNull( pStmRuled) || ! pStmRuled->IsValid() ||
! vStmRuled.emplace_back( Release( pStmRuled)))
return nullptr ;
#if DEBUG
LOG_INFO( GetEGkLogger(), ( string{ "Strip generation : "} + ToString( PC.Stop())).c_str()) ;
VT.emplace_back( vStmRuled.back()->Clone()) ;
VC.emplace_back( _cCol) ;
_cCol.SetAlpha( .5) ;
#endif
}
#if DEBUG
SaveGeoObj( VT, VC, "C:\\Temp\\Strips.nge") ;
PC.Start() ;
#endif
// compongo la superficie finale
PtrOwner<ISurfTriMesh> pStmOrig( CloneSurfTriMesh( pStm)) ;
if ( IsNull( pStmOrig) || ! pStmOrig->IsValid())
return nullptr ;
PtrOwner<ISurfTriMesh> pStmRef( Release( pStmOrig)) ;
if ( IsNull( pStmRef) || ! pStmRef->IsValid())
return nullptr ;
for ( int nStrip = 0 ; nStrip < int( vStmRuled.size()) ; ++ nStrip) {
if ( ! pStmRef->DoSewing( *vStmRuled[nStrip]))
return nullptr ;
}
if ( ! pStmRef->DoSewing( *pStmOffs))
return nullptr ;
pStmRef->Repair() ;
#if DEBUG
LOG_INFO( GetEGkLogger(), ( string{ "Sewing : "} + ToString( PC.Stop())).c_str()) ;
#endif
return ( ( ! IsNull( pStmRef) && pStmRef->IsValid()) ? Release( pStmRef) : nullptr) ;
}
+10 -10
View File
@@ -36,25 +36,25 @@ class Tool
bool SetAdditiveTool( const std::string& sToolName, double dH, double dR, double dRc, int nToolNum) ;
bool SetToolNum( int nToolNum)
{ m_nCurrentNum = nToolNum ; return true ; }
int GetType() const
int GetType( void) const
{ return m_nType ; }
int GetToolNum() const
int GetToolNum( void) const
{ return m_nCurrentNum ; }
double GetHeigth() const
double GetHeigth( void) const
{ return m_dHeight ; }
double GetTipHeigth() const
double GetTipHeigth( void) const
{ return m_dTipHeight ; }
double GetRadius() const
double GetRadius( void) const
{ return m_dRadius ; }
double GetTipRadius() const
double GetTipRadius( void) const
{ return m_dTipRadius ; }
double GetCornRadius() const
double GetCornRadius( void) const
{ return m_dRCorner ; }
double GetRefRadius() const
double GetRefRadius( void) const
{ return m_dRefRadius ; }
double GetMrtChsWidth() const
double GetMrtChsWidth( void) const
{ return m_dMrtChsWidth ; }
double GetMrtChsThickness() const
double GetMrtChsThickness( void) const
{ return m_dMrtChsThickness ; }
const CurveComposite& GetOutline( void) const
{ return ( m_Outline) ; }
+355 -132
View File
File diff suppressed because it is too large Load Diff
+35 -19
View File
@@ -23,7 +23,8 @@
#include <utility>
struct PairHashInt64 {
size_t operator()(const std::pair<int64_t, int64_t>& key) const {
size_t
operator()( const std::pair<int64_t, int64_t>& key) const {
size_t h1 = std::hash<int64_t>{}(key.first) ;
size_t h2 = std::hash<int64_t>{}(key.second) ;
return h1 ^ (h2 << 1); // Combine hashes
@@ -33,14 +34,20 @@ struct PairHashInt64 {
//----------------------------------------------------------------------------
struct Inters {
int nIn ;
PNTVECTOR vpt ;
int nOut ;
PNTVECTOR vpt ;
bool bCCW ;
int nChunk ;
bool bSortedbyStart ;
// riordino le intersezioni per lato in senso antiorario dal top
// se ho più intersezioni che entrano in un lato le riordino considerando che percorro i lati in senso antiorario a partire da ptTR
bool operator < ( Inters& b)
// nIn e nOut sono flag che indicano da quale lato ho l'ingresso e l'uscita a partire dal lato top in senso antiorario
// oltre il 3 sono le celle adiacenti in diagonale al vertice-> 4 corrisponde al ptTl e da lì in senso antiorario
// -1 se la curva è sempre dentro la cella
// riordino le intersezioni per lato in senso antiorario dal top
// se ho più intersezioni che entrano in un lato le riordino considerando che percorro i lati in senso antiorario a partire da ptTR
bool
operator < ( Inters& b)
{
// trovo in che ordine stanno i due start, tenendo conto anche della possibilità che siano vertici
INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6, 3} ;
@@ -75,7 +82,8 @@ struct Inters {
( bEqIn && nEdgeIn == 3 && vpt[0].y < b.vpt[0].y)) ;
}
static bool FirstEncounter( Inters& a, Inters& b)
static bool
FirstEncounter( Inters& a, Inters& b)
{
// riordino in base al lato toccato, o dall'uscita o dall'ingresso, che viene prima.
// ottengo l'ordine che avrei percorrendo il bordo da ptTR e considerando i loop che incontro, indipendentemente se li incontro nel punto di uscita o ingresso
@@ -135,18 +143,18 @@ struct Inters {
( nPos1 == 3 && a.vpt[nFirstA].y < b.vpt[nFirstB].y) ;
}
bool operator == ( Inters& b)
bool
operator == ( Inters& b)
{
return AreSamePointExact( vpt[0], b.vpt[0]) ;
}
bool operator != ( Inters& b)
bool
operator != ( Inters& b)
{
return ! AreSamePointExact( vpt[0], b.vpt[0]) ;
}
} ;
// nIn e nOut sono flag che indicano da quale lato ho l'ingresso e l'uscita a partire dal lato top in senso antiorario
// oltre il 3 sono le celle adiacenti in diagonale al vertice-> 4 corrisponde al ptTl e da lì in senso antiorario
// -1 se la curva è sempre dentro la cella
//----------------------------------------------------------------------------
class Cell
@@ -160,17 +168,24 @@ class Cell
// | |
// |_________________|
// Edge 5 ( SW) Edge 2 (Bottom) Edge 6 ( SE)
public :
enum Collapsed { TO_VERIFY = -1, // da verificare
NO_COLLAPSE = 0, // non ho coppie di lati collassati
VERT_EDGES = 1, // coppia di lati verticali(1-3) sono collassati
HORIZ_EDGES = 2} ; // coppia di lati verticali(0-2) sono collassati
public :
~Cell( void) {}
Cell( void)
: m_nId( -1), m_nTop( -2), m_nBottom( -2), m_nLeft( -2), m_nRight( -2), m_nParent( -2), m_nDepth( 0),
m_dSplit( 0), m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_bLabelled( false), m_nRightEdgeIn( -1),
m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1), m_ptPbl( ORIG),
m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1), m_nCollapsed( -1), m_ptPbl( ORIG),
m_ptPtr( SBZ_TREG_COEFF, SBZ_TREG_COEFF, 0), m_bProcessed( false), m_bSplitVert( true) {}
Cell( const Point3d& ptBL, const Point3d& ptTR)
: m_nId( -1), m_nTop( -2), m_nBottom( -2), m_nLeft( -2), m_nRight( -2), m_nParent( -2), m_nDepth( 0),
m_dSplit( 0), m_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_bLabelled( 0), m_nRightEdgeIn( -1),
m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1), m_ptPbl( ptBL),
m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1), m_nCollapsed( -1), m_ptPbl( ptBL),
m_ptPtr( ptTR), m_bProcessed( false), m_bSplitVert( true) {}
bool IsSame( const Cell& cOtherCell) const
{ return ( m_nId == cOtherCell.m_nId) ; }
@@ -231,6 +246,7 @@ class Cell
int m_nVertToErase ; // vertice da eliminare dal poligono della cella, in caso di lato sovrapposto ad un lato di polo
// contati in senso CCW a partire dal bottom left
INTVECTOR m_vnPolyId ; // indici dei poligoni associati a questa cella nel vettore m_vPolygons del Tree
int m_nCollapsed ; // flag che indica se la coppia di lati verticali (1) o orizzontali(2) sono collassati
private :
Point3d m_ptPbl ; // punto bottom left
@@ -251,7 +267,7 @@ class Tree
bool BuildTree( double dLinTol = LIN_TOL_STD,
double dSideMin = 1, // è la minima lunghezza del lato di una cella
double dSideMax = INFINITO) ; // è la massima dimensione di un triangolo della trimesh
bool GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, std::vector<ICRVCOMPOPOVECTOR>& vCCEdges3D, ICRVCOMPOPOVECTOR& vCCLoops) ;
bool GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d, std::vector<ICRVCOMPOPOVECTOR>& vCCEdges3D, ICRVCOMPOPOVECTOR& vCCLoops, bool bUpdateEdges) ;
bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, POLYLINEVECTOR& vPolygonsCorrected, POLYLINEVECTOR& vPolygons3d) ; // restituisce il poligono corrispondente ad ogni cella foglia dell'albero
// ad ogni poligono sono stati aggiunti tutti i vertici dei vicini posizionati sui suoi lati
// ad alcuni poligoni potrebbero venire tolti dei punti per evitare errori dovuti ad eventuali poli sui bordi del parametrico
@@ -276,10 +292,10 @@ class Tree
bool Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert
int GetHeightLeaves( int nId, INTVECTOR& vnLeaves, int d = 0) const ; // altezza del subtree a partire dal nodo nId
int GetDepth( int nId, int nRef) const ; // livello del nodo nId
void GetTopNeigh( int nId, INTVECTOR& vTopNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato top
void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato bottom
void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato left
void GetRightNeigh( int nId, INTVECTOR& vRightNeighs) const ; // restituisce le celle foglie che sono adiacenti al lato right
void GetTopNeigh( int nId, INTVECTOR& vTopNeighs, DBLDBL ddInt = DBLDBL(0,0)) const ; // restituisce le celle foglie che sono adiacenti al lato top ( la coppia di double è per dare un intervallo diverso su cui limitare i vicini)
void GetBottomNeigh( int nId, INTVECTOR& vBottomNeighs, DBLDBL ddInt = DBLDBL(0,0)) const ; // restituisce le celle foglie che sono adiacenti al lato bottom
void GetLeftNeigh( int nId, INTVECTOR& vLeftNeighs, DBLDBL ddInt = DBLDBL(0,0)) const ; // restituisce le celle foglie che sono adiacenti al lato left
void GetRightNeigh( int nId, INTVECTOR& vRightNeighs, DBLDBL ddInt = DBLDBL(0,0)) const ; // restituisce le celle foglie che sono adiacenti al lato right
void GetRootNeigh( int nEdge, INTVECTOR& vNeigh) ; // restituisce le foglie dell'albero che sono adiacenti al lato nEdge, numerato a partire dal top ( 0) in senso antiorario
void ResetTree( void) ; // resetto m_bProcessed a false per tutti i nodi dell'albero
INTVECTOR FindCell( const Point3d& ptToAssign, const CurveLine& cl, bool bRecurs = false) const ; // dato un punto, trova la cella foglia a cui appartiene
@@ -329,4 +345,4 @@ class Tree
INTVECTOR m_vnParents ; // vettore delle celle ottenute dalla divisione preliminare in singole patch
ICRVCOMPOPOVECTOR m_vCCLoop2D ; // vettore che contiene le CurveCompo che rappresentano i loop di trim tenendo conto della divisione in celle
std::vector<std::pair<BIPNTVECTOR, ChainCurves>> m_vCEdge2D ; // vettore che le chain che rappresentano ciò che resta degli edge originali, tenendo conto dei trim.
} ;
} ;
+4843
View File
File diff suppressed because it is too large Load Diff
+14 -3
View File
@@ -133,6 +133,7 @@ VolZmap::CopyFrom( const VolZmap& vzmSrc)
m_nFracLin[0] = vzmSrc.m_nFracLin[0] ;
m_nFracLin[1] = vzmSrc.m_nFracLin[1] ;
m_nFracLin[2] = vzmSrc.m_nFracLin[2] ;
m_nDexVoxRatio = vzmSrc.m_nDexVoxRatio ;
m_nConnectedCompoCount = vzmSrc.m_nConnectedCompoCount ;
m_MapFrame = vzmSrc.m_MapFrame ;
@@ -208,6 +209,10 @@ VolZmap::Dump( string& sOut, bool bMM, const char* szNewLine) const
{
// tipo
sOut += "Type=" + string( m_nMapNum == 1 ? "dexel" : "tridexel") + szNewLine ;
// visualizzazione spigoli
sOut += "ShowEdges=" + ToString( GetShowEdges()) + szNewLine ;
// dexel per voxel (DexToVoxRatio)
sOut += "DexVoxRat=" + ToString( m_nDexVoxRatio) + szNewLine ;
// forma
switch ( m_nShape) {
default : sOut += "Shape=generic" ; break ;
@@ -229,8 +234,6 @@ VolZmap::Dump( string& sOut, bool bMM, const char* szNewLine) const
// numero di blocchi
sOut += "Blocks=" + ToString( m_nNumBlock) + " (" + ToString( m_nFracLin[0]) + "x" +
ToString( m_nFracLin[1]) + "x" + ToString( m_nFracLin[2]) + ")" + szNewLine ;
// dexel per voxel (DexToVoxRatio)
sOut += "DexVoxRat=" + ToString( m_nDexVoxRatio) + szNewLine ;
return true ;
}
@@ -504,11 +507,15 @@ VolZmap::GetLocalBBox( BBox3d& b3Loc, int nFlag) const
}
// passo al punto successivo
dX += m_dStep ;
if ( m_nMapNum == N_MAPS)
dX = min( dX, m_dMaxZ[1]) ;
}
// passo alla riga successiva
dY += m_dStep ;
if ( m_nMapNum == N_MAPS)
dY = min( dY, m_dMaxZ[2]) ;
}
//
return true ;
}
@@ -548,9 +555,13 @@ VolZmap::GetBBox( const Frame3d& frRef, BBox3d& b3Ref, int nFlag) const
}
// passo al punto successivo
dX += m_dStep ;
if ( m_nMapNum == N_MAPS)
dX = min( dX, m_dMaxZ[1]) ;
}
// passo alla riga successiva
dY += m_dStep ;
if ( m_nMapNum == N_MAPS)
dY = min( dY, m_dMaxZ[2]) ;
}
return true ;
+8 -6
View File
@@ -21,9 +21,8 @@
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include <unordered_map>
#include <stack>
#include <mutex>
#include <atomic>
#include <tuple>
#include <atomic>
typedef std::pair<Point3d, Vector3d> PNTVEC3D ;
typedef std::vector<PNTVEC3D> PNTVEC3DVECTOR ; // vettore di intersezioni punto, vettore, tipo superficie
@@ -472,15 +471,18 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool UpdateVolZMapBySurfThickeningSharpedOffset( const ISurfTriMesh* Surf, int nType, double dOffs, double dTol) ;
bool CreateOffsetSphereOnVertex( const Point3d& ptV, double dOffs, int nGrid, int nVertexType = 0) ;
bool CreateOffsetCylinderOnEdge( const Point3d& ptP1, const Point3d& ptP2, double dOffs, int nGrid, int nVertexType = 0) ;
bool CreateFatOffsetExtrusionFace( const ISurfTriMesh* Surf, double dOffs, bool bThickle) ;
bool CreateFatOffsetExtrusionFace( const ISurfTriMesh* Surf, double dOffs, bool bThickle, int nTool = 0) ;
bool CreateOrientedOffsetExtrusionFace( const ISurfTriMesh* Surf, double dOffs) ;
bool SubtractIntervalsForOffset( int nGrid, int nI, int nJ,
double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
int nToolNum, bool bSkipSwap = false) ;
bool AddIntervalsForOffset( int nGrid, int nI, int nJ,
double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
int nToolNum, bool bSkipSwap = false) ;
int nToolMin, int nToolMax, bool bSkipSwap = false) ;
bool CutByPlaneForOffset( const Plane3d& plCut) ;
bool AddSurfTmForOffset( const ISurfTriMesh* pStm, int nTool) ;
bool AddMapPartForOffset( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, int nTool, IntersParLinesSurfTm& intPLSTM) ;
// Funzioni per Offset di Zmap
bool OffsetFillet( double dOffs) ;
bool OffsetSharped( double dOffs, int nType) ;
@@ -554,9 +556,9 @@ class VolZmap : public IVolZmap, public IGeoObjRW
mutable std::vector<InterVoxMatter> m_SliceXY ;
mutable std::vector<InterVoxMatter> m_SliceXZ ;
mutable std::vector<InterVoxMatter> m_SliceYZ ;
mutable std::mutex m_SliceMutex ;
mutable std::atomic_flag m_SliceFlag ;
std::atomic<bool> m_bIsBox ;
bool m_bIsBox ;
int m_nCurrTool ;
std::vector<Tool> m_vTool ;
+24 -22
View File
@@ -2294,7 +2294,7 @@ VolZmap::IntersLineConus( const Point3d& ptLineSt, const Vector3d& vtLineDir,
vtN1.Normalize() ;
}
// altrimenti piano inferiore
else if( nBasInt == 1) {
else if ( nBasInt == 1) {
// Punto di intersezione
ptInt2 = ptP + vdRoots[0] * vtV ;
// Normale alla superficie del cono verso l'interno
@@ -3080,17 +3080,18 @@ VolZmap::GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) c
return false ;
// Se c'è intersezione valuto tutti i voxel interni
if ( TestIntersPlaneBox( plPlaneLoc, b3BlockBox)) {
// Ciclo sui voxel del blocco.
// Triangoli smooth
for ( int nV = 0 ; nV < int( m_BlockSmoothTria[nB].size()) ; ++ nV) {
// ciclo sui voxel del blocco.
for ( int nV = 0 ; nV < ssize( m_BlockSmoothTria[nB]) ; ++ nV) {
// Box del voxel
BBox3d b3Vox ;
GetVoxelBox( m_BlockSmoothTria[nB][nV].i, m_BlockSmoothTria[nB][nV].j, m_BlockSmoothTria[nB][nV].k, b3Vox) ;
// Se non c'è intersezione col voxel, passo al successivo.
// Se non c'è intersezione col voxel, passo al successivo.
if ( ! TestIntersPlaneBox( plPlaneLoc, b3Vox))
continue ;
for ( int nT = 0 ; nT < int( m_BlockSmoothTria[nB][nV].vTria.size()) ; ++ nT) {
Triangle3d trTria = m_BlockSmoothTria[nB][nV].vTria[nT] ;
// ciclo sui triangoli del voxel
for ( int nT = 0 ; nT < ssize( m_BlockSmoothTria[nB][nV].vTria) ; ++ nT) {
const Triangle3d& trTria = m_BlockSmoothTria[nB][nV].vTria[nT] ;
Point3d ptSt, ptEn ;
int nIntersType = IntersPlaneTria( plPlane, trTria, ptSt, ptEn) ;
if ( nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
@@ -3102,18 +3103,18 @@ VolZmap::GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) c
}
}
// Triangoli sharp interni al blocco
for ( int nV = 0 ; nV < int( m_BlockSharpTria[nB].size()) ; ++ nV) {
// ciclo sui voxel del blocco.
for ( int nV = 0 ; nV < ssize( m_BlockSharpTria[nB]) ; ++ nV) {
// Box del voxel
BBox3d b3Vox ;
GetVoxelBox( m_BlockSharpTria[nB][nV].i, m_BlockSharpTria[nB][nV].j, m_BlockSharpTria[nB][nV].k, b3Vox) ;
// Se non c'è intersezione col voxel, passo al successivo.
// Ciclo sulle componenti connesse
for ( int nC = 0 ; nC < int( m_BlockSharpTria[nB][nV].vCompoTria.size()) ; ++ nC) {
for ( int nT = 0 ; nT < int( m_BlockSharpTria[nB][nV].vCompoTria[nC].size()) ; ++ nT) {
Triangle3d trTria = m_BlockSharpTria[nB][nV].vCompoTria[nC][nT] ;
for ( int nC = 0 ; nC < ssize( m_BlockSharpTria[nB][nV].vCompoTria) ; ++ nC) {
for ( int nT = 0 ; nT < ssize( m_BlockSharpTria[nB][nV].vCompoTria[nC]) ; ++ nT) {
const Triangle3d& trTria = m_BlockSharpTria[nB][nV].vCompoTria[nC][nT] ;
Point3d ptSt, ptEn ;
int nIntersType = IntersPlaneTria(plPlane, trTria, ptSt, ptEn) ;
if (nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
int nIntersType = IntersPlaneTria( plPlane, trTria, ptSt, ptEn) ;
if ( nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
// Costruisco il tratto di curva
CurveLine cvLine ;
if ( cvLine.Set(ptSt, ptEn))
@@ -3123,10 +3124,10 @@ VolZmap::GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) c
}
}
// Triangoli grandi del blocco
for ( int nT = 0 ; nT < int( m_BlockBigTria[nB].size()) ; ++ nT) {
Triangle3d trTria = m_BlockBigTria[nB][nT] ;
for ( int nT = 0 ; nT < ssize( m_BlockBigTria[nB]) ; ++ nT) {
const Triangle3d& trTria = m_BlockBigTria[nB][nT] ;
Point3d ptSt, ptEn ;
int nIntersType = IntersPlaneTria(plPlane, trTria, ptSt, ptEn) ;
int nIntersType = IntersPlaneTria( plPlane, trTria, ptSt, ptEn) ;
if ( nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
// Costruisco il tratto di curva
CurveLine cvLine ;
@@ -3136,11 +3137,11 @@ VolZmap::GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) c
}
}
// In ogni caso valuto i triangoli sharp fra blocchi
for ( int nV = 0 ; nV < int( m_InterBlockSharpTria[nB].size()) ; ++ nV) {
for ( int nV = 0 ; nV < ssize( m_InterBlockSharpTria[nB]) ; ++ nV) {
// Ciclo sulle componenti connesse
for ( int nC = 0 ; nC < int( m_InterBlockSharpTria[nB][nV].vCompoTria.size()) ; ++ nC) {
for ( int nT = 0 ; nT < int( m_InterBlockSharpTria[nB][nV].vCompoTria[nC].size()) ; ++ nT) {
Triangle3d trTria = m_InterBlockSharpTria[nB][nV].vCompoTria[nC][nT] ;
for ( int nC = 0 ; nC < ssize( m_InterBlockSharpTria[nB][nV].vCompoTria) ; ++ nC) {
for ( int nT = 0 ; nT < ssize( m_InterBlockSharpTria[nB][nV].vCompoTria[nC]) ; ++ nT) {
const Triangle3d& trTria = m_InterBlockSharpTria[nB][nV].vCompoTria[nC][nT] ;
Point3d ptSt, ptEn ;
int nIntersType = IntersPlaneTria( plPlane, trTria, ptSt, ptEn) ;
if ( nIntersType == IPTT_EDGE || nIntersType == IPTT_YES) {
@@ -3156,9 +3157,9 @@ VolZmap::GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) c
// Creo i loop
ChainCurves LoopCreator ;
LoopCreator.Init( false, EPS_SMALL, int( vLine.size())) ;
LoopCreator.Init( false, EPS_SMALL, ssize( vLine)) ;
// Carico le curve per concatenarle
for ( int nCv = 0 ; nCv < int( vLine.size()) ; ++ nCv) {
for ( int nCv = 0 ; nCv < ssize( vLine) ; ++ nCv) {
Point3d ptSt = vLine[nCv].GetStart() ;
Point3d ptEn = vLine[nCv].GetEnd() ;
Vector3d vtDir; vLine[nCv].GetStartDir(vtDir) ;
@@ -3176,6 +3177,7 @@ VolZmap::GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) c
if ( ! pLoop->AddCurve( vLine[i - 1], true, 10 * EPS_SMALL))
return false ;
}
pLoop->TestClosure( 10 * EPS_SMALL) ;
pLoop->SetExtrusion( plPlane.GetVersN()) ;
pLoop->MergeCurves( 10 * EPS_SMALL, ANG_TOL_STD_DEG) ;
// Inserisco la curva composita nella raccolta da ritornare
+26 -13
View File
@@ -24,6 +24,7 @@
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#define EIGEN_NO_IO
#include "/EgtDev/Extern/Eigen/Core"
#include "/EgtDev/Extern/Eigen/SVD"
#include <thread>
@@ -950,7 +951,7 @@ VolZmap::UpdateTripleMapGraphics( void) const
}
}
// Standarda è multithread
// Standard è multithread
constexpr bool MULTITHREAD = true ;
if ( MULTITHREAD) {
@@ -1270,13 +1271,15 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const
bDefTopology = true ;
}
if ( GetBlockNFromIJK( nSlBlockIJK, nSlBlockN)) {
m_SliceMutex.lock() ;
while ( m_SliceFlag.test_and_set( memory_order_acquire))
m_SliceFlag.wait( true, memory_order_relaxed) ;
auto it = m_SliceYZ[nSlBlockN].find( nSliceN) ;
if ( it != m_SliceYZ[nSlBlockN].end()) {
bMatOnSlice = it->second ;
bDefTopology = true ;
}
m_SliceMutex.unlock() ;
m_SliceFlag.clear( memory_order_release) ;
m_SliceFlag.notify_one() ;
}
}
else if ( abs( nAdjVox3[nCount]) == 2) {
@@ -1286,13 +1289,15 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const
bDefTopology = true ;
}
if ( GetBlockNFromIJK( nSlBlockIJK, nSlBlockN)) {
m_SliceMutex.lock() ;
while ( m_SliceFlag.test_and_set( memory_order_acquire))
m_SliceFlag.wait( true, memory_order_relaxed) ;
auto it = m_SliceXZ[nSlBlockN].find( nSliceN) ;
if ( it != m_SliceXZ[nSlBlockN].end()) {
bMatOnSlice = it->second ;
bDefTopology = true ;
}
m_SliceMutex.unlock() ;
m_SliceFlag.clear( memory_order_release) ;
m_SliceFlag.notify_one() ;
}
}
else if ( abs( nAdjVox3[nCount]) == 3) {
@@ -1302,13 +1307,15 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const
bDefTopology = true ;
}
if ( GetBlockNFromIJK( nSlBlockIJK, nSlBlockN)) {
m_SliceMutex.lock() ;
while ( m_SliceFlag.test_and_set( memory_order_acquire))
m_SliceFlag.wait( true, memory_order_relaxed) ;
auto it = m_SliceXY[nSlBlockN].find( nSliceN) ;
if ( it != m_SliceXY[nSlBlockN].end()) {
bMatOnSlice = it->second ;
bDefTopology = true ;
}
m_SliceMutex.unlock() ;
m_SliceFlag.clear( memory_order_release) ;
m_SliceFlag.notify_one() ;
}
}
}
@@ -1373,27 +1380,33 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const
if ( nSlBlockN == nBlock)
SliceYZ.emplace( nSliceN, bMatOnSlice) ;
else {
m_SliceMutex.lock() ;
while ( m_SliceFlag.test_and_set( memory_order_acquire))
m_SliceFlag.wait( true, memory_order_relaxed) ;
m_SliceYZ[nSlBlockN].emplace( nSliceN, bMatOnSlice) ;
m_SliceMutex.unlock() ;
m_SliceFlag.clear( memory_order_release) ;
m_SliceFlag.notify_one() ;
}
}
else if ( abs(nAdjVox3[nCount]) == 2) {
if ( nSlBlockN == nBlock)
SliceXZ.emplace( nSliceN, bMatOnSlice) ;
else {
m_SliceMutex.lock() ;
while ( m_SliceFlag.test_and_set( memory_order_acquire))
m_SliceFlag.wait( true, memory_order_relaxed) ;
m_SliceXZ[nSlBlockN].emplace( nSliceN, bMatOnSlice) ;
m_SliceMutex.unlock() ;
m_SliceFlag.clear( memory_order_release) ;
m_SliceFlag.notify_one() ;
}
}
else if ( abs(nAdjVox3[nCount]) == 3) {
if ( nSlBlockN == nBlock)
SliceXY.emplace(nSliceN, bMatOnSlice) ;
else {
m_SliceMutex.lock() ;
while ( m_SliceFlag.test_and_set( memory_order_acquire))
m_SliceFlag.wait( true, memory_order_relaxed) ;
m_SliceXY[nSlBlockN].emplace( nSliceN, bMatOnSlice) ;
m_SliceMutex.unlock() ;
m_SliceFlag.clear( memory_order_release) ;
m_SliceFlag.notify_one() ;
}
}
}
+747 -196
View File
File diff suppressed because it is too large Load Diff
+558 -495
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -21,6 +21,7 @@
#include "Voronoi.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Extern/vroni/Include/vroni_object.h"
using namespace std ;
+6 -6
View File
@@ -19,17 +19,17 @@
#include "/EgtDev/Include/EGkCurveBezier.h"
#include "/EgtDev/Include/EGkCurveComposite.h"
#include "/EgtDev/Include/EGkCurveLine.h"
#include "/EgtDev/Extern/vroni/Include/vroni_object.h"
//----------------------------------------------------------------------------
static const bool USE_VORONOI = true ;
static const int VORONOI_STD_BOUND = 3 ;
static const double VRONI_OFFS_TOL = 1e-9 ;
static const double VRONI_JUNCTION_OPEN = 1.0 ;
static const double VRONI_JUNCTION_CLOSED = 2.0 ;
static constexpr bool USE_VORONOI = true ;
static constexpr int VORONOI_STD_BOUND = 3 ;
static constexpr double VRONI_OFFS_TOL = 1e-9 ;
static constexpr double VRONI_JUNCTION_OPEN = 1.0 ;
static constexpr double VRONI_JUNCTION_CLOSED = 2.0 ;
//-------------------------- Forward Definitions -------------------------------
class ISurfFlatRegion ;
class vroniObject ;
//----------------------------------------------------------------------------
class Voronoi