Compare commits

...

325 Commits

Author SHA1 Message Date
Daniele Bariletti 6eb621d1e1 EgtGeomKernel :
- nuova versione dell'intersezione linea-linea che richiede revisioni anche delle intersezioni arco-linea e arco-arco.
2026-01-15 16:03:29 +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
Daniele Bariletti 2d481c8a71 Merge branch 'master' into FasterVMill5Axis_Bez3x1 2025-10-09 10:34:53 +02:00
Daniele Bariletti 7968a4e5ed EgtGeomKernel :
- miglioria gestione box (Oriented BB).
- pulizia codice.
2025-10-09 10:25:58 +02:00
Riccardo Elitropi 39d295f412 EgtGeomKernel :
- Migliorata e Corretta la funzione MakeUniform per VolZMap.
2025-10-09 09:50:07 +02:00
Dario Sassi 0bf2cc2a77 EgtGeomKernel :
- aggiunte funzioni per copia da un db a un altro (CopyEx e CopyGlobEx).
2025-10-08 18:31:15 +02:00
Daniele Bariletti 433f486091 EgtGeomKernel :
- corretto un bug nel taglio spilloni.
2025-10-07 17:03:07 +02:00
Riccardo Elitropi fee6604d5e EgtGeomKernel 2.7j1 :
- in CalcPocketing migliorata la gestione delle svuotature Conformal.
2025-10-07 14:38:07 +02:00
Daniele Bariletti c339fced5c EgtGeomKernel :
- correzioni e debug.
2025-10-07 10:23:23 +02:00
Daniele Bariletti a87351778d EgtGeomKernel :
- tolte parti di debug.
2025-10-06 09:43:15 +02:00
Daniele Bariletti 42687457e0 Merge branch 'master' into FasterVMill5Axis_Bez3x1 2025-10-06 09:39:07 +02:00
Daniele Bariletti 4a541402da EgtGeomKernel :
- log per calcolo tempi.
2025-10-06 09:31:59 +02:00
Riccardo Elitropi ecef487746 EgtGeomKernel 2.7i7 :
- In SurfFlatRegion corretta funzione di Clear.
2025-10-03 10:30:31 +02:00
Riccardo Elitropi df483b5623 EgtGeomKernel :
- In CalcPocketing piccola correzione per i punti iniziali nei casi Spiral e per i Trapezi.
2025-10-02 17:57:41 +02:00
Daniele Bariletti e4d3f5f9a4 EgtGeomkernel :
- confronto tempi.
2025-09-30 17:22:23 +02:00
Daniele Bariletti 02e164dcdf EgtGeomKernel :
- evitati duplicati di archi di bezier.
2025-09-30 16:05:59 +02:00
Daniele Bariletti ead94e7915 EgtGeomKernel :
- VM 5 assi verisione con box object oriented.
2025-09-30 10:01:01 +02:00
Daniele Bariletti dfc3c29439 EgtGeomKernel :
- aggiunto codice per debug.
2025-09-29 16:00:34 +02:00
Daniele Bariletti ab538f4bf7 Merge branch 'master' into FasterVMill5Axis_Bez3x1 2025-09-29 09:20:34 +02:00
Daniele Bariletti 00b6f8583a EgtGeomKernel :
- piccola correzione.
2025-09-26 12:48:48 +02:00
Daniele Bariletti 4cf4a99107 EgtGeomKernel :
- puliza codice.
2025-09-26 12:10:18 +02:00
Daniele Bariletti 137289e843 EgtGeomKernel :
- correzione del merge.
2025-09-26 11:00:20 +02:00
Daniele Bariletti e7b066e75e Merge branch 'FasterVMill5Axis_Bez3x1' 2025-09-26 10:49:41 +02:00
Daniele Bariletti cd0828f3e0 Merge branch 'master' into FasterVMill5Axis_Bez3x1 2025-09-26 10:49:25 +02:00
Daniele Bariletti 563697f840 EgtGeomKernel :
- correzione al box del volume spazzato VM 5assi
- modificata gestione conversione curve a bezier.
2025-09-26 10:47:06 +02:00
Dario Sassi 61fc814528 EgtGeomKernel :
- piccola modifica per migliorare ricerca di inizio con stringa (starts_with).
2025-09-24 17:19:37 +02:00
Dario Sassi 7c90dbabea EgtGeomKernel 2.7i6 :
- ricompilazione con cambio versione (e abilitato multithread in MillingGeneralMotionStep).
2025-09-24 10:38:35 +02:00
Daniele Bariletti 5ee0f3c373 Merge branch 'master' into FasterVMill5Axis_Bez3x1 2025-09-24 10:30:21 +02:00
Daniele Bariletti 098bdd0076 EgtGeomKernel :
- semplificazione VM5assi.
2025-09-24 10:29:57 +02:00
Daniele Bariletti 40b6da6b44 EgtGeomKernel :
- correzione selezione caso VM5assi.
2025-09-24 09:46:02 +02:00
Daniele Bariletti b083dabc6b EgtGeomKernel :
- correzione piccolo errore
2025-09-24 09:35:52 +02:00
Daniele Bariletti 7fcc3ed42d Merge branch 'master' into FasterVMill5Axis_Bez3x1 2025-09-24 09:10:54 +02:00
Dario Sassi 4ed362f226 EgtGeomKernel 2.7i5 :
- ritorno alla vecchia modalità per virtual milling a 5 assi
- piccoli aggiustamenti soprattutto estetici.
2025-09-22 18:59:27 +02:00
Dario Sassi 39d98f79fb EgtGeomKernel :
- migliorie e correzioni per creazione Zmap da trimesh e riconoscimento box.
2025-09-19 11:13:22 +02:00
Dario Sassi c79f7ba245 EgtGeomKernel 2.7i4 :
- eliminato memory leak in ArcToBezierCurve
- altre piccole modifiche stilistiche.
2025-09-18 19:11:59 +02:00
Dario Sassi 16354ff435 EgtGeomKernel :
- piccola correzione (seno non coseno).
2025-09-18 08:43:22 +02:00
Daniele Bariletti f3a191dd62 EgtGeomKernel :
- modificato valore di soglia per angolo di intersezione tra spillone e trimesh nella costruzione di una Zmap.
2025-09-17 15:38:44 +02:00
Daniele Bariletti cb0a5092fb Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2025-09-16 14:35:53 +02:00
Daniele Bariletti 8730f55308 EgtGeomKernel :
- correzione valore di default   di ingrandimento box per la costruzione VolZmap da trimesh.
2025-09-16 14:35:47 +02:00
Daniele Bariletti 932e98d19c EgtGeomKernel :
- correzione alla creazione di un VolZmap da trimesh.
2025-09-16 14:32:36 +02:00
Riccardo Elitropi 3a69dcfa79 EgtGeomKernel (2.7i3) :
- Aggiunta funzione in DistPointSurfTm per ottenere i triangoli a minima distanza
- Aggiunte funzioni per Offset Fillet di VolZmap e per Offset generici di superfici TriMesh aperte.
2025-09-12 17:01:14 +02:00
Daniele Bariletti 5930674d4a EgtGeomKernel :
- correzione alla chiamata della ArcToBezierCurve.
2025-09-12 16:12:43 +02:00
Daniele Bariletti df6b20d97f EgtGeomKernel :
- correzioni alle chiamate della ArcToBezierCurve.
2025-09-12 16:02:55 +02:00
Daniele Bariletti 4200af5296 Merge branch 'FasterVMill5Axis_Bez3x1' 2025-09-12 15:42:44 +02:00
Daniele Bariletti b0c9c5be2e EgtGeomKernel :
- aggiornate le funzioni per la conversione di curve in/da bezier.
2025-09-12 15:40:39 +02:00
Daniele Bariletti f2bb1deac4 Merge branch 'master' into FasterVMill5Axis_Bez3x1 2025-09-12 15:12:05 +02:00
Daniele Bariletti 94ec83aa60 EgtGeomKernel :
- pulizia avvisi compilatore.
2025-09-12 15:11:30 +02:00
Daniele Bariletti e183eec3ea EgtGeomKernel :
- puliza codice.
2025-09-12 15:07:18 +02:00
Daniele Bariletti b179771ec9 EgtGeomKernel :
- pulizia codice.
2025-09-12 15:02:15 +02:00
Daniele Bariletti d7380a09c1 EgtGeomKernel :
- correzioni e ottimizzazioni al VM 5 assi 3x1.
2025-09-12 09:02:39 +02:00
Dario Sassi afc316cd1d EgtGeomKernel 2.7i2 :
- aggiunta funzione globale SetDefaultFont.
2025-09-11 15:21:51 +02:00
Riccardo Elitropi b6f820258a EgtGeomKernel :
- piccola correzione In Invert per SurfTriMesh.
2025-09-11 09:30:08 +02:00
Daniele Bariletti 116b605cb1 EgtGeomKernel :
- correzioni e migliorie al VM 5 assi 3x1.
2025-09-10 17:59:43 +02:00
Daniele Bariletti 9f5ce42393 EgtGeomKernel :
- aggiornamento dell'enum per le intersezioni linea bezier.
2025-09-10 09:48:36 +02:00
Daniele Bariletti 9716d93c15 Merge branch 'master' into FasterVMill5Axis_Bez3x1. 2025-09-09 14:58:35 +02:00
Daniele Bariletti 3465179379 EgtGeomKernel :
- debug.
2025-09-09 14:47:37 +02:00
Dario Sassi c7aad8d917 EgtGeomKernel :
- piccole migliorie e correzioni.
2025-09-09 09:12:53 +02:00
SaraP 8ddc1c70e1 EgtGeomKernel :
- ripristinata AssociatePolyLinesMinDistPoints ( la modifica è stata spostata nell'executor solo per associazione nel caso di spiralize della curva).
2025-09-08 17:32:46 +02:00
Daniele Bariletti 5230261be8 EgtGeomKernel :
- aggiunta funzione per l'accoppiamento di punti di due polyline.
2025-09-08 17:21:16 +02:00
Daniele Bariletti 8cc8d6eb03 EgtGeomKernel :
- aggiunta funzione per l'accoppiamento di punti di due polyline.
2025-09-08 17:19:23 +02:00
Riccardo Elitropi 7a95e4c5a3 Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-09-08 16:51:20 +02:00
Riccardo Elitropi 1c0f182bbc EgtGeomKernel :
- correzione controllo indici per AddIntervals su VolZmap.
2025-09-08 16:51:11 +02:00
SaraP 736e20e599 EgtGeomKernel :
- nell'associare i punti a minima distanza delle polylines aggiuta gestione speciale per gli spigoli.
2025-09-08 15:21:27 +02:00
Daniele Bariletti c71c8e8c12 EgtGeomKernel :
- miglioria per il VM 5 assi: riduco i tagli inutili.
2025-09-08 12:25:54 +02:00
Dario Sassi 9c7a29f939 EgtGeomKernel :
- piccola miglioria.
2025-09-08 11:02:08 +02:00
Riccardo Elitropi 40bb15e46b EgtGeomKernel :
- Aggiunta gestione Offset Thickening per superfici TriMesh
- Aggiunta gestione Offset Chamfer ed Extend per superfici TriMesh.
2025-09-05 17:01:59 +02:00
Daniele Bariletti fb957b61d2 Merge branch 'master' of https://gitlab.steamware.net/egalware-cadcam/libreriebase/EgtGeomKernel 2025-09-05 10:03:31 +02:00
Daniele Bariletti 4da9dcb062 EgtGeomKernel :
- aggiunto limite per la divisione del parametrico di una bezier.
2025-09-05 10:03:25 +02:00
Dario Sassi 60f9302c3f EgtGeomKernel 2.7i1 :
- ricompilazione con cambio versione.
2025-09-04 19:35:29 +02:00
Daniele Bariletti 2553f15e7b EgtGeomKernel :
- uniformazione delle funzioni per l'approssimazione curve con bezier.

(cherry picked from commit 05c0b0a18b)
(cherry picked from commit 6f1f3441ea)
2025-09-04 15:08:52 +02:00
Daniele Bariletti e8d31f2020 EgtGeomKernel :
- piccola correzione.
2025-09-04 12:55:54 +02:00
Daniele Bariletti 4c693ccd60 EgtGeomkernel :
- aggiunta intersezione linea - superficie bezier bilineare.
2025-09-04 12:43:50 +02:00
Daniele Bariletti c550fb1848 EgtGeomKernel :
- piccoli aggiustamenti.
2025-09-04 12:43:16 +02:00
Daniele Bariletti e49bd5a2a0 EgtGeonKernel :
- correzioni a VM5 assi con bezier 3x1.
2025-09-02 12:51:39 +02:00
Daniele Bariletti 81be6ce7b9 EgtGeomKernel :
- correzioni al VM 5 assi con bezier 3x1.
2025-09-01 14:54:30 +02:00
Dario Sassi 2d6bf3d9dc EgtGeomKernel :
- piccole migliorie a curve e superfici di Bezier.
2025-08-30 10:51:48 +02:00
Dario Sassi b2244b7f43 EgtGeomKernel :
- ricuperate correzioni di Daniele sugli include.
2025-08-29 20:14:27 +02:00
Dario Sassi 53dcd9c863 Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-08-29 19:53:34 +02:00
Dario Sassi 75f70d2b30 EgtGeomKernel 2.7h2 :
- piccola miglioria in proiezione curve su superfici di Bezier.
2025-08-29 19:52:13 +02:00
Daniele Bariletti 36b1df1a27 EgtGeomKernel :
- correzione al merge.
2025-08-29 08:50:00 +02:00
Daniele Bariletti 5a445c5c0b Merge remote-tracking branch 'origin/master' into FasterVMill5Axis_Bez3x1 2025-08-28 16:12:59 +02:00
Riccardo Elitropi df828ab2ba EgtGeomKernel :
- in CalcPocketing piccola miglioria per Conformal.
2025-08-28 14:41:44 +02:00
Daniele Bariletti db855ca99b EgtGeomKernel :
- correzione per il caso no_base_inters in VM5 assi 3x1.
2025-08-28 13:04:10 +02:00
Daniele Bariletti d79cb50aca EgtGeomKernel :
- tolto l'uso di namespace std dagli header.

(cherry picked from commit 704a977475)
2025-08-28 10:12:17 +02:00
Dario Sassi 371ff54d9c EgtGeomKernel :
- aggiunte funzioni GetSurfBezierAuxSurfTol e GetSurfBezierAuxSurfRefinedTol.
2025-08-24 19:13:18 +02:00
Daniele Bariletti df7b4ff81f EgtGeomKernel :
- correzioni e miglioramenti per il VM5assi con superfici bezier di grado 3x1.
2025-08-22 12:34:52 +02:00
Dario Sassi f22ea484db EgtGeomKernel :
- modifiche e migliorie calcoli per approssimazione di superfici di Bezier con trimesh
- aggiunte funzioni globali per impostare tolleranze di approssimazione delle superfici di Bezier
- eliminazione dell'uso della funzione pow (inefficiente) dove non necessaria
- utilizzo di Pow (efficiente) per potenze con esponente intero.
2025-08-22 11:44:56 +02:00
Daniele Bariletti 574041cf18 EgtGeomKernel :
- aggiunta funzione per restituire tutti i punti di controllo di una surf di bezier.
2025-08-22 09:41:13 +02:00
Daniele Bariletti ff2cc4f999 EgtGeomKernel :
- prima versione del VM5 assi con superfici di bezier 3x1.
2025-08-07 11:22:43 +02:00
Daniele Bariletti 05c0b0a18b EgtGeomKernel :
- uniformazione delle funzioni per l'approssimazione curve con bezier.
2025-08-07 11:22:20 +02:00
Riccardo Elitropi 1b9738eace EgtGeomKernel :
- In CalcPocketing piccola correzione per lavorazione Conformal
- In IntersParLinesSurfTm aggiunta estensione per intersezione con vettore di superfici TriMesh e aggiunto indice di superficie in IntLinStmInfo.
2025-08-04 14:40:43 +02:00
Daniele Bariletti 8ee5bc74d5 EgtGeomKernel :
- aggiunta e miglioramento funzioni per la gesitone di curve bezier.
2025-08-04 09:56:48 +02:00
Dario Sassi 0a8cc414a5 EgtGeomKernel 2.7h1 :
- ricompilazione con cambio versione.
2025-08-03 13:39:03 +02:00
Riccardo Elitropi 7a682653cd EgtGeomKernel :
- in CAvParSilhouettesSurfTm corretta estensione XY della griglia per utensili a cui è applicato un Offset Radiale.
2025-08-01 16:34:46 +02:00
Daniele Bariletti 9286ab6535 EgtGeomKernel :
- correzioni e miglioramenti al VM 5assi.
2025-08-01 10:29:01 +02:00
Riccardo Elitropi 85736ab03f Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-07-30 13:22:57 +02:00
Riccardo Elitropi 673f5c7a9b EgtGeomKernel :
- In CalcPocketing corretto punto di ingresso per caso ottimizzato a Spirale con curve di Bordo Open.
2025-07-30 13:21:38 +02:00
Dario Sassi 34d0bcbdfe EgtGeomKernel :
- in FromPolyLine di CurveComposite conservo i parametri degli estremi.
2025-07-28 08:34:44 +02:00
Riccardo Elitropi 7abf3027d4 EgtGeomKernel :
- in CalcPocketing corretta gestione superficie limite per Conformal.
2025-07-24 11:21:22 +02:00
Daniele Bariletti ffe3d44cac EgtGeomKernel :
- correzioni al VM 5 assi con bilineari.
2025-07-23 14:56:20 +02:00
Daniele Bariletti dd23b848ac Merge branch 'master' into FasterVMill5Axis 2025-07-22 14:40:30 +02:00
Daniele Bariletti 33cca03698 EgtGeomKernel :
- piccole migliorie tecniche.
2025-07-22 13:13:49 +02:00
Daniele Bariletti d4d14dd866 EgtGeomKernel :
- correzioni alla funzione IsClosed per le surf Bezier.
2025-07-22 11:33:51 +02:00
Daniele Bariletti d6f0fdac50 EgtGeomKernel :
- correzioni VM 5 assi.
2025-07-22 09:12:34 +02:00
Dario Sassi 080605510c EgtGeomKernel :
- prime modifiche e correzioni a creazione di superfici di Bezier.
2025-07-22 08:30:27 +02:00
Daniele Bariletti 1a7b789ef3 EgtGeomKernel :
- aggiornata funzione IsClosed per le superfici di Bezier.
2025-07-21 12:33:42 +02:00
Daniele Bariletti cc4183a677 Merge branch 'master' into FasterVMill5Axis 2025-07-21 09:03:18 +02:00
Daniele Bariletti c2bae56656 EgtGeomKernel :
- versione completa VM 5 assi con bilineari e volumi chiusi.
2025-07-21 08:27:47 +02:00
Dario Sassi 38a5c0cbb3 EgtGeomKernel :
- correzione nell'aggiunta di curve a CurveComposite (gestito caso di altra curva che va trasformata in segmento di retta).
2025-07-15 19:25:36 +02:00
SaraP 81a8eb698e EgtGeomKernel :
- correzione del test per archi degeneri nell'offset con Voronoi.
2025-07-15 15:07:50 +02:00
SaraP ee4bb7d7c4 EgtGeomKernel :
- correzione nell'offset con Voronoi per archi piccoli.
2025-07-15 11:52:23 +02:00
Riccardo Elitropi 8b0d5bddbf EgtGeomKernel :
- In CalcPocketing piccola miglioria per il calcolo delle regioni non svuotate.
2025-07-14 17:46:36 +02:00
Daniele Bariletti ba75033f0a EgtGeomKernel :
- VM 5 assi con volumi chiusi, con bilineari.
2025-07-14 17:30:03 +02:00
Riccardo Elitropi eb2b90c6f2 EgtGeomKernel :
- In CalcPocketing aggiunto flag per calcolo delle regioni non svuotate.
2025-07-14 10:14:04 +02:00
Riccardo Elitropi 3b5c34cb05 EgtGeomKernel :
- in CalcPocketing migliorati i collegamenti per lavorazioni Conformal e migliorato l'orientamento delle curve per lavorazioni Spiral.
2025-07-11 15:38:55 +02:00
Dario Sassi 2fe22a62c2 EgtGeomKernel :
- in svuotature SpiralOut non si eliminano le passate iniziali adiacenti.
2025-07-09 15:36:36 +02:00
Dario Sassi ff6307fcca EgtGeomKernel :
- prime sistemazioni per offset superfici trimesh tramite Zmap.
2025-07-07 14:59:06 +02:00
Daniele Bariletti c6e80a0b6a EgtGeomKernel :
- accorpamento del codice VM 5 assi.
2025-07-04 17:14:04 +02:00
Riccardo Elitropi b957cc75be EgtGeomKernel :
- aggiunte funzioni per calcolo di Zmap e TriMesh di Offset Fillet Thickening.
2025-07-04 12:59:43 +02:00
Daniele Bariletti fc18539472 EgtGeomKernel :
- correzioni a VM 5assi.
2025-07-04 12:37:06 +02:00
Daniele Bariletti de7229aee7 EgtGeomKernel :
- correzioni a VM 5 assi con casi ottimizzati.
2025-07-02 17:14:08 +02:00
Riccardo Elitropi 53e66032a0 EgtGeomKernel 2.7g1 :
- migliorata e corretta la classe di calcolo delle Silhouette (l'Offset viene eseguito su tutte le curve e non singolarmente e l'estensione XY del Box locale tiene conto del raggio utensile per utensili non standard)
- in SurfTriMesh aggiunte le funzioni per il calcolo dei Box delle Parts
- in Offset delle superfici, ripristinata la funzione di somma di intervalli senza media delle normali e rimozione di memoryLeaks.
2025-07-02 11:44:10 +02:00
Daniele Bariletti 2fc6c30c8f EgtGeomKernel :
- imbastimento versione VM 5 assi con gestione casi diversi.
2025-06-27 15:53:24 +02:00
Riccardo Elitropi f05c5f1261 EgtGeomKernel :
- aggiunte funzioni per Offset e FatOffset per un insieme di curve
- in VolZmapOffset migliorata la gestione delle normali per l'addizione di intervalli.
2025-06-25 15:51:19 +02:00
Daniele Bariletti 6af5591cf6 EgtGeomKernel :
- estensione del VM 5 assi e 3 assi ai casi con utensili diversi dal cilindro.
2025-06-20 16:20:12 +02:00
Daniele Bariletti 41cbe862e5 EgtGeomKernel :
- versione corretta del VM a 5 assi per lama e 3 assi.
2025-06-19 16:26:31 +02:00
Riccardo Elitropi 057b8273e2 EgtGeomKernel :
- in VolZmap::CreateFromTriMesh() corretta espansione per caso Box in attesa di correzione in marching Cubes.
2025-06-19 12:47:35 +02:00
SaraP 6421c12408 EgtGeomKernel :
- piccola modifica.
2025-06-17 08:24:47 +02:00
Daniele Bariletti 0aca5aeb07 Merge branch 'master' into FasterVMill5Axis 2025-06-16 15:12:20 +02:00
Daniele Bariletti bdbd3583b8 EgtGeomKernel :
- versione temporanea per VM5assi per caso lama e 3 assi.
2025-06-16 15:10:10 +02:00
Riccardo Elitropi 626d5b0e51 EgtGeomKernel 2.7f2 :
- Aggiunte funzioni per calcolo di Offset per superfici chiuse TriMesh
- Piccola miglioria alla triangolazione (con SaraP)
- Migliorie per rimozioni TJunction, calcolo delle normali dei triangoli e creazione di una TriMesh a partire da uno ZMap (con SaraP)
- Aggiunte funzioni di SubtractMap e piccole modifiche per estensione dei Box di creazione per gli Zmap.
2025-06-16 11:34:23 +02:00
SaraP 0bffa0039c EgtGeomKernel 2.7f1 :
- migliorie e piccole correzioni varie nelle trimesh ( booleane, chiusura).
2025-06-09 15:47:11 +02:00
Riccardo Elitropi 9819c8cee8 EgtGeomKernel :
- In CalcPocketing piccola modifica sui nomi dei parametri della funzione.
2025-06-09 12:13:56 +02:00
Riccardo Elitropi 53ab676750 EgtGeomKernel :
- In CalcPocketing correzione piccolo errore.
2025-06-09 11:38:46 +02:00
Riccardo Elitropi afa4872c97 EgtGeomKernel :
- In CalcPocketing piccola modifica per smussi sui raccordi speciali.
2025-06-06 16:51:25 +02:00
Riccardo Elitropi bf56d53faf EgtGeomKernel :
- In CalcPocketing sistemate le tolleranze di merge per le curve e migliorati i controlli per raccordi a circonferenza.
- In CurveComposite aggiunto controllo su Archi con angolo al centro circa a giro seguiti/precedeuti da curve di lunghezza sotto alla tolleranza lineare.
2025-06-04 16:26:33 +02:00
Daniele Bariletti f03adb9206 EgtGeomKernel :
- nuova versione VM 5 assi per caso lama e 3 assi.
2025-06-03 15:48:37 +02:00
Daniele Bariletti 529fa2e4a0 EgtGeomKernel :
- correzioni a VMill 5 assi e tentaivo di miglioramento per caso lama e 3 assi.
2025-06-03 09:30:48 +02:00
Dario Sassi 6df1b90e95 EgtGeomKernel 2.7e3 :
- in CurveComposite AddPoint comprende le funzionalità di FromPoint che è stata eliminata
- modifiche conseguenti in altre parti.
2025-05-31 11:54:21 +02:00
Riccardo Elitropi 9cba0e6d15 EgtGeomKernel :
- piccoli miglioramenti in CalcPocketing.
2025-05-30 17:04:19 +02:00
Riccardo Elitropi f16de3a20c EgtGeomKernel :
- in CalcPocketing, corretta gestione aree non svuotate nel caso di assenza di smussi o di cambio tipo di lavorazione.
2025-05-30 13:28:10 +02:00
Riccardo Elitropi 8cfa41d09f EgtGeomKernel :
- piccola correzione in CalcPocketing.
2025-05-30 12:18:23 +02:00
Riccardo Elitropi b59b501366 EgtGeomKernel :
- piccola correnzione in CalcPocketing.
2025-05-30 12:15:19 +02:00
Riccardo Elitropi 504bb50b13 EgtGeomKernel :
- modifica prototipi
- piccola miglioria per casi ottimizzati a Spirale in CalcPocketing.
2025-05-30 11:46:37 +02:00
Dario Sassi 969f1266e7 EgtGeomKernel :
- correzione euristica su Vmill a 5assi, in attesa di soluzione definitiva in sviluppo
2025-05-30 10:59:40 +02:00
Riccardo Elitropi fa680b7799 EgtGeomKernel :
- Aggiunto controllo sulla scalatura nella funzione GetSilhouette in SurfTriMesh
- In CalcPocketing, aggiunte funzioni ausiliarie per Debug.
2025-05-29 11:52:19 +02:00
Dario Sassi e185c85d5e EgtGeomKernel :
- piccola correzione provvisoria su Vmill a 5assi, in attesa di soluzione definitiva in sviluppo.
2025-05-29 08:30:50 +02:00
Daniele Bariletti acb0a5bd5e EgtGeomKernel :
- correzione e miglioramento del VM 5 assi per il caso lama e lavorazione 3 assi.
2025-05-28 17:57:03 +02:00
Riccardo Elitropi 62ce576d4d Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-05-28 17:22:55 +02:00
Riccardo Elitropi 161d3d9b17 EgtGeomKernel :
- In CalcPocketing aggiunte correzioni e migliorie per raccordi tra offset, per calcolo e rimozione delle regioni non svuotate e scelta degli offset per i percorsi.
2025-05-28 17:22:49 +02:00
Dario Sassi d88baa070f EgtGeomKernel 2.7e2 :
- ricompilazione con cambio versione.
2025-05-27 16:00:17 +02:00
Riccardo Elitropi 2b087dde51 Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-05-27 14:27:25 +02:00
Riccardo Elitropi 7894a8fdc8 EgtGeomKernel :
- In CalcPocketing aggiunto riconoscimento per curve SpiralCirle.
2025-05-27 14:27:20 +02:00
SaraP 0f14e8335a EgtGeomKernel :
- aggiornata funzione CalcZigZagInfill per modifiche a CalcZigZag.
2025-05-27 12:05:04 +02:00
Riccardo Elitropi 7edf4bced8 EgtGeomKernel :
- Aggiunto parametro alle funzioni per creare la FatCurve.
2025-05-27 08:28:56 +02:00
Riccardo Elitropi 4a5639780b EgtGeomKernel :
- In CalcPocketing aggiunto controllo di MaxOptSize anche sulle curve singole di lavorazione.
2025-05-22 12:02:53 +02:00
Riccardo Elitropi 0a21a582be EgtGeomKernel :
- correzione scelta basi e tempProps per le curve a trapezio.
2025-05-22 10:32:36 +02:00
Dario Sassi 0e663c02c4 EgtGeomKernel :
- piccola miglioria suggeritra da compilatore 64bit.
2025-05-21 09:34:18 +02:00
Riccardo Elitropi 21afe8165c EgtGeomKernel :
- In CalcPocketing aggiunto controllo su Feed per lati aperti
- In CalcPocketing inizio stesura funzioni per Biarchi.
2025-05-20 17:28:05 +02:00
Daniele Bariletti 0247fe5e7c Merge branch 'master' into FasterVMill5Axis 2025-05-20 11:06:49 +02:00
Daniele Bariletti 50bad83fba EgtGeomKernel :
- accorpamento del codice per Virtual milling 5assi.
2025-05-20 11:06:21 +02:00
Daniele Bariletti 9c93d6c2f3 EgtGeomKernel :
- aggiunte funzioni per le lavorazioni generiche a 5 assi.
2025-05-20 10:14:39 +02:00
Riccardo Elitropi 4d9a50cf94 Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-05-20 09:11:46 +02:00
Riccardo Elitropi bbdaac5d8d EgtGeomKernel :
- In CalcPocketing aggiunto controllo per angoli per segmento di entrata da fuori e aggiunto controllo con superficie limite da Offset Conformal.
2025-05-20 09:11:40 +02:00
Dario Sassi 0417c43bcf EgtGeomKernel :
- correzione a Pocketing per calcolo punto di inizio con lati aperti.
2025-05-19 17:39:26 +02:00
Riccardo Elitropi 15585b8f11 EgtGeomKernel :
- in PolygonElevation aggiunto controllo sul punto centrale della PolyLinea.
2025-05-16 15:48:41 +02:00
Daniele Bariletti 59755ec8a5 EgtGeomKernel :
- piccole correzioni.
2025-05-15 16:34:01 +02:00
Riccardo Elitropi b16dd260d8 EgtGEomKernel :
- In CalcPocketing aggiunto controllo lunghezza dei lati aperti,  aggiunto parametro MaxOptSize e aggiunte migliorie a percorsi Conformal.
2025-05-15 16:23:53 +02:00
SaraP d37a5a37b7 EgtGeomKernel :
- piccola correzione in GetSideAtMinDistPoint in un caso particolare di punto minimo nello start di curva chiusa.
2025-05-15 14:40:34 +02:00
Daniele Bariletti 79dfb4ae87 EgtGeomKernel :
- aggiunta di una funzione per  la VirtualMilling a 5 assi usando le bilineari.
2025-05-15 12:13:55 +02:00
Riccardo Elitropi 8b75b6e4c3 EgtGeomKernel :
- In CalcPocketing piccola miglioria per contorni ZigZag.
2025-05-13 11:41:08 +02:00
Riccardo Elitropi bcaad08b61 EgtGeomKernel :
- In CalcPocketing migliorata la gestione delle curve di svuotatura singole.
2025-05-09 16:08:34 +02:00
Riccardo Elitropi cbdeffd93a EgtGeomKernel :
- In CalcPocketing aggiunto merge dei percorsi nel caso di intersezione delle estensioni presso le uscite libere.
2025-05-07 15:00:04 +02:00
Riccardo Elitropi 0ce477a3e7 EgtGeomKernel :
- In CalcPocketing migliorata la gesitone delle lavorazioni Conformal
- In CalcPocketing migliorate le curve di bordo per lavorazioni OneWay e ZigZag.
2025-05-06 17:07:56 +02:00
Riccardo Elitropi 44eb4d1834 Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-05-05 16:57:24 +02:00
Riccardo Elitropi 2e26b73208 EgtGeomKernel :
- in CalcPocketing piccola modifica per la creazione delle curve a ricciolo per aree non svuotate.
2025-05-05 16:57:20 +02:00
Dario Sassi de3fa3201e EgtGeomKernel 2.7e1 :
- ricompilazione con cambio versione.
2025-05-05 13:25:12 +02:00
Riccardo Elitropi f068aafbb5 Merge branch 'master' of https://gitlab.steamware.net/egaltech/EgtGeomKernel 2025-05-05 12:25:16 +02:00
Riccardo Elitropi daedb07135 EgtGeomKernel :
- in CalcPocketing, aggiunta inversione del percorso per spirali in lavorazione SPIRAL_OUT.
2025-05-05 12:25:12 +02:00
SaraP 702e1e446d EgtGeomKernel :
- piccole correzioni nelle approssimazioni delle curve.
2025-04-28 15:14:05 +02:00
SaraP ea87db1ae1 EgtGeomKernel :
- negli offset gestite autointersezioni per raccordi chamfer ed extend.
2025-04-24 14:12:34 +02:00
Dario Sassi b65800843a EgtGeomKernel :
- proiezione curve su superficie ora accetta più superfici.
2025-04-23 12:18:16 +02:00
Dario Sassi e4c5d8645d Merge commit '85b06c29b4bf9af0f6c54bfa74ff2dd38c1103bd' 2025-04-22 18:01:34 +02:00
Daniele Bariletti 85b06c29b4 Merge branch 'FasterBezier_NoMultiThread' 2025-04-22 14:56:42 +02:00
Daniele Bariletti 5254d0c5ca EgtGeomKernel :
- rimosso header di debug.
2025-04-22 14:56:18 +02:00
Daniele Bariletti 292c2bf87a EgtGeomKernel :
- piccola correzione.
2025-04-22 11:43:47 +02:00
Dario Sassi 9d038142a8 Merge remote-tracking branch 'origin/master' 2025-04-21 10:03:06 +02:00
Dario Sassi c5573e438b EgtGeomKernel 2.7d2 :
- in VolZmap migliorato calcolo step per Vmill 4assi.
2025-04-21 10:01:41 +02:00
Daniele Bariletti 8c7a0ac026 Merge branch 'FasterBezier_NoMultiThread' 2025-04-14 11:23:11 +02:00
Daniele Bariletti e45bbf2afd EgtGeomKernel:
- piccola correzione.
2025-04-14 11:22:56 +02:00
Daniele Bariletti fc6de68d83 Merge branch 'master' into FasterBezier_NoMultiThread 2025-04-14 09:01:39 +02:00
Daniele Bariletti a008c169ae EgtGeomKernel :
- aggiunta seconda trimesh alle bezier.
2025-04-14 09:01:15 +02:00
SaraP 3cd6c9299f EgtGeomKernel :
- correzione riferimenti in CalcSpecialPointOffset.
2025-04-11 16:41:13 +02:00
Daniele Bariletti 8e5801d656 Merge remote-tracking branch 'origin/HEAD' into FasterBezier_NoMultiThread 2025-04-11 16:02:12 +02:00
Daniele Bariletti 1691b7f84a EgtGeomKernel: - correzione al taglio di superfici di bezier con piani. 2025-04-11 16:01:14 +02:00
Daniele Bariletti 76e4197729 EgtGeomKernel:
- correzione errori nel taglio con piani di Surf di bezier.
2025-04-11 11:27:38 +02:00
Daniele Bariletti fb8bac8681 EgtGeomKernel:
- correzione di un errore di taglio con piani nelle surf Bezier.
2025-04-10 15:34:57 +02:00
Daniele Bariletti 55a9685add EgtGeomKernel:
- piccole correzioni.
2025-04-08 15:34:48 +02:00
Dario Sassi afa4be3717 EgtGeomKernel :
- modifiche solo estetiche.
2025-04-08 13:07:57 +02:00
Daniele Bariletti 57c03a54c9 Merge branch 'master' into FasterBezier_NoMultiThread 2025-04-08 12:56:30 +02:00
Daniele Bariletti 8657fa32c5 Merge remote-tracking branch 'origin/master' into FasterBezier_NoMultiThread 2025-04-07 10:21:23 +02:00
Daniele Bariletti 851c053f7c - pulizia del codice. 2025-03-25 12:37:13 +01:00
Daniele Bariletti 71276a8de3 - ottimizzazione del codice e gestione delle copie di polyline nel tree. 2025-03-25 12:17:06 +01:00
Daniele Bariletti b2e799e1d6 - ulteriore riduzione di copie di costruzione e copie di polyline in tree. 2025-03-24 12:42:56 +01:00
Daniele Bariletti eb9aaef53a - riduzione del numero di copie di polyline nel tree di una bezier. 2025-03-24 10:09:39 +01:00
Daniele Bariletti 0b9c9f375c - aggiunta mappa per il calcolo dei punti 3d di una bezier. 2025-03-17 14:19:08 +01:00
Daniele Bariletti cd56f80790 - piccola modifica alla mappa dei polinomi di bernstein. 2025-03-17 14:19:03 +01:00
Daniele Bariletti 9d34df708d - piccole correzioni
- passaggio da key int, double a int, int per la mappa di Bernstein per le bezier.
2025-03-12 12:43:10 +01:00
Daniele Bariletti 72947f1e36 Merge remote-tracking branch 'origin/HEAD' into FasterBezier 2025-03-12 09:41:01 +01:00
Daniele Bariletti 1cdae73b24 - aggiunta del membro statico per tenere in cache i polinomi di bernstein
- allocazione della memoria per il calcolo di bernstein fatto solo una volta per superficie.
2025-03-11 14:48:34 +01:00
81 changed files with 19525 additions and 6565 deletions
+152 -109
View File
@@ -311,7 +311,6 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int
const Frame3d& frGrid, double dDimZ, double dLevel, double dStep, double dAngTol,
bool bAdvCorners)
{
// se non ho polylinee, allora esco
if ( vPL.empty())
return true ;
@@ -341,10 +340,45 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int
if ( ! CalcRegionPolyLines( vPL, vtN, mIndMat, vbInv))
return false ;
#if ENABLE_SHARPED_EDGES_DEBUG
vector<vector<IGeoObj*>> vvpGObj ; vvpGObj.resize( 7) ;
vector<vector<Color>> vvCol ; vvCol.resize( 7) ;
// ombra del tool
PtrOwner<ICurveArc> pCrvToolShape( CreateCurveArc()) ;
pCrvToolShape->Set( ORIG, Z_AX, cavTstm.GetToolRadius()) ;
// 1° gruppo, griglia di punti
for ( int j = 0 ; j <= nStepY ; ++ j) {
for ( int i = 0 ; i <= nStepX ; ++ i) {
Point3d ptP = Point3d( i * dStep, j * dStep, dDimZ) ;
PtrOwner<IGeoPoint3d> myPtGrid( CreateGeoPoint3d()) ;
myPtGrid->Set( ptP) ;
vvpGObj[0].emplace_back( static_cast<IGeoObj*>( Release( myPtGrid))) ;
vvCol[0].emplace_back( BLUE) ;
}
}
// 2° gruppo, superfici
CISURFTMPVECTOR myStmVector = cavTstm.GetvStm() ;
for ( int i = 0 ; i < int( myStmVector.size()) ; ++ i) {
PtrOwner<ISurfTriMesh> pMyStm( CloneSurfTriMesh( myStmVector[i])) ;
if ( ! IsNull( pMyStm)) {
pMyStm->ToLoc( frGrid) ;
vvpGObj[1].emplace_back( static_cast<IGeoObj*>( Release( pMyStm))) ;
vvCol[1].emplace_back( Color( 0., 1., 0., .5)) ;
}
}
#endif
// vettore delle polyline visitate ( viste però come curve composite)
ICRVCOMPOPOVECTOR vPL_AsCompo ; vPL_AsCompo.reserve( vPL.size()) ;
// scorro i Chunk della matrice di interi, quindi le righe
for ( int nChunk = 0 ; nChunk < int( mIndMat.size()) ; ++ nChunk) {
// scorro le PolyLinee presenti nel Chunk
for ( int nPol = 0 ; nPol < int( vPL.size()) ; ++ nPol) {
for ( int nLoop = 0 ; nLoop < int( mIndMat[nChunk].size()) ; ++ nLoop) {
// recupero l'indice della PolyLine di riferimento
int nPol = mIndMat[nChunk][nLoop] ;
if ( nPol < 0 || nPol >= int( vPL.size()))
return false ;
// essendo chiusa, se presenti meno di 4 punti, non faccio nulla
int nPts = vPL[nPol].GetPointNbr() ;
if ( nPts < 4)
@@ -380,33 +414,6 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int
vAdvPt.emplace_back( make_pair( myPt, PointType::VALID)) ;
#if ENABLE_SHARPED_EDGES_DEBUG
vector<vector<IGeoObj*>> vvpGObj ; vvpGObj.resize( 7) ;
vector<vector<Color>> vvCol ; vvCol.resize( 7) ;
// ombra del tool
PtrOwner<ICurveArc> pCrvToolShape( CreateCurveArc()) ;
pCrvToolShape->Set( ORIG, Z_AX, cavTstm.GetToolRadius()) ;
// 1° gruppo, griglia di punti
for ( int j = 0 ; j <= nStepY ; ++ j) {
for ( int i = 0 ; i <= nStepX ; ++ i) {
Point3d ptP = Point3d( i * dStep, j * dStep, dDimZ) ;
PtrOwner<IGeoPoint3d> myPtGrid( CreateGeoPoint3d()) ;
myPtGrid->Set( ptP) ;
vvpGObj[0].emplace_back( static_cast<IGeoObj*>( Release( myPtGrid))) ;
vvCol[0].emplace_back( BLUE) ;
break ;
}
break ;
}
// 2° gruppo, superfici
CISURFTMPVECTOR myStmVector = cavTstm.GetvStm() ;
for ( int i = 0 ; i < int( myStmVector.size()) ; ++ i) {
PtrOwner<ISurfTriMesh> pMyStm( CloneSurfTriMesh( myStmVector[i])) ;
if ( ! IsNull( pMyStm)) {
pMyStm->ToLoc( frGrid) ;
vvpGObj[1].emplace_back( static_cast<IGeoObj*>( Release( pMyStm))) ;
vvCol[1].emplace_back( Color( 0., 1., 0., .5)) ;
}
}
// 3° gruppo, punti della PolyLine
for ( int i = 0 ; i < int( vAdvPt.size()) ; ++ i) {
PtrOwner<IGeoPoint3d> myPt( CreateGeoPoint3d()) ;
@@ -416,23 +423,23 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int
}
#endif
// modifico la posizione dei punti
if ( ! ModifyPolyLineToSharped( vAdvPt, cavTstm, frGrid, dAngTol, dStep, dSegLen))
return false ;
// modifico la posizione dei punti
if ( ! ModifyPolyLineToSharped( vAdvPt, cavTstm, frGrid, dAngTol, dStep, dSegLen))
return false ;
// ricostrusico la polyLine
vPL[nPol].Clear() ;
// ricostrusico la polyLine a partire da una vuota
PolyLine PL_New ;
double dPar = -1 ;
for ( int j = 0 ; j < int( vAdvPt.size()) ; ++ j) {
// se punto valido o sharped di angolo interno, lo aggiungo
if ( j == 0 || j == int( vAdvPt.size() - 1) ||
vAdvPt[j].second == PointType::VALID || vAdvPt[j].second == PointType::SHARPED_INT)
vPL[nPol].AddUPoint( ++ dPar, vAdvPt[j].first) ;
PL_New.AddUPoint( ++ dPar, vAdvPt[j].first) ;
// se è un punto sharped di un angolo esterno
else if ( vAdvPt[j].second == PointType::SHARPED_EXT) {
// se non richiesto il calcolo avanzato del punto a minima distanza dallo spigolo, aggiungo il punto
if ( ! bAdvCorners)
vPL[nPol].AddUPoint( ++ dPar, vAdvPt[j].first) ;
PL_New.AddUPoint( ++ dPar, vAdvPt[j].first) ;
else {
// ricavo il punto a minima distanza dal materiale mediante metodo di bisezione
Vector3d vtPrev = ( vAdvPt[j-1].first - vAdvPt[j].first) ;
@@ -463,51 +470,29 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int
DistPointLine distPtLSucc( ptTest, vAdvPt[j].first, vAdvPt[j+1].first) ;
distPtLPrev.GetMinDistPoint( ptMinDistA) ;
distPtLSucc.GetMinDistPoint( ptMinDistB) ;
vPL[nPol].AddUPoint( ++ dPar, ptMinDistA) ;
vPL[nPol].AddUPoint( ++ dPar, ptTest) ;
vPL[nPol].AddUPoint( ++ dPar, ptMinDistB) ;
}
PL_New.AddUPoint( ++ dPar, ptMinDistA) ;
PL_New.AddUPoint( ++ dPar, ptTest) ;
PL_New.AddUPoint( ++ dPar, ptMinDistB) ;
#if ENABLE_SHARPED_EDGES_DEBUG
// 5° gruppo, punti minDist A e B e ptMid
/*PtrOwner<IGeoPoint3d> myPtA( CreateGeoPoint3d()) ;
myPtA->Set( ptMinDistA) ;
vvpGObj[4].emplace_back( static_cast<IGeoObj*>( Release( myPtA))) ;
vvCol[4].emplace_back( BROWN) ;
PtrOwner<IGeoPoint3d> myPtB( CreateGeoPoint3d()) ;
myPtB->Set( ptMinDistB) ;
vvpGObj[4].emplace_back( static_cast<IGeoObj*>( Release( myPtB))) ;
vvCol[4].emplace_back( BROWN) ;
PtrOwner<IGeoPoint3d> myPtMid( CreateGeoPoint3d()) ;
myPtMid->Set( ptTest) ;
vvpGObj[4].emplace_back( static_cast<IGeoObj*>( Release( myPtMid))) ;
vvCol[4].emplace_back( BROWN) ;*/
#endif
#if ENABLE_SHARPED_EDGES_DEBUG
// 5° gruppo, punti minDist A e B e ptMid
PtrOwner<IGeoPoint3d> myPtA( CreateGeoPoint3d()) ;
myPtA->Set( ptMinDistA) ;
vvpGObj[4].emplace_back( static_cast<IGeoObj*>( Release( myPtA))) ;
vvCol[4].emplace_back( BROWN) ;
PtrOwner<IGeoPoint3d> myPtB( CreateGeoPoint3d()) ;
myPtB->Set( ptMinDistB) ;
vvpGObj[4].emplace_back( static_cast<IGeoObj*>( Release( myPtB))) ;
vvCol[4].emplace_back( BROWN) ;
PtrOwner<IGeoPoint3d> myPtMid( CreateGeoPoint3d()) ;
myPtMid->Set( ptTest) ;
vvpGObj[4].emplace_back( static_cast<IGeoObj*>( Release( myPtMid))) ;
vvCol[4].emplace_back( BROWN) ;
#endif
}
}
}
// riposiziono la polyLine
#if ENABLE_SHARPED_EDGES_DEBUG
// 6° gruppo, curve composita derivante dalla polyline
PtrOwner<ICurveComposite> pCrvCompoPoly( CreateCurveComposite()) ;
pCrvCompoPoly->FromPolyLine( vPL[nPol]) ;
//pCrvCompoPoly->SetExtrusion( frGrid.VersZ()) ;
vvpGObj[5].emplace_back( static_cast<IGeoObj*>( CloneCurveComposite( pCrvCompoPoly))) ;
vvCol[5].emplace_back( RED) ;
// 7° gruppo, controOffset
OffsetCurve offsCrv ;
offsCrv.Make( pCrvCompoPoly, - ( cavTstm.GetToolRadius() - 2 * EPS_SMALL), ICurve::OFF_EXTEND) ;
pCrvCompoPoly.Set( ConvertCurveToComposite( offsCrv.GetLongerCurve())) ;
vvpGObj[6].emplace_back( static_cast<IGeoObj*>( Release( pCrvCompoPoly))) ;
vvCol[6].emplace_back( WHITE) ;
string myName = Sharped_Edges_Debug_File_Name +
to_string( nChunk) + "_" +
to_string( nPol) + "_" +
to_string( dLevel) + "_" +
to_string( dAngTol) + ".nge" ;
SaveGeoObj( vvpGObj, vvCol, myName) ;
#endif
// se la polyLinea si autointerseca, allora non la modifico ( essendo a distanza R dalla
// trimesh rischio di evere Chunk distinti uniti in un unico Chunk
PtrOwner<ICurveComposite> pCompo( CreateCurveComposite()) ;
@@ -515,11 +500,53 @@ TestEdgesClosedPolyLines( POLYLINEVECTOR& vPL, const CAvToolSurfTm& cavTstm, int
return false ;
pCompo->FromPolyLine( vPL[nPol]) ;
SelfIntersCurve SIC( *pCompo) ;
if ( SIC.GetCrossOrOverlapIntersCount() > 0)
continue ;
bool bDiscard = ( SIC.GetCrossOrOverlapIntersCount() > 0) ;
if ( ! bDiscard) {
// se la polyLine interseca una delle PolyLine precedenti, non la modifico
for ( auto& pCompoPL_Prev : vPL_AsCompo) {
IntersCurveCurve ICC( *pCompo, *pCompoPL_Prev) ;
if ( ICC.GetCrossOrOverlapIntersCount() > 0) {
bDiscard = true ;
break ;
}
}
}
// se nuova approssimazione da conservare, memorizzo i risultati
if ( ! bDiscard) {
vPL[nPol] = PL_New ;
vPL_AsCompo.emplace_back( Release( pCompo)) ;
}
}
}
#if ENABLE_SHARPED_EDGES_DEBUG
ICURVEPVECTOR vpCrv ; vpCrv.reserve( vPL.size()) ;
for ( const auto& PL : vPL) {
// 6° gruppo, curve composita derivante dalla polyline
PtrOwner<ICurveComposite> pCrvCompoPoly( CreateCurveComposite()) ;
pCrvCompoPoly->FromPolyLine( PL) ;
vvpGObj[5].emplace_back( static_cast<IGeoObj*>( CloneCurveComposite( pCrvCompoPoly))) ;
vvCol[5].emplace_back( RED) ;
vpCrv.emplace_back( Release( pCrvCompoPoly)) ;
}
// 7° gruppo, controOffset
ICURVEPOVECTOR vCrvCompoOffs ;
if ( ! CalcOffsetCurves( vpCrv, vCrvCompoOffs, - ( cavTstm.GetToolRadius() - 2 * EPS_SMALL), ICurve::OFF_EXTEND)) {
for ( auto& pCrv : vpCrv) { delete( pCrv) ; pCrv = nullptr ;}
return false ;
}
for ( auto& pCrv : vpCrv) { delete( pCrv) ; pCrv = nullptr ;}
for ( const auto& pCvrOffs : vCrvCompoOffs) {
vvpGObj[6].emplace_back( static_cast<IGeoObj*>( CloneCurveComposite( pCvrOffs))) ;
vvCol[6].emplace_back( WHITE) ;
}
string myName = Sharped_Edges_Debug_File_Name +
to_string( dLevel) + "_" +
to_string( dAngTol) + ".nge" ;
SaveGeoObj( vvpGObj, vvCol, myName) ;
#endif
return true ;
}
@@ -785,21 +812,31 @@ MarchingSquares( const DBLVECTOR& vdGrid, int nStepX, int nStepY, double dStep,
if ( TestEdgesClosedPolyLines( vPL_Sharped, cavTstm, nStepX, nStepY, frGrid, dDimZ, dLevel, dStep, ANG_TOL_STD_DEG, false))
swap( vPL_Sharped, vPL) ;
// se vettore di PolyLine vuoto, non faccio nulla
if ( vPL.empty())
return true ;
// se non ho impostato un utensile, devo effettuare un contro-offset
if ( ! bTool) {
POLYLINEVECTOR vPL_Offs ;
for ( int i = 0 ; i < int( vPL.size()) ; ++ i) {
CurveComposite crvCompo ;
if ( ! crvCompo.FromPolyLine( vPL[i]))
return false ;
OffsetCurve offsCompo ;
offsCompo.Make( &crvCompo, - ( dRad - 2 * EPS_SMALL), ICurve::OFF_EXTEND) ;
PtrOwner<ICurve> pCrvOffset( offsCompo.GetLongerCurve()) ;
while ( ! IsNull( pCrvOffset)) {
ICURVEPOVECTOR vpOwCrv ; vpOwCrv.reserve( vPL.size()) ;
ICURVEPVECTOR vpCrv ; vpCrv.reserve( vPL.size()) ;
for ( const auto& PL : vPL) {
PtrOwner<ICurveComposite> pCrvCompoPoly( CreateCurveComposite()) ;
pCrvCompoPoly->FromPolyLine( PL) ;
vpOwCrv.emplace_back( Release( pCrvCompoPoly)) ;
vpCrv.emplace_back( vpOwCrv.back()) ;
}
// calcolo l'Offset
ICURVEPOVECTOR vpCrvOffs ;
if ( ! CalcOffsetCurves( vpCrv, vpCrvOffs, - ( dRad - 2 * EPS_SMALL), ICurve::OFF_EXTEND))
return false ;
// resituisco le PolyLine
POLYLINEVECTOR vPL_Offs ; vPL_Offs.reserve( vpCrvOffs.size()) ;
for ( auto& pCrv : vpCrvOffs) {
if ( pCrv != nullptr && pCrv->IsValid()) {
PolyLine myPolyLine ;
pCrvOffset->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, myPolyLine) ;
pCrv->ApproxWithLines( 10 * EPS_SMALL, ANG_TOL_STD_DEG, ICurve::APL_STD, myPolyLine) ;
vPL_Offs.emplace_back( myPolyLine) ;
pCrvOffset.Set( offsCompo.GetLongerCurve()) ;
}
}
swap( vPL_Offs, vPL) ;
@@ -976,28 +1013,13 @@ CAvParSilhouettesSurfTm::Prepare( void)
return false ;
b3All.Add( b3Surf) ;
}
// calcolo dati della griglia
const double EXTRA_XY = ( m_bTool ? m_dRad + 2 : 1.5 * m_dTol) ;
// espansione in Z del Box
const double EXTRA_Z = 10 * m_dTol + ( m_dMaxDepth > EPS_SMALL ? max( 0., m_dMaxDepth - b3All.GetDimZ()) : 0) ;
b3All.Expand( EXTRA_XY, EXTRA_XY, EXTRA_Z) ;
m_nStepX = int( ceil( b3All.GetDimX() / m_dTol)) ;
m_nStepY = int( ceil( b3All.GetDimY() / m_dTol)) ;
m_frGrid.ChangeOrig( GetToGlob( b3All.GetMin(), m_frGrid)) ;
b3All.Expand( 0., 0., EXTRA_Z) ;
m_dDimZ = b3All.GetDimZ() ;
m_dLevelOffs = - b3All.GetMin().z ;
// calcolo dei punti della griglia (sul top del cilindro)
PNTUVECTOR vPntM( ( m_nStepX + 1) * ( m_nStepY + 1)) ;
for ( int j = 0 ; j <= m_nStepY ; ++ j) {
for ( int i = 0 ; i <= m_nStepX ; ++ i) {
int nInd = i + j * ( m_nStepX + 1) ;
Point3d ptP = GetToGlob( Point3d( i * m_dTol, j * m_dTol, m_dDimZ), m_frGrid) ;
vPntM[nInd] = { ptP, 0.} ;
}
}
// esecuzione della verifica
// set utensile corrente per calcolo delle collisioni
double dExtraXY = m_dRad + m_dOffsR ;
if ( m_dSideAng < EPS_ANG_SMALL)
m_cavTstm.SetStdTool( m_dDimZ + m_dOffsR, m_dRad + m_dOffsR, m_dCornRad + m_dOffsR) ;
else {
@@ -1015,8 +1037,29 @@ CAvParSilhouettesSurfTm::Prepare( void)
double dStemRad = m_dRad + dDeltaRad ;
double dTipRad = m_dRad ;
dExtraXY = dStemRad + m_dOffsR ;
m_cavTstm.SetAdvTool( m_dDimZ + m_dOffsR, dStemRad + m_dOffsR, m_dMaxMat, dTipRad + m_dOffsR, m_dCornRad + m_dOffsR) ;
}
// calcolo dati della griglia
const double EXTRA_XY = ( m_bTool ? dExtraXY + 2. : 1.5 * m_dTol) ;
b3All.Expand( EXTRA_XY, EXTRA_XY, 0.) ;
m_frGrid.ChangeOrig( GetToGlob( b3All.GetMin(), m_frGrid)) ;
m_dLevelOffs = - b3All.GetMin().z ;
m_nStepX = int( ceil( b3All.GetDimX() / m_dTol)) ;
m_nStepY = int( ceil( b3All.GetDimY() / m_dTol)) ;
// calcolo dei punti della griglia (sul top del cilindro)
PNTUVECTOR vPntM( ( m_nStepX + 1) * ( m_nStepY + 1)) ;
for ( int j = 0 ; j <= m_nStepY ; ++ j) {
for ( int i = 0 ; i <= m_nStepX ; ++ i) {
int nInd = i + j * ( m_nStepX + 1) ;
Point3d ptP = GetToGlob( Point3d( i * m_dTol, j * m_dTol, m_dDimZ), m_frGrid) ;
vPntM[nInd] = { ptP, 0.} ;
}
}
// esecuzione verifica della collisione
if ( m_vpStm.empty() || ! m_cavTstm.SetSurfTm( *( m_vpStm[0])))
return false ;
for ( int k = 1 ; k < int( m_vpStm.size()) ; ++ k)
+1866 -1252
View File
File diff suppressed because it is too large Load Diff
+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 ;
+359 -140
View File
@@ -25,12 +25,14 @@
#include "/EgtDev/Include/EGkStringUtils3d.h"
#include "/EgtDev/Include/EGkUiUnits.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include "/EgtDev/Include/EGkCurveByInterp.h"
#define EIGEN_NO_IO
#include "/EgtDev/Extern/Eigen/Dense"
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
@@ -515,6 +517,10 @@ CurveToBezierCurve( const ICurve* pCrv, int nDeg, bool bMakeRatOrNot)
ICurveBezier*
LineToBezierCurve( const ICurveLine* pCrvLine, int nDeg, bool bMakeRatOrNot)
{
// verifico che esista la linea
if ( pCrvLine == nullptr)
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) ;
@@ -526,12 +532,11 @@ LineToBezierCurve( const ICurveLine* pCrvLine, int nDeg, bool bMakeRatOrNot)
//----------------------------------------------------------------------------
ICurve*
ArcToBezierCurve( const ICurve* pCrv, int nDeg, bool bMakeRatOrNot)
ArcToBezierCurve( const ICurveArc* pArc, int nDeg, bool bMakeRatOrNot)
{
// una spirale non può essere forzata al grado 2
// verifico sia un arco
const CurveArc* pArc = GetBasicCurveArc( pCrv) ;
// verifico che esista l'arco
if ( pArc == nullptr)
return nullptr ;
@@ -541,8 +546,15 @@ ArcToBezierCurve( const ICurve* pCrv, int nDeg, bool bMakeRatOrNot)
PtrOwner<ICurveBezier> pCrvBez( CreateBasicCurveBezier()) ;
if ( IsNull( pCrvBez) || ! pCrvBez->FromArc( *pArc))
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)
while ( pCrvBez->GetDegree() < nDeg)
pCrvBez.Set( BezierIncreaseDegree( pCrvBez)) ;
// restituisco la curva
return Release( pCrvBez) ;
@@ -555,20 +567,18 @@ ArcToBezierCurve( const ICurve* pCrv, int nDeg, bool bMakeRatOrNot)
return nullptr ;
// inserisco nella CC le curve di Bezier equivalenti alle parti dell'arco
int nParts = (int) ceil( abs( pArc->GetAngCenter()) / ( BEZARC_ANG_CEN_MAX + EPS_ANG_SMALL)) ;
//if ( ! bDeg3OrDeg2 && abs( pArc->GetDeltaN()) > EPS_ZERO)
// nParts *= 2 ;
nParts = max( nParts, 2) ;
for ( int i = 0 ; i < nParts ; ++ i) {
// copio l'arco originale
CurveArc cArc = *pArc ;
CurveArc cArc = *GetBasicCurveArc( pArc) ;
// lo limito alla parte di interesse
cArc.TrimStartEndAtParam( i / double( nParts), ( i + 1) / double( nParts)) ;
cArc.TrimStartEndAtParam( double( i) / nParts, double( i + 1) / nParts) ;
// creo la curva di Bezier equivalente
PtrOwner<ICurveBezier> pCrvBez( CreateBasicCurveBezier()) ;
if ( IsNull( pCrvBez) || ! pCrvBez->FromArc( cArc))
return nullptr ;
// aumento il grado della curva come richiesto
while( pCrvBez->GetDegree() < nDeg)
while ( pCrvBez->GetDegree() < nDeg)
pCrvBez.Set( BezierIncreaseDegree( pCrvBez)) ;
// aggiungo la curva di Bezier a quella composita
if ( ! pCrvCompo->AddCurve( Release( pCrvBez)))
@@ -586,7 +596,11 @@ ArcToBezierCurve( const ICurve* pCrv, int nDeg, bool bMakeRatOrNot)
ICurve*
CompositeToBezierCurve( const ICurveComposite* pCC, int nDeg, bool bMakeRatOrNot)
{
// converto tutte le curve in bezier razionali di grado 2
// verifico che esista la curva
if ( pCC == nullptr)
return nullptr ;
// converto tutte le curve in bezier razionali di grado 2
PtrOwner<ICurveComposite> pCCBezier( CreateCurveComposite()) ;
for ( int i = 0 ; i < int( pCC->GetCurveCount()) ; ++i) {
PtrOwner<ICurve> pCrvNew ;
@@ -595,7 +609,7 @@ CompositeToBezierCurve( const ICurveComposite* pCC, int nDeg, bool bMakeRatOrNot
ICurve* pCrvBezier = ArcToBezierCurve( crArc) ;
if ( pCrvBezier == nullptr)
return nullptr ;
// se la curva è di grado superiore al secondo allora devo ricondurla al secondo grado
// se la curva è di grado superiore al secondo allora devo ricondurla al secondo grado
pCrvNew.Set( pCrvBezier) ;
}
else if ( pCC->GetCurve(i)->GetType() == CRV_LINE) {
@@ -624,25 +638,28 @@ EditBezierCurve( const ICurveBezier* pCrvBezier, int nDeg, bool bMakeRatOrNot, d
{
// se nDeg == -1 allora viene mantenuto il grado della curva originale
if( nDeg == 2 || nDeg == 1)
// verifico sia una bezier
if ( pCrvBezier == nullptr)
return nullptr ;
if ( nDeg == 2 || nDeg == 1)
return nullptr ;
PtrOwner<ICurveBezier> pCrvNew( pCrvBezier->Clone()) ;
int nDegCurr = pCrvNew->GetDegree() ;
bool bRat = pCrvNew->IsRational() ;
int nDegWanted = nDeg == -1 ? nDegCurr : nDeg ;
if( ! bMakeRatOrNot) {
if( ! pCrvNew->MakeNonRational( dTol)) {
if ( ! bMakeRatOrNot) {
if ( ! pCrvNew->MakeNonRational( dTol)) {
// se ho fallito la conversione diretta in curva non razionale allora la spezzo in bezier cubiche
PtrOwner<ICurveComposite> pBezCubics( CreateCurveComposite()) ;
pBezCubics->AddCurve( ApproxBezierWithCubics(pCrvBezier, dTol)) ;
if( IsNull( pBezCubics))
if ( IsNull( pBezCubics))
return nullptr ;
// adatto ogni sottocurva cubica
PtrOwner<ICurveComposite> pCCEdited( CreateCurveComposite()) ;
for ( int i = 0 ; i < pBezCubics->GetCurveCount() ; ++i) {
if( ! pCCEdited->AddCurve( EditBezierCurve( GetCurveBezier( pBezCubics->GetCurve( i)), nDegWanted, bMakeRatOrNot, dTol)) )
if ( ! pCCEdited->AddCurve( EditBezierCurve( GetCurveBezier( pBezCubics->GetCurve( i)), nDegWanted, bMakeRatOrNot, dTol)) )
return nullptr ;
}
return Release( pCCEdited) ;
@@ -661,7 +678,7 @@ EditBezierCurve( const ICurveBezier* pCrvBezier, int nDeg, bool bMakeRatOrNot, d
else if ( nDegCurr > nDegWanted) {
while ( nDegCurr > nDegWanted) {
ICurveBezier* pCrvDec = BezierDecreaseDegree( pCrvNew, dTol) ;
if( pCrvDec == nullptr || ! pCrvDec->IsValid()) {
if ( pCrvDec == nullptr || ! pCrvDec->IsValid()) {
// se ho fallito la riduzione di grado entro la tolleranza richiesta allora la spezzo in bezier cubiche prima di adattare
PtrOwner<ICurveComposite> pBezCubics( CreateCurveComposite()) ;
pBezCubics->AddCurve( ApproxBezierWithCubics(pCrvBezier, dTol)) ;
@@ -670,7 +687,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) ;
@@ -687,20 +704,22 @@ EditBezierCurve( const ICurveBezier* pCrvBezier, int nDeg, bool bMakeRatOrNot, d
//----------------------------------------------------------------------------
ICurveBezier*
BezierIncreaseDegree(const ICurveBezier* pCrvBezier)
BezierIncreaseDegree( const ICurveBezier* pCrvBezier)
{
if ( pCrvBezier == nullptr)
return nullptr ;
// creo la versione con grado aumentato
// creo la versione con grado aumentato
PtrOwner<ICurveBezier> pNewBezier( CreateCurveBezier()) ;
int nDeg = pCrvBezier->GetDegree() + 1;
bool bRat = pCrvBezier->IsRational();
pNewBezier->Init( nDeg , bRat) ;
// prev e curr sono riferiti alla curva di partenza
// salvo il primo punto
if ( IsNull( pNewBezier))
return nullptr ;
int nDeg = pCrvBezier->GetDegree() + 1 ;
bool bRat = pCrvBezier->IsRational() ;
pNewBezier->Init( nDeg, bRat) ;
// prev e curr sono riferiti alla curva di partenza
// salvo il primo punto
Point3d ptCtrlPrev = pCrvBezier->GetControlPoint( 0) ;
double dWprev = 1 ;
if ( bRat ) {
if ( bRat) {
dWprev = pCrvBezier->GetControlWeight( 0) ;
pNewBezier->SetControlPoint( 0, ptCtrlPrev, dWprev) ;
}
@@ -709,26 +728,26 @@ BezierIncreaseDegree(const ICurveBezier* pCrvBezier)
// ciclo sui punti di controllo intermedi per calcolare quelli nuovi
Point3d ptCtrlCurr ;
double dWcurr ;
for ( double i = 1 ; i < nDeg ; ++i) {
ptCtrlCurr = pCrvBezier->GetControlPoint( int( i)) ;
double dAlpha = i / nDeg ;
for ( int i = 1 ; i < nDeg ; ++i) {
ptCtrlCurr = pCrvBezier->GetControlPoint( i) ;
double dAlpha = double( i) / nDeg ;
if ( bRat) {
dWcurr = pCrvBezier->GetControlWeight( int( i)) ;
dWcurr = pCrvBezier->GetControlWeight( i) ;
double dWnew = dAlpha * dWprev + ( 1 - dAlpha) * dWcurr ;
Point3d ptNew = dAlpha * ptCtrlPrev * dWprev + ( 1 - dAlpha) * ptCtrlCurr * dWcurr;
ptNew /= dWnew ;
pNewBezier->SetControlPoint( int( i), ptNew, dWnew) ;
pNewBezier->SetControlPoint( i, ptNew, dWnew) ;
dWprev = dWcurr ;
}
else {
Point3d ptNew = dAlpha * ptCtrlPrev + ( 1 - dAlpha) * ptCtrlCurr ;
pNewBezier->SetControlPoint( int( i), ptNew) ;
pNewBezier->SetControlPoint( i, ptNew) ;
}
ptCtrlPrev = ptCtrlCurr ;
}
// salvo l'ultimo punto
ptCtrlCurr = pCrvBezier->GetControlPoint( nDeg - 1) ;
if ( bRat ) {
if ( bRat) {
dWcurr = pCrvBezier->GetControlWeight( nDeg - 1) ;
pNewBezier->SetControlPoint( nDeg, ptCtrlCurr, dWcurr) ;
}
@@ -880,7 +899,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 ;
@@ -889,8 +908,13 @@ BezierDecreaseDegree(const ICurveBezier* pCrvBezier, double dTol)
//----------------------------------------------------------------------------
ICurve*
ApproxBezierWithCubics(const ICurveBezier* pCrvBezier, double dTol)
ApproxBezierWithCubics(const ICurve* pCrv, double dTol)
{
// verifico sia una bezier
const CurveBezier* pCrvBezier = GetBasicCurveBezier( pCrv) ;
if ( pCrvBezier == nullptr)
return nullptr ;
// cerco di stimare quanti cambi di concavità ho
// tiro una linea tra il primo punto di controllo e l'ultimo e poi scorro gli altri punti di controllo
// controllando quante volte salto da un lato all'altro della linea
@@ -911,10 +935,8 @@ ApproxBezierWithCubics(const ICurveBezier* pCrvBezier, double dTol)
Vector3d vtStartDir, vtEndDir ;
pCrvBezier->GetPointD1D2( 0, ICurve::FROM_MINUS, ptStart, &vtStartDir) ;
pCrvBezier->GetPointD1D2( 1, ICurve::FROM_PLUS, ptEnd, &vtEndDir) ;
Plane3d plPLane ;
plPLane.Set( ptStart, ptCtrl, ptEnd) ;
vtStartDir.Rotate( plPLane.GetVersN(), 90) ;
vtEndDir.Rotate( plPLane.GetVersN(), 90) ;
vtStartDir.Rotate( vtN, 90) ;
vtEndDir.Rotate( vtN, 90) ;
Point3d ptAux1 = ptStart + vtStartDir ;
Point3d ptAux2 = ptEnd + vtEndDir ;
PtrOwner<CurveLine> pCL1( CreateBasicCurveLine()) ;
@@ -929,7 +951,7 @@ ApproxBezierWithCubics(const ICurveBezier* pCrvBezier, double dTol)
double dDist2 = Dist( ptEnd, ptCen) ;
if ( abs(dDist1 - dDist2) < EPS_SMALL ) {
CurveArc cArc ;
cArc.SetC2PN( ptCen, ptStart, ptEnd, plPLane.GetVersN()) ;
cArc.SetC2PN( ptCen, ptStart, ptEnd, vtN) ;
// controllo se il raggio della circonferenza risultante coincide con quello calcolato prima
// impongo inoltre che l'angolo al centro sia minore di 90 gradi
if ( abs( cArc.GetRadius() - dDist1) < EPS_SMALL && cArc.GetAngCenter() < 90 + EPS_SMALL)
@@ -973,7 +995,7 @@ ApproxBezierWithCubics(const ICurveBezier* pCrvBezier, double dTol)
if ( ! bIsArc)
pCrvCubic.Set( ApproxCurveBezierWithSingleCubic( pCrvPart)) ;
else {
pCrvCubic.Set( ApproxArcCurveBezierWithSingleCubic( pCrvPart, ptCen)) ;
pCrvCubic.Set( ApproxArcCurveBezierWithSingleCubic( pCrvPart, ptCen, vtN)) ;
if ( IsNull( pCrvCubic)) {
// se fallisce allora riprovo usando più di una bezier
bIsArc = false ;
@@ -983,7 +1005,7 @@ ApproxBezierWithCubics(const ICurveBezier* pCrvBezier, double dTol)
pCrvCubic.Set( ApproxCurveBezierWithSingleCubic( pCrvPart)) ;
}
}
CalcBezierApproxError( pCrvPart, pCrvCubic, dErr) ;
CalcApproxError( pCrvPart, pCrvCubic, dErr) ;
if ( dErr > dTol && ! bOneIsEnough)
nParts += 2 ;
else {
@@ -1012,8 +1034,13 @@ ApproxBezierWithCubics(const ICurveBezier* pCrvBezier, double dTol)
//----------------------------------------------------------------------------
ICurveBezier*
ApproxCurveBezierWithSingleCubic( const ICurveBezier* pCrvBez)
ApproxCurveBezierWithSingleCubic( const ICurve* pCrv)
{
// verifico sia una bezier
const CurveBezier* pCrvBez = GetBasicCurveBezier( pCrv) ;
if ( pCrvBez == nullptr)
return nullptr ;
Point3d ptStart, ptEnd ;
pCrvBez->GetStartPoint( ptStart) ;
pCrvBez->GetEndPoint( ptEnd) ;
@@ -1042,8 +1069,22 @@ ApproxCurveBezierWithSingleCubic( const ICurveBezier* pCrvBez)
//----------------------------------------------------------------------------
ICurveBezier*
ApproxArcCurveBezierWithSingleCubic( const ICurveBezier* pCrvBez, const Point3d& ptCen)
ApproxArcCurveBezierWithSingleCubic( const ICurve* pCrv, const Point3d& ptCen, const Vector3d& vtN)
{
// verifico sia una bezier
const CurveBezier* pCrvBez = GetBasicCurveBezier( pCrv) ;
if ( pCrvBez == nullptr)
return nullptr ;
// mi metto nel frame della curva ( lavoro nel piano XY)
Point3d ptStart = pCrvBez->GetControlPoint( 0) ;
Point3d ptEnd = pCrvBez->GetControlPoint( 2) ;
Frame3d frCrv; frCrv.Set( ptStart, vtN) ;
ptStart = ORIG ;
ptEnd.ToLoc( frCrv) ;
Point3d ptCenLoc = ptCen ;
ptCenLoc.ToLoc( frCrv) ;
// converto una curva di bezier che definisce un arco perfetto di circonferenza
// dato il centro( della circonferenza), inizio e fine
// N.B. : per archi con angolo al centro < 90
@@ -1052,9 +1093,7 @@ ApproxArcCurveBezierWithSingleCubic( const ICurveBezier* pCrvBez, const Point3d&
bool bRat = pCrvBez->IsRational() ;
if ( nDeg != 2 || ! bRat)
return nullptr ;
Point3d ptStart = pCrvBez->GetControlPoint( 0) ;
Point3d ptEnd = pCrvBez->GetControlPoint( 2) ;
if ( AreSamePointEpsilon( ptStart, ptEnd, EPS_SMALL * 50))
return nullptr ;
nDeg = 3 ;
@@ -1064,13 +1103,13 @@ ApproxArcCurveBezierWithSingleCubic( const ICurveBezier* pCrvBez, const Point3d&
pCrvCubic->SetControlPoint( 3, ptEnd) ;
// from the article of Aleksas Riškus "Approximation of a cubic bezier curve by circular arcs and vice versa"
// with corrections from "Hans Muller's Flex Blog", page "More About Approximating Circular Arcs With a Cubic Bezier Path"
double ax = ptStart.x - ptCen.x ;
double ay = ptStart.y - ptCen.y ;
double bx = ptEnd.x - ptCen.x ;
double by = ptEnd.y - ptCen.y ;
double q1 = pow( ax, 2) + pow( ay, 2) ;
double ax = ptStart.x - ptCenLoc.x ;
double ay = ptStart.y - ptCenLoc.y ;
double bx = ptEnd.x - ptCenLoc.x ;
double by = ptEnd.y - ptCenLoc.y ;
double q1 = ax * ax + ay * ay ;
double q2 = q1 + ax * bx + ay * by ;
double k2 = 4./3 * ( sqrt( 2 * q1 * q2) - q2) / ( ax * by - ay * bx) ;
double k2 = 4. / 3 * ( sqrt( 2 * q1 * q2) - q2) / ( ax * by - ay * bx) ;
Point3d ptCtrl1, ptCtrl2 ;
ptCtrl1.x = ptStart.x - k2 * ay ;
ptCtrl1.y = ptStart.y + k2 * ax ;
@@ -1079,43 +1118,108 @@ ApproxArcCurveBezierWithSingleCubic( const ICurveBezier* pCrvBez, const Point3d&
pCrvCubic->SetControlPoint( 1, ptCtrl1) ;
pCrvCubic->SetControlPoint( 2, ptCtrl2) ;
// ritorno nel frame originale
pCrvCubic->ToGlob( frCrv) ;
return Release( pCrvCubic) ;
}
//----------------------------------------------------------------------------
ICurve*
ApproxCurveWithBezier( const ICurve*, double dTol)
static bool
FindSpan( double dU, int nDeg, const DBLVECTOR& vKnots, int& nSpan)
{
// interpolazione di punti con una curva bezier
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 = int( vKnots.size()) ;
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 ;
}
PtrOwner<ICurveComposite> pCC( CreateBasicCurveComposite()) ;
return Release( pCC) ;
//----------------------------------------------------------------------------
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 ( vBasis.size() != nDeg + 1)
return false ;
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)
{
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 ;
}
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 ;
@@ -1127,7 +1231,7 @@ InterpolatePointSetWithBezier( const PNTVECTOR& vPnt, double dTol)
for ( int i = nDeg ; i < nPoints - 1 ; ++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 ;
@@ -1136,21 +1240,26 @@ InterpolatePointSetWithBezier( const PNTVECTOR& vPnt, double dTol)
Eigen::MatrixXd mA( nPoints, nPoints) ;
mA.fill( 0) ;
for ( int i = 0 ; i < nPoints ; ++i) {
int nSpan = 0 ; FindSpan(vPntParam[i], nDeg, vKnots, nSpan) ;
if ( i == 0)
mA.row(0).col(0) << 1 ;
else if ( i == nPoints - 1)
mA.row(i).col(nPoints - 1) << 1 ;
mA.row(i).col(nPoints - 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 ;
@@ -1164,76 +1273,140 @@ 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 = int( vPnt.size()) ;
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 < int( vPnt.size()) ; ++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.size() != 0) {
if ( nEnd == 0)
nEnd = nPoints - 1 ;
pCrvInt->AddCurve( InterpolatePointSetWithBezierNoIntermedLines( vPnt, nStart, nEnd, nDeg, vLen, dLenTot)) ;
}
if ( bFoundLine) {
CurveLine cl ; cl.Set( vPnt[nEnd], vPnt[nEnd+1]) ;
pCrvInt->AddCurve( LineToBezierCurve( &cl, nDeg, false)) ;
++ nEnd ;
}
bOk = pCrvInt->IsValid() ;
nStart = nEnd ;
}
CalcApproxError( pCrvOri, pCrvInt, dErr) ;
if ( dErr > dLinTol && dMaxLen > 200 * EPS_SMALL)
dMaxLen /= 2 ;
++ nItCount ;
}
return true ;
if ( ! IsNull( pCrvInt) && pCrvInt->IsValid() && dErr < dLinTol)
return Release( pCrvInt) ;
else
return nullptr ;
}
//----------------------------------------------------------------------------
ICurve*
ApproxCurveWithBezier( const ICurve* pCrv , double dTol, int nType)
{
PolyLine plApprox ;
double dAngTolFine = 2 ;
pCrv->ApproxWithLines( dTol, dAngTolFine, ICurve::APL_STD, plApprox) ;
PNTVECTOR vPnt ;
Point3d pt ; plApprox.GetFirstPoint( pt) ;
do {
vPnt.push_back( pt) ;
} while ( plApprox.GetNextPoint( pt)) ;
// campiono punti lungo la curva e poi li interpolo
PtrOwner<ICurve> pCC( InterpolatePointSetWithBezier( vPnt, dTol, 100)) ;
if ( ! IsNull( pCC) && pCC->IsValid())
return Release( pCC) ;
else
return nullptr ;
}
//----------------------------------------------------------------------------
ICurve*
ApproxPointSetWithBezier( const ICurve* pCrv, double dTol)
{
// campiono punti lungo la curva e poi li interpolo
PtrOwner<ICurveComposite> pCC( CreateBasicCurveComposite()) ;
return Release( pCC) ;
}
//----------------------------------------------------------------------------
bool
CalcBezierApproxError( const ICurveBezier* pCrvOri, const ICurveBezier* pCrvNew, double& dErr, int nPoints)
CalcApproxError( const ICurve* pCrvOri, const ICurve* pCrvNew, double& dErr, int nPoints)
{
if ( pCrvOri->GetType() != CRV_BEZIER || pCrvNew->GetType() != CRV_BEZIER)
return false ;
// controllo l'errore effettivo campionando più finemente
double dLenOri = 0 ; pCrvOri->GetLength( dLenOri) ;
double dLenNew = 0 ; pCrvNew->GetLength( dLenNew) ;
@@ -1262,7 +1435,7 @@ CurveToNoArcsCurve( const ICurve* pCrv)
return nullptr ;
// se arco, devo trasformarlo in curva di Bezier (semplice o composta)
if ( pCrv->GetType() == CRV_ARC) {
return ArcToBezierCurve( pCrv) ;
return ArcToBezierCurve( GetCurveArc( pCrv)) ;
}
// se curva composita, devo trasformarla in composita senza archi
else if ( pCrv->GetType() == CRV_COMPO) {
@@ -2043,13 +2216,14 @@ CalcCurvesMedialAxis( const CICURVEPVECTOR& vCrvC, ICURVEPOVECTOR& vCrvs, int nS
//----------------------------------------------------------------------------
bool
CalcCurveFatCurve( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double dRadius, bool bSquareEnds, bool bSquareMids)
CalcCurveFatCurve( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double dRadius, bool bSquareEnds, bool bSquareMids,
bool bMergeOnlySameProps)
{
Voronoi* pVoronoiObj = GetCurveVoronoi( crvC) ;
if ( pVoronoiObj == nullptr)
return false ;
return pVoronoiObj->CalcFatCurve( vCrvs, dRadius, bSquareEnds, bSquareMids) ;
return pVoronoiObj->CalcFatCurve( vCrvs, dRadius, bSquareEnds, bSquareMids, bMergeOnlySameProps) ;
}
//----------------------------------------------------------------------------
@@ -2086,6 +2260,51 @@ CalcCurveSingleCurvesOffset( const ICurve& crvC, ICURVEPOVECTOR& vCrvs, double d
return pVoronoiObj->CalcSingleCurvesOffset( vCrvs, dOffs) ;
}
//----------------------------------------------------------------------------
bool CalcOffsetCurves( const ICURVEPVECTOR& vpCrvs, ICURVEPOVECTOR& vCrvs, double dOffs, int nType)
{
// creo oggetto Voronoi con le curve passate
PtrOwner<Voronoi> pVoronoiObj( new( std::nothrow) Voronoi()) ;
if ( pVoronoiObj == nullptr)
return false ;
for ( int i = 0 ; i < int( vpCrvs.size()) ; i ++) {
if ( ! pVoronoiObj->AddCurve( vpCrvs[i]))
return false ;
}
return pVoronoiObj->CalcOffset( vCrvs, dOffs, nType) ;
}
//----------------------------------------------------------------------------
bool CalcFatOffsetCurves( const ICURVEPVECTOR& vpCrvs, ICURVEPOVECTOR& vCrvs, double dOffs,
bool bSquareEnds, bool bSquareMids, bool bMergeOnlySameProps)
{
// controllo validità delle curve
for ( auto& pCrv : vpCrvs) {
if ( pCrv == nullptr)
return false ;
}
// se offset nullo restituisco direttamente le curve
if ( abs( dOffs) < EPS_SMALL) {
for ( auto& pCrv : vpCrvs) {
if ( ! vCrvs.emplace_back( pCrv->Clone()))
return false ;
}
return true ;
}
// creo oggetto Voronoi con le curve passate
PtrOwner<Voronoi> pVoronoiObj( new( std::nothrow) Voronoi()) ;
if ( pVoronoiObj == nullptr)
return false ;
for ( int i = 0 ; i < int( vpCrvs.size()) ; i ++) {
if ( ! pVoronoiObj->AddCurve( vpCrvs[i]))
return false ;
}
return pVoronoiObj->CalcFatCurve( vCrvs, dOffs, bSquareEnds, bSquareMids, bMergeOnlySameProps) ;
}
//----------------------------------------------------------------------------
void
ResetCurveVoronoi( const ICurve& crvC)
+1 -1
View File
@@ -33,5 +33,5 @@ bool CurveGetArea( const ICurve& crvC, Plane3d& plPlane, double& dArea) ;
bool CurveDump( const ICurve& crvC, std::string& sOut, bool bMM, const char* szNewLine) ;
bool CopyExtrusion( const ICurve* pSouCrv, ICurve* pDestCrv) ;
bool CopyThickness( const ICurve* pSouCrv, ICurve* pDestCrv) ;
ICurveBezier* ApproxCurveBezierWithSingleCubic( const ICurveBezier* pCrvBez) ;
ICurveBezier* ApproxCurveBezierWithSingleCubic( const ICurve* pCrv) ;
Voronoi* GetCurveVoronoi( const ICurve& crvC) ;
+133 -43
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,7 +273,7 @@ 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 ;
@@ -367,8 +373,11 @@ 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 ;
m_vPtCtrl = cbSrc.m_vPtCtrl ;
if ( cbSrc.m_bRat)
m_vWeCtrl = cbSrc.m_vWeCtrl ;
@@ -516,21 +525,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) ;
@@ -1657,6 +1666,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)
@@ -1799,6 +1812,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)
@@ -1808,19 +1825,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 ;
@@ -1830,6 +1847,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.) ;
@@ -1839,7 +1860,7 @@ CurveBezier::TrimStartAtLen( double dLenTrim)
return false ;
// utilizzo il trim sui parametri
if( ! TrimStartAtParam( dUTrim))
if ( ! TrimStartAtParam( dUTrim))
return false ;
return true ;
@@ -1849,6 +1870,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.) ;
@@ -1858,7 +1883,7 @@ CurveBezier::TrimEndAtLen( double dLenTrim)
return false ;
// utilizzo il trim sui parametri
if( ! TrimEndAtParam( dUTrim))
if ( ! TrimEndAtParam( dUTrim))
return false ;
return true ;
@@ -1868,6 +1893,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 ;
@@ -1919,6 +1948,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 ;
@@ -2258,6 +2291,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
@@ -2272,19 +2309,23 @@ 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[0] ;
double dW0 = m_vWeCtrl.front() ;
double dWn = m_vWeCtrl.back() ;
if( dW0 > 1- EPS_ZERO && dWn > 1 - EPS_ZERO)
if ( dW0 > 1 - EPS_ZERO && dWn > 1 - EPS_ZERO)
return true ;
if( dW0 < EPS_ZERO || dWn < EPS_ZERO)
if ( dW0 < EPS_ZERO || dWn < EPS_ZERO)
return false ;
// formula del Farin
// formula del Farin
double dCoeff = pow( dW0 / dWn, 1. / m_nDeg) ;
for ( int i = 0 ; i < m_nDeg + 1 ; ++i)
m_vWeCtrl[i] *= pow( dCoeff, i) / dW0 ;
m_vWeCtrl[i] *= Pow( dCoeff, i) / dW0 ;
return true ;
}
@@ -2293,13 +2334,17 @@ CurveBezier::MakeRationalStandardForm( void)
bool
CurveBezier::MakeNonRational( double dTol)
{
if( ! m_bRat)
// la curva deve essere valida
if ( m_nStatus != OK)
return false ;
if ( ! m_bRat)
return true ;
// controllo se i pesi sono tutti == 1 allora è una finta razionale e mi basta fare una copia dei punti di controllo
bool bIsActualRat = false ;
for ( int i = 0 ; i < m_nDeg ; ++i) {
if ( abs(m_vWeCtrl[i] - 1) > EPS_SMALL) {
if ( abs( m_vWeCtrl[i] - 1) > EPS_SMALL) {
bIsActualRat = true ;
break ;
}
@@ -2307,15 +2352,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 ;
@@ -2323,8 +2397,8 @@ CurveBezier::MakeNonRational( double dTol)
pNewBez->Init( nDeg, false) ;
PNTVECTOR vPntCtrl ;
PNTVECTOR vPntSampling ;
for ( int p = 0 ; p < nDeg + 1; ++p) {
Point3d pt ; GetPointD1D2( double(p) / nDeg, pt) ;
for ( int p = 0 ; p < nDeg + 1 ; ++p) {
Point3d pt ; GetPointD1D2( double( p) / nDeg, pt) ;
pNewBez->SetControlPoint( p, pt) ;
vPntCtrl.push_back( pt) ;
}
@@ -2334,11 +2408,11 @@ CurveBezier::MakeNonRational( double dTol)
while ( dErr > dTol && c < 100) {
double dErrMax = 0 ;
// calcolo le differenze tra i punti di sampling sulla nuova curva e quelli sulla curva originale
for ( int p = 0 ; p < nDeg + 1; ++p) {
Point3d pt ; pNewBez->GetPointD1D2( double(p) / nDeg, pt) ;
for ( int p = 0 ; p < nDeg + 1 ; ++p) {
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 ;
@@ -2351,17 +2425,17 @@ CurveBezier::MakeNonRational( double dTol)
}
// calcolo l'errore di approssimazione sulla curva
CalcBezierApproxError( this, pNewBez, dErr) ;
CalcApproxError( this, pNewBez, dErr) ;
bOk = dErr < dTol ;
if( bOk) {
if ( bOk) {
// aggiorno la curva di bezier originale con quella approssimata
Init( nDeg, false) ;
for( int i = 0 ; i < nDeg + 1 ; ++i) {
for ( int i = 0 ; i < nDeg + 1 ; ++i) {
SetControlPoint( i, pNewBez->GetControlPoint( i)) ;
SetControlWeight( i, pNewBez->GetControlWeight( i)) ;
}
}
else if( nDeg < m_nDeg + 4)
else if ( nDeg < m_nDeg + 4)
goto retry ;
}
@@ -2372,14 +2446,30 @@ 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 ;
}
//----------------------------------------------------------------------------
PNTVECTOR
CurveBezier::GetAllControlPoints( void) const
{
PNTVECTOR vPntCtrl ;
// la curva deve essere valida
if ( m_nStatus != OK)
return vPntCtrl ;
return m_vPtCtrl ;
}
+2 -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 ;
@@ -153,6 +153,7 @@ class CurveBezier : public ICurveBezier, public IGeoObjRW
bool MakeRationalStandardForm( void) override ;
bool MakeNonRational( double dTol) override ;
bool IsALine( void) const override ;
PNTVECTOR GetAllControlPoints( void) const ; // non aggiunta in interfaccia
public : // IGeoObjRW
int GetNgeId( void) const override ;
+5 -2
View File
@@ -502,8 +502,9 @@ CurveByApprox::BiArcOrSplit( int nLev, PolyLine& PL, double dLinTol, double dAng
m_vPrevDer[nI].ToSpherical( nullptr, nullptr, &dDir1Deg) ;
// costruisco un biarco sulla polilinea (secondo metodo di Z. Sir)
pCrv.Set( GetBiArc( ptP0, dDir0Deg, ptP1, dDir1Deg, PL, dMaxDist, dLinTol)) ;
// forzo la spezzatura della curva
if ( IsNull( pCrv))
return false ;
dMaxDist = 2 * dLinTol ;
}
// se la polilinea è formata da 2 punti
else if ( PL.GetPointNbr() == 2) {
@@ -524,13 +525,15 @@ CurveByApprox::BiArcOrSplit( int nLev, PolyLine& PL, double dLinTol, double dAng
// se raggiunto il massimo livello di recursione, forzo l'accettazione del biarco
if ( nLev >= MAX_LEV) {
if ( IsNull( pCrv))
return false ;
dMaxDist = 0 ;
// segnalo situazione per debug
if ( GetEGkDebugLev() >= 5)
LOG_DBG_ERR( GetEGkLogger(), "ERROR : Exceeded recursions")
}
// se lunghezza abbastanza picccola, forzo l'accettazione della curva
// se lunghezza abbastanza piccola, forzo l'accettazione della curva
double dLen ;
if ( PL.GetApproxLength( dLen) && dLen < 10 * EPS_SMALL)
dMaxDist = 0 ;
+11 -1
View File
@@ -55,7 +55,7 @@ CurveByInterp::GetCurve( int nMethod, int nType)
if ( ! CalcBesselTangents())
return nullptr ;
}
else {
else if ( nType != CUBIC_BEZIERS_LONG) {
if ( ! CalcAkimaTangents( nMethod == AKIMA_CORNER))
return nullptr ;
}
@@ -103,6 +103,16 @@ CurveByInterp::GetCurve( int nMethod, int nType)
return ::Release( pCrvCompo) ;
}
// 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)) ;
if ( IsNull(pCrv) || ! pCrv->IsValid())
return nullptr ;
return Release( pCrv) ;
}
return nullptr ;
}
+79 -39
View File
@@ -192,7 +192,7 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT
return false ;
// verifico lo stato
if ( m_nStatus != OK && ! ( m_CrvSmplS.empty() && m_nStatus == TO_VERIFY))
if ( m_nStatus != OK && ! ( m_CrvSmplS.empty() && ( m_nStatus == TO_VERIFY || m_nStatus == IS_A_POINT)))
return false ;
// controllo la tolleranza
@@ -224,8 +224,11 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT
// lunghezza della curva originale
double dOldLen ; pCrv->GetLength( dOldLen) ;
// eseguo modifica
if ( ! pCrv->ModifyStart( ptEnd))
return false ;
if ( ! pCrv->ModifyStart( ptEnd)) {
CurveLine crvLine ;
if ( ! crvLine.Set( ptEnd, ptCrvEnd) || ! pCrv.Set( crvLine.Clone()))
return false ;
}
// verifico che la lunghezza non sia variata troppo
double dNewLen ; pCrv->GetLength( dNewLen) ;
if ( abs( dNewLen - dOldLen) > 10 * dLinTol)
@@ -246,8 +249,11 @@ CurveComposite::AddSimpleCurve( ICurve* pSmplCrv, bool bEndOrStart, double dLinT
// lunghezza della curva originale
double dOldLen ; pCrv->GetLength( dOldLen) ;
// eseguo modifica
if ( ! pCrv->ModifyEnd( ptStart))
return false ;
if ( ! pCrv->ModifyEnd( ptStart)) {
CurveLine crvLine ;
if ( ! crvLine.Set( ptCrvStart, ptStart) || ! pCrv.Set( crvLine.Clone()))
return false ;
}
// verifico che la lunghezza non sia variata troppo
double dNewLen ; pCrv->GetLength( dNewLen) ;
if ( abs( dNewLen - dOldLen) > 10 * dLinTol)
@@ -375,9 +381,10 @@ CurveComposite::FromPolyLine( const PolyLine& PL)
return false ;
// ciclo di inserimento dei segmenti che uniscono i punti
double dParIni, dParFin ;
Point3d ptIni, ptFin ;
PL.GetFirstPoint( ptIni) ;
while ( PL.GetNextPoint( ptFin)) {
PL.GetFirstUPoint( &dParIni, &ptIni) ;
while ( PL.GetNextUPoint( &dParFin, &ptFin)) {
// se i punti della coppia coincidono, passo alla coppia successiva
if ( AreSamePointApprox( ptIni, ptFin))
continue ;
@@ -388,10 +395,14 @@ CurveComposite::FromPolyLine( const PolyLine& PL)
// assegno i punti estremi
if ( ! pCrvLine->Set( ptIni, ptFin))
return false ;
// assegno i parametri degli estremi
pCrvLine->SetTempParam( dParIni, 0) ;
pCrvLine->SetTempParam( dParFin, 1) ;
// aggiungo la retta alla curva composita
if ( ! AddSimpleCurve( Release( pCrvLine)))
return false ;
// aggiorno dati prossimo punto iniziale
dParIni = dParFin ;
ptIni = ptFin ;
}
@@ -878,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
@@ -1696,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)
@@ -1718,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)
@@ -1778,10 +1796,11 @@ bool
CurveComposite::AddPoint( const Point3d& ptStart)
{
// verifico lo stato
if ( m_nStatus != TO_VERIFY)
if ( m_nStatus != TO_VERIFY && m_nStatus != IS_A_POINT)
return false ;
// assegno il punto
// assegno il punto e setto lo stato
m_ptStart = ptStart ;
m_nStatus = IS_A_POINT ;
return true ;
}
@@ -1825,7 +1844,7 @@ bool
CurveComposite::AddLine( const Point3d& ptNew, bool bEndOrStart)
{
// verifico lo stato
if ( m_nStatus != OK && m_nStatus != TO_VERIFY)
if ( m_nStatus != OK && m_nStatus != IS_A_POINT)
return false ;
// costruisco la linea
PtrOwner<CurveLine> pLine( CreateBasicCurveLine()) ;
@@ -3034,7 +3053,7 @@ CurveComposite::ArcsToBezierCurves( void)
// se arco, devo trasformare in una o più curve di Bezier
if ( (*Iter)->GetType() == CRV_ARC) {
// eseguo trasformazione
PtrOwner<ICurve> pNewCrv( ArcToBezierCurve( (*Iter))) ;
PtrOwner<ICurve> pNewCrv( ArcToBezierCurve( GetCurveArc( *Iter))) ;
if ( IsNull( pNewCrv))
return false ;
// se risultato è singola curva
@@ -3168,11 +3187,26 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn
// se precedente molto corta
double dLenP ;
if ( pCrvP->GetLength( dLenP) && dLenP < dCurrLinTol) {
// se abbastanza allineata alla successiva
// se abbastanza allineata alla successiva
Vector3d vtDirP, vtDirC ;
if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) {
Point3d ptStart ;
return ( pCrvP->GetStartPoint( ptStart) && pCrvC->ModifyStart( ptStart) ? -1 : 0) ;
bool bModifStart = ( pCrvC->GetType() != CRV_ARC) ;
if ( ! bModifStart) {
/* nel caso in cui la curva corrente sia un arco, bisogna controllare che la somma tra
l'angolo al centro e l'angolo sotteso dalla curva precedente non superi l'angolo giro; in
caso positivo, la modifica del punto inziale dell'arco ( curva corrente) rimoverebbe
tutti gli angoli superiori a 360deg [curve a ricciolo per regioni non svuotate in Pocketing] */
Point3d ptS ; pCrvP->GetStartPoint( ptS) ;
Point3d ptE ; pCrvC->GetStartPoint( ptE) ;
const ICurveArc* pArcC = GetBasicCurveArc( pCrvC) ;
double dAngRef = ( Dist( ptS, ptE) / pArcC->GetRadius()) * RADTODEG ;
bModifStart = ( abs( pArcC->GetAngCenter()) + dAngRef < ANG_FULL - 10 * EPS_ANG_SMALL) ;
}
if ( bModifStart) {
Point3d ptStart ;
return ( pCrvP->GetStartPoint( ptStart) && pCrvC->ModifyStart( ptStart) ? -1 : 0) ;
}
}
}
// se corrente molto corta
@@ -3181,10 +3215,24 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn
// se abbastanza allineata alla precedente
Vector3d vtDirP, vtDirC ;
if ( pCrvP->GetEndDir( vtDirP) && pCrvC->GetStartDir( vtDirC) && ( vtDirP * vtDirC) >= dCosAngTol) {
Point3d ptEnd ;
return ( pCrvC->GetEndPoint( ptEnd) && pCrvP->ModifyEnd( ptEnd) ? 1 : 0) ;
bool bModifEnd = ( pCrvP->GetType() != CRV_ARC) ;
if ( ! bModifEnd) {
/* nel caso in cui la curva predecente sia un arco, bisogna controllare che la somma tra
l'angolo al centro e l'angolo sotteso dalla curva corrente non superi l'angolo giro; in
caso positivo, la modifica del punto finale dell'arco ( curva precedente) rimoverebbe
tutti gli angoli superiori a 360deg [curve a ricciolo per regioni non svuotate in Pocketing] */
Point3d ptS ; pCrvP->GetEndPoint( ptS) ;
Point3d ptE ; pCrvC->GetEndPoint( ptE) ;
const CurveArc* pArcP = GetBasicCurveArc( pCrvP) ;
double dAngRef = ( Dist( ptS, ptE) / pArcP->GetRadius()) * RADTODEG ;
bModifEnd = ( abs( pArcP->GetAngCenter()) + dAngRef < ANG_FULL - 10. * EPS_ANG_SMALL) ;
}
if ( bModifEnd) {
Point3d ptEnd ;
return ( pCrvC->GetEndPoint( ptEnd) && pCrvP->ModifyEnd( ptEnd) ? 1 : 0) ;
}
}
}
}
// coefficiente deduzione tolleranza
const double COEFF_TOL = 0.7 ;
// se entrambe rette
@@ -3264,11 +3312,12 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn
if ( ! bPlaneArcs) {
ptP1.Scale( frRef, 1, 1, 0) ;
ptP2.Scale( frRef, 1, 1, 0) ;
ptP3.Scale( frRef, 1, 1, 0) ;
ptP3.Scale( frRef, 1, 1, 0) ;
ptC1Fin.Scale( frRef, 1, 1, 0) ;
}
// verifico se circonferenza completa
bool bCirc = ( AreSamePointApprox( ptP1, ptP3)) ;
bool bCirc = ( AreSamePointEpsilon( ptP1, ptP3, dCurrLinTol)) ;
if ( bCirc) {
pArcC->GetMidPoint( ptP3) ;
if ( ! bPlaneArcs)
@@ -3277,6 +3326,10 @@ MergeTwoCurves( ICurve* pCrvP, ICurve* pCrvC, double& dCurrLinTol, double dCosAn
CurveArc NewArc ;
if ( NewArc.Set3P( ptP1, ptP2, ptP3, bCirc)) {
// se vicino a circonferenza arco per 3 punti potrebbe non dare il risultato desiderato quindi faccio controllo su raggio e centro
if ( Dist( NewArc.GetCenter(), ptC1Fin) > 2 * dCurrLinTol || abs( NewArc.GetRadius() - pArcP->GetRadius()) > 2 * dCurrLinTol)
return 0 ;
// verifico normale al piano dell'arco
if ( NewArc.GetNormVersor() * pArcC->GetNormVersor() < 0)
NewArc.InvertN() ;
@@ -3794,19 +3847,6 @@ CurveComposite::ResetVoronoiObject() const
m_pVoronoiObj = nullptr ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::FromPoint(Point3d& ptStart)
{
// verifico lo stato
if ( m_nStatus != TO_VERIFY)
return false ;
// assegno il punto e setto lo stato
m_ptStart = ptStart ;
m_nStatus = IS_A_POINT ;
return true ;
}
//----------------------------------------------------------------------------
bool
CurveComposite::GetOnlyPoint(Point3d& ptStart) const
+4 -5
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
@@ -177,8 +177,7 @@ class CurveComposite : public ICurveComposite, public IGeoObjRW
bool GetCurveTempProp( int nCrv, int& nProp, int nPropInd = 0) const override ;
bool SetCurveTempParam( int nCrv, double dParam, int nParamInd = 0) override ;
bool GetCurveTempParam( int nCrv, double& dParam, int nParamInd = 0) const override ;
bool FromPoint( Point3d& ptStart) override ; // funzione per settare la curva ad un unico punto
bool GetOnlyPoint( Point3d& ptStart) const override ; // funzione per recuperare l'unico punto da cui è composta la curva ( degenere)
bool GetOnlyPoint( Point3d& ptStart) const override ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
@@ -199,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
+17 -6
View File
@@ -152,7 +152,7 @@ DistPointCurve::GetMinDistPoint( double dNearParam, Point3d& ptMinDist, int& nFl
}
}
// cerco punto discreto più vicino (anche estremi di zone continue)
// cerco punto discreto più vicino (anche estremi di zone continue)
double dParam ;
for ( int i = 0 ; i < (int) m_Info.size() ; ++ i) {
if ( i == 0 ||
@@ -197,7 +197,7 @@ DistPointCurve::GetParamAtMinDistPoint( double dNearParam, double& dParam, int&
}
}
// cerco punto discreto più vicino (anche estremi di zone continue)
// cerco punto discreto più vicino (anche estremi di zone continue)
for ( int i = 0 ; i < (int) m_Info.size() ; ++ i) {
if ( i == 0 ||
abs( m_Info[i].dPar - dNearParam) < abs( dParam - dNearParam)) {
@@ -232,9 +232,20 @@ DistPointCurve::GetSideAtMinDistPoint( int nInd, const Vector3d& vtN, int& nSide
Vector3d vtTg = 0.5 * ( vtPreTg + vtPostTg) ;
// se tangenti opposte, si deve ricalcolare spostandosi un poco
if ( ! vtTg.Normalize()) {
double dDeltaU = 1000 * EPS_PARAM ;
if ( ! m_pCurve->GetPointTang( m_Info[nInd].dPar - dDeltaU, ICurve::FROM_MINUS, ptQ, vtPreTg) ||
! m_pCurve->GetPointTang( m_Info[nInd].dPar + dDeltaU, ICurve::FROM_PLUS, ptQ, vtPostTg))
double dDeltaU = 1000 * EPS_PARAM ;
double dParPre = m_Info[nInd].dPar - dDeltaU ;
double dParPost = m_Info[nInd].dPar + dDeltaU ;
// verifico se il parametro deve essere modificato per adattarsi a curva chiusa
if ( m_pCurve->IsClosed()) {
double dParS, dParE ;
m_pCurve->GetDomain( dParS, dParE) ;
if ( dParPre < dParS)
dParPre = dParE - dDeltaU ;
if ( dParPost > dParE)
dParPost = dParS + dDeltaU ;
}
if ( ! m_pCurve->GetPointTang( dParPre, ICurve::FROM_MINUS, ptQ, vtPreTg) ||
! m_pCurve->GetPointTang( dParPost, ICurve::FROM_PLUS, ptQ, vtPostTg))
return false ;
vtTg = 0.5 * ( vtPreTg + vtPostTg) ;
if ( ! vtTg.Normalize( EPS_ZERO))
@@ -264,7 +275,7 @@ DistPointCurve::GetSideAtMinDistPoint( double dNearParam, const Vector3d& vtN, i
if ( m_dDist < 0 || m_Info.empty())
return false ;
// cerco punto discreto più vicino (anche estremi di zone continue)
// cerco punto discreto più vicino (anche estremi di zone continue)
int nInd ;
double dParam ;
for ( int i = 0 ; i < (int) m_Info.size() ; ++ i) {
+119
View File
@@ -0,0 +1,119 @@
//----------------------------------------------------------------------------
// 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)
{
// Bezier non valida
if ( &pSrfBz == nullptr || ! 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::GetParamPoint( Point3d& ptParamPoint) const
{
// Distanza non valida
if ( m_dDist < -EPS_ZERO)
return false ;
// Distanza valida
ptParamPoint = m_ptParam ;
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 ;
}
+18
View File
@@ -94,6 +94,8 @@ DistPointSurfTm::Calculate( const Point3d& ptP, const ISurfTriMesh& tmSurf)
{
// Inizializzo distanza non calcolata
m_dDist = - 1. ;
// Vettore di indici dei triangoli più vicini inizialmente vuoto
m_vnMinDistTriaIndex.clear() ;
// Controllo se la superficie è chiusa
m_bIsSurfClosed = tmSurf.IsClosed() ;
@@ -184,6 +186,10 @@ DistPointSurfTm::Calculate( const Point3d& ptP, const ISurfTriMesh& tmSurf)
if ( nMinDistTriaIndex == SVT_NULL)
return ;
// Inizializzo il vettore dei triangoli a minima distanza
for ( auto& Tria : vTria)
m_vnMinDistTriaIndex.emplace_back( Tria.first) ;
// salvo la distanza minima
m_dDist = dMinDist ;
// salvo il punto a distanza minima
@@ -279,6 +285,18 @@ DistPointSurfTm::GetMinDistTriaIndex( int& nMinDistIndex) const
return true ;
}
//----------------------------------------------------------------------------
bool
DistPointSurfTm::GetMinDistTriaIndices( INTVECTOR& vMinDistTriaIndex) const
{
// Distanza non valida
if ( m_dDist < - EPS_ZERO)
return false ;
// Distanza valida
vMinDistTriaIndex = m_vnMinDistTriaIndex ;
return true ;
}
//----------------------------------------------------------------------------
int
GetSurfTmNearestVertex( const Point3d& ptP, const ISurfTriMesh& tmSurf)
+12 -3
View File
@@ -159,11 +159,20 @@ InitFontManager( const string& sNfeFontDir, const string& sDefaultFont)
{
// recupero il font manager
FontManager& fntMgr = FontManager::GetFontManager() ;
// lo inizializzo
fntMgr.Init( sNfeFontDir, sDefaultFont) ;
}
//-----------------------------------------------------------------------------
void
SetDefaultFont( const string& sDefaultFont)
{
// recupero il font manager
FontManager& fntMgr = FontManager::GetFontManager() ;
// imposto il dato
fntMgr.SetDefaultFont( sDefaultFont) ;
}
//-----------------------------------------------------------------------------
const string&
GetNfeFontDir( void)
@@ -185,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.
+12 -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>
@@ -310,7 +310,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 +322,10 @@ 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" />
<ClCompile Include="PolygonElevation.cpp" />
<ClCompile Include="Quaternion.cpp" />
<ClCompile Include="RotationMinimizingFrame.cpp" />
@@ -338,11 +344,13 @@ copy $(TargetPath) \EgtProg\Dll64</Command>
<ClInclude Include="..\Include\EGkIntersLineVolZmap.h" />
<ClInclude Include="..\Include\EGkIntersPlaneBox.h" />
<ClInclude Include="..\Include\EGkIntersPlaneVolZmap.h" />
<ClInclude Include="..\Include\EGkMultiGeomDB.h" />
<ClInclude Include="..\Include\EGkPolygonElevation.h" />
<ClInclude Include="..\Include\EGkQuaternion.h" />
<ClInclude Include="..\Include\EGkRotationMinimizingFrame.h" />
<ClInclude Include="..\Include\EGkRotationXplaneFrame.h" />
<ClInclude Include="..\Include\EGkSubtractProjectedFacesOnStmFace.h" />
<ClInclude Include="..\Include\EGkSurfTriMeshAux.h" />
<ClInclude Include="CAvSilhouetteSurfTm.h" />
<ClInclude Include="CDeBoxTria.h" />
<ClInclude Include="CDeCapsTria.h" />
+27
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">
@@ -546,6 +549,24 @@
<ClCompile Include="DistPointSurfFr.cpp">
<Filter>File di origine\GeoDist</Filter>
</ClCompile>
<ClCompile Include="VolZmapOffset.cpp">
<Filter>File di origine\Geo</Filter>
</ClCompile>
<ClCompile Include="SurfTriMeshOffset.cpp">
<Filter>File di origine\GeoOffset</Filter>
</ClCompile>
<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>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@@ -1226,6 +1247,12 @@
<ClInclude Include="CAvSilhouetteSurfTm.h">
<Filter>File di intestazione</Filter>
</ClInclude>
<ClInclude Include="..\Include\EGkSurfTriMeshAux.h">
<Filter>File di intestazione\Include</Filter>
</ClInclude>
<ClInclude Include="..\Include\EGkMultiGeomDB.h">
<Filter>File di intestazione\Include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="EgtGeomKernel.rc">
+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
+3 -1
View File
@@ -29,6 +29,8 @@ class FontManager
public :
bool Init( const std::string& sNfeFontDir, const std::string& sDefaultFont) ;
bool SetDefaultFont( const std::string& sDefaultFont)
{ m_sDefaultFont = sDefaultFont ; return true ; }
bool SetCurrFont( const std::string& sFont, int nWeight, bool bItalic,
double dHeight, double dRatio, double dAddAdvance) ;
const std::string& GetNfeFontDir( void) const
@@ -54,7 +56,7 @@ class FontManager
OsFont m_OsFont ;
private :
FontManager( void) {}
FontManager( void) : m_bCurrNfeFont( false) {}
FontManager( FontManager const& copy) = delete ;
FontManager& operator=( FontManager const& copy) = delete ;
} ;
+2 -2
View File
@@ -336,7 +336,7 @@ GdbGeo::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double dCoe
// curva originale
ICurve* pCrv = GetCurve( m_pGeoObj) ;
// trasformo in curva di Bezier (semplice o composta)
ICurve* pCrvNew = ArcToBezierCurve( pCrv) ;
ICurve* pCrvNew = ArcToBezierCurve( GetCurveArc( pCrv)) ;
if ( pCrvNew == nullptr)
return false ;
// assegno alla nuova curva estrusione e spessore di quella originale
@@ -389,7 +389,7 @@ GdbGeo::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtDi
if ( ! pArc->IsPlane() ||
! AreSameOrOppositeVectorExact( pArc->GetNormVersor(), vtNorm)) {
// trasformo in curva di Bezier (semplice o composta)
ICurve* pCrvNew = ArcToBezierCurve( GetCurve( m_pGeoObj)) ;
ICurve* pCrvNew = ArcToBezierCurve( GetCurveArc( m_pGeoObj)) ;
if ( pCrvNew == nullptr)
return false ;
// assegno alla nuova curva estrusione e spessore di quella originale
+14
View File
@@ -101,6 +101,20 @@ GdbObj::CopyFrom( const GdbObj* pSou)
return ( CopyAttribsFrom( pSou) && CopyTextureDataFrom( pSou) && CopyUserObjFrom( pSou)) ;
}
//----------------------------------------------------------------------------
bool
GdbObj::CopyStippleDataFrom( const GdbObj* pSou)
{
// se l'oggetto sorgente non esiste
if ( pSou == nullptr)
return false ;
// copio stipple
m_nStpFactor = pSou->m_nStpFactor ;
m_nStpPattern = pSou->m_nStpPattern ;
return true ;
}
//----------------------------------------------------------------------------
bool
GdbObj::CopyAttribsFrom( const GdbObj* pSou)
+1
View File
@@ -57,6 +57,7 @@ class GdbObj
GdbObj( void) ;
bool CopyFrom( const GdbObj* pSou) ;
bool CopyAttribsFrom( const GdbObj* pSou) ;
bool CopyStippleDataFrom( const GdbObj* pSou) ;
bool CopyTextureDataFrom( const GdbObj* pSou) ;
bool CopyUserObjFrom( const GdbObj* pSou) ;
+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 ; }
} ;
+13 -11
View File
@@ -38,20 +38,22 @@ using namespace std ;
class LockAddErase
{
public :
LockAddErase(std::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 :
std::atomic_flag& m_bAddEraseOn ;
atomic_flag& m_bAddEraseOn ;
bool m_bUse ;
} ;
@@ -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 ;
@@ -877,7 +879,7 @@ GeomDB::GetFirstNameInGroup( int nGroupId, const string& sName) const
// se ha il nome o la parte iniziale di nome cercato
string sObjName ;
if ( pGdbO->GetName( sObjName) &&
(( ! bWild && sObjName == sToFind) || ( bWild && sObjName.find( sToFind) == 0)))
(( ! bWild && sObjName == sToFind) || ( bWild && sObjName.rfind( sToFind, 0) == 0)))
return ( pGdbO->m_nId) ;
// passo al successivo
pGdbO = pGdbO->GetNext() ;
@@ -905,7 +907,7 @@ GeomDB::GetNextName( int nId, const string& sName) const
// se ha il nome o la parte iniziale di nome cercato
string sObjName ;
if ( pGdbNext->GetName( sObjName) &&
(( ! bWild && sObjName == sToFind) || ( bWild && sObjName.find( sToFind) == 0)))
(( ! bWild && sObjName == sToFind) || ( bWild && sObjName.rfind( sToFind, 0) == 0)))
return ( pGdbNext->m_nId) ;
// passo al successivo
pGdbNext = pGdbNext->GetNext() ;
@@ -933,7 +935,7 @@ GeomDB::GetLastNameInGroup( int nGroupId, const string& sName) const
// se ha il nome o la parte iniziale di nome cercato
string sObjName ;
if ( pGdbO->GetName( sObjName) &&
(( ! bWild && sObjName == sToFind) || ( bWild && sObjName.find( sToFind) == 0)))
(( ! bWild && sObjName == sToFind) || ( bWild && sObjName.rfind( sToFind, 0) == 0)))
return ( pGdbO->m_nId) ;
// passo al precedente
pGdbO = pGdbO->GetPrev() ;
@@ -961,7 +963,7 @@ GeomDB::GetPrevName( int nId, const string& sName) const
// se ha il nome o la parte iniziale di nome cercato
string sObjName ;
if ( pGdbPrev->GetName( sObjName) &&
(( ! bWild && sObjName == sToFind) || ( bWild && sObjName.find( sToFind) == 0)))
(( ! bWild && sObjName == sToFind) || ( bWild && sObjName.rfind( sToFind, 0) == 0)))
return ( pGdbPrev->m_nId) ;
// passo al precedente
pGdbPrev = pGdbPrev->GetPrev() ;
+4
View File
@@ -29,6 +29,10 @@ class GeomDB : public IGeomDB
friend class GdbObj ;
friend class GdbGroup ;
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 ;
+42
View File
@@ -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)
+451
View File
@@ -0,0 +1,451 @@
//----------------------------------------------------------------------------
// 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()
{
if ( m_Info.size() < 2)
return ;
// 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 ;
+77 -19
View File
@@ -14,6 +14,7 @@
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "IntersLineLine.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include <algorithm>
using namespace std ;
@@ -156,35 +157,92 @@ IntersLineLine::IntersFiniteLines( const CurveLine& Line1, const CurveLine& Line
double dCrossXY = CrossXY( vtDir1, vtDir2) ;
// flag per linee parallele
bool bParallel = ( abs( dCrossXY) < SIN_EPS_ANG_ZERO * ( dLen1XY * dLen2XY)) ;
// flag per segmenti che si allontanano significativamente
// 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 && ! AreSamePointXYEpsilon( ptS1, ptS2, 2 * EPS_SMALL)) ||
( nS1Side == 0 && nE2Side == 0 && ! AreSamePointXYEpsilon( ptS1, ptE2, 2 * EPS_SMALL)) ||
( nE1Side == 0 && nS2Side == 0 && ! AreSamePointXYEpsilon( ptE1, ptS2, 2 * EPS_SMALL)) ||
( nE1Side == 0 && nE2Side == 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
m_Info.IciA[0].dU = CrossXY( ( ptS2 - ptS1), vtDir2) / dCrossXY ;
m_Info.IciB[0].dU = CrossXY( ( ptS2 - ptS1), vtDir1) / dCrossXY ;
// verifica posizione intersezione su prima linea
// verifica posizione intersezione su prima linea
int nPos1 = ICurve::PP_NULL ; // fuori
if ( abs( m_Info.IciA[0].dU * dLen1XY) < EPS_SMALL)
nPos1 = ICurve::PP_START ; // vicino a inizio
else if ( abs(( 1 - m_Info.IciA[0].dU) * dLen1XY) < EPS_SMALL)
nPos1 = ICurve::PP_END ; // vicino a fine
else if ( m_Info.IciA[0].dU > 0 && m_Info.IciA[0].dU < 1)
nPos1 = ICurve::PP_MID ; // nell'interno
else
return ;
if ( nS1Side == 0 || nE1Side == 0) {
if( nS1Side == 0) {
nPos1 = ICurve::PP_START ;
m_Info.IciA[0].dU = 0 ;
m_Info.IciB[0].dU = vtDir2 * ( ptS1 - ptS2) / Pow( vtDir2.Len(), 2) ;
}
else {
nPos1 = ICurve::PP_END ;
m_Info.IciA[0].dU = 1 ;
m_Info.IciB[0].dU = vtDir2 * ( ptE1 - ptS2) / Pow( vtDir2.Len(), 2) ;
}
}
else {
if ( abs( m_Info.IciA[0].dU * dLen1XY) < EPS_SMALL)
nPos1 = ICurve::PP_START ; // vicino a inizio
else if ( abs(( 1 - m_Info.IciA[0].dU) * dLen1XY) < EPS_SMALL)
nPos1 = ICurve::PP_END ; // vicino a fine
else if ( m_Info.IciA[0].dU > 0 && m_Info.IciA[0].dU < 1)
nPos1 = ICurve::PP_MID ; // nell'interno
else
return ;
}
// verifica posizione intersezione su seconda linea
int nPos2 = ICurve::PP_NULL ; // fuori
if ( abs( m_Info.IciB[0].dU * dLen2XY) < EPS_SMALL)
nPos2 = ICurve::PP_START ; // vicino a inizio
else if ( abs(( 1 - m_Info.IciB[0].dU) * dLen2XY) < EPS_SMALL)
nPos2 = ICurve::PP_END ; // vicino a fine
else if ( m_Info.IciB[0].dU > 0 && m_Info.IciB[0].dU < 1)
nPos2 = ICurve::PP_MID ; // nell'interno
else
return ;
// limito i parametri a stare sui segmenti (0...1)
if ( nS2Side == 0 || nE2Side == 0) {
if( nS2Side == 0) {
nPos2 = ICurve::PP_START ;
m_Info.IciB[0].dU = 0 ;
m_Info.IciA[0].dU = vtDir1 * (ptS2 - ptS1) / Pow( vtDir1.Len(), 2) ;
}
else {
nPos2 = ICurve::PP_END ;
m_Info.IciB[0].dU = 1 ;
m_Info.IciA[0].dU = vtDir1 * (ptE2 - ptS1) / Pow( vtDir1.Len(), 2) ;
}
}
else {
if ( abs( m_Info.IciB[0].dU * dLen2XY) < EPS_SMALL)
nPos2 = ICurve::PP_START ; // vicino a inizio
else if ( abs(( 1 - m_Info.IciB[0].dU) * dLen2XY) < EPS_SMALL)
nPos2 = ICurve::PP_END ; // vicino a fine
else if ( m_Info.IciB[0].dU > 0 && m_Info.IciB[0].dU < 1)
nPos2 = ICurve::PP_MID ; // nell'interno
else
return ;
} // limito i parametri a stare sui segmenti (0...1)
m_Info.IciA[0].dU = min( max( m_Info.IciA[0].dU, 0.), 1.) ;
m_Info.IciB[0].dU = min( max( m_Info.IciB[0].dU, 0.), 1.) ;
// calcolo i punti sulle due linee (possono differire in Z)
+271 -14
View File
@@ -14,11 +14,17 @@
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "CurveLine.h"
#include "CurveBezier.h"
#include "CurveComposite.h"
#include "SurfFlatRegion.h"
#include "/EgtDev/Include/EGkDistPointLine.h"
#include "/EgtDev/Include/EGkDistLineLine.h"
#include "/EgtDev/Include/EGkDistPointSurfFr.h"
#include "/EgtDev/Include/EGkIntersLineTria.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
#include "/EgtDev/Include/EGkIntersLineSurfBez.h"
#include "/EgtDev/Include/EGkSurfBezier.h"
#include "/EgtDev/Include/ENkPolynomialRoots.h"
using namespace std ;
@@ -28,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 ;
@@ -42,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 ;
@@ -67,11 +72,11 @@ static void
UpdateInfoIntersLineSurfBz( const Point3d& ptL, const Vector3d& vtDir, int nILT, int nT, const Point3d& ptSP, const Point3d& ptIBz, double dCos,
const Point3d& ptSP2, const Point3d& ptIBz2, double dCos2, ILSBIVECTOR& vInfo)
{
if ( nILT == ILTT_IN || nILT == ILTT_EDGE || nILT == ILTT_VERT) {
if ( nILT == ILTA_IN || nILT == ILTA_EDGE || nILT == ILTA_VERT || nILT == ILTA_NO_TRIA) {
double dU = ( ptIBz - ptL) * vtDir ;
vInfo.emplace_back( nILT, dU, nT, dCos, ptIBz, ptSP) ;
}
else if ( nILT == ILTT_SEGM || nILT == ILTT_SEGM_ON_EDGE) {
else if ( nILT == ILTA_SEGM || nILT == ILTA_SEGM_ON_EDGE) {
double dU = ( ptIBz - ptL) * vtDir ;
double dU2 = ( ptIBz2 - ptL) * vtDir ;
vInfo.emplace_back( nILT, dU, dU2, nT, dCos2, ptIBz, ptIBz2, ptSP, ptSP2) ;
@@ -88,8 +93,8 @@ OrderInfoIntersLineSurfBz( ILSBIVECTOR& vInfo)
// ordino il vettore delle intersezioni secondo il senso crescente del parametro di linea
sort( vInfo.begin(), vInfo.end(),
[]( const IntLinSbzInfo& a, const IntLinSbzInfo& b)
{ double dUa = ( ( a.nILTT == ILTT_SEGM || a.nILTT == ILTT_SEGM_ON_EDGE) ? ( a.dU + a.dU2) / 2 : a.dU) ;
double dUb = ( ( b.nILTT == ILTT_SEGM || b.nILTT == ILTT_SEGM_ON_EDGE) ? ( b.dU + b.dU2) / 2 : b.dU) ;
{ double dUa = ( ( a.nILTA == ILTA_SEGM || a.nILTA == ILTA_SEGM_ON_EDGE) ? ( a.dU + a.dU2) / 2 : a.dU) ;
double dUb = ( ( b.nILTA == ILTA_SEGM || b.nILTA == ILTA_SEGM_ON_EDGE) ? ( b.dU + b.dU2) / 2 : b.dU) ;
return ( dUa < dUb) ; }) ;
}
@@ -137,16 +142,16 @@ 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)
if ( InfoTm.nILTT == ILTT_SEGM || InfoTm.nILTT == ILTT_SEGM_ON_EDGE ) {
if ( InfoTm.nILTT == ILTA_SEGM || InfoTm.nILTT == ILTA_SEGM_ON_EDGE ) {
pSurfBz->UnprojectPointFromStm( InfoTm.nT, InfoTm.ptI2, ptSP2, InfoTm.nILTT) ;
if ( ! RefineIntersNewton(ptL, vtL, dLen, bFinite, pSurfBz, ptSP2, ptIBz2) ) {
int nVert[3] ;
@@ -157,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) ;
@@ -176,7 +181,7 @@ FilterLineSurfBzInters( const ILSBIVECTOR& vInfo, INTDBLVECTOR& vInters)
// ciclo sulle intersezioni
for ( const auto& Info : vInfo) {
// se intersezione puntuale
if ( Info.nILTT == ILTT_VERT || Info.nILTT == ILTT_EDGE || Info.nILTT == ILTT_IN) {
if ( Info.nILTA == ILTA_VERT || Info.nILTA == ILTA_EDGE || Info.nILTA == ILTA_IN) {
int nFlag = LSBT_TOUCH ;
if ( Info.dCosDN > EPS_ZERO)
nFlag = LSBT_OUT ;
@@ -185,7 +190,7 @@ FilterLineSurfBzInters( const ILSBIVECTOR& vInfo, INTDBLVECTOR& vInters)
vInters.emplace_back( nFlag, Info.dU) ;
}
// se altrimenti intersezione con coincidenza
else if ( Info.nILTT == ILTT_SEGM || Info.nILTT == ILTT_SEGM_ON_EDGE) {
else if ( Info.nILTA == ILTA_SEGM || Info.nILTA == ILTA_SEGM_ON_EDGE) {
vInters.emplace_back( LSBT_TG_INI, Info.dU) ;
vInters.emplace_back( LSBT_TG_FIN, Info.dU2) ;
}
@@ -232,3 +237,255 @@ FilterLineSurfBzInters( const ILSBIVECTOR& vInfo, INTDBLVECTOR& vInters)
}
return true ;
}
//----------------------------------------------------------------------------
// Intersezione di una linea con una superficie di Bezier
//----------------------------------------------------------------------------
bool
IntersLineSurfBzBilinear( const Point3d& ptL, const Vector3d& vtL, double dLen, const ISurfBezier* pSurfBz,
ILSBIVECTOR& vInfo, bool bFinite)
{
int nDegU, nDegV, nSpanU, nSpanV ;
bool bRat, bTrimmed ;
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)
return false ;
int nInters = int( vInfo.size()) ;
PNTVECTOR vPntCtrl ;
for ( int p = 0 ; p < 4 ; ++p) {
bool bOk = false ;
vPntCtrl.push_back( pSurfBz->GetControlPoint( p, &bOk)) ;
}
Vector3d a = vPntCtrl[3] - vPntCtrl[1] + ( vPntCtrl[0] - vPntCtrl[2]) ;
Vector3d b = vPntCtrl[1] - vPntCtrl[0] ;
Vector3d c = vPntCtrl[2] - vPntCtrl[0] ;
Vector3d d = vPntCtrl[0] - ORIG ;
double A1 = a.x * vtL.z - a.z * vtL.x ;
double B1 = b.x * vtL.z - b.z * vtL.x ;
double C1 = c.x * vtL.z - c.z * vtL.x ;
double A2 = a.y * vtL.z - a.z * vtL.y ;
double B2 = b.y * vtL.z - b.z * vtL.y ;
double C2 = c.y * vtL.z - c.z * vtL.y ;
double D1 = ( d.x - ptL.x) * vtL.z - ( d.z - ptL.z) * vtL.x ;
double D2 = ( d.y - ptL.y) * vtL.z - ( d.z - ptL.z) * vtL.y ;
DBLVECTOR vdCoeff, vdRoots ;
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) {
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) {
dU = (dV * (C1 - C2) + ( D1 - D2)) / ( dV * ( A2 - A1) + ( B2 - B1)) ;
if ( dU > - EPS_ZERO && dU < 1 + EPS_ZERO) {
Point3d ptIBez, ptIBez2 ;
Vector3d vtN ;
pSurfBz->GetPointNrmD1D2(dU, dV, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptIBez, vtN) ;
Point3d ptSP( dU, dV, 0), ptSP2 ;
double dCos = vtN * vtL, dCos2 = 0 ;
UpdateInfoIntersLineSurfBz( ptL, vtL, ILTA_NO_TRIA, -1, ptSP, ptIBez, dCos, ptSP2, ptIBez2, dCos2, vInfo) ;
bFound = true ;
}
}
}
}
// 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) {
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) {
PolyLine plApprox ; vCrvEdge[0]->ApproxWithLines( EPS_SMALL, dAngTolDeg, ICurve::ApprLineType::APL_STD, plApprox) ;
//CurveComposite cCC ;
//cCC.FromPolyLine( plApprox) ;
int nClosestLine = -1 ;
double dMinDist = INFINITO ;
Point3d pt ; plApprox.GetFirstPoint( pt) ;
Point3d ptClosest ;
int c = 0 ;
int nTot = plApprox.GetPointNbr() ;
for ( int j = 0 ; j < nTot ; ++j) {
DistPointLine dpl( pt, ptL, vtL, dLen, bFinite) ;
double dDist = INFINITO ;
dpl.GetDist( dDist) ;
if ( dDist < dMinDist) {
nClosestLine = c ;
dMinDist = dDist ;
}
plApprox.GetNextPoint( pt) ;
++ c ;
}
Point3d ptInt1, ptInt2 ;
if ( nClosestLine < nTot - 1 && nClosestLine > 0) {
// 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)
plApprox.GetNextPoint( ptStart) ;
plApprox.GetNextPoint( ptEnd) ;
// linea precedente al punto
Vector3d vtLinePre = ptEnd - ptStart ;
double dLenPre = vtLinePre.Len() ;
DistLineLine dllPre( ptStart, vtLinePre, dLenPre, ptL, vtL,dLen) ;
double dDistPre = INFINITO ;
dllPre.GetDist( dDistPre) ;
// linea che inzia con quel punto
ptStart = ptEnd ;
plApprox.GetNextPoint( ptEnd) ;
Vector3d vtLineCurr = ptEnd - ptStart ;
double dLenCurr = vtLineCurr.Len() ;
DistLineLine dllCurr( ptStart, vtLineCurr, dLenCurr, ptL, vtL,dLen) ;
double dDistCurr = INFINITO ;
dllCurr.GetDist( dDistCurr) ;
if ( dDistPre < dDistCurr)
dllPre.GetMinDistPoints( ptInt1, ptInt2) ;
else
dllCurr.GetMinDistPoints( ptInt1, ptInt2) ;
}
else if ( nClosestLine == 0) {
// il punto più vicino è sulla prima linea
Point3d ptStart ; plApprox.GetFirstPoint( ptStart) ;
Point3d ptEnd ; plApprox.GetNextPoint( ptEnd) ;
Vector3d vtLineCurr = ptEnd - ptStart ;
double dLenCurr = vtLineCurr.Len() ;
DistLineLine dllCurr( ptStart, vtLineCurr, dLenCurr, ptL, vtL,dLen) ;
dllCurr.GetMinDistPoints( ptInt1, ptInt2) ;
}
else if ( nClosestLine == nTot- 1) {
// il punto più vicino è sull'ultima linea
Point3d ptStart ; plApprox.GetFirstPoint( ptStart) ;
Point3d ptEnd ;
for ( int z = 1 ; z < nClosestLine - 1 ; ++z)
plApprox.GetNextPoint( ptStart) ;
plApprox.GetNextPoint( ptEnd) ;
Vector3d vtLinePre = ptEnd - ptStart ;
double dLenPre = vtLinePre.Len() ;
DistLineLine dllCurr( ptStart, vtLinePre, dLenPre, ptL, vtL,dLen) ;
dllCurr.GetMinDistPoints( ptInt1, ptInt2) ;
}
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) {
//dV1 = 0 ; dV2 = 0 ;
vCrvEdge[0]->GetParamAtPoint( ptInt1, dU1) ;
vCrvEdge[0]->GetParamAtPoint( ptInt2, dU2) ;
}
else if ( i == 1) {
//dU1 = 1 ; dU2 = 1 ;
vCrvEdge[1]->GetParamAtPoint( ptInt1, dV1) ;
vCrvEdge[1]->GetParamAtPoint( ptInt2, dV2) ;
}
else if ( i == 2){
//dV1 = 1 ; dV2 = 1 ;
vCrvEdge[2]->GetParamAtPoint( ptInt1, dU1) ;
vCrvEdge[2]->GetParamAtPoint( ptInt2, dU2) ;
}
else if ( i == 3){
//dU1 = 0 ; dU2 = 0 ;
vCrvEdge[3]->GetParamAtPoint( ptInt1, dV1) ;
vCrvEdge[3]->GetParamAtPoint( ptInt2, dV2) ;
}
Point3d ptIBez1, ptIBez2 ;
Vector3d vtN1, vtN2 ;
pSurfBz->GetPointNrmD1D2(dU1, dV1, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptIBez1, vtN1) ;
pSurfBz->GetPointNrmD1D2(dU2, dV2, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptIBez2, vtN2) ;
Point3d ptSP1( dU1, dV1, 0) ;
double dCos1 = vtN1 * vtL ;
Point3d ptSP2( dU2, dV2, 0) ;
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) {
int nNewTot = int(vInfo.size()) ;
int nNewInters = nNewTot - nInters ;
bool bAlreadyFound = false ;
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) ;
break ;
}
}
}
UpdateInfoIntersLineSurfBz( ptL, vtL, ILTA_NO_TRIA, -1, ptSP1, ptIBez1, dCos1, ptSP2, ptIBez2, dCos2, vInfo) ;
bFound = true ;
break ;
}
// se ho trovato un punto a distanza zero dalla linea allora ho trovato l'intersezione
else if ( dMinDist < EPS_SMALL) {
if ( i == 0) {
//dV1 = 0 ;
vCrvEdge[0]->GetParamAtPoint( ptInt1, dU1) ;
}
else if ( i == 1) {
//dU1 = 1 ;
vCrvEdge[1]->GetParamAtPoint( ptInt1, dV1) ;
}
else if ( i == 2) {
//dV1 = 1 ;
vCrvEdge[2]->GetParamAtPoint( ptInt1, dU1) ;
}
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) {
int nNewTot = int(vInfo.size()) ;
int nNewInters = nNewTot - nInters ;
bool bAlreadyFound = false ;
for ( int i = 0 ; i < nNewInters ; ++i)
bAlreadyFound = AreSamePointApprox(vInfo[nNewTot - i].ptUV, ptSP1) ;
if ( bAlreadyFound)
continue ;
}
Point3d ptIBez1, ptIBez2 ;
Vector3d vtN1, vtN2 ;
pSurfBz->GetPointNrmD1D2(dU1, dV1, ISurfBezier::Side::FROM_MINUS, ISurfBezier::Side::FROM_MINUS, ptIBez1, vtN1) ;
double dCos1 = vtN1 * vtL, dCos2 = 0 ;
UpdateInfoIntersLineSurfBz( ptL, vtL, ILTA_NO_TRIA, -1, ptSP1, ptIBez1, dCos1, ptSP2, ptIBez2, dCos2, vInfo) ;
bFound = true ;
}
}
}
// se la superficie è trimmed verifico che i punti trovati siano all'interno del parametrico trimmato
if ( bTrimmed && bFound) {
int nNewTot = int(vInfo.size()) ;
int nNewInters = nNewTot - nInters ;
const ISurfFlatRegion* pFRTrim = pSurfBz->GetTrimRegion() ;
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)
vInfo.erase( vInfo.begin() + nNewTot - i) ;
}
}
return true ;
}
+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]) ;
}
}
+106 -21
View File
@@ -23,20 +23,20 @@ using namespace std ;
//----------------------------------------------------------------------------
static void
UpdateInfoIntersLineSurfTm( const Point3d& ptL, const Vector3d& vtDir, double dLen,
int nT, const Triangle3d& Tria, ILSIVECTOR& vInfo, bool bFinite)
int nStm, int nT, const Triangle3d& Tria, ILSIVECTOR& vInfo, bool bFinite)
{
Point3d ptInt, ptInt2 ;
int nRes = IntersLineTria( ptL, vtDir, dLen, Tria, ptInt, ptInt2, bFinite) ;
if ( nRes == ILTT_IN || nRes == ILTT_EDGE || nRes == ILTT_VERT) {
double dU = ( ptInt - ptL) * vtDir ;
double dCosDN = vtDir * Tria.GetN() ;
vInfo.emplace_back( nRes, dU, nT, dCosDN, ptInt) ;
vInfo.emplace_back( nRes, dU, nStm, nT, dCosDN, ptInt) ;
}
else if ( nRes == ILTT_SEGM || nRes == ILTT_SEGM_ON_EDGE) {
double dU = ( ptInt - ptL) * vtDir ;
double dU2 = ( ptInt2 - ptL) * vtDir ;
double dCosDN = vtDir * Tria.GetN() ;
vInfo.emplace_back( nRes, dU, dU2, nT, dCosDN, ptInt, ptInt2) ;
vInfo.emplace_back( nRes, dU, dU2, nStm, nT, dCosDN, ptInt, ptInt2) ;
}
}
@@ -48,7 +48,7 @@ OrderInfoIntersLineSurfTm( ILSIVECTOR& vInfo)
if ( vInfo.empty())
return ;
// ordino il vettore delle intersezioni secondo il senso crescente del parametro di linea
sort( vInfo.begin(), vInfo.end(),
sort( vInfo.begin(), vInfo.end(),
[]( const IntLinStmInfo& a, const IntLinStmInfo& b)
{ double dUa = ( ( a.nILTT == ILTT_SEGM || a.nILTT == ILTT_SEGM_ON_EDGE) ? ( a.dU + a.dU2) / 2 : a.dU) ;
double dUb = ( ( b.nILTT == ILTT_SEGM || b.nILTT == ILTT_SEGM_ON_EDGE) ? ( b.dU + b.dU2) / 2 : b.dU) ;
@@ -108,7 +108,7 @@ IntersLineSurfTm( const Point3d& ptL, const Vector3d& vtL, double dLen, const IS
Triangle3d Tria ;
Stm.GetTriangle( nT, Tria) ;
// aggiorno info con intersezione
UpdateInfoIntersLineSurfTm( ptL, vtDir, dLen, nT, Tria, vInfo, bFinite) ;
UpdateInfoIntersLineSurfTm( ptL, vtDir, dLen, 0, nT, Tria, vInfo, bFinite) ;
}
}
}
@@ -124,19 +124,23 @@ IntersLineSurfTm( const Point3d& ptL, const Vector3d& vtL, double dLen, const IS
// Intersezione di molte linee parallele con una superficie TriMesh
//----------------------------------------------------------------------------
IntersParLinesSurfTm::IntersParLinesSurfTm( const Frame3d& frLines, const ISurfTriMesh& Stm)
: m_bOk( false), m_frLines( frLines), m_pSTm( &Stm)
: m_bOk( false), m_frLines( frLines), m_vpSTm( {&Stm})
{
// verifico esistenza superficie
if ( m_pSTm == nullptr || ! m_pSTm->IsValid())
if ( m_vpSTm[0] == nullptr || ! m_vpSTm[0]->IsValid())
return ;
// creo HashGrid 2d
const int LIM_HG_TRIA = 127 ;
m_HGrids.SetActivationGrid( m_pSTm->GetTriangleCount() > LIM_HG_TRIA) ;
// aggiorno il vettore degli indici di base per mappare i triangoli con le rispettivi superfici
// ( in questo caso la superficie è unica, quindi ho solo due elementi)
m_vBaseInd = { 0, m_vpSTm[0]->GetTriangleCount()} ;
// riempio HashGrid
// creo HashGrid 2d ed eventualmente attivo la griglia
const int LIM_HG_TRIA = 127 ;
m_HGrids.SetActivationGrid( m_vBaseInd.back() > LIM_HG_TRIA) ;
// riempio HashGrid
Triangle3d Tria ;
int nT = Stm.GetFirstTriangle( Tria) ;
int nT = m_vpSTm[0]->GetFirstTriangle( Tria) ;
while ( nT != SVT_NULL) {
// calcolo il BBox del triangolo nel riferimento scelto
Tria.ToLoc( m_frLines) ;
@@ -145,10 +149,55 @@ IntersParLinesSurfTm::IntersParLinesSurfTm( const Frame3d& frLines, const ISurfT
b3Tria.Add( Tria.GetP( 1)) ;
b3Tria.Add( Tria.GetP( 2)) ;
// inserisco nella griglia
if ( ! m_HGrids.Add( nT, b3Tria))
if ( ! m_HGrids.Add( nT, b3Tria)) // ( 0 + nT, Tria)
return ;
// passo al prossimo triangolo
nT = Stm.GetNextTriangle( nT, Tria) ;
// passo al prossimo triangolo
nT = m_vpSTm[0]->GetNextTriangle( nT, Tria) ;
}
// aggiorno
m_bOk = m_HGrids.Update() ;
}
//----------------------------------------------------------------------------
// Intersezione di molte linee parallele con un vettore di superfici TriMesh
//----------------------------------------------------------------------------
IntersParLinesSurfTm::IntersParLinesSurfTm( const Frame3d& frLines, const CISURFTMPVECTOR& vStm)
: m_bOk( false), m_frLines( frLines), m_vpSTm( vStm), m_vBaseInd( {0})
{
// verifico esistenza superfici
if ( m_vpSTm.empty())
return ;
for ( const ISurfTriMesh* pStm : m_vpSTm) {
if ( pStm == nullptr || ! pStm->IsValid())
return ;
}
// aggiorno il vettore degli indici di base per mappare i triangoli con le rispettivi superfici
// NB. dal costruttore è già inizializzato a {0}
for ( int i = 0 ; i < int( m_vpSTm.size()) ; ++ i)
m_vBaseInd.emplace_back( m_vBaseInd.back() + m_vpSTm[i]->GetTriangleCount()) ;
// creo HashGrid 2d ed eventualmente attivo la griglia
const int LIM_HG_TRIA = 256 ;
m_HGrids.SetActivationGrid( m_vBaseInd.back() > LIM_HG_TRIA) ;
// riempio HashGrid
for ( int i = 0 ; i < int( m_vpSTm.size()) ; ++ i) {
Triangle3d Tria ;
int nT = m_vpSTm[i]->GetFirstTriangle( Tria) ;
while ( nT != SVT_NULL) {
// calcolo il BBox del triangolo nel riferimento scelto
Tria.ToLoc( m_frLines) ;
BBox3d b3Tria ;
b3Tria.Add( Tria.GetP( 0)) ;
b3Tria.Add( Tria.GetP( 1)) ;
b3Tria.Add( Tria.GetP( 2)) ;
// inserisco nella griglia ( aggiungo shift per indice del triangolo)
if ( ! m_HGrids.Add( m_vBaseInd[i] + nT, b3Tria))
return ;
// passo al prossimo triangolo
nT = m_vpSTm[i]->GetNextTriangle( nT, Tria) ;
}
}
// aggiorno
m_bOk = m_HGrids.Update() ;
@@ -162,7 +211,7 @@ IntersParLinesSurfTm::GetInters( const Point3d& ptL, double dLen, ILSIVECTOR& vI
if ( &vInfo == nullptr)
return false ;
vInfo.clear() ;
// verifico validità
// verifico validità
if ( ! m_bOk)
return false ;
@@ -174,15 +223,22 @@ IntersParLinesSurfTm::GetInters( const Point3d& ptL, double dLen, ILSIVECTOR& vI
Point3d ptLL = ptL ;
ptLL.ToGlob( m_frLines) ;
// recupero indici triangoli che intersecano box in 2d
// recupero indici triangoli che intersecano box in 2d
INTVECTOR vnIds ;
if ( m_HGrids.Find( b3Line, vnIds)) {
for ( int i = 0 ; i < int( vnIds.size()) ; ++ i) {
int nT = vnIds[i] ;
// recupero la superficie
int nInd = vnIds[i] ;
int nSurf = GetSurfInd( nInd) ;
if ( nSurf == -1)
return false ;
// recupero il triangolo
int nT = nInd - m_vBaseInd[nSurf] ;
Triangle3d Tria ;
m_pSTm->GetTriangle( nT, Tria) ;
if ( ! m_vpSTm[nSurf]->GetTriangle( nT, Tria))
return false ;
// aggiorno info con intersezione
UpdateInfoIntersLineSurfTm( ptLL, m_frLines.VersZ(), dLen, nT, Tria, vInfo, bFinite) ;
UpdateInfoIntersLineSurfTm( ptLL, m_frLines.VersZ(), dLen, nSurf, nT, Tria, vInfo, bFinite) ;
}
}
@@ -192,6 +248,35 @@ IntersParLinesSurfTm::GetInters( const Point3d& ptL, double dLen, ILSIVECTOR& vI
return true ;
}
//----------------------------------------------------------------------------
int
IntersParLinesSurfTm::GetSurfInd( int nT) const
{
// verifico la presenza di almeno un intervallo
if ( m_vBaseInd.size() < 2)
return -1 ;
// se la superficie è unica, allora non devo cercarla
if ( int( m_vBaseInd.size()) == 2)
return 0 ;
// ricerca binaria dell'intervallo contenente la posizione del triangolo
int nS = 0 ;
int nE = int( m_vBaseInd.size()) - 1 ;
while ( true) {
if ( nT < m_vBaseInd[nS] || nT >= m_vBaseInd[nE])
return -1 ;
if ( nE - nS == 1)
return nS ;
int nM = ( nS + nE) / 2 ;
if ( nT == m_vBaseInd[nM])
return nM ;
if ( nT < m_vBaseInd[nM])
nE = nM ;
else
nS = nM ;
}
return -1 ;
}
//----------------------------------------------------------------------------
bool
FilterLineSurfTmInters( const ILSIVECTOR& vInfo, INTDBLVECTOR& vInters)
@@ -217,7 +302,7 @@ FilterLineSurfTmInters( const ILSIVECTOR& vInfo, INTDBLVECTOR& vInters)
for ( size_t j = 1 ; j < vInters.size() ; ) {
// intersezione precedente
size_t i = j - 1 ;
// se hanno lo stesso parametro
// se hanno lo stesso parametro
if ( abs( vInters[i].second - vInters[j].second) < EPS_SMALL) {
// se sono entrambe entranti o uscenti, elimino la seconda
if ( ( vInters[i].first == LST_IN && vInters[j].first == LST_IN) ||
+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) ;
+258
View File
@@ -0,0 +1,258 @@
//----------------------------------------------------------------------------
// EgalTech 2025-2025
//----------------------------------------------------------------------------
// File : MultiGeomDB.cpp Data : 08.10.25 Versione : 2.7j1
// Contenuto : Implementazione delle funzioni tra due GeomDB.
//
//
//
// Modifiche : 08.10.25 DS Creazione modulo.
//
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "GeomDB.h"
#include "/EgtDev/Include/EGkMultiGeomDB.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
using namespace std ;
//----------------------------------------------------------------------------
static int
CopyGeoObj( const GeomDB* pSouGDB, int nSouId, GeomDB* pDstGDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob)
{
// recupero l'oggetto da copiare dal GeomDB sorgente
PtrOwner<IGeoObj> pGObj( pSouGDB->GetGeoObj( nSouId)->Clone()) ;
if ( IsNull( pGObj))
return GDB_ID_NULL ;
// se in globale
if ( bGlob) {
// recupero il riferimento del sorgente
Frame3d frSou ;
if ( ! pSouGDB->GetGlobFrame( nSouId, frSou))
return GDB_ID_NULL ;
// recupero il riferimento del gruppo destinazione
Frame3d frDest ;
int nDestParentId = ( IS_GDB_SON( nSonBeforeAfter) ? nRefId : pDstGDB->GetParentId( nRefId)) ;
if ( ! pDstGDB->GetGroupGlobFrame( nDestParentId, frDest))
return GDB_ID_NULL ;
// porto la copia da riferimento sorgente a quello destinazione
pGObj->LocToLoc( frSou, frDest) ;
}
// lo inserisco nel GeomDB destinazione
int nNewId = pDstGDB->InsertGeoObj( nDestId, nRefId, nSonBeforeAfter, Release( pGObj)) ;
if ( nNewId == GDB_ID_NULL)
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
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)) ;
// se in globale
if ( bGlob) {
// recupero il riferimento del gruppo in globale
if ( ! pSouGDB->GetGroupGlobFrame( nSouId, frFrame))
return GDB_ID_NULL ;
// recupero il riferimento del gruppo destinazione
Frame3d frDest ;
int nDestParentId = ( IS_GDB_SON( nSonBeforeAfter) ? nRefId : pDstGDB->GetParentId( nRefId)) ;
if ( ! pDstGDB->GetGroupGlobFrame( nDestParentId, frDest))
return GDB_ID_NULL ;
// porto la copia da riferimento sorgente a quello destinazione
frFrame.ToLoc( frDest) ;
}
// inserisco un nuovo gruppo nel GeomDB destinazione
int nNewId = pDstGDB->InsertGroup( nDestId, nRefId, nSonBeforeAfter, frFrame) ;
if ( nNewId == GDB_ID_NULL)
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) {
// 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 = 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) ;
// se copia non riuscita, esco con errore
if ( nSonNewId == GDB_ID_NULL)
return GDB_ID_NULL ;
// passo al figlio successivo
nSonSouId = pSouGDB->GetNext( nSonSouId) ;
}
return nNewId ;
}
//----------------------------------------------------------------------------
static int
Copy( IGeomDB* pSouGeomDB, int nSouId, IGeomDB* pDestGeomDB, int nDestId, int nRefId, int nSonBeforeAfter, bool bGlob)
{
// adatto e verifico i GeomDB
const GeomDB* pSouGDB = static_cast<GeomDB*>( pSouGeomDB) ;
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
int nSouType = pSouGDB->GetGdbType( nSouId) ;
// se l'oggetto da copiare è geometrico
if ( nSouType == GDB_TY_GEO) {
nNewId = CopyGeoObj( pSouGDB, nSouId, pDstGDB, nDestId, nRefId, nSonBeforeAfter, bGlob) ;
}
// se altrimenti è un gruppo
else if ( nSouType == GDB_TY_GROUP) {
nNewId = CopyGroupObj( pSouGDB, nSouId, pDstGDB, nDestId, nRefId, nSonBeforeAfter, bGlob) ;
}
return nNewId ;
}
//----------------------------------------------------------------------------
int
Copy( IGeomDB* pSouGeomDB, int nSouId, IGeomDB* pDestGeomDB, int nDestId, int nRefId, int nSonBeforeAfter)
{
return Copy( pSouGeomDB, nSouId, pDestGeomDB, nDestId, nRefId, nSonBeforeAfter, false) ;
}
//----------------------------------------------------------------------------
int
CopyGlob( IGeomDB* pSouGeomDB, int nSouId, IGeomDB* pDestGeomDB, int nDestId, int nRefId, int nSonBeforeAfter)
{
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 ;
} ;
+149 -25
View File
@@ -16,9 +16,17 @@
#include "CurveArc.h"
#include "CurveLine.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkIntervals.h"
#include "/EgtDev/Include/EGkIntersCurves.h"
#include "/EgtDev/Include/EGkChainCurves.h"
using namespace std ;
//----------------------------------------------------------------------------
static bool IsFillet( const ICurve* pCrv, double dDist) ;
static bool ModifyFillet( ICurve* pCrv, double dDist, int nType, ICurveComposite& ccAux) ;
static bool AdjustIntersections( ICRVCOMPOPVECTOR& CrvList) ;
//----------------------------------------------------------------------------
bool
IdentifyFillets( ICurveComposite* pCrvCo, double dDist)
@@ -52,36 +60,76 @@ IsFillet( const ICurve* pCrv, double dDist)
//----------------------------------------------------------------------------
bool
AdjustCurveFillets( ICurveComposite* pCrvCo, double dDist, int nType)
AdjustCurveFillets( ICURVEPOVECTOR& vOffset, double dDist, int nType)
{
ICURVEPLIST CrvLst ;
PtrOwner<ICurve> pCrv( pCrvCo->RemoveFirstOrLastCurve( false)) ;
while ( ! IsNull( pCrv)) {
// se identificato come fillet lo trasformo in smusso o estensione
if ( pCrv->GetTempParam() > EPS_SMALL) {
CurveComposite ccTemp ;
ModifyFillet( pCrv, dDist, nType, ccTemp) ;
// metto in lista le curve risultanti
if ( ccTemp.GetCurveCount() > 0) {
PtrOwner<ICurve> pCrv2( ccTemp.RemoveFirstOrLastCurve( false)) ;
while ( ! IsNull( pCrv2)) {
CrvLst.push_back( Release( pCrv2)) ;
pCrv2.Set( ccTemp.RemoveFirstOrLastCurve( false)) ;
}
if ( vOffset.empty())
return true ;
// suddivido le curve di offset individuando i fillet e isolandoli dagli altri tratti
ICRVCOMPOPVECTOR vCrvs ;
for ( int i = 0 ; i < int( vOffset.size()) ; i ++) {
CurveComposite* pCompo = GetBasicCurveComposite( vOffset[i]) ;
if ( pCompo == nullptr)
return false ;
bool bNewCrv = true ;
PtrOwner<ICurve> pCrv( pCompo->RemoveFirstOrLastCurve(false)) ;
while ( ! IsNull( pCrv)) {
if ( pCrv->GetTempParam() > EPS_SMALL) {
// se fillet calcolo il nuovo raccordo
CurveComposite* ccTemp = CreateBasicCurveComposite() ;
ModifyFillet( pCrv, dDist, nType, *ccTemp) ;
// assegno temp param per identificarlo nei conti successivi
ccTemp->SetTempParam( 1) ;
vCrvs.push_back( ccTemp) ;
bNewCrv = true ;
}
else {
// aggiungo la curva
if ( bNewCrv) {
bNewCrv = false ;
CurveComposite* pCompo = ConvertCurveToBasicComposite( Release( pCrv)) ;
if ( pCompo == nullptr)
return false ;
vCrvs.push_back( pCompo) ;
}
else
vCrvs.back()->AddCurve( Release( pCrv)) ;
}
// passo alla curva successiva
pCrv.Set( pCompo->RemoveFirstOrLastCurve( false)) ;
}
// altrimenti salvo in lista
else
CrvLst.push_back( Release( pCrv)) ;
// passo alla curva successiva
pCrv.Set( pCrvCo->RemoveFirstOrLastCurve( false)) ;
}
// rimetto le curve nella composita
for ( auto pCrv : CrvLst) {
pCrvCo->AddCurve( pCrv) ;
vOffset.clear() ;
// gestione delle intersezioni
if ( ! AdjustIntersections( vCrvs))
return false ;
// concateno i tratti ottenuti
ChainCurves ChainCrv ;
ChainCrv.Init( false, 2 * EPS_SMALL, vCrvs.size()) ;
for ( int i = 0 ; i < int( vCrvs.size()); ++ i) {
Point3d ptS, ptE ;
Vector3d vtS, vtE ;
vCrvs[i]->GetStartPoint( ptS) ;
vCrvs[i]->GetEndPoint( ptE) ;
vCrvs[i]->GetStartDir( vtS) ;
vCrvs[i]->GetEndDir( vtE) ;
ChainCrv.AddCurve( i + 1, ptS, vtS, ptE, vtE) ;
}
// recupero i concatenamenti
Point3d ptRef ; vCrvs[0]->GetStartPoint( ptRef) ;
INTVECTOR vIds ;
while ( ChainCrv.GetChainFromNear( ptRef, false, vIds)) {
PtrOwner<CurveComposite> pCompo( CreateBasicCurveComposite()) ;
if ( IsNull( pCompo))
return false ;
for ( auto i : vIds)
pCompo->AddCurve( vCrvs[i-1]) ;
pCompo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ;
pCompo->GetEndPoint( ptRef) ;
vOffset.emplace_back( Release( pCompo)) ;
}
// unisco tratti allineati
pCrvCo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ;
return true ;
}
@@ -175,3 +223,79 @@ ModifyFillet( ICurve* pCrv, double dDist, int nType, ICurveComposite& ccAux)
}
return false ;
}
//----------------------------------------------------------------------------
bool
AdjustIntersections( ICRVCOMPOPVECTOR& vCrvs)
{
// sistema le curve nel vettore vCrvs eliminando le parti coinvolte nelle intersezioni
vector<Intervals> vIntervals( vCrvs.size()) ;
INTVECTOR vFillets ;
for ( int i = 0 ; i < int( vCrvs.size()) ; i ++) {
// salvo i parametri della curva
double dParS, dParE ;
vCrvs[i]->GetDomain( dParS, dParE) ;
vIntervals[i].Set( dParS, dParE) ;
// verifico se raccordo
if ( vCrvs[i]->GetTempParam() > EPS_SMALL)
vFillets.emplace_back( i) ;
}
// verifico se i raccordi intersecano le altre curve
bool bInters = false ;
for ( int i = 0 ; i < int( vFillets.size()) ; i ++) {
int nIdx = vFillets[i] ;
for ( int j = 0 ; j < int( vCrvs.size()) ; j ++) {
if ( j == nIdx)
continue ;
IntersCurveCurve intCC( *vCrvs[nIdx], *vCrvs[j]) ;
int nCnt = intCC.GetIntersCount() ;
if ( nCnt > 1) {
// aggiorno gli intervalli della curva sottraendo la parte coinvolta dall'intersezione
for ( int k = 0 ; k < nCnt - 1 ; k = k+2) {
IntCrvCrvInfo iccInfo1, iccInfo2 ;
intCC.GetIntCrvCrvInfo( k, iccInfo1) ;
// verifico non sia intersezione nell'estremo iniziale o sovrapposizione
if ( iccInfo1.IciA[0].dU < EPS_SMALL || iccInfo1.bOverlap) {
k-- ;
continue ;
}
intCC.GetIntCrvCrvInfo( k+1, iccInfo2) ;
vIntervals[nIdx].Subtract( iccInfo1.IciA[0].dU, iccInfo2.IciA[0].dU) ;
vIntervals[j].Subtract( iccInfo1.IciB[0].dU, iccInfo2.IciB[0].dU) ;
bInters = true ;
}
}
}
}
if ( ! bInters)
return true ;
// aggiorno le curve eliminando i tratti coinvolti nelle intersezioni
for ( int i = 0 ; i < int( vIntervals.size()) ; i++) {
if ( vIntervals[i].GetCount() > 1) {
PtrOwner<CurveComposite> pCompo( CloneBasicCurveComposite( vCrvs[i])) ;
if ( IsNull( pCompo))
return false ;
double dParS, dParE ;
vIntervals[i].GetFirst( dParS, dParE) ;
vCrvs[i]->TrimStartEndAtParam( dParS, dParE) ;
while ( vIntervals[i].GetNext( dParS, dParE)) {
CurveComposite* pCrv = ConvertCurveToBasicComposite( pCompo->CopyParamRange( dParS, dParE)) ;
if ( pCrv == nullptr)
return false ;
vCrvs.emplace_back( pCrv) ;
}
}
else {
double dParS, dParE ;
vIntervals[i].GetFirst( dParS, dParE) ;
vCrvs[i]->TrimStartEndAtParam( dParS, dParE) ;
}
}
return true ;
}
+1 -3
View File
@@ -16,6 +16,4 @@
//----------------------------------------------------------------------------
bool IdentifyFillets( ICurveComposite* pCrvCo, double dDist) ;
bool IsFillet( const ICurve* pCrv, double dDist) ;
bool AdjustCurveFillets( ICurveComposite* pCrvCo, double dDist, int nType) ;
bool ModifyFillet( ICurve* pCrv, double dDist, int nType, ICurveComposite& ccAux) ;
bool AdjustCurveFillets( ICURVEPOVECTOR& vCrvs, double dDist, int nType) ;
+33 -25
View File
@@ -60,8 +60,8 @@ OffsetCurve::Reset( void)
}
}
m_CrvLst.clear() ;
m_pt = P_INVALID ;
m_vt = V_INVALID ;
m_ptOffs = P_INVALID ;
m_vtOut = V_INVALID ;
return true ;
}
@@ -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
@@ -674,12 +674,20 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType)
}
// nono passo : se con smusso o estensione, sostituisco i fillet con questi
// NB questa parte non è gestita in modo efficiente perchè dovrebbe essere sempre disabilitata.
// Le funzioni sono state ottimizzate per lavorare con voronoi
if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0) {
for ( auto iIter = m_CrvLst.begin() ; iIter != m_CrvLst.end() ; ++ iIter) {
CurveComposite* pCrvCo = GetBasicCurveComposite( *iIter) ;
IdentifyFillets( pCrvCo, dDist) ;
AdjustCurveFillets( pCrvCo, dDist, nType) ;
}
ICURVEPOVECTOR vCrvs ;
vCrvs.reserve( m_CrvLst.size()) ;
for ( auto pCrv : m_CrvLst) {
IdentifyFillets( GetCurveComposite( pCrv), dDist) ;
vCrvs.emplace_back( pCrv) ;
}
if ( ! AdjustCurveFillets( vCrvs, dDist, nType))
return false ;
m_CrvLst.clear() ;
for ( int j = 0 ; j < int( vCrvs.size()) ; j ++)
m_CrvLst.emplace_back( Release( vCrvs[j])) ;
}
}
@@ -714,8 +722,8 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType)
// ( e.g. alcune curve aperte) non se ne restiusce nessuno. Da estendere, se necessario, individuando i punti dal lato
// di offset richiesto
if ( vPntOffs.size() == 1) {
m_pt = vPntOffs[0].first ;
m_vt = vPntOffs[0].second ;
m_ptOffs = vPntOffs[0].first ;
m_vtOut = vPntOffs[0].second ;
}
}
}
@@ -747,20 +755,20 @@ OffsetCurve::Make( const ICurve* pCrv, double dDist, int nType)
pCrv->Scale( GLOB_FRM, 1 / dExtrOnN, 1, 1) ;
pCrv->ToGlob( frCopy) ;
}
if ( m_pt.IsValid()) {
m_pt.Scale( GLOB_FRM, 1 / dExtrOnN, 1, 1) ;
m_pt.ToGlob( frCopy) ;
m_vt.Scale( GLOB_FRM, 1 / dExtrOnN, 1, 1) ;
m_vt.ToGlob( frCopy) ;
if ( m_ptOffs.IsValid()) {
m_ptOffs.Scale( GLOB_FRM, 1 / dExtrOnN, 1, 1) ;
m_ptOffs.ToGlob( frCopy) ;
m_vtOut.Scale( GLOB_FRM, 1 / dExtrOnN, 1, 1) ;
m_vtOut.ToGlob( frCopy) ;
}
}
else if ( bNeedRef) {
for ( auto pCrv : m_CrvLst)
pCrv->ToGlob( frCopy) ;
if ( m_pt.IsValid()) {
m_pt.ToGlob( frCopy) ;
m_vt.ToGlob( frCopy) ;
if ( m_ptOffs.IsValid()) {
m_ptOffs.ToGlob( frCopy) ;
m_vtOut.ToGlob( frCopy) ;
}
}
@@ -841,14 +849,14 @@ OffsetCurve::GetShorterCurve( void)
//----------------------------------------------------------------------------
bool
OffsetCurve::GetPointOffset( Point3d& pt, Vector3d& vt)
OffsetCurve::GetPointOffset( Point3d& ptOffs, Vector3d& vtOut)
{
// verifico se valori validi da restituire
if ( ! m_pt.IsValid() || ! m_vt.IsValid())
if ( ! m_ptOffs.IsValid() || ! m_vtOut.IsValid())
return false ;
pt = m_pt ;
vt = m_vt ;
ptOffs = m_ptOffs ;
vtOut = m_vtOut ;
return true ;
}
+1
View File
@@ -14,6 +14,7 @@
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "PointsPCA.h"
#define EIGEN_NO_IO
#include "/EgtDev/Extern/Eigen/Dense"
+337 -14
View File
@@ -18,6 +18,8 @@
#include "PolygonPlane.h"
#include "PointsPCA.h"
#include "GeoConst.h"
#include "CurveComposite.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkPolyLine.h"
#include "/EgtDev/Include/EGkPlane3d.h"
#include "/EgtDev/Include/EGkDistPointLine.h"
@@ -773,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)
@@ -796,7 +798,7 @@ PolyLine::RemoveAlignedPoints( double dToler)
vInd.push_back( 0) ;
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, 0, int( vPtU.size()) - 1, vInd))
return false ;
vInd.push_back( vPtU.size() - 1) ;
vInd.push_back( int( vPtU.size()) - 1) ;
}
// altrimenti chiusa
else {
@@ -817,15 +819,15 @@ PolyLine::RemoveAlignedPoints( double dToler)
vInd.push_back( nMaxInd) ;
if ( ! DouglasPeuckerSimplification( vPtU, dSqTol, nMaxInd, int( vPtU.size()) - 1, vInd))
return false ;
vInd.push_back( vPtU.size() - 1) ;
vInd.push_back( int( vPtU.size()) - 1) ;
}
// 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) {
if ( DistPointLine( vPtU[vInd[0]].first, vPtU[vInd[1]].first, vPtU[vInd[vInd.size()-2]].first).IsEpsilon( dToler)) {
// 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() ;
}
@@ -1445,7 +1447,7 @@ IsPointInsidePolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler
}
// Determino tangente di riferimento
Vector3d vtTang ;
// se minima distanza nell'estremo iniziale del segmento
// se minima distanza nell'estremo iniziale del segmento
if ( AreSamePointApprox( ptMinDist, prev( itMinDistEnd)->first)) {
// direzione del segmento
Vector3d vtCurrTg = itMinDistEnd->first - prev( itMinDistEnd)->first ;
@@ -1461,7 +1463,7 @@ IsPointInsidePolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler
vtTang = vtPrevTg + vtCurrTg ;
vtTang.Normalize() ;
}
// se altrimenti minima distanza nell'estremo finale del segmento
// se altrimenti minima distanza nell'estremo finale del segmento
else if ( AreSamePointApprox( ptMinDist, itMinDistEnd->first)) {
// direzione del segmento
Vector3d vtCurrTg = itMinDistEnd->first - prev( itMinDistEnd)->first ;
@@ -1477,7 +1479,7 @@ IsPointInsidePolyLine( const Point3d& ptP, const PolyLine& plPoly, double dToler
vtTang = vtCurrTg + vtNextTg ;
vtTang.Normalize() ;
}
// altrimenti minima distanza con l'interno
// altrimenti minima distanza con l'interno
else {
vtTang = itMinDistEnd->first - prev( itMinDistEnd)->first ;
}
@@ -1529,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() ;
@@ -1612,8 +1618,9 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV
int nPnt2 = PL2.GetPointNbr() ;
if ( nPnt1 == 0 || nPnt2 == 0)
return false ;
bCommonInternalPoints = false ; // indica la presenza di punti interni in comune tra le due polylines
// indica la presenza di punti interni in comune tra le due polylines
bCommonInternalPoints = false ;
vPnt1.reserve( PL1.GetPointNbr()) ;
Point3d ptP1 ;
@@ -1657,7 +1664,7 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV
nMinJ = nLastJ ;
// verifica se è un punto interno in comune con l'altra polyline
if ( i < nTotP1 - 1 && dDist < EPS_SMALL && abs( dMinDistPar - floor( dMinDistPar + 0.5)) < EPS_SMALL)
if ( i < nTotP1 - 1 && dDist < EPS_SMALL && abs( dMinDistPar - floor( dMinDistPar + 0.5)) < EPS_SMALL)
bCommonInternalPoints = true ;
vPnt1[i].second = nMinJ ;
@@ -1687,12 +1694,328 @@ AssociatePolyLinesMinDistPoints( const PolyLine& PL1, const PolyLine& PL2, PNTIV
if ( nMinI < nLastI)
nMinI = nLastI ;
if ( j < nTotP2 - 1 && dDist < EPS_SMALL && abs( dMinDistPar - floor( dMinDistPar + 0.5)) < EPS_SMALL)
if ( j < nTotP2 - 1 && dDist < EPS_SMALL && abs( dMinDistPar - floor( dMinDistPar + 0.5)) < EPS_SMALL)
bCommonInternalPoints = true ;
vPnt2[j].second = nMinI ;
nLastI = nMinI ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
MatchPolyLinesAddingPoints( const PolyLine& PL1, const PolyLine& PL2, int nType, PNTIVECTOR& vPnt1, PNTIVECTOR& vPnt2)
{
// prima trovo le associazioni senza aggiunte di punti
Point3d ptP2 ;
CurveComposite cc1, cc2 ;
cc1.FromPolyLine( PL1) ;
cc2.FromPolyLine( PL2) ;
int nPnt1 = PL1.GetPointNbr() ;
int nPnt2 = PL2.GetPointNbr() ;
vector<POINTU> vMatch2 ;
PL2.GetFirstPoint( ptP2) ;
while ( PL2.GetNextPoint( ptP2, true)) {
DistPointCurve dpc( ptP2, cc1, false) ;
int nFlag = 0 ;
double dParam ; dpc.GetParamAtMinDistPoint( 0, dParam, nFlag) ;
Point3d ptJoint ; dpc.GetMinDistPoint( 0, ptJoint, nFlag) ;
vMatch2.emplace_back( ptJoint, dParam) ;
}
int nAtStart2 = 0 ; // match ripetuti dalla curva U0 allo start della curva U1
int nAtEnd2 = 0 ;
Point3d ptP1 ; PL1.GetFirstPoint( ptP1) ;
int c = 0 ;
int nRep1 = 0 ; // match interni consecutivi uguali di punti della curva U0 con punti della curva U1
int nRep2 = 0 ;
double dLastParamMatch = 0 ;
Point3d ptLastPointMatch = ptP1 ;
BOOLVECTOR vbRep1( nPnt1) ;
INTVECTOR vnAddedOrNextIsRep1 ; // 0 non Rep, 1 Rep, 2 Next is Rep ;
DBLVECTOR vdSplit1 ;
DBLVECTOR vdMatch1 ;
fill( vbRep1.begin(), vbRep1.end(), false) ;
while ( PL1.GetNextPoint( ptP1, true)) {
// devo salvarmi se matcho più punti con lo start o l'end della curva totale
DistPointCurve dpc( ptP1, cc2, false) ;
int nFlag = 0 ;
double dParam ; dpc.GetParamAtMinDistPoint( 0, dParam, nFlag) ;
Point3d ptJoint ; dpc.GetMinDistPoint( 0, ptJoint, nFlag) ;
vdMatch1.push_back( dParam) ;
if ( dParam < EPS_SMALL ) {
++nAtStart2 ;
vbRep1[c] = true ;
++c ;
continue ;
}
else if ( dParam > nPnt2 - EPS_SMALL ) {
vbRep1[c] = nAtEnd2 == 0 ? false : true ;
vbRep1.back() = true ;
++ nAtEnd2 ;
++c ;
continue ;
}
if ( dParam <= dLastParamMatch || AreSamePointApprox( ptJoint, ptLastPointMatch)) {
dParam = dLastParamMatch ;
vbRep1[c] = true ;
++ nRep1 ;
++c ;
continue ;
}
else {
dLastParamMatch = dParam ;
ptLastPointMatch = ptJoint ;
// se sono già troppo vicino ad un split esistente allora non faccio nulla
if ( abs(dParam - round( dParam)) < 100 * EPS_PARAM) {
++c ;
continue ;
}
vdSplit1.push_back( dParam) ;
// verifico se ho un match per questo punto
// in tal caso vuol dire che sto creando una ripetizione nRep1
int nCase = 0 ;
for ( int j = 0 ; j < int( vMatch2.size()) ; ++j) {
if ( abs(vMatch2[j].second - (c + 1)) < EPS_SMALL) {
// devo però verificare che non ci sia un match successivo, perché in quel caso non ho una ripetizione
bool bFoundMatch = false ;
for ( int z = int( vMatch2[j].second) ; z < int( vdMatch1.size()) ; ++z) {
if ( abs( vdMatch1[z] - ( j + 1 )) < EPS_SMALL ) {
bFoundMatch = true ;
break ;
}
}
if ( ! bFoundMatch) {
++ nRep2 ;
// capisco se il punto è rep o se lo è il suo successivo
if ( j + 1 < dParam)
nCase = 1 ;
else
nCase = 2 ;
}
break ;
}
}
vnAddedOrNextIsRep1.push_back( nCase) ;
}
++c ;
}
int nAtStart1 = 0 ;
int nAtEnd1 = 0 ;
PL2.GetFirstPoint( ptP2) ;
c = 0 ;
dLastParamMatch = 0 ;
ptLastPointMatch = ptP2 ;
INTVECTOR vnAddedOrNextIsRep2 ; // 0 non Rep, 1 Rep, 2 Next is Rep ;
DBLVECTOR vdSplit2 ;
BOOLVECTOR vbRep2( nPnt2) ;
fill( vbRep2.begin(), vbRep2.end(), false) ;
while ( PL2.GetNextPoint( ptP2, true)) {
DistPointCurve dpc( ptP2, cc1, false) ;
int nFlag = 0 ;
double dParam ; dpc.GetParamAtMinDistPoint( 0, dParam, nFlag) ;
Point3d ptJoint ; dpc.GetMinDistPoint( 0, ptJoint, nFlag) ;
if ( dParam < EPS_SMALL ) {
++nAtStart1 ;
vbRep2[c] = true ;
++c ;
continue ;
}
else if ( dParam > nPnt1 - EPS_SMALL ) {
vbRep2[c] = ( nAtEnd1 == 0 ? false : true) ;
vbRep2.back() = true ;
++ nAtEnd1 ;
++c ;
continue ;
}
if ( dParam <= dLastParamMatch || AreSamePointApprox( ptJoint, ptLastPointMatch)) {
dParam = dLastParamMatch ;
vbRep2[c] = true ;
++ nRep2 ;
++c ;
continue ;
}
else {
dLastParamMatch = dParam ;
ptLastPointMatch = ptJoint ;
// se sono troppo vicino ad uno split esistente allora non faccio nulla
if ( abs( dParam - round( dParam)) < 100 * EPS_PARAM) {
++c ;
continue ;
}
vdSplit2.push_back( dParam) ;
// verifico se ho un match per questo punto
// in tal caso vuol dire che sto creando una ripetizione nRep0
int nCase = 0 ;
for ( int j = 0 ; j < int( vdMatch1.size()) ; ++j) {
if ( abs( vdMatch1[j] - (c + 1)) < EPS_SMALL) {
// devo però verificare che non ci sia un match successivo, perché in quel caso non ho una ripetizione
bool bFoundMatch = false ;
for ( int z = int( vdMatch1[j]) ; z < int( vMatch2.size()) ; ++z) {
if ( abs( vMatch2[z].second - ( j + 1 )) < EPS_SMALL) {
bFoundMatch = true ;
break ;
}
}
if ( ! bFoundMatch) {
++nRep1 ;
// capisco se il punto è rep o se lo è il suo successivo
if ( j + 1 < dParam)
nCase = 1 ;
else
nCase = 2 ;
}
break ;
}
}
vnAddedOrNextIsRep2.push_back( nCase) ;
}
++c ;
}
// applico effettivamente gli split e aggiungo gli elementi ai vettori vbRep
int nUnit = 0 ;
if ( ! vdSplit1.empty())
nUnit = int( vdSplit1.back()) ;
for ( int z = int( vdSplit1.size()) - 1 ; z >= 0 ; --z) {
double dSplit = vdSplit1[z] ;
int nSplit = int( dSplit) ;
// se sto cercando di fare uno split sulla stessa curva che ho già splittato al passaggio precedente allora devo
// riscalare
if ( nSplit == nUnit && z < int( vdSplit1.size()) - 1) {
dSplit = nSplit + ( dSplit - nSplit) / ( vdSplit1[z+1] - nSplit) ;
}
nUnit = nSplit ;
cc2.AddJoint( dSplit) ;
switch ( vnAddedOrNextIsRep1[z]) {
case 0 :
if ( vbRep2[nSplit])
++ nRep2 ;
// di default aggiungerei false, ma se il successivo è già un Rep allora anche questo deve esserlo
vbRep2.insert( vbRep2.begin() + nSplit, vbRep2[nSplit]) ;
break ;
case 1 :
vbRep2.insert( vbRep2.begin() + nSplit, true) ;
break ;
case 2 :
if ( vbRep2[nSplit])
--nRep2 ;
else
vbRep2[nSplit] = true ;
vbRep2.insert( vbRep2.begin() + nSplit, false) ;
break ;
}
}
if ( ! vdSplit2.empty())
nUnit = int( vdSplit2.back()) ;
for ( int z = int( vdSplit2.size()) - 1 ; z >= 0 ; --z) {
double dSplit = vdSplit2[z] ;
int nSplit = int( dSplit) ;
// se sto cercando di fare uno split sulla stessa curva che ho già splittato al passaggio precedente allora devo
// riscalare
if ( nSplit == nUnit && z < int( vdSplit2.size()) - 1) {
dSplit = nSplit + ( dSplit - nSplit) / (vdSplit2[z+1] - nSplit) ;
}
nUnit = nSplit ;
cc1.AddJoint( dSplit) ;
switch ( vnAddedOrNextIsRep2[z]) {
case 0 :
if ( vbRep1[nSplit])
++ nRep1 ;
// di default aggiungerei false, ma se il successivo è già un Rep allora anche questo deve esserlo
vbRep1.insert( vbRep1.begin() + nSplit, vbRep1[nSplit]) ;
break ;
case 1 :
vbRep1.insert( vbRep1.begin() + nSplit, true) ;
break ;
case 2 :
if ( vbRep1[nSplit])
-- nRep1 ;
else
vbRep1[nSplit] = true ;
vbRep1.insert( vbRep1.begin() + nSplit, false) ;
break ;
}
}
nPnt1 = cc1.GetCurveCount() ;
nPnt2 = cc2.GetCurveCount() ;
//aggiusto i vettori delle ripetizioni in modo in modo che non arrivino mai ad essere contemporaneamente true
int nAddedSpan = 0 ;
int nCrv1 = 0 ;
int nCrv2 = 0 ;
while ( nAddedSpan < nPnt1 + nAtStart1 + nAtEnd1 + nRep2) {
if ( nCrv1 >= nPnt1)
nCrv1 = nPnt1 - 1 ;
if ( nCrv2 >= nPnt2)
nCrv2 = nPnt2 - 1 ;
bool bRep1 = vbRep1[nCrv1] ;
bool bRep2 = vbRep2[nCrv2] ;
if ( bRep1 && bRep2) {
vbRep1[nCrv1] = false ;
bRep1 = false ;
vbRep2[nCrv2] = false ;
bRep2 = false ;
-- nRep1 ;
-- nRep2 ;
}
if ( ! bRep1 || nCrv2 == nPnt2 - 1)
++ nCrv2 ;
if ( ! bRep2 || nCrv1 == nPnt1 - 1)
++ nCrv1 ;
++ nAddedSpan ;
}
// se non sono arrivato all'ultima curva su U0 o U1 vuol dire che ho creato delle ripetizioni che non ho contato prima
if ( nCrv2 < nPnt2) {
nRep2 += nPnt2 - nCrv2 ;
for ( int z = int( vbRep2.size()) - 1 ; z >= nCrv2 ; --z)
vbRep2[z] = true ;
}
if ( nCrv1 < nPnt1) {
nRep1 += nPnt1 - nCrv1 ;
for ( int z = int( vbRep1.size()) - 1 ; z >= nCrv1 ; --z)
vbRep1[z] = true ;
}
// trovo il numero di span che dovrà avere la superficie
// ( numero di sottocurve che compongono la U0 + tutte le ripetizioni dei match di punti della curva U1 con i punti di U0)
int nPnt = nPnt1 + nAtStart1 + nAtEnd1 + nRep2 ;
if ( nPnt != nPnt2 + nAtStart2 + nAtEnd2 + nRep1)
LOG_DBG_ERR( GetEGkLogger(), "There could be an error in the creation of a ruled surface in mode RLT_B_MINDIST_PLUS") ;
// aggiungo i punti di controllo scorrendo in contemporanea le due curve
nAddedSpan = 0 ;
nCrv1 = 0 ;
nCrv2 = 0 ;
bool bLast1 = false ;
bool bLast2 = false ;
while ( nAddedSpan < nPnt) {
if ( nCrv1 >= nPnt1) {
nCrv1 = nPnt1 - 1 ;
bLast1 = true ;
}
if ( nCrv2 >= nPnt2) {
nCrv2 = nPnt2 - 1 ;
bLast2 = true ;
}
bool bRep1 = vbRep1[nCrv1] ;
bool bRep2 = vbRep2[nCrv2] ;
const ICurve* pSubCrv1 = cc1.GetCurve( nCrv1) ;
Point3d ptStart1 ; pSubCrv1->GetStartPoint( ptStart1) ;
vPnt1.emplace_back( ptStart1, nAddedSpan) ;
const ICurve* pSubCrv2 = cc2.GetCurve( nCrv2) ;
Point3d ptStart2 ; pSubCrv2->GetStartPoint( ptStart2) ;
vPnt2.emplace_back( ptStart2, nAddedSpan) ;
if ( ! bRep2)
++ nCrv1 ;
if ( ! bRep1)
++ nCrv2 ;
++ nAddedSpan ;
}
return true ;
}
}
+7 -2
View File
@@ -150,12 +150,18 @@ PolygonElevationInClosedSurfTm( const Polygon3d& pgFacet, const ISurfTriMesh& Cl
Vector3d vtN = pgFacet.GetVersN() ;
PolyLine PL = pgFacet.GetPolyLine() ;
// calcolo elevazione massima del contorno della faccia
// calcolo elevazione massima del contorno della faccia e nel suo centro
const double RAY_LEN = 100000 ;
dElev = 0 ;
PNTVECTOR vptP ; vptP.reserve( PL.GetPointNbr()) ;
Point3d ptP ;
bool bFound = PL.GetFirstPoint( ptP) ;
while ( bFound) {
vptP.push_back( ptP) ;
bFound = PL.GetNextPoint( ptP, true) ;
}
vptP.push_back( ptCen) ;
for ( const Point3d& ptP : vptP) {
ILSIVECTOR vInters ;
IntersLineSurfTm( ptP, vtN, RAY_LEN, CldStm, vInters, true) ;
for ( int i = 0 ; i < int( vInters.size()) ; ++ i) {
@@ -171,7 +177,6 @@ PolygonElevationInClosedSurfTm( const Polygon3d& pgFacet, const ISurfTriMesh& Cl
else if ( Inters.nILTT == ILTT_SEGM || Inters.nILTT == ILTT_SEGM_ON_EDGE)
dElev = max( dElev, Inters.dU2) ;
}
bFound = PL.GetNextPoint( ptP, true) ;
}
// calcolo elevazione massima degli eventuali spigoli (e vertici) della superficie chiusa dalla parte positiva della faccia e che cadono in essa
int nEdgeCnt = CldStm.GetEdgeCount() ;
+5 -5
View File
@@ -19,10 +19,10 @@
void
PolygonPlane::AddPoint( const Point3d& ptP)
{
// se è il primo punto (parto da -1 perchè verrà contato alla chiusura)
// se è il primo punto (parto da -1 perchè verrà contato alla chiusura)
if ( m_nPntNbr == -1) {
// inizializzazioni
m_dLenN = 0 ;
m_dLenN = -1 ;
m_vtN = V_NULL ;
m_ptMid = ORIG ;
m_dSXy = 0 ; m_dSXz = 0 ;
@@ -60,16 +60,16 @@ PolygonPlane::AddPoint( const Point3d& ptP)
bool
PolygonPlane::Finalize( void)
{
// almeno 3 punti (il triangolo è il poligono con minimo numero di lati)
// almeno 3 punti (il triangolo è il poligono con minimo numero di lati)
if ( m_nPntNbr + 1 < 3)
return false ;
// se il poligono non è stato chiuso, aggiungo calcolo per ultimo lato
// se il poligono non è stato chiuso, aggiungo calcolo per ultimo lato
if ( ! AreSamePointExact( m_ptFirst, m_ptLast)) {
// aggiungo il primo punto per far eseguire i conti sul lato di chiusura
AddPoint( m_ptFirst) ;
}
// se non effettuato, eseguo il calcolo finale
if ( m_dLenN < EPS_SMALL) {
if ( m_dLenN < 0) {
// lunghezza della normale (doppio dell'area del poligono)
m_dLenN = m_vtN.Len() ;
if ( m_dLenN < SQ_EPS_SMALL)
+581 -412
View File
File diff suppressed because it is too large Load Diff
+91 -689
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -115,7 +115,8 @@ GetSurfFlatRegionDisk( double dRadius)
//-------------------------------------------------------------------------------
ISurfFlatRegion*
GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, bool bSquareMids, double dOffsLinTol)
GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, bool bSquareMids, double dOffsLinTol,
bool bMergeOnlySameProps)
{
// metodo di calcolo impostato da USE_VORONOI
@@ -330,7 +331,7 @@ GetSurfFlatRegionFromFatCurve( ICurve* pCrv, double dRadius, bool bSquareEnds, b
else {
// calcolo la fat curve con Voronoi
ICURVEPOVECTOR vFatCurves ;
if ( ! CalcCurveFatCurve( *pCurve, vFatCurves, dRadius, bSquareEnds, bSquareMids))
if ( ! CalcCurveFatCurve( *pCurve, vFatCurves, dRadius, bSquareEnds, bSquareMids, bMergeOnlySameProps))
return nullptr ;
// costruisco la superficie a partire dalle curve
+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
+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 ;
}
+13 -9
View File
@@ -37,12 +37,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 +66,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 +84,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 +136,7 @@ NurbsSurfaceCanonicalize( SNurbsSurfData& snData)
}
}
snData.bPeriodicV = false ;
snData.nCPV = int( snData.mCP[0].size()) ;
snData.nCPV = ssize( snData.mCP[0]) ;
}
return true ;
}
+1907 -739
View File
File diff suppressed because it is too large Load Diff
+52 -41
View File
@@ -20,11 +20,9 @@
#include "SurfTriMesh.h"
#include "SurfFlatRegion.h"
#include "/EgtDev/Include/EGkSurfBezier.h"
#include "/EgtDev/Include/EGkIntersLineTria.h"
#include "/EgtDev/Include/EGkGeoCollection.h"
using namespace std ;
class Tree ;
//----------------------------------------------------------------------------
class SurfBezier : public ISurfBezier, public IGeoObjRW
{
@@ -69,16 +67,15 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
public : // ISurf
bool IsSimple( void) const override
{ return true ; }
bool IsClosed( void) const override
{ return false ; }
bool IsClosed( void) const override ;
bool GetArea( double& dArea) const override ;
bool GetVolume( double& dVolume) const override
{ if ( &dVolume == nullptr)
return false ;
if( m_pSTM == nullptr)
if ( m_pSTM == nullptr)
GetAuxSurf() ;
dVolume = 0 ;
if( m_pSTM != nullptr)
if ( m_pSTM != nullptr)
m_pSTM->GetVolume( dVolume) ;
return true ; }
bool GetCentroid( Point3d& ptCen) const override ;
@@ -103,6 +100,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
{ return GetControlWeight( GetInd( nIndU, nIndV), pbOk) ; }
double GetControlWeight( int nInd, bool* pbOk) const override ;
bool IsAPoint( void) const override ;
bool GetPoint( double dU, double dV, Side nUs, Side nVs, Point3d& ptPos) const override ;
bool GetPointD1D2( double dU, double dV, Side nUs, Side nVs,
Point3d& ptPos,
Vector3d* pvtDerU = nullptr, Vector3d* pvtDerV = nullptr,
@@ -113,23 +111,23 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
Vector3d* pvtDerUU = nullptr, Vector3d* pvtDerVV = nullptr, Vector3d* pvtDerUV = nullptr) const override ;
CurveComposite* GetCurveOnU( double dV) const override ;
CurveComposite* GetCurveOnV( double dU) const override ;
CurveComposite* GetLoop( int nLoop) const override ; // nLoop 0-based (1°esterno, successivi interni)
CurveComposite* GetLoop( int nLoop) const override ; // nLoop 0-based (1°esterno, successivi interni)
bool GetControlCurveOnU( int nIndV, PolyLine& plCtrlU) const override ;
bool GetControlCurveOnV( int nIndU, PolyLine& plCtrlV) const override ;
const SurfTriMesh* GetAuxSurf( void) const override ;
SurfTriMesh* GetApproxSurf( double dTol, double dSideMin = 100 * EPS_SMALL) const override ;
const SurfTriMesh* GetAuxSurfRefined( void) const override ;
SurfTriMesh* GetApproxSurf( double dTol, double dSideMin = 100 * 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 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 ;
// pPlCut è il piano di taglio su cui giace la curva
// 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 = 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).
// bSaveOnEq indica se tenere i triangoli (della trimesh associata) che sono sul piano
@@ -138,8 +136,10 @@ 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 ;
@@ -148,6 +148,11 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
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 ICURVEPOVECTOR& vCrv, const ICURVEPOVECTOR& vNewCrv, const INTVECTOR& vShown ,const INTINTVECTOR& vNewOrEdited) ;
bool RemoveCollapsedSpans() override ;
bool SwapParameters() ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
@@ -159,7 +164,7 @@ class SurfBezier : public ISurfBezier, public IGeoObjRW
public :
SurfBezier( void) ;
SurfBezier( const SurfBezier& sbSrc)
SurfBezier( const SurfBezier& sbSrc) : m_pSTM( nullptr), m_pSTMRefined( nullptr), m_pTrimReg(nullptr)
{ if ( ! CopyFrom( sbSrc))
LOG_ERROR( GetEGkLogger(), "SurfBezier : copy constructor error") }
SurfBezier& operator =( const SurfBezier& sbSrc)
@@ -201,36 +206,42 @@ 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 ;
bool UpdateEdgesFromTree( Tree& tr) 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 ;
bool ReorderPntVector( const POLYLINEVECTOR& vPL, bool bTriangulatedIn3D, const PNTVECTOR& vPnt, const POLYLINEVECTOR& vPLToOrd, PNTVECTOR& vPntOrd) const ;
bool ReorderPntEnhancedVector( const POLYLINEVECTOR& vPL, bool bTriangulatedIn3D, const PNTVECTOR& vPnt, const POLYLINEVECTOR& vPLToOrd, PNTVECTOR& vPntOrd) const ;
bool GetBernstein( double dU, int nDegU, DBLVECTOR& vBernU) const ;
private :
ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto
mutable SurfTriMesh* m_pSTM ; // superficie trimesh ausiliaria
Status m_nStatus ; // stato
int m_nDegU ; // grado in U
int m_nDegV ; // grado in V
int m_nSpanU ; // numero di pezze in U
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 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
SurfFlatRegion* m_pTrimReg ; // eventuale regione di trim
int m_nTempProp[2] ; // vettore proprietà temporanee
double m_dTempParam[2] ; // vettore parametri temporanei
mutable vector<ICRVCOMPOPOVECTOR> m_mCCEdge ;// vettore dei vettori che contengono le curve compo degli edge della superficie nello spazio 3D
mutable ICRVCOMPOPOVECTOR m_vCCLoop ; // vettore dei loop della superficie trimmata
mutable int m_nIsPlanar ; // enum che indica se la superficie è piana ( -1, non è stato calcolato)
ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto
mutable SurfTriMesh* m_pSTM ; // superficie trimesh ausiliaria per la visualizzazione
mutable SurfTriMesh* m_pSTMRefined ; // superficie trimesh ausiliaria raffinata per i calcoli
Status m_nStatus ; // stato
int m_nDegU ; // grado in U
int m_nDegV ; // grado in V
int m_nSpanU ; // numero di pezze in U
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 ( 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
SurfFlatRegion* m_pTrimReg ; // eventuale regione di trim
int m_nTempProp[2] ; // vettore proprietà temporanee
double m_dTempParam[2] ; // vettore parametri temporanei
mutable std::vector<ICRVCOMPOPOVECTOR> m_mCCEdge ; // vettore dei vettori che contengono le curve compo degli edge della superficie nello spazio 3D
mutable ICRVCOMPOPOVECTOR m_vCCLoop ; // vettore dei loop della superficie trimmata
mutable int m_nIsPlanar ; // enum che indica se la superficie è piana ( -1, non è stato calcolato)
mutable DBLVECTOR m_vBernU ;
mutable PNTVECTOR m_ptTemp ;
mutable DBLVECTOR m_vBernV ;
mutable PNTVECTOR m_ptTempW ;
mutable DBLVECTOR m_dTempW ;
mutable PNTVECTOR m_vPtWCtrlLoc ;
mutable DBLVECTOR m_vWeCtrlLoc ;
} ;
//-----------------------------------------------------------------------------
+2 -1
View File
@@ -56,6 +56,7 @@ SurfFlatRegion::Clear( void)
for ( auto& pLoop : m_vpLoop)
delete pLoop ;
m_vpLoop.clear() ;
m_vExtInd.clear() ;
m_nTempProp[0] = 0 ;
m_nTempProp[1] = 0 ;
@@ -827,7 +828,7 @@ SurfFlatRegion::ConvertArcsToBezierCurves( void)
// ciclo sui loop
for ( auto& pLoop : m_vpLoop) {
if ( pLoop->GetType() == CRV_ARC) {
ICurve* pCrvNew = ArcToBezierCurve( pLoop) ;
ICurve* pCrvNew = ArcToBezierCurve( GetCurveArc(pLoop)) ;
if ( pCrvNew == nullptr)
return false ;
delete pLoop ;
+282 -45
View File
@@ -234,9 +234,13 @@ SurfTriMesh::AddTriangle( const int nIdVert[3], int nTFlag)
m_vPart.clear() ;
m_OGrMgr.Reset() ;
ResetHashGrids3d() ;
if ( ! vtN.Normalize( EPS_ZERO))
return SVT_DEL ;
// inserisco il triangolo
try { m_vTria.emplace_back( nIdVert, nTFlag) ;}
catch(...) { return SVT_NULL ;}
// aggiorno la sua normale
m_vTria.back().vtN = vtN ;
// aggiorno massimo TFlag
m_nMaxTFlag = max( m_nMaxTFlag, nTFlag) ;
// ne determino l'indice
@@ -513,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 ;
}
@@ -866,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 ;
@@ -883,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 ;
}
@@ -893,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
@@ -1220,16 +1251,17 @@ SurfTriMesh::GetSilhouette( const Plane3d& plPlane, double dTol, POLYLINEVECTOR&
// se rimasto qualcosa
if ( pgTria.GetSideCount() > 0) {
// lo proietto sul piano e creo la regione
pgTria.Scale( frOCS, 1, 1, 0) ;
PtrOwner<SurfFlatRegion> pSfrTria( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLine( pgTria.GetPolyLine()))) ;
if ( ! IsNull( pSfrTria)) {
if ( bAllTria && Tria.GetN() * vtVers < 0)
pSfrTria->Invert() ;
pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ;
if ( IsNull( pSfr))
pSfr.Set( pSfrTria) ;
else
pSfr->Add( *pSfrTria) ;
if ( pgTria.Scale( frOCS, 1, 1, 0)) {
PtrOwner<SurfFlatRegion> pSfrTria( GetBasicSurfFlatRegion( GetSurfFlatRegionFromPolyLine( pgTria.GetPolyLine()))) ;
if ( ! IsNull( pSfrTria)) {
if ( bAllTria && Tria.GetN() * vtVers < 0)
pSfrTria->Invert() ;
pSfrTria->Offset( dTol, ICurve::OFF_FILLET) ;
if ( IsNull( pSfr))
pSfr.Set( pSfrTria) ;
else
pSfr->Add( *pSfrTria) ;
}
}
}
}
@@ -1335,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) ;
@@ -1687,11 +1721,13 @@ SurfTriMesh::AdjustVertices( void)
//----------------------------------------------------------------------------
bool
SurfTriMesh::AdjustAdjacencies( void)
SurfTriMesh::AdjustAdjacencies( bool AdjustVert)
{
// sistemo le relazioni tra triangoli e vertici
if ( ! AdjustVertices())
return false ;
if ( AdjustVert) {
if ( ! AdjustVertices())
return false ;
}
// matrice di incidenza vertici-triangoli
INTMATRIX mVertTria( GetVertexSize()) ;
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
@@ -1874,7 +1910,7 @@ SurfTriMesh::TestSealing( void)
m_vTria[i].nIdAdjac[1] == SVT_NULL ||
m_vTria[i].nIdAdjac[2] == SVT_NULL) {
bClosed = false ;
break ;
break ;
}
}
}
@@ -1936,7 +1972,7 @@ SurfTriMesh::PackVertices( void)
++ nFirstFree ;
}
else
vVId.push_back( nId) ;
vVId.push_back( nId) ;
}
else {
if ( nFirstFree == SVT_NULL)
@@ -3043,7 +3079,7 @@ SurfTriMesh::AddBiTriangle( const int nIdVert[4])
//----------------------------------------------------------------------------
bool
SurfTriMesh::DoCompacting( double dTol)
{
{
// imposto ricalcolo
m_nStatus = ERR ;
m_OGrMgr.Reset() ;
@@ -3084,6 +3120,7 @@ SurfTriMesh::DoCompacting( double dTol)
int nVIdSize = int( vVId.size()) ;
// sistemo gli indici dei vertici nei triangoli
INTVECTOR vInvalidIds ;
for ( int nId = 0 ; nId < GetTriangleSize() ; ++ nId) {
// salto i triangoli cancellati
if ( m_vTria[nId].nIdVert[0] == SVT_DEL)
@@ -3100,15 +3137,51 @@ SurfTriMesh::DoCompacting( double dTol)
// aggiorno il triangolo
m_vTria[nId].nIdVert[0] = vVId[vOId[0]] ;
m_vTria[nId].nIdVert[1] = vVId[vOId[1]] ;
m_vTria[nId].nIdVert[2] = vVId[vOId[2]] ;
// se due vertici coincidono o la normale non è calcolabile, cancello il triangolo
if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[1] ||
m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[2] ||
m_vTria[nId].nIdVert[1] == m_vTria[nId].nIdVert[2] ||
! CalcTriangleNormal( nId))
RemoveTriangle( nId) ;
m_vTria[nId].nIdVert[2] = vVId[vOId[2]] ;
// verifico se triangolo da rimuovere per vertici coincidenti
bool bRemove = false ;
int nTAdj1 = SVT_NULL, nTAdj2 = SVT_NULL ;
if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[1]) {
nTAdj1 = m_vTria[nId].nIdAdjac[1] ;
nTAdj2 = m_vTria[nId].nIdAdjac[2] ;
bRemove = true ;
}
else if ( m_vTria[nId].nIdVert[0] == m_vTria[nId].nIdVert[2]) {
nTAdj1 = m_vTria[nId].nIdAdjac[0] ;
nTAdj2 = m_vTria[nId].nIdAdjac[1] ;
bRemove = true ;
}
else if ( m_vTria[nId].nIdVert[1] == m_vTria[nId].nIdVert[2]) {
nTAdj1 = m_vTria[nId].nIdAdjac[0] ;
nTAdj2 = m_vTria[nId].nIdAdjac[2] ;
bRemove = true ;
}
if ( bRemove) {
// sistemo le contro adiacenze
if ( nTAdj1 != SVT_NULL) {
for ( int j = 0 ; j < 3 ; ++ j)
if ( m_vTria[nTAdj1].nIdAdjac[j] == nId)
m_vTria[nTAdj1].nIdAdjac[j] = nTAdj2 ;
}
if ( nTAdj2 != SVT_NULL) {
for ( int j = 0 ; j < 3 ; ++ j)
if ( m_vTria[nTAdj2].nIdAdjac[j] == nId)
m_vTria[nTAdj2].nIdAdjac[j] = nTAdj1 ;
}
// rimuovo il triangolo
RemoveTriangle( nId) ;
}
// verifico se il triangolo va rimosso per normale non calcolabile
else if ( ! CalcTriangleNormal( nId))
vInvalidIds.emplace_back( nId) ;
}
// elimino triangoli invalidi ( con gestione speciale per evitare T-junctions)
if ( ! vInvalidIds.empty())
RemoveInvalidTriangles( vInvalidIds) ;
// compatto il vettore dei vertici
if ( ! PackVertices())
return false ;
@@ -3345,22 +3418,23 @@ SurfTriMesh::Scale( const Frame3d& frRef, double dCoeffX, double dCoeffY, double
bMirror = ( bMirror ? ( dCoeffY > 0) : ( dCoeffY < 0)) ;
bMirror = ( bMirror ? ( dCoeffZ > 0) : ( dCoeffZ < 0)) ;
// aggiorno le facce
for ( int i = 0 ; i < GetTriangleSize() ; ++ i) {
if ( m_vTria[i].nIdVert[0] != SVT_DEL) {
// se c'è mirror, devo invertire la faccia
if ( bMirror)
InvertTriangle( i) ;
// aggiorno la normale
if ( ! CalcTriangleNormal( i)) {
// elimino il triangolo
RemoveTriangle( i) ;
}
}
// se c'è mirror, devo invertire le facce
if ( bMirror) {
for ( int i = 0 ; i < GetTriangleSize() ; ++ i)
if ( m_vTria[i].nIdVert[0] != SVT_DEL)
InvertTriangle( i) ;
}
// rimuovo i triangoli resi invalidi dalla scalatura
bool bOk = DoCompacting() ;
return DoCompacting() ;
// rimuovo i triangoli doppi
bool bModified = false ;
bOk = bOk && RemoveDoubleTriangles( bModified) ;
if ( bModified)
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
return bOk ;
}
//----------------------------------------------------------------------------
@@ -3592,6 +3666,18 @@ SurfTriMesh::Invert( void)
for ( int i = 0 ; i < GetTriangleSize() ; ++ i)
InvertTriangle( i) ;
// se bordi della sfaccettatura validi
if ( m_bFacEdged) {
for ( int nE = 0 ; nE < GetEdgeCount() ; ++ nE) {
// inversione dei vertici nel vettore delle sfaccettature
swap( m_vFacEdge[nE].nIdVert[0], m_vFacEdge[nE].nIdVert[1]) ;
// inversione delle adiacenze nel vettore delle sfaccettature
swap( m_vFacEdge[nE].nIdFacAdj[0], m_vFacEdge[nE].nIdFacAdj[1]) ;
// inversione dell'angolo interno
m_vFacEdge[nE].dIntAng *= -1. ;
}
}
return true ;
}
@@ -3984,6 +4070,56 @@ SurfTriMesh::CloneShell( int nShell) const
return Release( pSurfTM) ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetPartLocalBBox( int nP, BBox3d& b3Loc) const
{
// verifico esistenza della parte
if ( nP < 0 || nP >= GetPartCount())
return false ;
// assegno il box in locale
b3Loc.Reset() ;
for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) {
// recupero il vettore delle Shell della parte corrente
const auto& vShell = m_vPart[nP].vShell ;
// scorro i triangoli validi contenuti nella Shell
if ( m_vTria[i].nIdVert[0] != SVT_DEL &&
find( vShell.begin(), vShell.end(), m_vTria[i].nShell) != vShell.end()) {
// ciclo sui tre vertici
for ( int j = 0 ; j < 3 ; ++ j)
b3Loc.Add( m_vVert[m_vTria[i].nIdVert[j]].ptP) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::GetPartBBox( int nP, const Frame3d& frRef, BBox3d& b3Ref) const
{
// verifico esistenza della parte
if ( nP < 0 || nP >= GetPartCount())
return false ;
// assegno il box in locale
b3Ref.Reset() ;
for ( int i = 0 ; i < int( m_vTria.size()) ; ++ i) {
// recupero il vettore delle Shell della parte corrente
const auto& vShell = m_vPart[nP].vShell ;
// scorro i triangoli validi contenuti nella Shell
if ( m_vTria[i].nIdVert[0] != SVT_DEL &&
find( vShell.begin(), vShell.end(), m_vTria[i].nShell) != vShell.end()) {
// ciclo sui tre vertici
for ( int j = 0 ; j < 3 ; ++ j)
b3Ref.Add( GetToGlob( m_vVert[m_vTria[i].nIdVert[j]].ptP, frRef)) ;
}
}
return true ;
}
//----------------------------------------------------------------------------
int
SurfTriMesh::GetPartCount( void) const
@@ -4322,3 +4458,104 @@ SurfTriMesh::SetTempInt( int nId, int nTempInt) const
m_vTria[nId].nTemp = nTempInt ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::AddTriaFromZMap( const TRIA3DEXVECTOR& vTria, PointGrid3d& VertGrid, double dVertexTol)
{
// scorro i triangoli
for ( const Triangle3dEx& Tria : vTria) {
// ciclo sui tre vertici
int nIdV[3]{} ;
for ( int nV = 0 ; nV < 3 ; ++ nV) {
// verifico se vertice già presente
int nId ;
if ( ! VertGrid.Find( Tria.GetP( nV), dVertexTol, nId)) {
// se non presente, lo aggiugo
nIdV[nV] = AddVertex( Tria.GetP( nV)) ;
if ( nIdV[nV] == SVT_NULL)
return false ;
VertGrid.InsertPoint( Tria.GetP( nV), nIdV[nV]) ;
}
else
nIdV[nV] = nId ;
}
// se i vertici sono tutti diversi tra loro, inserisco il triangolo
if ( nIdV[0] != nIdV[1] && nIdV[0] != nIdV[2] && nIdV[1] != nIdV[2]) {
int nT = AddTriangle( nIdV, Tria.GetGrade()) ;
if ( nT != SVT_NULL && nT != SVT_DEL) {
// associo relazione vertice-triangolo
for ( int i = 0 ; i < 3 ; ++ i)
m_vVert[nIdV[i]].nIdTria = nT ;
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::AdjustTopologyFromZMap( void)
{
// cancello tutti i vertici che puntano a triangoli cancellati
bool bPack = false ;
for ( int i = 0 ; i < GetVertexSize() ; ++ i) {
if ( m_vVert[i].nIdTria == SVT_NULL) {
m_vVert[i].nIdTria = SVT_DEL ;
bPack = true ;
}
}
if ( bPack)
PackVertices() ;
m_nStatus = SurfTriMesh::OK ;
// calcolo le adiacenze
if ( ! AdjustAdjacencies())
return false ;
// verifico l'orientamento ( TODO -- Da migliorare...)
// Ora per funzionare è necessario che il ciclo sui triangoli parta da un triangolo orientato
// correttamente e che i triangoli invertiti siano "circondati" da triangoli tutti orientati correttamente
if ( ! AdjustOrientations())
return false ;
// calcolo le facce
if ( ! VerifyFaceting())
return false ;
// rimozione delle TJunction
bool bModified = false ;
if ( ! RemoveTJunctions( bModified, SQ_EPS_SMALL))
return false ;
if ( bModified) {
if ( ! AdjustVertices() || ! DoCompacting())
return false ;
}
else
TestSealing() ;
// semplifico le facce ( anche più piccola)
if ( ! SimplifyFacets( MAX_EDGE_LEN_STD, false, 5. * EPS_SMALL))
LOG_ERROR( GetEGkLogger(), "Error in SimplifyFacets of Stm::AdjustTopologyFromZMap")
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 ;
}
+23 -5
View File
@@ -18,6 +18,7 @@
#include "GeoObjRW.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include "/EgtDev/Include/EGkHashGrids3d.h"
#include "/EgtDev/Include/EGkPointGrid3d.h"
#include <deque>
#include <set>
@@ -321,13 +322,15 @@ 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 ;
bool Intersect( const ISurfTriMesh& Other) override ;
bool Subtract( const ISurfTriMesh& Other) override ;
bool GetSurfClassification( const ISurfTriMesh& ClassifierSurf,
INTVECTOR& vTriaIn, INTVECTOR& vTriaOut, INTVECTOR& vTriaOnP, INTVECTOR& vTriaOnM, INTVECTOR& vTriaIndef) override ;
INTVECTOR& vTriaIn, INTVECTOR& vTriaOut, INTVECTOR& vTriaOnP, INTVECTOR& vTriaOnM, INTVECTOR& vTriaIndef) override ;
bool CutWithOtherSurf( const ISurfTriMesh& CutterSurf, bool bInVsOut, bool bSaveOnEq) override ;
bool Repair( double dMaxEdgeLen = MAX_EDGE_LEN_STD) override ;
bool GetAllTriaOverlapBox( const BBox3d& b3Box, INTVECTOR& vT) const override ;
@@ -336,6 +339,8 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool GetShellArea( int nShell, double& dArea) const override ;
bool RemoveShell( int nShell) override ;
SurfTriMesh* CloneShell( int nShell) const override ;
bool GetPartLocalBBox( int nP, BBox3d& b3Loc) const override ;
bool GetPartBBox( int nP, const Frame3d& frRef, BBox3d& b3Ref) const override ;
int GetPartCount( void) const override ;
bool RemovePart( int nPart) override ;
bool GetPartArea( int nPart, double& dArea) const override ;
@@ -373,6 +378,9 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool GetTempInt( int nId, int& nTempInt) const ;
bool ResetTempInts( void) const ;
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 ;
@@ -388,7 +396,7 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool CopyFrom( const SurfTriMesh& clSrc) ;
bool Validate( bool bCorrect = false) ;
bool AdjustVertices( void) ;
bool AdjustAdjacencies( void) ;
bool AdjustAdjacencies( bool AdjustVert = true) ;
bool AdjustOrientations( void) ;
bool AdjustTriaOrientation( TRINTDEQUE& S3iQ) ;
bool TestSealing( void) ;
@@ -406,6 +414,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 ;
@@ -433,14 +442,16 @@ class SurfTriMesh : public ISurfTriMesh, public IGeoObjRW
bool IntersectTriMeshTriangle( SurfTriMesh& Other) ;
bool IdentifyShells( void) const ;
bool RemoveDoubleTriangles( bool& bModified) ;
bool RemoveTJunctions( bool& bModified) ;
bool RemoveTJunctions( bool& bModified, double dMinSqDist = SQ_EPS_TRIA_H) ;
bool FlipTriangles( int nTA, int nTB) ;
bool SimplifyFacets( double dMaxEdgeLen = MAX_EDGE_LEN_STD, bool bForced = true) ;
bool SimplifyFacets( double dMaxEdgeLen = MAX_EDGE_LEN_STD, bool bForced = true, double dTolAlign = 50 * EPS_SMALL) ;
bool AddChainToChain( const Chain& ChainToAdd, PNTVECTOR& OrigChain) ;
bool DistPointFacet( const Point3d& ptP, const POLYLINEVECTOR& vPolyVec, double& dPointFacetDist) ;
bool ChangeStart( const Point3d& ptNewStart, PNTVECTOR& Loop) ;
bool SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECTOR& Loop1, PNTVECTOR& Loop2) ;
bool AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, double dTolAlign, bool& bModif) const ;
bool RemoveInvalidTriangles( const INTVECTOR& vIds) ;
bool FindAdjacentOnLongerEdge( int nT, int& nEdge, int& nAdjTrg) const ;
private :
ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto
Status m_nStatus ; // stato
@@ -483,3 +494,10 @@ inline SurfTriMesh* GetBasicSurfTriMesh( IGeoObj* pGObj)
{ if ( pGObj == nullptr || pGObj->GetType() != SRF_TRIMESH)
return nullptr ;
return ( static_cast<SurfTriMesh*>( pGObj)) ; }
//----------------------------------------------------------------------------
// Raccolte di puntatori a SurfTriMesh
typedef std::vector<const SurfTriMesh*> CISRFTMPVECTOR ; // vettore di puntatori a const SurfTriMesh
typedef std::vector<SurfTriMesh*> ISRFTMPVECTOR ; // vettore di puntatori a SurfTriMesh
typedef std::list<SurfTriMesh*> ISRFTMPLIST ; // lista di puntatori a SurfTriMesh
typedef std::vector<PtrOwner<SurfTriMesh>> ISRFTMPOVECTOR ; // vettore di puntatori esclusivi a SurfTriMesh
+43 -84
View File
@@ -41,7 +41,7 @@
using namespace std ;
//----------------------------------------------------------------------------
const double BOOLEAN_SCALE = 1024 ;
const double BOOLEAN_SCALE = PREC_SCALE_COEFF ;
//----------------------------------------------------------------------------
bool
@@ -502,9 +502,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
}
}
}
// -------------------------------------------------------------------------------------------
// Creo il loop chiuso padre di tutti, il perimetro del triangolo. Questo viene diviso in sotto-loop
// chiusi mediante quelli aperti. I loop chiusi trovati precedentemente sono interni a uno dei
// sotto-loop chiusi di cui è formato il perimetro.
@@ -704,16 +702,18 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
}
}
}
// Elimino loop interni non validi
bool bDouble = true ;
// Verifico se i loop interni sono validi
bool bAllInvalid = true ;
for ( int nInnLoop = 0 ; nInnLoop < int( vInnerLoop.size()) ; ++ nInnLoop) {
if ( cvClosedChain[vInnerLoop[nInnLoop]].size() > 2) {
bDouble = false ;
// se chain formata da tre segmenti significa che si tratta di due linee sovrapposte ( il terzo tratto è quello aggiunto
// per forzare la chiusura)
if ( cvClosedChain[vInnerLoop[nInnLoop]].size() > 3) {
bAllInvalid = false ;
break ;
}
}
if ( vInnerLoop.empty() || bDouble) {
if ( vInnerLoop.empty() || bAllInvalid) {
// Eseguo triangolazione
PNTVECTOR vPt ;
INTVECTOR vTr ;
@@ -753,63 +753,20 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
vPolygons.emplace_back( CurLoop) ;
}
// poligono
Polygon3d pgPol ;
pgPol.FromPolyLine( vPolygons[1]) ;
// controllo direzioni delle normali
bool bCodirectedNormals = trTria.GetN() * pgPol.GetVersN() > 0. ;
// Aggiungo al loop esterno i punti dei loop interni che si trovano su di esso
PNTULIST& ExternLoopList = vPolygons[0].GetUPointList() ;
// Ciclo sui segmenti del loop esterno
auto itSt = ExternLoopList.begin() ;
auto itEn = itSt ;
++ itEn ;
for ( ; itSt != ExternLoopList.end() && itEn != ExternLoopList.end() ; ++ itSt, ++ itEn) {
// Estremi del segmento corrente del loop esterno e scorrispondente vettore
Point3d ptSt = itSt->first ;
Point3d ptEn = itEn->first ;
Vector3d vtSeg = ptEn - ptSt ;
double dSegLen = vtSeg.Len() ;
vtSeg /= dSegLen ;
// Vettore dei punti dei loop interni che stanno sul segmento del loop esterno
PNTUVECTOR vPointWithOrder ;
// Ciclo sui loop interni
for ( int nInnPoly = 1 ; nInnPoly < int( vPolygons.size()) ; ++ nInnPoly) {
// Ciclo sui punti dei loop interni
Point3d ptInnPoint ;
bool bIsFirst = true ;
bool bContinue = vPolygons[nInnPoly].GetFirstPoint( ptInnPoint) ;
while ( bContinue) {
DistPointLine DistCalculator( ptInnPoint, ptSt, ptEn) ;
double dDist ;
DistCalculator.GetDist( dDist) ;
double dLongPos = ( ptInnPoint - ptSt) * vtSeg ;
if ( dDist < EPS_SMALL && dLongPos > 0. && dLongPos < dSegLen) {
POINTU NewPointU ;
NewPointU.first = ptInnPoint ;
NewPointU.second = dLongPos ;
if ( ! bIsFirst)
vPointWithOrder.emplace_back( NewPointU) ;
}
bIsFirst = false ;
bContinue = vPolygons[nInnPoly].GetNextPoint( ptInnPoint) ;
}
}
// Riordino i punti interni sul segmento esterno in funzione della distanza dall'origine di esso
for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) - 1 ; ++ nPi) {
for ( int nPj = nPi + 1 ; nPj < int( vPointWithOrder.size()) ; ++ nPj) {
if ( vPointWithOrder[nPi].second > vPointWithOrder[nPj].second) {
swap( vPointWithOrder[nPi], vPointWithOrder[nPj]) ;
}
}
}
// Aggiungo i punti al loop esterno
for ( int nPi = 0 ; nPi < int( vPointWithOrder.size()) ; ++ nPi) {
itSt = ExternLoopList.emplace( itEn, vPointWithOrder[nPi]) ;
}
// controllo la direzione della normale del triangolo con quella del poligono di area maggiore
// ( per gestire eventuali inscatolamenti)
Vector3d vtPoly = V_NULL ;
double dMaxArea = -1 ;
for ( int i = 1 ; i < int( vPolygons.size()) ; i ++) {
Plane3d plPoly ;
double dAreaPoly ;
vPolygons[i].IsClosedAndFlat( plPoly, dAreaPoly) ;
if ( dAreaPoly > dMaxArea) {
vtPoly = plPoly.GetVersN() ;
dMaxArea = dAreaPoly ;
}
}
bool bCodirectedNormals = trTria.GetN() * vtPoly > 0. ;
PNTVECTOR vPt ;
INTVECTOR vTr ;
@@ -836,6 +793,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
}
// Divido i loop che si autointercettano
// TO DO : da verificare. Questa porzione di codice non dovrebbe andare prima della triangolazione?
int nInitialLoopNum = int( vPolygons.size()) ;
for ( int nL = 1 ; nL < nInitialLoopNum ; ++ nL) {
// Lista dei punti della PolyLine Loop corrente
@@ -883,11 +841,11 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
itSt2 = LoopPointList.emplace( itEn2, vAddingPointWithOrder[nPi]) ;
}
}
// Spezzo i loop autointersecantesi
POLYLINEVECTOR vAuxPolygons ;
vAuxPolygons.emplace_back( vPolygons[nL]) ;
bool bSplitted = true ;
while ( bSplitted) {
bSplitted = false ;
@@ -956,16 +914,13 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
vPolygons.erase( vPolygons.begin() + i) ;
else
++ i ;
}
bool bCordirectedNormals_intLoop = bCodirectedNormals ;
// eventuale inversione della prima curva ( che determina il verso della triangolazione) per averla orientata
// come il triangolo
if ( ! vPolygons.empty()) {
Polygon3d pgPol ;
pgPol.FromPolyLine( vPolygons[0]) ;
// controllo direzioni delle normali
bCordirectedNormals_intLoop = trTria.GetN() * pgPol.GetVersN() > 0. ;
if ( ! bCordirectedNormals_intLoop)
if ( trTria.GetN() * pgPol.GetVersN() < 0.)
vPolygons[0].Invert() ;
}
@@ -981,7 +936,7 @@ SurfTriMesh::RetriangulationForBooleanOperation( CHAINMAP& LoopLines, TRIA3DVECT
Surf.m_vTria[nNewTriaNum].nETempFlag[0] = 0 ;
Surf.m_vTria[nNewTriaNum].nETempFlag[1] = 0 ;
Surf.m_vTria[nNewTriaNum].nETempFlag[2] = 0 ;
if ( bCordirectedNormals_intLoop)
if ( bCodirectedNormals)
Surf.m_vTria[nNewTriaNum].nTempShell = 1 ;
else
Surf.m_vTria[nNewTriaNum].nTempShell = -1 ;
@@ -1123,7 +1078,7 @@ SurfTriMesh::AmbiguosTriangleManager( TRIA3DVECTORMAP& Ambiguos, SurfTriMesh& Su
//----------------------------------------------------------------------------
bool
SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
{
{
bool bModif = false ;
SurfTriMesh& SurfB = Other ;
@@ -1176,7 +1131,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
INTVECTOR vNearTria ;
SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ;
// I scorro tutti i triangoli di B che intersecano il box di A
// Scorro tutti i triangoli di B che intersecano il box di A
for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) {
// Se il triangolo B non è valido, continuo
@@ -1365,7 +1320,7 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
// Triangoli sovrapposti
if ( bContinue) {
int nTriaNum2A = GetTriangleSize() ;
// Resetto e ricalcolo la HashGrid della superficie B
// Resetto e ricalcolo la HashGrid della superficie B
SurfB.ResetHashGrids3d() ;
for ( int nTA = 0 ; nTA < nTriaNum2A ; ++ nTA) {
// Se il triangolo A non è valido, continuo
@@ -1375,15 +1330,19 @@ SurfTriMesh::IntersectTriMeshTriangle( SurfTriMesh& Other)
// Box del triangolo A
BBox3d b3dTriaA ;
trTriaA.GetLocalBBox( b3dTriaA) ;
// Recupero i triangoli di B che interferiscono col box del triangolo di A
// Recupero i triangoli di B che interferiscono col box del triangolo di A
INTVECTOR vNearTria ;
SurfB.GetAllTriaOverlapBox( b3dTriaA, vNearTria) ;
for ( int nTB = 0 ; nTB < int( vNearTria.size()) ; ++ nTB) {
// Se il triangolo B non è valido, continuo
// Se il triangolo B non è valido, continuo
Triangle3d trTriaB ;
if ( ! SurfB.GetTriangle( vNearTria[nTB], trTriaB) || ! trTriaB.Validate( true))
continue ;
// Se i triangoli sono sovrapposti
// Se sono già stati classificati entrambi come sovrapposti continuo
if ( abs( m_vTria[nTA].nTempShell) == 2 && abs( SurfB.m_vTria[vNearTria[nTB]].nTempShell) == 2)
continue ;
// Se i triangoli sono sovrapposti
TRIA3DVECTOR vTriaAB ;
Point3d ptTempA, ptTempB ;
int nIntTypeAB = IntersTriaTria( trTriaA, trTriaB, ptTempA, ptTempB, vTriaAB) ;
@@ -1475,7 +1434,7 @@ SurfTriMesh::Add( const ISurfTriMesh& Other)
// tengo una copia di B ( la superficie B viene modificata durante la ritriangolazione )
SurfTriMesh SurfA_cl ;
SurfA_cl.CopyFrom( this) ;
// ritriangolo le due superfici mediante ogni intersezione Triangolo-Triangolo
IntersectTriMeshTriangle( SurfB) ;
@@ -1625,12 +1584,12 @@ SurfTriMesh::Intersect( const ISurfTriMesh& Other)
AddTriangle( nNewVert, m_nMaxTFlag) ;
}
}
// sistemazioni varie
bool bOk = ( AdjustVertices() && DoCompacting()) ;
bool bModified = false ;
bOk = bOk && RemoveDoubleTriangles( bModified) ;
if ( bModified)
bOk = bOk && RemoveDoubleTriangles( bModified) ;
if ( bModified)
bOk = bOk && ( AdjustVertices() && DoCompacting()) ;
bOk = bOk && RemoveTJunctions( bModified) ;
if ( bModified)
+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 ;
}
+791
View File
@@ -0,0 +1,791 @@
//----------------------------------------------------------------------------
// EgalTech 2025
//----------------------------------------------------------------------------
// File : SurfTriMeshOffset.cpp Data : 07.07.25 Versione : 2.7g1
// Contenuto : Implementazione funzione per Offset di Superfici TriMesh.
//
//
//
// 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.
//
//----------------------------------------------------------------------------
//--------------------------- Include ----------------------------------------
#include "stdafx.h"
#include "VolZmap.h"
#include "SurfTriMesh.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"
#include "/EgtDev/Include/EGkStmStandard.h"
#include "/EgtDev/Include/EgtPerfCounter.h"
std::vector<IGeoObj*> VT ;
std::vector<Color> VC ;
#endif
using namespace std ;
//----------------------------------------------------------------------------
static ISurfTriMesh*
SumStm( const CISURFTMPVECTOR& vStm)
{
// se vettore vuoto, non faccio nulla
if ( vStm.empty())
return nullptr ;
// definisco la superficie somma tra tutte ( la prima deve essere valida)
PtrOwner<ISurfTriMesh> pStmAdd( CreateSurfTriMesh()) ;
if ( IsNull( pStmAdd))
return nullptr ;
// scorro le superfici
for ( const ISurfTriMesh* pStm : vStm) {
if ( pStm == nullptr || ! pStm->IsValid() || pStm->GetTriangleCount() == 0)
continue ;
if ( ! pStmAdd->IsValid() || pStmAdd->GetTriangleCount() == 0) {
if ( ! pStmAdd->CopyFrom( pStm))
return nullptr ;
}
else
pStmAdd->Add( *pStm) ;
}
// restituisco la superficie ottenuta
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
//----------------------------------------------------------------------------
ISurfTriMesh*
CreateSurfTriMeshOffset( const ISurfTriMesh* pStm, double dOffs, double dPrec, int nType)
{
return ( CreateSurfTriMeshesOffset( { pStm}, dOffs, dPrec, nType)) ;
}
//----------------------------------------------------------------------------
// Funzione che crea il Fat Offset di una superficie TriMesh
//----------------------------------------------------------------------------
ISurfTriMesh*
CreateSurfTriMeshThickeningOffset( const ISurfTriMesh* pStm, double dOffs, double dPrec, int nType)
{
return ( CreateSurfTriMeshesThickeningOffset( { pStm}, dOffs, dPrec, nType)) ;
}
//----------------------------------------------------------------------------
// Funzione che crea l'Offset di un insieme di superfici
//----------------------------------------------------------------------------
ISurfTriMesh*
CreateSurfTriMeshesOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPrec, int nType)
{
// se vettore delle superfici vuoto, non faccio nulla
if ( vStm.empty())
return nullptr ;
// controllo sul valore di tolleranza lineare
double dMyPrec = max( dPrec, 100. * EPS_SMALL) ;
// --- NB. ( Il valore di Offset deve essere maggiore di 10 * EPS_SMALL in valore assoluto)
// Nel caso sia minore, restituisco semplicemente la somma delle superfici
// ( questo valore serve per rimanere coerente con l'Offset delle curve)
if ( abs( dOffs) < 10. * EPS_SMALL)
return SumStm( vStm) ;
// creo lo Zmap associato alle superfici TriMesh
VolZmap myVolZmap ;
if ( ! myVolZmap.CreateFromTriMeshOffset( vStm, dOffs, dMyPrec, nType))
return nullptr ;
if ( ! myVolZmap.IsValid())
return nullptr ;
// recupero le superfici aperte
CISURFTMPVECTOR vStmOpen ;
for ( const ISurfTriMesh* pStm : vStm) {
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 ( myVolZmap.GetSurfTriMesh()) ;
}
// --- se ho delle superfici chiuse
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
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) ;
}
}
}
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
return ( Release( pStmOffs)) ;
}
//----------------------------------------------------------------------------
//* Funzione che crea il Fat Offset di un insieme di superfici
//----------------------------------------------------------------------------
ISurfTriMesh*
CreateSurfTriMeshesThickeningOffset( const CISURFTMPVECTOR& vStm, double dOffs, double dPrec, int nType)
{
// se vettore delle superfici vuoto, non faccio nulla
if ( vStm.empty())
return nullptr ;
// controllo sul valore di tolleranza lineare
double dMyPrec = max( dPrec, 100 * EPS_SMALL) ;
// --- NB. ( Il valore di Offset deve essere maggiore di 10 * EPS_SMALL in valore assoluto)
// Nel caso sia minore, restituisco semplicemente la somma delle superfici
// ( questo valore serve per rimanere coerente con l'Offset delle curve)
if ( abs( dOffs) < 10 * EPS_SMALL)
return SumStm( vStm) ;
// creo lo Zmap associato alle superfici TriMesh
VolZmap OneVolZmap ;
if ( ! OneVolZmap.CreateFromTriMeshThickeningOffset( vStm, dOffs, dMyPrec, nType))
return nullptr ;
if ( ! OneVolZmap.IsValid())
return nullptr ;
// 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) ;
}
+204 -31
View File
@@ -17,7 +17,6 @@
#include "Triangulate.h"
#include "/EgtDev/Include/EGkDistPointLine.h"
#include "/EgtDev/Include/EGkDistLineLine.h"
#include <unordered_map>
using namespace std ;
@@ -35,6 +34,7 @@ SurfTriMesh::RemoveDoubleTriangles( bool& bModified)
// recupero i vertici dei triangoli
int nIdV[3] ;
GetTriangle( nT, nIdV) ;
bool bToRemove = false ;
// ciclo sui triangoli adiacenti
for ( int nE = 0 ; nE < 3 ; ++ nE) {
// recupero triangolo adiacente, se non esiste passo al successivo
@@ -53,10 +53,14 @@ SurfTriMesh::RemoveDoubleTriangles( bool& bModified)
}
}
if ( nCoinc == 3) {
RemoveTriangle( nAdjT) ;
// se i vertici coincidono rimuovo entrambi i triangoli
bToRemove = true ;
bModified = true ;
RemoveTriangle( nAdjT) ;
}
}
if ( bToRemove)
RemoveTriangle( nT) ;
}
return true ;
@@ -86,8 +90,8 @@ SurfTriMesh::FlipTriangles( int nTA, int nTB)
// Recupero i vertici del triangolo A
Point3d ptSegSt, ptSegEn, ptVertA ;
if ( ! GetVertex( m_vTria[nTA].nIdVert[nEdgeA], ptSegSt) ||
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 1) % 3], ptSegEn) ||
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3], ptVertA))
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 1) % 3], ptSegEn) ||
! GetVertex( m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3], ptVertA))
return false ;
// Recupero il vertice opposto del triangolo B
Point3d ptVertB ;
@@ -98,23 +102,43 @@ SurfTriMesh::FlipTriangles( int nTA, int nTB)
if ( ! DiagDist.IsSmall())
return false ;
double dPos1, dPos2 ;
if ( ! DiagDist.GetPositionsAtMinDistPoints( dPos1, dPos2) ||
dPos1 < EPS_SMALL || dPos1 > ( ptSegEn - ptSegSt).Len() - EPS_SMALL ||
dPos2 < EPS_SMALL || dPos2 > ( ptVertB - ptVertA).Len() - EPS_SMALL)
return false ;
if ( ! DiagDist.GetPositionsAtMinDistPoints( dPos1, dPos2))
return false ;
if ( dPos1 < - EPS_SMALL || dPos1 > ( ptSegEn - ptSegSt).Len() + EPS_SMALL ||
dPos2 < - EPS_SMALL || dPos2 > ( ptVertB - ptVertA).Len() + EPS_SMALL)
return false ;
// Eseguo il flipping
m_vTria[nTA].nIdVert[nEdgeA] = m_vTria[nTB].nIdVert[( nEdgeB + 2) % 3] ;
m_vTria[nTB].nIdVert[nEdgeB] = m_vTria[nTA].nIdVert[( nEdgeA + 2) % 3] ;
m_vTria[nTA].nIdAdjac[nEdgeA] = m_vTria[nTB].nIdAdjac[( nEdgeB + 2) % 3] ;
m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] = nTB ;
m_vTria[nTB].nIdAdjac[nEdgeB] = m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] ;
m_vTria[nTA].nIdAdjac[( nEdgeA + 2) % 3] = nTB ;
m_vTria[nTB].nIdAdjac[( nEdgeB + 2) % 3] = nTA ;
// sistemo anche le contro-adiacenze
int nTC = m_vTria[nTA].nIdAdjac[nEdgeA] ;
if ( nTC != SVT_NULL) {
for ( int i = 0 ; i < 3 ; i++)
if ( m_vTria[nTC].nIdAdjac[i] == nTB) {
m_vTria[nTC].nIdAdjac[i] = nTA ;
break ;
}
}
int nTD = m_vTria[nTB].nIdAdjac[nEdgeB] ;
if ( nTD != SVT_NULL) {
for ( int i = 0 ; i < 3 ; i++)
if ( m_vTria[nTD].nIdAdjac[i] == nTA) {
m_vTria[nTD].nIdAdjac[i] = nTB ;
break ;
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::RemoveTJunctions( bool& bModified)
SurfTriMesh::RemoveTJunctions( bool& bModified, double dMinSqDist)
{
bModified = false ;
@@ -123,6 +147,11 @@ SurfTriMesh::RemoveTJunctions( bool& bModified)
// Ciclo sui triangoli della superficie per determinare gli altri vertici sul loro perimetro
for ( int nT = 0 ; nT < int( m_vTria.size()) ; ++ nT) {
// se adiacenze tutte valide, passo al successivo
if ( m_vTria[nT].nIdAdjac[0] != SVT_DEL && m_vTria[nT].nIdAdjac[0] != SVT_NULL &&
m_vTria[nT].nIdAdjac[1] != SVT_DEL && m_vTria[nT].nIdAdjac[1] != SVT_NULL &&
m_vTria[nT].nIdAdjac[2] != SVT_DEL && m_vTria[nT].nIdAdjac[2] != SVT_NULL)
continue ;
// Se il triangolo non è valido, passo al successivo
Triangle3d trTria ;
if ( ! GetTriangle( nT, trTria) || ! trTria.Validate( true))
@@ -150,6 +179,8 @@ SurfTriMesh::RemoveTJunctions( bool& bModified)
if ( dSegLen < EPS_SMALL)
continue ;
vtSeg /= dSegLen ;
int nV1 = m_vTria[nT].nIdVert[nSeg] ;
int nV2 = m_vTria[nT].nIdVert[Next( nSeg)] ;
// Ciclo sui triangoli vicini
for ( int nI = 0 ; nI < int( vNearTria.size()) ; ++ nI) {
// Salto il triangolo se è quello di riferimento
@@ -157,13 +188,16 @@ SurfTriMesh::RemoveTJunctions( bool& bModified)
continue ;
// Cerco i vertici che stanno sul lato del triangolo
for ( int nVert = 0 ; nVert < 3 ; ++ nVert) {
int nCurrVert = m_vTria[vNearTria[nI]].nIdVert[nVert] ;
if ( nCurrVert == nV1 || nCurrVert == nV2)
continue ;
Point3d ptVert ;
if ( ! GetVertex( m_vTria[vNearTria[nI]].nIdVert[nVert], ptVert))
continue ;
double dProj = ( ptVert - ptSegSt) * vtSeg ;
double dOrt = ( ( ptVert - ptSegSt) - dProj * vtSeg).SqLen() ;
if ( dProj > EPS_SMALL && dProj < dSegLen - EPS_SMALL && dOrt < SQ_EPS_TRIA_H)
vVertOtl.emplace_back( m_vTria[vNearTria[nI]].nIdVert[nVert]) ;
double dOrt = ( ( ptVert - ptSegSt) - dProj * vtSeg).SqLen() ;
if ( dProj > EPS_SMALL && dProj < dSegLen - EPS_SMALL && dOrt < dMinSqDist)
vVertOtl.emplace_back( m_vTria[vNearTria[nI]].nIdVert[nVert]) ;
}
}
// Riordino i vertici sul segmento
@@ -307,16 +341,42 @@ ChooseGoodStartPoint( PNTULIST& PointList)
return false ;
}
//----------------------------------------------------------------------------
static bool
AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif)
// -------------------------------------------------------------
bool
SurfTriMesh::AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, double dTolAlign, bool& bModif) const
{
// vettore dei loop della faccia adiacente
POLYLINEVECTOR LoopVec ;
// Ciclo sui punti del loop
auto itLast = PointList.begin() ;
for ( auto it = next( itLast) ; it != PointList.end() ; ++ it) {
// Se dal punto corrente inizia un segmento adiacente a un'altra faccia
if ( itLast->second != it->second) {
// bisogna fermarsi per analizzare il tratto corrente alla ricerca di punti allineati se dal punto corrente
// inizia un tratto adiacente ad un'altra faccia oppure se il punto corrente non verrà eliminato dal loop
// della faccia adiacente
bool bAnalyze = ( itLast->second != it->second) ;
if ( bAnalyze)
LoopVec.clear() ;
if ( ! bAnalyze && itLast->second != - 1) {
if ( LoopVec.empty())
GetFacetLoops( int( itLast->second), LoopVec) ;
for ( int i = 0 ; i < int( LoopVec.size()) && ! bAnalyze ; i ++) {
const PNTULIST& PointListAdj = LoopVec[i].GetUPointList() ;
int nSamePoints = 0 ;
for ( auto itAdj = PointListAdj.begin() ; itAdj != prev( PointListAdj.end()) ; ++ itAdj) {
// cerco il punto corrente sul loop della faccia adiacente
if ( AreSamePointApprox( it->first, itAdj->first))
++ nSamePoints ;
if ( ( nSamePoints == 1 && int( PointListAdj.size()) <= 4) || nSamePoints > 1) {
bAnalyze = true ;
break ;
}
}
}
}
if ( bAnalyze) {
// Raccolgo i punti in una polyline
PolyLine PL ;
int nPar = -1 ;
@@ -326,7 +386,7 @@ AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif)
}
PL.AddUPoint( ++nPar, it->first) ;
// Provo ad eliminare i punti allineati
PL.RemoveAlignedPoints( 50 * EPS_SMALL) ;
PL.RemoveAlignedPoints( dTolAlign) ;
if ( PL.GetPointNbr() < nPar + 1) {
// rimuovo dalla lista dei punti gli eliminati (salto gli estremi)
int nUCurr = 1 ;
@@ -418,7 +478,7 @@ AdjustLoop( PNTULIST& PointList, double dMaxEdgeLen, bool& bModif)
//----------------------------------------------------------------------------
bool
SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced, double dTolAlign)
{
// La trimesh deve essere valida
if ( ! IsValid())
@@ -433,8 +493,8 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
// Ciclo sulle facce della mesh per trovare quelle da ritriangolare
unordered_map< int, pair< PNTVECTOR, INTVECTOR>> FacetMap ;
for ( int nF = 0 ; nF < nFacetCnt ; ++ nF) {
// Recupero i loop della faccia (il parametro indica la faccia adiacente)
// Recupero i loop della faccia ( il parametro indica la faccia adiacente)
POLYLINEVECTOR LoopVec ;
GetFacetLoops( nF, LoopVec) ;
@@ -445,13 +505,17 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
// Lista dei punti del loop
PNTULIST& PointList = LoopVec[nL].GetUPointList() ;
// Se il loop è un triangolo, non va modificato
if ( int( PointList.size()) <= 4)
continue ;
// Mi assicuro che il punto iniziale/finale non sia all'interno di un possibile segmento
if ( ! ChooseGoodStartPoint( PointList))
continue ;
// Sistemo il loop
bool bModif = false ;
if ( ! AdjustLoop( PointList, dMaxEdgeLen, bModif))
if ( ! AdjustLoop( PointList, dMaxEdgeLen, dTolAlign, bModif))
return false ;
if ( bModif)
bToRetriangulate = true ;
@@ -479,9 +543,8 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
// Eseguo la ritriangolazione della faccia
PNTVECTOR vPt ;
INTVECTOR vTr ;
if ( Triangulate().Make( LoopVec, vPt, vTr)) {
if ( Triangulate().Make( LoopVec, vPt, vTr) && ! vTr.empty())
FacetMap.emplace( nF, make_pair( vPt, vTr)) ;
}
// Se non riesco a triangolare anche solo questa faccia, interrompo tutto
else
return false ;
@@ -502,17 +565,17 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
// Cancello i triangoli
for ( int nT : vDelTria)
RemoveTriangle( nT) ;
// Applico le nuove triangolazioni delle facce
for ( auto itF = FacetMap.begin() ; itF != FacetMap.end() ; ++ itF) {
const PNTVECTOR& vPt = itF->second.first ;
const INTVECTOR& vTr = itF->second.second ;
// Inserisco i nuovi triangoli
// Inserisco i nuovi triangoli
bool bFirstTria = true ;
for ( int n = 0 ; n < int( vTr.size()) - 2 ; n += 3) {
int nNewId[3] = { AddVertex( vPt[vTr[n]]),
AddVertex( vPt[vTr[n + 1]]),
AddVertex( vPt[vTr[n + 2]])} ;
AddVertex( vPt[vTr[n + 1]]),
AddVertex( vPt[vTr[n + 2]])} ;
auto itCol = ColorMap.find( itF->first) ;
int nTFlag = ( itCol != ColorMap.end() ? itCol->second : 0) ;
int nNewTriaId = AddTriangle( nNewId, nTFlag) ;
@@ -525,7 +588,7 @@ SurfTriMesh::SimplifyFacets( double dMaxEdgeLen, bool bForced)
}
}
}
// dichiaro necessità ricalcolo della grafica e di hashgrids3d
m_OGrMgr.Reset() ;
ResetHashGrids3d() ;
@@ -722,3 +785,113 @@ SurfTriMesh::SplitAtPoint( const Point3d& ptStop, const PNTVECTOR& Loop, PNTVECT
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::FindAdjacentOnLongerEdge( int nT, int& nEdge, int& nAdjTrg) const
{
// recupero il lato più lungo del triangolo
double dLen0 = SqDist( m_vVert[m_vTria[nT].nIdVert[0]].ptP, m_vVert[m_vTria[nT].nIdVert[1]].ptP) ;
double dLen1 = SqDist( m_vVert[m_vTria[nT].nIdVert[1]].ptP, m_vVert[m_vTria[nT].nIdVert[2]].ptP) ;
double dLen2 = SqDist( m_vVert[m_vTria[nT].nIdVert[2]].ptP, m_vVert[m_vTria[nT].nIdVert[0]].ptP) ;
nEdge = -1 ;
if ( dLen0 > dLen1 && dLen0 > dLen2)
nEdge = 0 ;
else if ( dLen1 > dLen2)
nEdge = 1 ;
else
nEdge = 2 ;
// recupero il triangolo adiacente sul lato più lungo
nAdjTrg = m_vTria[nT].nIdAdjac[nEdge] ;
return true ;
}
//----------------------------------------------------------------------------
bool
SurfTriMesh::RemoveInvalidTriangles( const INTVECTOR& vIds)
{
// al momento gestito solo per trimesh con adiacenze definite, eventualmente da estendere.
// Analoga a RemoveFistInvalidTrg in Triangulate.cpp
// TO DO da capire e gestire casi in cui flip lascia triangoli invalidi
unordered_map<int, bool> InvalidMap ;
for ( auto nId : vIds)
InvalidMap[nId] = true ;
for ( int i = 0 ; i < int( vIds.size()) ; i++) {
int nTA = vIds[i] ;
if ( ! InvalidMap[nTA])
continue ;
// recupero il triangolo adiacente sul suo lato più lungo
int nTB, nEdgeA ;
FindAdjacentOnLongerEdge( nTA, nEdgeA, nTB) ;
// se adiacente è nullo posso rimuovere tranquillamente il triangolo senza creare TJunctions
if ( nTB == SVT_NULL) {
RemoveTriangle( nTA) ;
continue ;
}
// se adiacente è valido posso fare il flip per rendere valido nTA
else if ( ! InvalidMap[nTB]) {
FlipTriangles( nTA, nTB) ;
InvalidMap[nTA] = false ;
}
// se adiacente è invalido creo una catena da risolvere non appena si trova un triangolo valido
else {
INTVECTOR vChain = {nTA} ;
INTVECTOR vChainEdges = {nEdgeA} ;
int nTCurr = nTB ;
while ( nTCurr != SVT_NULL && InvalidMap[nTCurr]) {
// calcolo il successivo
int nTOther, nEdgeCurr ;
FindAdjacentOnLongerEdge( nTCurr, nEdgeCurr, nTOther) ;
if ( nTOther == vChain.back()) {
// se ho trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi)
// flip dei due triangoli per modificare il lato più lungo e togliere adiacenza ambigua
FlipTriangles( nTCurr, nTOther) ;
if ( vChain.size() > 1) {
vChain.pop_back() ;
vChainEdges.pop_back() ;
// individuo il nuovo adiacente all'ultimo triangolo della catena dopo aver fatto flip
nTOther = m_vTria[vChain.back()].nIdAdjac[vChainEdges.back()] ;
}
}
else {
vChain.emplace_back( nTCurr) ;
vChainEdges.emplace_back( nEdgeCurr) ;
}
// aggiorno per iterazione successiva
nTCurr = nTOther ;
}
// se la catena termina su triangolo nullo, posso rimuovere tutti i triangoli della catena
if ( nTCurr == SVT_NULL) {
for ( int k = 0 ; k < int( vChain.size()) ; k++) {
RemoveTriangle( vChain[k]) ;
InvalidMap[vChain[k]] = false ;
}
}
// se catena termina su un triangolo valido, applico il flip a cascata a partire dall'ultimo triangolo invalido trovato
else {
FlipTriangles( vChain.back(), nTCurr) ;
InvalidMap[vChain.back()] = false ;
for ( int i = int( vChain.size()) - 2 ; i >= 0 ; i--) {
int nTA = vChain[i] ;
if ( ! InvalidMap[nTA])
continue ;
// eseguo il flip con il triangolo adiacente sul suo lato più lungo
int nTOther = m_vTria[nTA].nIdAdjac[vChainEdges[i]] ;
FlipTriangles( nTA, nTOther) ;
InvalidMap[nTA] = false ;
}
}
}
}
return true ;
}
+1101 -1515
View File
File diff suppressed because it is too large Load Diff
+85 -78
View File
@@ -20,6 +20,15 @@
#include "/EgtDev/Include/EGkPolyLine.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include <map>
#include <utility>
struct PairHashInt64 {
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
}
} ;
//----------------------------------------------------------------------------
struct Inters {
@@ -33,13 +42,13 @@ struct Inters {
// 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
// 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} ;
const auto iter1 = find( vEdges.begin(), vEdges.end(), nIn) ;
int nPos1 = std::distance( vEdges.begin(), iter1) ;
const auto iter2 = find( vEdges.begin(), vEdges.end(), b.nIn) ;
int nPos2 = std::distance( vEdges.begin(), iter2) ;
// se sono loop interni li ordino in modo decrescente rispetto all'area
// se sono loop interni li ordino in modo decrescente rispetto all'area
bool bEqIn = ( nIn == b.nIn) ;
double dAreaA = 0 , dAreaB = 0 ;
if ( bEqIn && nIn == -1) {
@@ -54,7 +63,7 @@ struct Inters {
pl.Close() ;
pl.GetAreaXY( dAreaB) ;
}
// se nIn è un vertice sistemo il valore
// se nIn è un vertice sistemo il valore
int nEdgeIn = nIn ;
if ( nIn > 3)
nEdgeIn = nIn - 4 ;
@@ -66,13 +75,13 @@ 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
// nell'intersezione salvo se il taglio è stato ordinato guardando l'ingresso o l'uscita
// 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
// nell'intersezione salvo se il taglio è stato ordinato guardando l'ingresso o l'uscita
INTVECTOR vEdges = { 7, 0, 4, 1, 5, 2, 6, 3} ;
// trovo i lati di ingresso e uscita
// trovo i lati di ingresso e uscita
const auto iter1 = find( vEdges.begin(), vEdges.end(), a.nIn) ;
int nPos1 = std::distance( vEdges.begin(), iter1) ;
const auto iter2 = find( vEdges.begin(), vEdges.end(), a.nOut) ;
@@ -83,13 +92,13 @@ struct Inters {
int nPos4 = std::distance( vEdges.begin(), iter4) ;
int nFirstA = 0 ;
int nFirstB = 0 ;
// salvo l'indice del primo punto dell'intersezione che ho incontrato scorrendo il bordo da ptTR
// salvo il lato che viene prima confrontando ingresso e uscita
// salvo l'indice del primo punto dell'intersezione che ho incontrato scorrendo il bordo da ptTR
// salvo il lato che viene prima confrontando ingresso e uscita
if ( nPos2 < nPos1) {
nPos1 = nPos2 ;
nFirstA = int( a.vpt.size()) - 1 ;
}
// se ingresso e uscita sono sullo stesso lato allora confronto le coordinate per capire se viene prima l'ingresso o l'uscita
// se ingresso e uscita sono sullo stesso lato allora confronto le coordinate per capire se viene prima l'ingresso o l'uscita
else if ( nPos2 == nPos1 ) {
if ( nPos1 == 0 )
nFirstA = a.vpt[0].x > a.vpt.back().x ? 0 : ( int( a.vpt.size()) - 1) ;
@@ -116,11 +125,11 @@ struct Inters {
}
a.bSortedbyStart = nFirstA == 0 ;
b.bSortedbyStart = nFirstB == 0 ;
// se sono diversi ritorno il confronto
// se sono diversi ritorno il confronto
if ( nPos1 != nPos3)
return nPos1 < nPos3 ;
// se sono uguali devo valutare il punto di intersezione
return ( nPos1 == 0 && a.vpt[nFirstA].x > b.vpt[nFirstB].x) ||
// se sono uguali devo valutare il punto di intersezione
return ( nPos1 == 0 && a.vpt[nFirstA].x > b.vpt[nFirstB].x) ||
( nPos1 == 1 && a.vpt[nFirstA].y > b.vpt[nFirstB].y) ||
( nPos1 == 2 && a.vpt[nFirstA].x < b.vpt[nFirstB].x) ||
( nPos1 == 3 && a.vpt[nFirstA].y < b.vpt[nFirstB].y) ;
@@ -151,20 +160,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_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1),
m_ptPbl( ORIG), m_ptPtr( SBZ_TREG_COEFF, SBZ_TREG_COEFF, 0), m_bProcessed( false), m_bSplitVert( true)
{
Point3d ptTr ( 1 * SBZ_TREG_COEFF, 1 * SBZ_TREG_COEFF) ;
m_ptPtr = 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( false), m_nRightEdgeIn( -1),
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_nChild1( -2), m_nChild2( -2), m_nFlag( -1), m_nFlag2( 0), m_nRightEdgeIn( -1), m_bOnLeftEdge( false), m_bOnTopEdge( false), m_nVertToErase( -1),
m_ptPbl( ptBL), m_ptPtr( ptTR), m_bProcessed( false), m_bSplitVert( true) {}
: 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_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) ; }
void SetBottomLeft( const Point3d& ptBL)
@@ -183,9 +196,11 @@ class Cell
{ return Point3d( m_ptPbl.x, m_ptPtr.y) ; }
Point3d GetBottomRight( void) const
{ return Point3d( m_ptPtr.x, m_ptPbl.y); }
Point3d GetCenter( void) const
{ return ( m_ptPbl + m_ptPtr) / 2 ; }
double GetSplitValue( void) const
{ return m_dSplit ; }
bool IsSplitVert( void) const // se true la cella verrebbe splittata verticalmente, sennò orizzontalmente
bool IsSplitVert( void) const // se true la cella verrebbe splittata verticalmente, altrimenti orizzontalmente
{ return m_bSplitVert ; }
bool IsLeaf( void) const // flag che indica se la cella ha figli o se è una foglia
{ return ( m_nChild1 == -2 && m_nChild2 == -2) ; }
@@ -194,9 +209,11 @@ class Cell
void SetProcessed( bool bProcessed = true)
{ m_bProcessed = bProcessed ; }
static bool minorX( const Cell& c1, const Cell& c2)
{ return c1.m_ptPbl.x < c2.m_ptPbl.x ; }
{ return c1.m_ptPbl.x < c2.m_ptPbl.x ; }
static bool minorY( const Cell& c1, const Cell& c2)
{ return c1.m_ptPbl.y < c2.m_ptPbl.y ; }
{ return c1.m_ptPbl.y < c2.m_ptPbl.y ; }
void AddPoly( int nPolyId)
{ m_vnPolyId.push_back( nPolyId) ;}
public :
int m_nId ; // Id della cella
@@ -209,9 +226,9 @@ class Cell
double m_dSplit ; // parametro a cui è stata splittata la cella
int m_nChild1 ; // prima cella figlio
int m_nChild2 ; // seconda cella figlio
int m_nFlag ; // falg che indica la caratterizzazione della cella rispetto ai loop di trim
int m_nFlag ; // flag che indica la caratterizzazione della cella rispetto ai loop di trim
// 0 esterna, 1 intersecata, 2 contiene un loop, 3 intersecata e contenente un loop, 4 contenuta in un loop
int m_nFlag2 ; // falg che indica se la cella è stata attraversata durante l'ultima fase del labelling
bool m_bLabelled ; // flag che indica se la cella è stata attraversata durante l'ultima fase del labelling
int m_nRightEdgeIn ; // 0 right edge fuori, 1 right edge dentro, 2 metà e metà
bool m_bOnLeftEdge ; // flag che indica se la cella è sul lato sinistro ( per superfici chiuse sul parametro U)
bool m_bOnTopEdge ; // flag che indica se la cella è sul lato top ( per superfici chiuse sul parametro V)
@@ -219,6 +236,8 @@ class Cell
// ogni elemento del vettore è l'insieme dei punti che caratterizza un attraversamento della cella
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
@@ -233,53 +252,50 @@ class Tree
public :
~Tree( void) ;
Tree( void) ;
//Tree ( const SurfBezier* pSrfBz, bool bSplitPatches = true, const Point3d& ptMin = ORIG, const Point3d& ptMax = ORIG) ;
Tree( const Point3d ptBl, const Point3d ptTr) ; // creatore da usare solo nel caso in cui si voglia aggiungere tagli ad un'unica cella e del risultato ottenere il contorno
bool SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches = true, const Point3d& ptMin = ORIG, const Point3d& ptMax = ORIG) ;
bool GetIndependentTrees( BIPNTVECTOR& vTrees) ; // calcolo la suddivisione della superficie solo sulle singole bbox dei loop di trim ( unendo quelli vicini)
bool BuildTree( double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO) ; // dSideMax è il massimo per la dimensione maggiore di un triangolo della trimesh
// dSideMin è lunghezza minima del lato di una cella nello spazio reale
bool BuildTree_test( double dLinTol = LIN_TOL_STD, double dSideMin = 1, double dSideMax = INFINITO) ;
bool GetPolygons( POLYLINEMATRIX& vvPolygons) ;
bool GetPolygons( POLYLINEMATRIX& vvPolygons, POLYLINEMATRIX& vvPolygons3d) ;
bool GetPolygons( POLYLINEMATRIX& vPolygons, bool bForTriangulation, POLYLINEMATRIX& vvPolygons3d) ;
bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, POLYLINEVECTOR& vPolygonsCorrected, // restituisce il poligono corrispondente ad ogni cella foglia dell'albero
bool bForTriangulation, POLYLINEVECTOR& vPolygons3d, INTVECTOR vCells = {}) ; // ad ogni poligono sono stati aggiunti tutti i vertici dei vicini posizionati sui suoi lati
// se richiesti per la triangolazione ad alcuni poligoni potrebbero venire tolti dei punti per evitare errori dovuti ad eventuali poli sui bordi del parametrico
bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, POLYLINEVECTOR& vPolygonsCorrected, POLYLINEVECTOR& vPolygons3d) ;
bool GetPolygonsBasic( POLYLINEVECTOR& vPolygons, INTVECTOR vCells = {}) ;
bool GetLeaves ( std::vector<Cell>& vLeaves) const ; // restituisce gli indici delle foglie nell'albero
bool GetEdges3D ( POLYLINEMATRIX& mPLEdges) ; // restituisce gli edge 3D come polyline
bool GetSplitLoops( POLYLINEVECTOR& vPl) const // funzione che restituisce i loop splitatti ai confini delle celle
{ for ( int i = 0 ; i < int( m_vPlLoop2D.size()); ++i) vPl.emplace_back( m_vPlLoop2D[i]) ; return true ; };
void SetTestMode( void) { m_bTestMode = true ;} ; // attivando la test mode, per la costruzione dell'albero viene usata la funzione BuiltTree_test e viene corretta di conseguenza la FindCell
Tree( const Point3d ptBl, const Point3d ptTr) ; // da usare solo nel caso in cui si voglia aggiungere tagli ad un'unica cella e del risultato ottenere il contorno
bool SetSurf( const SurfBezier* pSrfBz, const Point3d& ptMin = ORIG, const Point3d& ptMax = ORIG) ;
bool GetIndependentTrees( BIPNTVECTOR& vTrees) ; // calcolo la suddivisione della superficie solo sulle singole bbox dei loop di trim ( unendo quelli vicini)
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 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
bool GetLeaves( std::vector<Cell>& vLeaves) const ; // restituisce gli indici delle foglie nell'albero
bool GetEdges3D( std::vector<ICRVCOMPOPOVECTOR>& mCCEdge, POLYLINEVECTOR& vPolygons) ; // restituisce gli edge 3D come polyline
bool GetSplitLoops( ICRVCOMPOPOVECTOR& vCCLoopSplit) const // restituisce i loop splitatti ai confini delle celle
{ for ( int i = 0 ; i < int( m_vCCLoop2D.size()); ++i)
vCCLoopSplit.emplace_back( m_vCCLoop2D[i]->Clone()) ;
return true ; }
// funzioni da usare per ricostruire tagli che vanno aggiunti allo spazio parametrico
bool AddCutsToRoot( POLYLINEVECTOR& vCuts) ; // aggiunge i tagli al tree
bool CreateCellContour( POLYLINEMATRIX& vPolygons) ; // crea il nuovo contorno esterno, tenendo conto dei tagli
bool IsClosedU( void) const { return m_bClosedU ;} ; // funzione che riferisce se la superficie è chiusa lungo il parametro U
bool IsClosedV( void) const { return m_bClosedV ;} ; // funzione che riferisce se la superficie è chiusa lungo il parametro V
std::vector<bool> GetPoles( void) { return m_vbPole ;} ; // funzione che restituisce i flag che indicano se i lati sono collassati in dei poli
bool IsClosedU( void) const // restituisce flag di chiusara in U
{ return m_bClosedU ; }
bool IsClosedV( void) const // restituisce flag di chiusara in V
{ return m_bClosedV ; }
BOOLVECTOR GetPoles( void) // restituisce i flag che indicano se i lati sono collassati in dei poli
{ return m_vbPole ; }
private :
bool LimitLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) const ; // funzione che limita i loop di trim allo spazio parametrico
bool Split( int nId, double dSplitValue) ; // funzione di split di una cella al parametro indicato nella direzione data da bVert
bool Split( int nId) ; // funzione di split di una cella dell'albero a metà nella direzione data da bVert
void Balance( void) ; // creo rami in modo che tutte tutte le foglie abbiano come adiacenti foglie ad una profondità di +- 1
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
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, 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
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
INTVECTOR FindCell( const Point3d& ptToAssign, const CurveLine& cl, INTVECTOR vCells, bool bRecurs = false) const ; // dato un punto, trova la cella foglia a cui appartiene
bool TraceLoopLabelCell( const POLYLINEVECTOR& vplPolygons) ; // tracing dei loop e labelling delle celle
bool FindInters( int& nId, const CurveLine& clTrim, const PolyLine& plPolygon, PNTVECTOR& vptInters, bool bFirstInters = true) ; // trova le intersezioni tra una cella e una linea di trim
// resituisce l'id della cella verso cui la curva di trim esce e il vettore delle intersezioni per la cella successiva con il primo punto
bool CreateCellPolygons( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vPolygons3d, INTVECTOR& vToCheck, int& nPoly, INTVECTOR& vnParentChunk, const PolyLine& plCell, const PolyLine& plCell3d) ; // crea i poligoni della cella passata. richiede anche la funzione CreateIslandAndHoles per completare i poligoni.
bool CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vvPolygons3d, int& nPoly, INTVECTOR& vnParentChunk, bool bForTriangulation,
bool CreateIslandAndHoles( int nLeafId, POLYLINEMATRIX& vPolygons, POLYLINEMATRIX& vvPolygons3d, int& nPoly, INTVECTOR& vnParentChunk,
const PolyLine& plPolygonsBasic, const PolyLine& plPolygonsBasic3d) ; // ai poligoni generati da CreatePolygonsCell aggiunge i loop che creano isole o buchi all'interno della singola cella
bool CheckIfBefore( const PolyLine& pl, int nEdge) const ; // controllo se ptEnd è prima di ptStart sul lato nEdge rispetto al senso antiorario
bool CheckIfBefore( const Inters& inA) const ; // controlla se l'ingresso è prima dell'uscita in senso antiorario a partire da ptTR.
@@ -294,39 +310,30 @@ class Tree
bool CheckIfBetween( const Inters& inA, const Inters& inB) const ; // / controllo se inB è compreso tra l'end e lo start di inA (in senso CCW)
bool OnWhichEdge( int nId, const Point3d& ptToAssign, int& nEdge) const ; // indica a quale edge o vertice il punto è vicino entro EPS_SMALL
bool AdjustCuts( void) ;
bool UpdateSplitLoop( PolyLine& pl, int& nCount, Point3d& pt) ;
bool CloseOpenCuts( void) ;
bool CloseOpenCuts( POLYLINEVECTOR& vPL, PolyLine& pl) const ;
bool UpdateSplitLoop( ICurveComposite* pCC, Point3d& pt) ;
bool VerifyLoopOrientation( ICURVEPLIST& vpCrv, BOOLVECTOR& vbOrientation) const ; // verifico l'orientazione ( CCW o CW) delle polyline in base a come sono contenute le une nelle altre
bool AdjustLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation) const ;
bool GetPoint(double dU, double dV, Point3d& ptP) const ;
bool SavePoint( double dU, double dV, const Point3d& ptP) ;
private :
const SurfBezier* m_pSrfBz ; // superficie di bezier
DBLVECTOR m_vDim ; // distanze tra i vertici della superficie di bezier in 3d in ordine antiorario a partire da ptP00
bool m_bTrimmed ; // superficie trimmata
//INTMATRIX m_vChunk ; // elenco dei loop divisi per chunk
std::unordered_map<int,int> m_mChunk ; // mappa in cui vengono salvati chunk di appartenza per ogni loop di trim
//ICURVEPOVECTOR m_vLoop ; // curve di loop
std::unordered_map<int,int> m_mChunk ; // mappa in cui vengono salvati chunk di appartenza per ogni loop di trim
std::vector<std::tuple<PolyLine,bool>> m_vPlApprox ; // vettore contenente le approssimazioni dei loop // il bool indica se la curva è CCW
bool m_bBilinear ; // superficie bilineare
bool m_bMulti ; // superficie multi-patch
bool m_bClosedU ; // superficie chiusa lungo il parametro U
bool m_bClosedV ; // superficie chiusa lungo il parametro V
BOOLVECTOR m_vbPole ; // vettore che indica se i vari lati sono collassati in poli ( indici riferiti all'ordine degli edge)
bool m_bSplitPatches ; // flag che indica se le patches sono state divise prima della creazione dell'albero
int m_nDegU ; // grado della superficie nel parametro U
int m_nDegV ; // grado della superficie nel parametro V
int m_nSpanU ; // numero di span lungo il parametro U
int m_nSpanV ; // numero di span lungo il parametro V
POLYLINEMATRIX m_vPolygons ; // matrice dei poligoni del tree
POLYLINEMATRIX m_vPolygonsCorr ; // matrice dei poligoni del tree, corretti per i punti che sono nei poli
POLYLINEMATRIX m_vPolygons3d ; // matrice dei poligoni3d del tree
std::unordered_map<int,Cell> m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root
std::unordered_map<int,PNTVECTOR> m_mVert ; // mappa che contiene tutti i vertici 3d delle celle del tree. L'Id è lo stesso che la cella ha in m_mTree. I punti sono nell'ordine P00, P10, P11, P01
std::unordered_map<int,Cell> m_mTree ; // mappa che contiene tutti i nodi e le foglie dell'albero. -2 è puntatore Null e -1 è root
mutable std::unordered_map<std::pair<int64_t,int64_t>,Point3d,PairHashInt64> m_mPt3d ; // mappa che contiene tutti i punti 3d della superficie calcolati (la chiave sono le coordinate, moltiplicate per 2^24 e trasformate in int)
INTVECTOR m_vnLeaves ; // vettore delle foglie
INTVECTOR m_vnParents ; // vettore delle celle ottenute dalla divisione preliminare in singole patch
bool m_bTestMode ; // bool che indica se la test mode è attiva
POLYLINEVECTOR m_vPlLoop2D ; // vettore che contiene le polyline che rappresentano i loop di trim tenendo conto della divisione in celle
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.
} ;
+53 -34
View File
@@ -818,7 +818,7 @@ Triangulate::TestTriangle( const PNTVECTOR& vPt, const INTVECTOR& vPol,
}
}
// If vertex k is inside the ear triangle, then this is not an ear
else if ( TestPointInTriangle( vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) {
else if ( TestPointInOrOnTriangle( vPt[vPol[k]], vPt[vPol[vPrev[i]]], vPt[vPol[i]], vPt[vPol[vNext[i]]])) {
bIsEar = false ;
break ;
}
@@ -978,6 +978,28 @@ Triangulate::TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const
return true ;
}
//----------------------------------------------------------------------------
// test if point p is inside or on the border of triangle (a, b, c)
bool
Triangulate::TestPointInOrOnTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC)
{
// If P is on a vertex is considered inside
if ( AreSamePoint( ptP, ptA))
return true ;
if ( AreSamePoint( ptP, ptB))
return true ;
if ( AreSamePoint( ptP, ptC))
return true ;
// If P is on the right of at least one edge is outside
if ( TriangleIsCCW( ptA, ptP, ptB, EPS_SMALL))
return false ;
if ( TriangleIsCCW( ptB, ptP, ptC, EPS_SMALL))
return false ;
if ( TriangleIsCCW( ptC, ptP, ptA, EPS_SMALL))
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
Triangulate::SortInternalLoops( const POLYLINEVECTOR& vPL, INTVECTOR& vOrd)
@@ -1385,6 +1407,7 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr)
// I triangoli cap se eliminati danno origine a T-junctions, quindi devono essere gestiti opportunamente con dei flip.
// I triangoli needle se eliminati non sono problematici, ma i loro vertici coincidenti vanno gestiti opportunamente nel
// calcolo delle adiacenze dei triangoli cap.
// TO DO da capire e gestire casi in cui flip lascia triangoli invalidi
int nTria = int( vTr.size()) / 3 ;
INTVECTOR vCapTria ;
@@ -1482,46 +1505,40 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr)
INTVECTOR vChain, vChainEdges ;
vChain.emplace_back( nTA) ;
vChainEdges.emplace_back( nEA) ;
while ( nTB != -1 && ! vbIsValidTria[nTB]) {
// aggiungo alla catena
vChain.emplace_back( nTB) ;
int nTCurr = nTB ;
int nEOther ;
while ( nTCurr != -1 && ! vbIsValidTria[nTCurr]) {
// calcolo il successivo
nTA = nTB ;
FindAdjacentOnLongerEdge( vPt, vTr, nTA, nEA, nTB, nEB) ;
vChainEdges.emplace_back( nEA) ;
int nTOther, nECurr ;
FindAdjacentOnLongerEdge( vPt, vTr, nTCurr, nECurr, nTOther, nEOther) ;
// verifico di non aver trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi)
// e quindi di non essere entrato in un loop
if ( nTB == vChain[vChain.size()-2]) {
if ( nTOther == vChain.back()) {
// se ho trovato un'adiacenza ambigua ( ovvero due triangoli invalidi adiacenti sui loro lati più lunghi)
// flip dei due triangoli per modificare il lato più lungo e togliere adiacenza ambigua
FlipTrg( vTr, nTA, nTB, nEA, nEB) ;
// aggiorno per iterazione successiva
if ( vChain.size() == 2) {
FlipTrg( vTr, nTCurr, nTOther, nECurr, nEOther) ;
if ( vChain.size() > 1) {
vChain.pop_back() ;
vChainEdges.pop_back() ;
FindAdjacentOnLongerEdge( vPt, vTr, vChain.back(), nEA, nTB, nEB) ;
vChainEdges[0] = nEA ;
// individuo il nuovo adiacente all'ultimo triangolo della catena tra i due appena flippati
TestAdjacentOnEdge( vTr, vChain.back(), vChainEdges.back(), nTCurr, nTOther, nTB, nEB) ;
nTOther = nTB ;
}
else {
// elimino gli ultimi due triangoli che sono appena stati flippati e ricalcolo adiacenza del triangolo
// precedente
vChain.pop_back() ;
vChain.pop_back() ;
vChainEdges.pop_back() ;
vChainEdges.pop_back() ;
int nTTest1 = nTA ;
int nTTest2 = nTB ;
TestAdjacentOnEdge( vTr, vChain.back(), vChainEdges.back(), nTTest1, nTTest2, nTB, nEB) ;
}
}
else {
vChain.emplace_back( nTCurr) ;
vChainEdges.emplace_back( nECurr) ;
}
// aggiorno per iterazione successiva
nTCurr = nTOther ;
}
// se la catena termina su triangolo nullo, annullo tutti i triangoli della catena
if ( nTB == -1) {
if ( nTCurr == -1) {
bRemovedTrg = true ;
for ( int k = 0 ; k < int( vChain.size()) ; k++) {
if ( vbIsValidTria[vChain[k]])
continue ;
vTr[3*vChain[k]] = -1 ;
vTr[3*vChain[k] + 1] = -1 ;
vTr[3*vChain[k] + 2] = -1 ;
@@ -1530,14 +1547,16 @@ RemoveFistInvalidTrg( PNTVECTOR& vPt, INTVECTOR& vTr)
}
// se catena termina su un triangolo valido, applico il flip a cascata a partire dall'ultimo triangolo invalido
else {
FlipTrg( vTr, vChain.back(), nTB, vChainEdges.back(), nEB) ;
FlipTrg( vTr, vChain.back(), nTCurr, vChainEdges.back(), nEOther) ;
vbIsValidTria[vChain.back()] = true ;
int nTrgTest1 = vChain.back() ;
int nTrgTest2 = nTB ;
for ( int i = int( vChain.size()-2) ; i >= 0 ; i--) {
int nTrgTest2 = nTCurr ;
for ( int j = int( vChain.size()-2) ; j >= 0 ; j--) {
// triangolo corrente
int nTA = vChain[i] ;
int nEA = vChainEdges[i] ;
int nTA = vChain[j] ;
if ( vbIsValidTria[nTA])
continue ;
int nEA = vChainEdges[j] ;
// devo trovare il nuovo adiacente dopo il flip dei successivi nella catena
TestAdjacentOnEdge( vTr, nTA, nEA, nTrgTest1, nTrgTest2, nTB, nEB) ;
// flip per rendere valido il triangolo corrente
@@ -1608,7 +1627,7 @@ MakeByFist( const POLYLINEVECTOR& vPL, PNTVECTOR& vPt, INTVECTOR& vTr)
vPt.reserve( fist.c_vertex.num_vertices) ;
for ( int i = 0 ; i < fist.c_vertex.num_vertices ; i ++)
vPt.emplace_back( fist.c_vertex.vertices[i].x, fist.c_vertex.vertices[i].y, fist.c_vertex.vertices[i].z) ;
// recupero i triangoli da fist
vTr.reserve( 3 * fist.c_vertex.num_triangles) ;
for ( int i = 0 ; i < fist.c_vertex.num_triangles ; i ++) {
+1
View File
@@ -45,6 +45,7 @@ class Triangulate
bool TriangleIsCCW( const Point3d& ptA, const Point3d& ptB, const Point3d& ptC, double dToler = 0.1 * EPS_SMALL) ;
bool TestIntersection( const Point3d& ptA1, const Point3d& ptA2, const Point3d& ptB1, const Point3d& ptB2) ;
bool TestPointInTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ;
bool TestPointInOrOnTriangle( const Point3d& ptP, const Point3d& ptA, const Point3d& ptB, const Point3d& ptC) ;
bool SortInternalLoops( const POLYLINEVECTOR& vPL, INTVECTOR& vOrd) ;
bool GetPntVectorFromPolyline( const PolyLine& PL, bool bXmaxStart, PNTVECTOR& vPi) ;
bool GetOuterPntToJoin( const PNTVECTOR& vPt, const Point3d& ptP, int& nI) ;
+3767
View File
File diff suppressed because it is too large Load Diff
+339 -147
View File
@@ -1,4 +1,4 @@
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// EgalTech 2015-2016
//----------------------------------------------------------------------------
// File : VolZmap.cpp Data : 22.01.15 Versione : 1.6a4
@@ -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 ;
@@ -563,10 +574,10 @@ VolZmap::GetPartLocalBBox( int nPart, BBox3d& b3Loc, int nFlag) const
// Verifico lo stato.
if ( m_nStatus != OK)
return false ;
// Se una sola mappa o il numero di componenti è indefinito, vi è un errore.
// Se una sola mappa o il numero di componenti è indefinito, vi è un errore.
if ( m_nMapNum == 1 || m_nConnectedCompoCount == - 1)
return false ;
// Se la componente richiesta non esiste, vi è un errore.
// Se la componente richiesta non esiste, vi è un errore.
if ( nPart < 0 || nPart > m_nConnectedCompoCount - 1)
return false ;
// Calcolo Bounding-box
@@ -614,10 +625,10 @@ VolZmap::GetPartBBox( int nPart, const Frame3d& frRef, BBox3d& b3Ref, int nFlag)
// Verifico lo stato.
if ( m_nStatus != OK)
return false ;
// Se una sola mappa o il numero di componenti è indefinito, vi è un errore.
// Se una sola mappa o il numero di componenti è indefinito, vi è un errore.
if ( m_nMapNum == 1 || m_nConnectedCompoCount == - 1)
return false ;
// Se la componente richiesta non esiste, vi è un errore.
// Se la componente richiesta non esiste, vi è un errore.
if ( nPart < 0 || nPart > m_nConnectedCompoCount - 1)
return false ;
// Calcolo Bounding-box
@@ -689,7 +700,7 @@ VolZmap::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, doub
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità dell'asse di rotazione
// verifico validità dell'asse di rotazione
if ( vtAx.IsSmall())
return false ;
@@ -722,7 +733,7 @@ VolZmap::Mirror( const Point3d& ptOn, const Vector3d& vtNorm)
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del piano di specchiatura
// verifico validità del piano di specchiatura
if ( vtNorm.IsSmall())
return false ;
@@ -736,7 +747,7 @@ VolZmap::Shear( const Point3d& ptOn, const Vector3d& vtNorm, const Vector3d& vtD
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità dei parametri
// verifico validità dei parametri
if ( vtNorm.IsSmall() || vtDir.IsSmall())
return false ;
@@ -750,11 +761,11 @@ VolZmap::ToGlob( const Frame3d& frRef)
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// se frame identità, non devo fare alcunché
// se frame identità, non devo fare alcunché
if ( IsGlobFrame( frRef))
return true ;
@@ -773,11 +784,11 @@ VolZmap::ToLoc( const Frame3d& frRef)
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità del frame
// verifico validità del frame
if ( frRef.GetType() == Frame3d::ERR)
return false ;
// se frame identità, non devo fare alcunché
// se frame identità, non devo fare alcunché
if ( IsGlobFrame( frRef))
return true ;
@@ -796,11 +807,11 @@ VolZmap::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// verifico validità dei frame
// verifico validità dei frame
if ( frOri.GetType() == Frame3d::ERR || frDest.GetType() == Frame3d::ERR)
return false ;
// se i due riferimenti coincidono, non devo fare alcunché
// se i due riferimenti coincidono, non devo fare alcunché
if ( AreSameFrame( frOri, frDest))
return true ;
@@ -816,10 +827,10 @@ VolZmap::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
int
VolZmap::GetPartCount( void) const
{
// Se mono-dexel la connessione è incalcolabile.
// Se mono-dexel la connessione è incalcolabile.
if ( m_nMapNum == 1)
return - 1 ;
// Se il numero delle componenti è indefinito
// Se il numero delle componenti è indefinito
// lo ricalcolo e restituisco il risultato.
if ( m_nConnectedCompoCount == - 1) {
const_cast<VolZmap*>(this)->CheckMapConnection() ;
@@ -870,7 +881,7 @@ VolZmap::CheckMapConnection( void)
IntervalsToProcessStackVec.resize( nThreadMax) ;
// Mi espando dal primo intervallo mettendo gli intervalli che intersecano nei vari thread
FirstExpansionFromZ( nThreadMax, NewInt, IntervalsToProcessStackVec) ;
// Lancio in parallelo più ricerche
// Lancio in parallelo più ricerche
int nActiveThread = 0 ;
vector<future<bool>> vRes ;
vRes.resize( nThreadMax) ;
@@ -891,7 +902,7 @@ VolZmap::CheckMapConnection( void)
}
}
}
// Se l'intervallo non attraversa un nodo o ha già
// Se l'intervallo non attraversa un nodo o ha già
// un indice assegnato salto questa iterazione.
else
continue ;
@@ -935,7 +946,7 @@ VolZmap::ExpandFromXInterval( IntContainer& IntCont)
double dZmin = m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].dMin ;
double dZmax = m_Values[0][tGrIndex1 * m_nNx[0] + tI][tIntZ].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dZmin - 2 * EPS_SMALL < dZ &&
dZmax + 2 * EPS_SMALL > dZ &&
@@ -955,7 +966,7 @@ VolZmap::ExpandFromXInterval( IntContainer& IntCont)
double dYmin = m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].dMin ;
double dYmax = m_Values[2][tI * m_nNx[2] + tGrIndex2][tIntY].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dYmin - 2 * EPS_SMALL < dY &&
dYmax + 2 * EPS_SMALL > dY &&
@@ -1006,7 +1017,7 @@ VolZmap::ExpandFromYInterval( IntContainer& IntCont)
double dZmin = m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].dMin ;
double dZmax = m_Values[0][tJ * m_nNx[0] + tGrIndex2][tIntZ].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dZmin - 2 * EPS_SMALL < dZ &&
dZmax + 2 * EPS_SMALL > dZ &&
@@ -1026,7 +1037,7 @@ VolZmap::ExpandFromYInterval( IntContainer& IntCont)
double dXmin = m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].dMin ;
double dXmax = m_Values[1][tGrIndex1 * m_nNx[1] + tJ][tIntX].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dXmin - 2 * EPS_SMALL < dX &&
dXmax + 2 * EPS_SMALL > dX &&
@@ -1077,7 +1088,7 @@ VolZmap::ExpandFromZInterval( IntContainer& IntCont)
double dXmin = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMin ;
double dXmax = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dXmin - 2 * EPS_SMALL < dX &&
dXmax + 2 * EPS_SMALL > dX &&
@@ -1097,7 +1108,7 @@ VolZmap::ExpandFromZInterval( IntContainer& IntCont)
double dYmin = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMin ;
double dYmax = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dYmin - 2 * EPS_SMALL < dY &&
dYmax + 2 * EPS_SMALL > dY &&
@@ -1146,7 +1157,7 @@ VolZmap::FirstExpansionFromZ( int nNumThread, IntervalIndexes IntSt, IntContaine
double dXmin = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMin ;
double dXmax = m_Values[1][tK * m_nNx[1] + tGrIndex2][tIntX].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dXmin - 2 * EPS_SMALL < dX &&
dXmax + 2 * EPS_SMALL > dX &&
@@ -1167,7 +1178,7 @@ VolZmap::FirstExpansionFromZ( int nNumThread, IntervalIndexes IntSt, IntContaine
double dYmin = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMin ;
double dYmax = m_Values[2][tGrIndex1 * m_nNx[2] + tK][tIntY].dMax ;
// Se i segmenti si incrociano e il nuovo trovato non
// ha già un indice assegnato, assegno l'indice e
// ha già un indice assegnato, assegno l'indice e
// aggiungo l'intervallo trovato allo stack.
if ( dYmin - 2 * EPS_SMALL < dY &&
dYmax + 2 * EPS_SMALL > dY &&
@@ -1214,13 +1225,13 @@ VolZmap::ClonePart( int nPart) const
// verifico lo stato
if ( m_nStatus != OK)
return nullptr ;
// Se è definita una sola griglia non sono definibili le parti, errore
// Se è definita una sola griglia non sono definibili le parti, errore
if ( m_nMapNum == 1)
return nullptr ;
// Se è richiesta una componente fuori intervallo, errore
// Se è richiesta una componente fuori intervallo, errore
if ( nPart < 0 || nPart >= m_nConnectedCompoCount)
return nullptr ;
// Se il numero di componenti è indefinito, lo ricalcolo.
// Se il numero di componenti è indefinito, lo ricalcolo.
if ( m_nConnectedCompoCount == - 1)
const_cast<VolZmap*>(this)->CheckMapConnection() ;
// Se non vi sono componenti, errore
@@ -1291,7 +1302,7 @@ VolZmap::ClonePart( int nPart) const
pVolume->m_Values[nMap].resize( pVolume->m_nDim[nMap]) ;
}
// Se almeno una griglia è nulla, non ha senso Zmap
// Se almeno una griglia è nulla, non ha senso Zmap
if ( pVolume->m_nDim[0] == 0 ||
pVolume->m_nDim[1] == 0 ||
pVolume->m_nDim[2] == 0)
@@ -1343,8 +1354,8 @@ VolZmap::ClonePart( int nPart) const
dNewOy = nMinIndJ[0] * m_dStep ;
dNewOz = nMinIndJ[1] * m_dStep ;
// Porto i dexel nel nuovo sistema di riferimento e le quote estreme Z. Non c'è bisogno di trasformare le normali,
// infatti i sistemi di riferimento in gioco differiscono al più per una traslazione.
// Porto i dexel nel nuovo sistema di riferimento e le quote estreme Z. Non c'è bisogno di trasformare le normali,
// infatti i sistemi di riferimento in gioco differiscono al più per una traslazione.
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
// Quote estreme Z
switch ( nMap) {
@@ -1407,10 +1418,10 @@ VolZmap::RemovePart( int nPart)
// verifico lo stato
if ( m_nStatus != OK)
return false ;
// Se è definita una sola griglia non sono definibili le parti, errore
// Se è definita una sola griglia non sono definibili le parti, errore
if ( m_nMapNum == 1)
return false ;
// Se il numero di componenti è indefinito, lo ricalcolo
// Se il numero di componenti è indefinito, lo ricalcolo
if ( m_nConnectedCompoCount == - 1)
CheckMapConnection() ;
// Se non vi sono componenti, abbiamo finito
@@ -1452,7 +1463,7 @@ VolZmap::GetPartMinDistFromPoint( const Point3d& ptP) const
// Verifico lo stato e che siano definibili le componenti connesse
if ( m_nStatus != OK || m_nMapNum == 1)
return - 1 ;
// Se il numero di componenti è indefinito, lo ricalcolo
// Se il numero di componenti è indefinito, lo ricalcolo
if ( m_nConnectedCompoCount == -1)
const_cast<VolZmap*>( this)->CheckMapConnection() ;
// Se non vi sono componenti, abbiamo finito
@@ -1485,7 +1496,7 @@ VolZmap::GetPartMinDistFromPoint( const Point3d& ptP) const
swap( ptEn.y, ptEn.z) ;
swap( ptEn.x, ptEn.z) ;
}
// Calcolo la distanza del punto dal segmento corrente. Se è minore della minima distanza aggiorno quest'ultima
// Calcolo la distanza del punto dal segmento corrente. Se è minore della minima distanza aggiorno quest'ultima
// e la corrispondente componente connessa di minima distanza con la distanza e la componente connessa correnti.
double dDist ;
DistPointLine DistCalc( ptPL, ptSt, ptEn) ;
@@ -1520,14 +1531,14 @@ VolZmap::AddSurfTm( const ISurfTriMesh* pStm)
// ciclo sulle griglie
bool bCompleted = true ;
for ( int g = 0 ; g < m_nMapNum ; ++ g) {
for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) {
// definisco dei sistemi di riferimento ausiliari
Frame3d frMapFrame ;
if ( g == 0)
if ( nG == 0)
frMapFrame = m_MapFrame ;
else if ( g == 1)
else if ( nG == 1)
frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ;
else if ( g == 2)
else if ( nG == 2)
frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ;
// oggetto per calcolo massivo intersezioni
@@ -1538,33 +1549,33 @@ VolZmap::AddSurfTm( const ISurfTriMesh* pStm)
vector<future<bool>> vRes ;
vRes.resize( nThreadMax) ;
// se dimensione griglia in X maggiore di dimensione Y
if ( m_nNx[g] > m_nNy[g]) {
int nDexNum = m_nNx[g] / nThreadMax ;
int nRemainder = m_nNx[g] % nThreadMax ;
if ( m_nNx[nG] > m_nNy[nG]) {
int nDexNum = m_nNx[nG] / nThreadMax ;
int nRemainder = m_nNx[nG] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, g,
nInfI, nSupI, 0, m_nNy[g], ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG,
nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
}
}
// se dimensione griglia in Y maggiore di dimensione X
else {
int nDexNum = m_nNy[g] / nThreadMax ;
int nRemainder = m_nNy[g] % nThreadMax ;
int nDexNum = m_nNy[nG] / nThreadMax ;
int nRemainder = m_nNy[nG] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, g,
0, m_nNx[g], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
vRes[nThread] = async( launch::async, &VolZmap::AddMapPart, this, nG,
0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
}
}
@@ -1589,107 +1600,285 @@ VolZmap::AddSurfTm( const ISurfTriMesh* pStm)
//----------------------------------------------------------------------------
bool
VolZmap::MakeUniform( double dToler)
VolZmap::SubtractSurfTm( const ISurfTriMesh* pStm)
{
// controllo validità dello Zmap
if ( ! IsValid())
// controllo sulla superficie
double dVol ;
if ( pStm == nullptr || ! pStm->IsValid() || ! pStm->IsClosed() ||
! pStm->GetVolume( dVol) || dVol < 0)
return false ;
// la tolleranza deve essere minore dello step
dToler = min( dToler, 0.95 * m_dStep) ;
// creo lo Zmpa che andrà a sostituire il corrente
PtrOwner<VolZmap> pOldVolZmap( CloneBasicVolZmap( this)) ;
if ( IsNull( pOldVolZmap))
// controllo se il Box3d della superficie si interseca con il Box3d dello Zmap corrente
BBox3d BBox_stm, BBox_curr ;
if ( ! pStm->GetLocalBBox( BBox_stm) || ! GetLocalBBox( BBox_curr))
return false ;
BBox3d BBox_inters ;
if ( BBox_stm.FindIntersection( BBox_curr, BBox_inters) && BBox_inters.IsEmpty())
return true ; // se non ci sono intersezioni, la superficie non influenza lo Zmap
Vector3d vtLen = BBox_curr.GetMax() - BBox_curr.GetMin() ; // dimensione massima dello spillone
// ciclo sulle griglie
for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) {
// salvo lo Zmap prima di modificare gli spilloni
PtrOwner<VolZmap> pVolZMapCurrGrid( CloneBasicVolZmap( this)) ;
if ( IsNull( pVolZMapCurrGrid))
return false ;
// ciclo sul numero di dexel presenti
for ( int nDex = 0 ; nDex < int( m_Values[nGrid].size()) ; ++ nDex) {
// se il dexel corrente non ha sotto-intervalli passo al successivo
if ( int( m_Values[nGrid][nDex].size()) == 0)
continue ;
// indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// salvo le informazioni dei sotto-intervalli del dexel corrente
vector<Data> vInfo ;
for ( int nExtr = 0 ; nExtr < int( m_Values[nGrid][nDex].size()) ; ++ nExtr)
vInfo.push_back( m_Values[nGrid][nDex][nExtr]) ;
// per ogni sotto-intervallo, estendo a destra e a sinistra della tolleranza
int nSub_intervals = int( vInfo.size()) ;
// scorro gli intervalli
for ( int nInfo = 0 ; nInfo < int( pVolZMapCurrGrid->m_Values[nGrid][nDex].size()) ; ++ nInfo) {
// estremo inferiore
if ( vInfo[nInfo].dMin - dToler > m_dMinZ[nGrid]) {
AddIntervals( nGrid, nI, nJ,
vInfo[nInfo].dMin - dToler,
vInfo[nInfo].dMin + dToler,
vInfo[nInfo].vtMinN, vInfo[nInfo].vtMinN, vInfo[nInfo].nToolMin,
true) ;
// se si sono uniti degli intervalli, potrei dover aggiungere degli spilloni nelle altre due
// direzioni nel voxel corrispondente
if ( IsTriDexel() && dToler > 0.5 * m_dStep - EPS_SMALL &&
nSub_intervals != int( m_Values[nGrid][nDex].size())) {
nSub_intervals = int( m_Values[nGrid][nDex].size()) ; // aggiorno gli intervalli correnti
// l'intervallo corrente si è unito con il precedente...
AddMissingIntervalsInVoxel( pOldVolZmap, nGrid, nI, nJ, vInfo[nInfo].dMin, dToler,
vInfo[nInfo].vtMinN, vInfo[nInfo].vtMinN,
vInfo[nInfo].nToolMin) ;
}
}
// estremo superiore
if ( vInfo[nInfo].dMax + dToler < m_dMaxZ[nGrid]) {
AddIntervals( nGrid, nI, nJ,
vInfo[nInfo].dMax - dToler,
vInfo[nInfo].dMax + dToler,
vInfo[nInfo].vtMaxN, vInfo[nInfo].vtMaxN, vInfo[nInfo].nToolMax,
true) ;
if ( IsTriDexel() && dToler > 0.5 * m_dStep - EPS_SMALL &&
nSub_intervals != int( m_Values[nGrid][nDex].size())) {
nSub_intervals = int( m_Values[nGrid][nDex].size()) ; // aggiorno gli intervalli correnti
AddMissingIntervalsInVoxel( pOldVolZmap, nGrid, nI, nJ, vInfo[nInfo].dMax, dToler,
vInfo[nInfo].vtMaxN, vInfo[nInfo].vtMaxN,
vInfo[nInfo].nToolMax) ;
}
}
bool bCompleted = true ;
for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) {
// definisco dei sistemi di riferimento ausiliari
Frame3d frMapFrame ;
if ( nG == 0)
frMapFrame = m_MapFrame ;
else if ( nG == 1)
frMapFrame.Set( m_MapFrame.Orig(), Y_AX, Z_AX, X_AX) ;
else if ( nG == 2)
frMapFrame.Set( m_MapFrame.Orig(), Z_AX, X_AX, Y_AX) ;
// oggetto per calcolo massivo intersezioni
IntersParLinesSurfTm intPLSTM( frMapFrame, *pStm) ;
// numero massimo di thread
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
vector<future<bool>> vRes ;
vRes.resize( nThreadMax) ;
// se dimensione griglia in X maggiore di dimensione Y
if ( m_nNx[nG] > m_nNy[nG]) {
int nDexNum = m_nNx[nG] / nThreadMax ;
int nRemainder = m_nNx[nG] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG,
nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
}
// per ogni sotto-intervallo ricavato fino ad ora, restringo della tolleranza
// ( NB. avendo aggiunto intervalli, il dexel può modificare la sua struttura interna )
for ( int nInfo = 0 ; nInfo < int( m_Values[nGrid][nDex].size()) ; ++ nInfo) {
// ( NB. la rimozione di un intervallo ora va definita per intervalli a destra e a sinistra,
// altrimenti rimuovo parti in eccesso )
if ( ! pVolZMapCurrGrid->m_Values[nGrid][nDex].empty()) {
if ( nInfo != 0 ||
pVolZMapCurrGrid->m_Values[nGrid][nDex][0].dMin - dToler > m_dMinZ[nGrid])
m_Values[nGrid][nDex][nInfo].dMin += dToler ;
if ( nInfo != int( m_Values[nGrid][nDex].size()) - 1 ||
pVolZMapCurrGrid->m_Values[nGrid][nDex].back().dMax + dToler < m_dMaxZ[nGrid])
m_Values[nGrid][nDex][nInfo].dMax -= dToler ;
}
// se dimensione griglia in Y maggiore di dimensione X
else {
int nDexNum = m_nNy[nG] / nThreadMax ;
int nRemainder = m_nNy[nG] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
// aggiungo le parti interessate alla mappa
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::SubtractMapPart, this, nG,
0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( m_MapFrame.Orig()),
ref( *pStm), ref( intPLSTM)) ;
}
}
// ciclo per attendere che tutti gli async abbiano terminato.
int nTerminated = 0 ;
while ( nTerminated < nThreadMax) {
for ( int nL = 0 ; nL < nThreadMax ; ++ nL) {
// async terminato
if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) {
++ nTerminated ;
bCompleted = bCompleted && vRes[nL].get() ;
}
}
}
if ( ! bCompleted)
return false ;
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::MakeUniform( double dToler, bool bIsExtensionFirst, int nToolNum)
{
// Controllo validità dello Zmap
if ( ! IsValid())
return false ;
// creo lo ZMap per i riferimenti degli intervalli sulle griglie
PtrOwner<VolZmap> pZMapCopy( CloneBasicVolZmap( this)) ;
if ( IsNull( pZMapCopy) || ! pZMapCopy->IsValid())
return false ;
// creo uno ZMap per gli intervalli da aggiungere o da rimuovere
PtrOwner<VolZmap> pZMapExtra( CreateBasicVolZmap()) ;
if ( IsNull( pZMapExtra) ||
! pZMapExtra->CreateEmpty( m_MapFrame.Orig(), m_dMaxZ[1] - m_dMinZ[1],
m_dMaxZ[2] - m_dMinZ[2], m_dMaxZ[0] - m_dMinZ[0],
m_dStep, IsTriDexel()))
return false ;
// Dovendo effettuare estensioni, allargo gli ingobri nelle direzioni principali
m_dMinZ[0] -= dToler ;
m_dMinZ[1] -= dToler ;
m_dMinZ[2] -= dToler ;
m_dMaxZ[0] += dToler ;
m_dMaxZ[1] += dToler ;
m_dMaxZ[2] += dToler ;
// NB. Tutti i parametri sono sempre presi dalla Copia dello ZMap corrente
// Ciclo sulle griglie
for ( int nGrid = 0 ; nGrid < pZMapCopy->m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti nella Copia
for ( int nDex = 0 ; nDex < int( pZMapCopy->m_Values[nGrid].size()) ; ++ nDex) {
// Se il dexel corrente non ha sotto-intervalli passo al successivo
if ( pZMapCopy->m_Values[nGrid][nDex].empty())
continue ;
// Indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// Recupero il numero di intervalli presenti nel Dexel corrente
int nIntervals = int( pZMapCopy->m_Values[nGrid][nDex].size()) ;
// Scorro gli intervalli presenti
for ( int nInfo = 0 ; nInfo < int( pZMapCopy->m_Values[nGrid][nDex].size()) ; ++ nInfo) {
// Recupero l'intervallo corrente
Data& Interval = pZMapCopy->m_Values[nGrid][nDex][nInfo] ;
// --- Se richiesta prima estensione
if ( bIsExtensionFirst) {
// *** Estremo inferiore -> Intervallo : [ dMin - dToler, dMin + dToler ]
// Aggiungo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy)
AddIntervals( nGrid, nI, nJ, Interval.dMin - dToler, Interval.dMin + dToler,
Interval.vtMinN, Interval.vtMinN, nToolNum, true) ;
// Se si sono uniti degli intervalli, potrei dover aggiungere degli spilloni nelle altre due direzioni
if ( IsTriDexel() && nIntervals != int( m_Values[nGrid][nDex].size())) {
// Aggiorno gli intervalli correnti ( dato che il corrente si è unito al precedente)
// ( lascio invariato lo ZMapCopy)
nIntervals = int( m_Values[nGrid][nDex].size()) ;
pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ,
pZMapCopy->m_Values[nGrid][nDex][nInfo-1].dMax,
Interval.dMin, dToler, true,
nToolNum, V_INVALID, V_INVALID) ;
}
// *** Estremo superiore -> Intervallo : [ dMax - dToler, dMax + dToler ]
// Aggiungo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy)
AddIntervals( nGrid, nI, nJ, Interval.dMax - dToler, Interval.dMax + dToler,
Interval.vtMaxN, Interval.vtMaxN, nToolNum, true) ;
// Se si sono uniti degli intervalli, potrei dover aggiungere degli spilloni nelle altre due direzioni
if ( IsTriDexel() && nIntervals != int( m_Values[nGrid][nDex].size())) {
// Aggiorno gli intervalli correnti ( dato che il corrente si è unito al successivo)
// ( lascio invariato lo ZMapCopy)
nIntervals = int( m_Values[nGrid][nDex].size()) ;
pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ,
Interval.dMax,
pZMapCopy->m_Values[nGrid][nDex][nInfo+1].dMin, dToler, true,
nToolNum, V_INVALID, V_INVALID) ;
}
}
// --- Se richiesta prima restrizione
else {
// *** Estremo inferiore -> Intervallo : [ dMin - dToler, dMin + dToler ]
// Sottraggo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy)
SubtractIntervals( nGrid, nI, nJ, Interval.dMin - dToler, Interval.dMin + dToler,
Interval.vtMinN, Interval.vtMinN, nToolNum, true) ;
// Se l'intervallo si è annullato, potrei dover sottrarre degli spilloni nelle altre due direzioni
if ( IsTriDexel() && nIntervals != int( m_Values[nGrid][nDex].size())) {
// Aggiorno gli intervalli correnti ( lascio invariato lo ZMapCopy)
nIntervals = int( m_Values[nGrid][nDex].size()) ;
pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ,
Interval.dMin,
Interval.dMax, dToler, true,
Tool::UNDEF, V_INVALID, V_INVALID) ;
}
// *** Estremo superiore -> Intervallo : [ dMax - dToler, dMax + dToler ]
// Sottraggo l'intervallo nello Zmap corrente ( lascio invariato lo ZMapCopy)
SubtractIntervals( nGrid, nI, nJ, Interval.dMax - dToler, Interval.dMax + dToler,
Interval.vtMaxN, Interval.vtMaxN, nToolNum, true) ;
// Se l'intervallo si è annullato, potrei dover sottrarre degli spilloni nelle altre due direzioni
if ( IsTriDexel() && nIntervals != int( m_Values[nGrid][nDex].size())) {
// Aggiorno gli intervalli correnti ( lascio invariato lo ZMapCopy)
nIntervals = int( m_Values[nGrid][nDex].size()) ;
pZMapExtra->UniformIntervalsInVoxel( nGrid, nI, nJ,
Interval.dMin,
Interval.dMax, dToler, true,
Tool::UNDEF, V_INVALID, V_INVALID) ;
}
}
}
}
}
// Ciclo sulle griglie ( uso lo Zmap Corrente, lascio invariato pZMapCopy)
for ( int nGrid = 0 ; nGrid < m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti
for ( int nDex = 0 ; nDex < int( m_Values[nGrid].size()) ; ++ nDex) {
// Se l'intervallo è vuoto, non faccio nulla
if ( m_Values[nGrid][nDex].empty())
continue ;
// Per ogni intervallo ricavato fino ad ora, restringo della tolleranza
for ( int nInfo = 0 ; nInfo < int( m_Values[nGrid][nDex].size()) ; ++ nInfo) {
// --- Se richiesta prima estensione
if ( bIsExtensionFirst) {
m_Values[nGrid][nDex][nInfo].dMin += dToler ;
m_Values[nGrid][nDex][nInfo].dMax -= dToler ;
}
// --- Se richiesta prima restrizione
else {
m_Values[nGrid][nDex][nInfo].dMin -= dToler ;
m_Values[nGrid][nDex][nInfo].dMax += dToler ;
}
// Definisco il colore
for ( int nOrigInfo = 0 ; nOrigInfo < int( pZMapCopy->m_Values[nGrid][nDex].size()) ; ++ nOrigInfo) {
if ( pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].dMin - m_Values[nGrid][nDex][nInfo].dMin < EPS_SMALL)
m_Values[nGrid][nDex][nInfo].nToolMin = pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].nToolMin ;
if ( pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].dMax - m_Values[nGrid][nDex][nInfo].dMax < EPS_SMALL)
m_Values[nGrid][nDex][nInfo].nToolMax = pZMapCopy->m_Values[nGrid][nDex][nOrigInfo].nToolMax ;
}
}
}
}
// Gestisco le parti Extra ricavate
// Ciclo sulle griglie ( uso lo ZmapExtra, lascio invariato pZMapCopy)
for ( int nGrid = 0 ; nGrid < pZMapExtra->m_nMapNum ; ++ nGrid) {
// Ciclo sul numero di dexel presenti
for ( int nDex = 0 ; nDex < int( pZMapExtra->m_Values[nGrid].size()) ; ++ nDex) {
// Se l'intervallo è vuoto, non faccio nulla
if ( pZMapExtra->m_Values[nGrid][nDex].empty())
continue ;
// Indici del dexel
int nI = nDex % m_nNx[nGrid] ;
int nJ = nDex / m_nNx[nGrid] ;
// Per ogni intervallo ricavato fino ad ora...
for ( int nInfo = 0 ; nInfo < int( pZMapExtra->m_Values[nGrid][nDex].size()) ; ++ nInfo) {
double dMin = pZMapExtra->m_Values[nGrid][nDex][nInfo].dMin ;
double dMax = pZMapExtra->m_Values[nGrid][nDex][nInfo].dMax ;
Vector3d vtNMin = pZMapExtra->m_Values[nGrid][nDex][nInfo].vtMinN ;
Vector3d vtNMax = pZMapExtra->m_Values[nGrid][nDex][nInfo].vtMaxN ;
// --- Se richiesta prima estensione
if ( bIsExtensionFirst) {
// ... aggiungo i contributi
AddIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, true) ;
}
// --- Se richiesta prima restrizione
else {
// ... sottraggo i contributi
SubtractIntervals( nGrid, nI, nJ, dMin, dMax, vtNMin, vtNMax, nToolNum, true) ;
}
}
}
}
// Restringo gli ingombri espensi in precedenza
m_dMinZ[0] += dToler ;
m_dMinZ[1] += dToler ;
m_dMinZ[2] += dToler ;
m_dMaxZ[0] -= dToler ;
m_dMaxZ[1] -= dToler ;
m_dMaxZ[2] -= dToler ;
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::SetToModifyDexelBlocks( int nGrid, int nDex, int nInt)
{
// Controllo sulla validità della griglia
// Controllo sulla validità della griglia
if ( nGrid < 0 || nGrid > 2)
return false ;
// Controllo sulla validità del dexel
// Controllo sulla validità del dexel
if ( nDex <= - 1 || nDex >= int( m_Values[nGrid].size()))
return false ;
// Controllo sulla validità dell'intervallo
// Controllo sulla validità dell'intervallo
if ( nInt <= - 1 || nInt >= int( m_Values[nGrid][nDex].size()))
return false ;
@@ -1841,8 +2030,6 @@ VolZmap::SetToModifyDexelBlocks( int nGrid, int nDex, int nInt)
bool
VolZmap::IsMapPartABox( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, double& dMinZ, double& dMaxZ)
{
if ( ! m_bIsBox)
return true ;
dMinZ = m_dMaxZ[nMap] ;
dMaxZ = m_dMinZ[nMap] ;
for ( int i = nInfI ; i < nSupI ; ++ i) {
@@ -1871,7 +2058,8 @@ VolZmap::IsMapPartABox( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, do
bool
VolZmap::IsBox( void)
{
// Se non tridexel, non posso stabilire con il metodo seguente se è un box
// Se non tridexel, non posso stabilire con il metodo seguente se è un box
// Verifico solo che gli spilloni di una mappa o sono nulli o hanno gli stessi estremi
if ( m_nMapNum == 1)
return false ;
// Numero massimo di thread per il calcolo parallelo.
@@ -1880,13 +2068,16 @@ VolZmap::IsBox( void)
if ( nThreadMax == 1) {
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
double dMinZ, dMaxZ ;
if ( ! IsMapPartABox( nMap, 0, m_nNx[nMap], 0, m_nNy[nMap], dMinZ, dMaxZ))
if ( ! IsMapPartABox( nMap, 0, m_nNx[nMap], 0, m_nNy[nMap], dMinZ, dMaxZ)) {
m_bIsBox = false ;
return false ;
}
}
m_bIsBox = true ;
return true ;
}
// Caso di più thread
// Caso di più thread
m_bIsBox = true ;
for ( int nMap = 0 ; nMap < m_nMapNum ; ++ nMap) {
vector< future<bool>> vRes ;
@@ -1931,15 +2122,16 @@ VolZmap::IsBox( void)
}
}
}
// Se uno dei thread trova che la sua porzione non è un box, non lo può essere il solido intero.
// Se uno dei thread trova che la sua porzione non è un box, non lo può essere il solido intero.
if ( ! m_bIsBox)
return false ;
// Controllo che gli estremi Z siano uguali.
for ( int nT = 1 ; nT < nThreadMax ; ++ nT) {
if ( abs( vMinZ[nT] - vMinZ[0]) > EPS_SMALL)
return false ;
if ( abs( vMaxZ[nT] - vMaxZ[0]) > EPS_SMALL)
if ( abs( vMinZ[nT] - vMinZ[0]) > EPS_SMALL ||
abs( vMaxZ[nT] - vMaxZ[0]) > EPS_SMALL) {
m_bIsBox = false ;
return false ;
}
}
}
@@ -1967,7 +2159,7 @@ VolZmap::Cut( const Plane3d& plPlane)
}
// Ciclo sui dexel della mappa
for ( int nD = 0 ; nD < int( m_Values[nMap].size()) ; ++ nD) {
// Se spillone già vuoto, passo al successivo
// Se spillone già vuoto, passo al successivo
if ( m_Values[nMap][nD].empty())
continue ;
// Indici di spillone
@@ -1983,20 +2175,20 @@ VolZmap::Cut( const Plane3d& plPlane)
double dEnDist = DistPointPlane( ptEn, plMyPlane) ;
// Se entrambi sotto il piano
if ( dStDist < EPS_SMALL && dEnDist < EPS_SMALL)
// Non devo fare alcunché
// Non devo fare alcunché
;
// se altrimenti entrambi gli estremi sono oltre il piano
else if ( dStDist > -EPS_SMALL && dEnDist > -EPS_SMALL) {
// Si elimina tutto
SubtractIntervals( nMap, nI, nJ, dMin, dMax, V_NULL, V_NULL, 1) ;
}
// se altrimenti è da tenere il punto iniziale
// se altrimenti è da tenere il punto iniziale
else if ( dStDist < 0) {
// Si elimina la parte tra intersezione e punto finale
double dInt = dMin + ( dMax - dMin) * abs( dStDist) / ( abs( dStDist) + abs( dEnDist)) ;
SubtractIntervals( nMap, nI, nJ, dInt, dMax, plMyPlane.GetVersN(), V_NULL, 1) ;
}
// se altrimenti è da tenere il punto finale
// se altrimenti è da tenere il punto finale
else if (dEnDist < 0) {
// Si elimina la parte tra punto iniziale e intersezione
double dInt = dMin + ( dMax - dMin) * abs( dStDist) / ( abs( dStDist) + abs( dEnDist)) ;
@@ -2086,7 +2278,7 @@ VolZmap::Compact( void)
}
}
// Se non vi è materiale
// Se non vi è materiale
if ( ! bNotEmptyGrid) {
m_nStatus = TO_VERIFY ;
m_nNumBlock = 0 ;
@@ -2108,8 +2300,8 @@ VolZmap::Compact( void)
double dNewOy = nMinJ[0] * m_dStep ;
double dNewOz = nMinJ[1] * m_dStep ;
// Porto i dexel nel nuovo sistema di riferimento e le quote estreme Z. Non c'è bisogno di trasformare le normali,
// infatti i sistemi di riferimento in gioco differiscono al più per una traslazione.
// Porto i dexel nel nuovo sistema di riferimento e le quote estreme Z. Non c'è bisogno di trasformare le normali,
// infatti i sistemi di riferimento in gioco differiscono al più per una traslazione.
for ( int nMap = 0 ; nMap < int( m_nMapNum) ; ++ nMap) {
// Quote estreme Z
switch ( nMap) {
+90 -17
View File
@@ -18,10 +18,15 @@
#include "Tool.h"
#include "/EgtDev/Include/EGkVolZmap.h"
#include "/EgtDev/Include/EGkIntersLineVolZmap.h"
#include "/EgtDev/Include/EGkSurfTriMesh.h"
#include <unordered_map>
#include <stack>
#include <mutex>
#include <atomic>
#include <tuple>
typedef std::pair<Point3d, Vector3d> PNTVEC3D ;
typedef std::vector<PNTVEC3D> PNTVEC3DVECTOR ; // vettore di intersezioni punto, vettore, tipo superficie
// ------------------------- FORWARD -------------------------------------------------------------
class IntersParLinesSurfTm ;
@@ -80,10 +85,11 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool Create( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex) override ;
bool CreateEmpty( const Point3d& ptO, double dDimX, double dDimY, double dDimZ, double dStep, bool bTriDex) override ;
bool CreateFromFlatRegion( const ISurfFlatRegion& Surf, double dDimZ, double dStep, bool bTriDex) override ;
bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex) override ;
bool CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox = 0) override ;
int GetBlockCount( void) const override ;
int GetBlockUpdatingCounter( int nBlock) const override ;
bool GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const override ;
ISurfTriMesh* GetSurfTriMesh( void) const override ;
bool GetEdges( ICURVEPOVECTOR& vpCurve) const override ;
bool GetVolume( double& dVol) const override ;
bool IsTriDexel( void) const override
@@ -93,7 +99,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW
{ return m_nDexVoxRatio ; }
bool ChangeResolution( int nDexVoxRatio) override ;
void SetShowEdges( bool bShow) override
{ m_bShowEdges = bShow ; // qui è necessario far ricreare la grafica
{ m_bShowEdges = bShow ; // qui è necessario far ricreare la grafica
m_OGrMgr.Clear() ; }
bool GetShowEdges( void) const override
{ return m_bShowEdges ; }
@@ -144,7 +150,9 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool RemovePart( int nPart) override ;
int GetPartMinDistFromPoint( const Point3d& ptP) const override ;
bool AddSurfTm( const ISurfTriMesh* pStm) override ;
bool MakeUniform( double dToler) override ;
bool SubtractSurfTm( const ISurfTriMesh* pStm) override ;
bool MakeUniform( double dToler, bool bIsExtensionFirst, int nToolNum) override ;
bool Offset( double dOffs, int nType) override ;
public : // IGeoObjRW
int GetNgeId( void) const override ;
@@ -165,6 +173,8 @@ class VolZmap : public IVolZmap, public IGeoObjRW
return *this ; }
bool GetLineIntersection( const Point3d& ptP, const Vector3d& vtD, ILZIVECTOR& vIntersInfo) const ;
bool GetPlaneIntersection( const Plane3d& plPlane, ICURVEPOVECTOR& vpLoop) const ;
bool CreateFromTriMeshOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = STMOFF_FILLET) ;
bool CreateFromTriMeshThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol, int nType = STMOFF_FILLET) ;
private :
enum CubeType { VOX_EXTERN = 1,
@@ -250,17 +260,21 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool AddIntervals( int nGrid, int nI, int nJ,
double dMin, double dMax, const Vector3d& vtNMin, const Vector3d& vtNMax,
int nToolNum, bool bSkipSwap = false) ;
bool AddMissingIntervalsInVoxel( VolZmap* VolZmapRef, int nGrid, int nI, int nJ, double dZ, double dToler,
Vector3d vtToolMin, Vector3d vtToolMax, int nToolNum) ;
bool AddSubIntervalInVoxel( VolZmap* VolZmapRef, int nGrid, int nI, int nJ, int nK, double& dMin, double& dMax,
Vector3d& vtMin, Vector3d& vtMax) ;
bool UniformIntervalsInVoxel( int nGrid, int nI, int nJ, double dZMin, double dZMax,
double dToler, bool bAdd, int nToolNum, const Vector3d& vtToolMin,
const Vector3d& vtToolMax) ;
bool ManageSubIntervalInVoxel( VolZmap* VolZmapRef, int nGrid, int nI, int nJ, int nK, double& dMin, double& dMax,
Vector3d& vtMin, Vector3d& vtMax) ;
// Spostamenti utensile
bool MillingTranslationStep( const Point3d& ptPs, const Point3d& ptPe, const Vector3d& vtD, const Vector3d& vtA) ;
bool MillingGeneralMotionStep( const Point3d& ptPs, const Vector3d& vtDs, const Vector3d& vtAs,
const Point3d& ptPe, const Vector3d& vtDe, const Vector3d& vtAe) ;
bool SelectGeneralMotion( int nGrid, const Point3d& ptPs, const Point3d& ptPe, const Vector3d& vtLs, const Vector3d& vtLe, int n5AxisType) ;
bool SelectMotion( int nGrid, const Point3d& ptLs, const Point3d& ptLe, const Vector3d& vtL, const Vector3d& vtAL) ;
bool InitializePointsAndVectors( const Point3d& ptPs, const Point3d& ptPe, const Vector3d& vtDs, const Vector3d& vtAs,
Point3d ptLs[3], Point3d ptLe[3], Vector3d vtLs[3], Vector3d vtALs[3]) ;
bool InitializeAuxPoints( Point3d ptTop1s[3], Point3d ptTop1e[3], Point3d ptTop2s[3], Point3d ptTop2e[3],
Point3d ptBottom1s[3], Point3d ptBottom1e[3], Point3d ptBottom2s[3], Point3d ptBottom2e[3]) ;
// SOTTRAZIONI
// UTENSILI
// Asse di simmetria parallelo a Z
@@ -288,11 +302,16 @@ class VolZmap : public IVolZmap, public IGeoObjRW
bool Conus_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir) ;
bool Conus_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir) ;
bool Mrt_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ;
bool Mrt_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ; // E' in realtà un Perp
bool Mrt_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ; // E' in realt un Perp
bool Chs_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ;
bool Chs_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ; // E' in realtà un Perp
bool Chs_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir, const Vector3d& vtAux) ; // E' in realt un Perp
bool GenTool_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir) ;
bool GenTool_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir) ;
// lavorazioni a 5 assi
bool GenTool_5AxisMilling(int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtLs, const Vector3d& vtLe, int nToolNum, int n5AxisType = ACROSS) ;
bool Cyl_5AxisMilling(int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtLs, const Vector3d& vtLe, int nToolNum, double dHeightCorr = 0, int n5AxisType = ACROSS) ;
bool CylBall_5AxisMilling(int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtLs, const Vector3d& vtLe, int nToolNum, int n5AxisType = ACROSS) ;
bool Conus_5AxisMilling(int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtLs, const Vector3d& vtLe, int nToolNum, int n5AxisType = ACROSS) ;
// COMPONENTI
// Asse di simmetria diretto come l'asse Z
@@ -311,7 +330,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW
const Vector3d& vtArcNormMaxR, const Vector3d& vtArcNormMinR, int nToolNum) ;
bool CompPar_ZMilling( int nGrid, double dLenX, double dLenY, double dLenZ,
const Point3d& ptS, const Point3d& ptE,
const Vector3d& vtToolDir, const Vector3d& vtAux, int nToolNum) ; // E' in realtà MillingPerp
const Vector3d& vtToolDir, const Vector3d& vtAux, int nToolNum) ; // E' in realt MillingPerp
// Asse di simmetria con orientazione generica
bool CompCyl_Drilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDir,
double dHei, double dRad, bool bTapB, bool bTapT, int nToolNum) ;
@@ -327,7 +346,15 @@ class VolZmap : public IVolZmap, public IGeoObjRW
const Vector3d& vtArcNormMaxR, const Vector3d& vtArcNormMinR, int nToolNum) ;
bool CompPar_Milling( int nGrid, double dLenX, double dLenY, double dLenZ,
const Point3d& ptS, const Point3d& ptE,
const Vector3d& vtToolDir, const Vector3d& vtAux, int nToolNum) ; // E' in realtà MillingPerp
const Vector3d& vtToolDir, const Vector3d& vtAux, int nToolNum) ; // E' in realtà MillingPerp
// lavorazioni a 5 assi
bool Comp_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtLs, const Vector3d& vtLe,
double dHeight, double dMaxRad, double dMinRad, int nToolNum, int n5AxisType) ;
bool CompCyl_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtLs, const Vector3d& vtLe,
double dHeight, double dRadius, int nToolNum, int n5AxisType) ;
bool CompConus_5AxisMilling( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtToolDirS, const Vector3d& vtToolDirE, double dHei, double dMaxRad, double dMinRad,
bool bTapB, bool bTapT, const Vector3d& vtArcNormMaxR, const Vector3d& vtArcNormMinR, int nToolNum, int n5AxisType) ;
// Generica traslazione sfera
bool CompBall_Milling( int nGrid, const Point3d& ptS, const Point3d& ptE, double dRad, int nToolNum) ;
// Additivi
@@ -341,7 +368,7 @@ class VolZmap : public IVolZmap, public IGeoObjRW
// BBox per utensili e solidi semplici con movimenti di traslazione
inline bool TestToolBBox( int nGrid, const Point3d& ptP1, const Point3d& ptP2, const Vector3d& vtV,
int& nStI, int& nStJ, int& nEnI, int& nEnJ) ;
inline bool TestCompoBBox( int nGrid, const Point3d& ptP1, const Point3d& ptP2, const Vector3d& vtV,
inline bool TestCompoBBox( int nGrid, const Point3d& ptP1, const Point3d& ptP2, const Vector3d& vtV, const Vector3d& vtV2,
double dRad, double dTipRad, double dHei,
int& nStI, int& nStJ, int& nEnI, int& nEnJ) ;
inline bool TestParaBBox( int nGrid, const Point3d& ptS, const Point3d& ptE, const Vector3d& vtD, const Vector3d& vtA,
@@ -432,17 +459,57 @@ class VolZmap : public IVolZmap, public IGeoObjRW
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
bool AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
bool SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM) ;
// Funzioni per Offset di superfici
bool InitVolZMapOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ;
bool InitVolZMapThickeningOffset( const CISURFTMPVECTOR& vSurf, double dOffs, double dTol) ;
bool UpdateVolZMapByOpenSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ;
bool UpdateVolZMapByOpenSurfSharpedOffset( const ISurfTriMesh* Surf, int nType, double dOffs, double dTol) ;
bool UpdateVolZMapByClosedSurfFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ;
bool UpdateVolZMapByClosedSurfSharpedOffset( const ISurfTriMesh* Surf, int nType, double dOffs, double dTol) ;
bool UpdateVolZMapBySurfThickeningFilletOffset( const ISurfTriMesh* Surf, double dOffs, double dTol) ;
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, 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 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) ;
private :
enum Status { ERR = 0, OK = 1, TO_VERIFY = 2} ;
enum Shape { GENERIC = 0, BOX = 1, EXTRUSION = 2} ;
enum Move5Axis {
ALONG_CONVEX = 0 ,
ALONG_CONCAVE = 1 ,
ACROSS = 2 ,
NO_BASE_INTERS = 3} ;
enum Status {
ERR = 0,
OK = 1,
TO_VERIFY = 2} ;
enum Shape {
GENERIC = 0,
BOX = 1,
EXTRUSION = 2,
OFFSET = 3} ;
static const int N_MAPS = 3 ;
static const int N_VOXBLOCK = 32 ;
private :
ObjGraphicsMgr m_OGrMgr ; // gestore grafica dell'oggetto
Status m_nStatus ; // stato
int m_nTempProp[2] ; // vettore proprietà temporanee
int m_nTempProp[2] ; // vettore proprietà temporanee
double m_dTempParam[2] ; // vettore parametri temporanei
bool m_bShowEdges ; // flag di visualizzazione spigoli vivi
Frame3d m_MapFrame ; // riferimento intrinseco dello Zmap
@@ -476,8 +543,8 @@ class VolZmap : public IVolZmap, public IGeoObjRW
mutable BOOLVECTOR m_BlockToUpdate ;
mutable INTVECTOR m_BlockUpdatingCounter ;
int m_nConnectedCompoCount ; // Se == - 1 il numero di componenti non è noto
// Se >= 0 è il numero di componenti connesse
int m_nConnectedCompoCount ; // Se == - 1 il numero di componenti non è noto
// Se >= 0 è il numero di componenti connesse
mutable std::vector<VoxelContainer> m_InterBlockVox ;
mutable SharpTriaMatrix m_InterBlockOriginalSharpTria ;
@@ -500,6 +567,12 @@ class VolZmap : public IVolZmap, public IGeoObjRW
double m_dToolAngTolDeg ;
} ;
// Offset
enum {
VOLZMAP_OFFS_FILLET = 0,
VOLZMAP_OFFS_CHANFER = 1,
VOLZMAP_OFFS_EXTENDED = 2
} ;
//-----------------------------------------------------------------------------
inline VolZmap* CreateBasicVolZmap( void)
+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
+167 -56
View File
@@ -17,6 +17,7 @@
#include "CurveLine.h"
#include "VolZmap.h"
#include "GeoConst.h"
#include "/EgtDev/Include/EGkStmFromCurves.h"
#include "/EgtDev/Include/EGkIntersLineSurfTm.h"
#include "/EgtDev/Include/EgtNumUtils.h"
#include <future>
@@ -504,6 +505,8 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
nSupJ < 0 || nSupJ > m_nNy[nMap])
return false ;
double dCosSmall = sin( EPS_ANG_SMALL * DEGTORAD) ;
// Determinazione e ridimensionamento dei dexel interni alla trimesh
for ( int i = nInfI ; i < nSupI ; ++ i) {
for ( int j = nInfJ ; j < nSupJ ; ++ j) {
@@ -551,7 +554,7 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
double dCos = IntersectionResults[k].dCosDN ;
// entro nella superficie trimesh
if ( dCos < - EPS_SMALL) {
if ( dCos < - dCosSmall) {
ptIn = IntersectionResults[k].ptI ;
@@ -564,7 +567,7 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
}
// esco dalla superficie trimesh
else if ( dCos > EPS_SMALL && bInside) {
else if ( dCos > dCosSmall && bInside) {
Point3d ptOut = IntersectionResults[k].ptI ;
@@ -597,6 +600,7 @@ VolZmap::CreateMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, co
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM)
@@ -691,7 +695,100 @@ VolZmap::AddMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const
//----------------------------------------------------------------------------
bool
VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex)
VolZmap::SubtractMapPart( int nMap, int nInfI, int nSupI, int nInfJ, int nSupJ, const Vector3d& vtLen, const Point3d& ptMapOrig,
const ISurfTriMesh& Surf, IntersParLinesSurfTm& intPLSTM)
{
// controllo sui parametri
if ( nMap < 0 || nMap > 2 ||
nInfI < 0 || nInfI > m_nNx[nMap] ||
nSupI < 0 || nSupI > m_nNx[nMap] ||
nInfJ < 0 || nInfJ > m_nNy[nMap] ||
nSupJ < 0 || nSupJ > m_nNy[nMap])
return false ;
// determinazione e ridimensionamento dei dexel interni alla trimesh
for ( int i = nInfI ; i < nSupI ; ++ i) {
for ( int j = nInfJ ; j < nSupJ ; ++ j) {
// definisco la retta da intersecare con la trimesh
double dX = ( i + 0.5) * m_dStep ;
double dY = ( j + 0.5) * m_dStep ;
Point3d ptP0( dX, dY, 0) ;
// intersezioni della retta con la TriMesh
ILSIVECTOR IntersectionResults ;
intPLSTM.GetInters( ptP0, vtLen.v[(nMap+2)%3], IntersectionResults) ;
// rimuovo le intersezioni in eccesso
for ( int nI = 0 ; nI < int( IntersectionResults.size()) - 3 ; ++ nI) {
int nJ = nI + 1 ; // prima successiva
int nK = nJ + 1 ; // seconda successiva
int nT = nK + 1 ; // terza successiva
// determino i segni delle 4 intersezioni tra la linea e il trangolo della TriMesh
int nSgnI = IntersectionResults[nI].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nI].dCosDN > -EPS_SMALL ? 0 : - 1 ;
int nSgnJ = IntersectionResults[nJ].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nJ].dCosDN > -EPS_SMALL ? 0 : - 1 ;
int nSgnK = IntersectionResults[nK].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nK].dCosDN > -EPS_SMALL ? 0 : - 1 ;
int nSgnT = IntersectionResults[nT].dCosDN > EPS_SMALL ? 1 : IntersectionResults[nT].dCosDN > -EPS_SMALL ? 0 : - 1 ;
// parametri dell'intersezione sulla linea
double dUJ = IntersectionResults[nJ].dU ;
double dUK = IntersectionResults[nK].dU ;
// controllo coerenza con segni...
if ( nSgnI != 0 && nSgnI == nSgnJ &&
nSgnK != 0 && nSgnK == nSgnT &&
nSgnI == - nSgnT &&
abs( dUJ - dUK) < EPS_SMALL) {
// ... ed elimino le intersezioni in eccesso...
IntersectionResults.erase( IntersectionResults.begin() + nK) ;
IntersectionResults.erase( IntersectionResults.begin() + nJ) ;
}
}
int nInt = int( IntersectionResults.size()) ; // numero di intersezioni valide
bool bInside = false ; // Flag entrata/uscita per tratto di retta
Point3d ptIn ; Vector3d vtInN ;
// per ogni intersezione valida trovata...
for ( int k = 0 ; k < nInt ; ++ k) {
// ricavo il tipo di intersezione
int nIntType = IntersectionResults[k].nILTT ;
// se c'è intersezione
if ( nIntType != ILTT_NO) {
// ricavo il cos tra i vettori ( normale del triangolo e tangente alla retta)
double dCos = IntersectionResults[k].dCosDN ;
// se entro nella superficie trimesh...
if ( dCos < - EPS_SMALL) {
ptIn = IntersectionResults[k].ptI ; // punto di intersezione
int nT = IntersectionResults[k].nT ; // triangolo di interesse
int nF = Surf.GetFacetFromTria( nT) ; // faccia di interesse
Surf.GetFacetNormal( nF, vtInN) ;
bInside = true ; // entrata
}
// ...se esco dalla superficie trimesh ( prima sono per forza entrato)
else if ( dCos > EPS_SMALL && bInside) {
Point3d ptOut = IntersectionResults[k].ptI ; // punto di intersezione
int nT = IntersectionResults[k].nT ; // triangolo di interesse
int nF = Surf.GetFacetFromTria( nT) ; // faccia di interesse
Vector3d vtOutN ; Surf.GetFacetNormal( nF, vtOutN) ; // vettore d'uscita
// Aggiungo un tratto al dexel
SubtractIntervals( nMap, i, j,
ptIn.v[(nMap+2)%3] - ptMapOrig.v[(nMap+2)%3],
ptOut.v[(nMap+2)%3] - ptMapOrig.v[(nMap+2)%3],
- vtInN, - vtOutN, 0, true) ;
bInside = false ; // uscita
}
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------
bool
VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex, double dExtraBox)
{
// Se la superficie non è chiusa oppure orientata al contrario non ha senso continuare
double dVol ;
@@ -704,14 +801,17 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
// Determino il bounding box della TriMesh
BBox3d SurfBBox ;
Surf.GetLocalBBox( SurfBBox) ;
// Determino i punti estremi del bounding box
Point3d ptMapOrig, ptMapEnd ;
SurfBBox.GetMinMax( ptMapOrig, ptMapEnd) ;
// Il dexel se parte da un triangolo della trimesh può non trovare l'intersezione,
// quindi espandiamo il bounding box per ovviare al problema.
SurfBBox.Expand( 100 * EPS_SMALL, 100 * EPS_SMALL, 100 * EPS_SMALL) ;
if ( dExtraBox > EPS_ZERO)
SurfBBox.Expand( dExtraBox) ;
else
dExtraBox = 0 ;
// Determino i punti estremi del bounding box
Point3d ptMapOrig, ptMapEnd ;
SurfBBox.GetMinMax( ptMapOrig, ptMapEnd) ;
// Sistema di riferimento intrinseco dello Zmap
m_MapFrame.Set( ptMapOrig, Frame3d::TOP) ;
@@ -760,72 +860,83 @@ VolZmap::CreateFromTriMesh( const ISurfTriMesh& Surf, double dStep, bool bTriDex
// ciclo sulle griglie
bool bCompleted = true ;
for ( int g = 0 ; g < m_nMapNum ; ++ g) {
for ( int nG = 0 ; nG < m_nMapNum ; ++ nG) {
// Definisco dei sistemi di riferimento ausiliari
Frame3d frMapFrame ;
if ( g == 0)
if ( nG == 0)
frMapFrame = m_MapFrame ;
else if ( g == 1)
else if ( nG == 1)
frMapFrame.Set( ptMapOrig, Y_AX, Z_AX, X_AX) ;
else if ( g == 2)
else if ( nG == 2)
frMapFrame.Set( ptMapOrig, Z_AX, X_AX, Y_AX) ;
// Oggetto per calcolo massivo intersezioni
IntersParLinesSurfTm intPLSTM( frMapFrame, Surf) ;
// Numero massimo di thread
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
vector< future<bool>> vRes ;
vRes.resize( nThreadMax) ;
if ( m_nNx[g] > m_nNy[g]) {
int nDexNum = m_nNx[g] / nThreadMax ;
int nRemainder = m_nNx[g] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, g,
nInfI, nSupI, 0, m_nNy[g], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM)) ;
}
}
else {
int nDexNum = m_nNy[g] / nThreadMax ;
int nRemainder = m_nNy[g] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, g,
0, m_nNx[g], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM)) ;
}
}
// Ciclo per attendere che tutti gli async abbiano terminato.
int nTerminated = 0 ;
while ( nTerminated < nThreadMax) {
for ( int nL = 0 ; nL < nThreadMax ; ++ nL) {
// Async terminato
if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) {
++ nTerminated ;
bCompleted = bCompleted && vRes[nL].get() ;
// Standarda è multithread
constexpr bool MULTITHREAD = true ;
if ( MULTITHREAD) {
// Numero massimo di thread
int nThreadMax = max( 1, int( thread::hardware_concurrency()) - 1) ;
vector< future<bool>> vRes ;
vRes.resize( nThreadMax) ;
if ( m_nNx[nG] > m_nNy[nG]) {
int nDexNum = m_nNx[nG] / nThreadMax ;
int nRemainder = m_nNx[nG] % nThreadMax ;
int nInfI = 0 ;
int nSupI = 0 ;
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfI = nSupI ;
nSupI = nInfI + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG,
nInfI, nSupI, 0, m_nNy[nG], ref( vtLen), ref( ptMapOrig), ref( Surf), ref( intPLSTM)) ;
}
}
else {
int nDexNum = m_nNy[nG] / nThreadMax ;
int nRemainder = m_nNy[nG] % nThreadMax ;
int nInfJ = 0 ;
int nSupJ = 0 ;
for ( int nThread = 0 ; nThread < nThreadMax ; ++ nThread) {
nInfJ = nSupJ ;
nSupJ = nInfJ + ( nThread < nRemainder ? nDexNum + 1 : nDexNum) ;
vRes[nThread] = async( launch::async, &VolZmap::CreateMapPart, this, nG,
0, m_nNx[nG], nInfJ, nSupJ, ref( vtLen), ref( ptMapOrig), ref( Surf),ref( intPLSTM)) ;
}
}
// Ciclo per attendere che tutti gli async abbiano terminato.
int nTerminated = 0 ;
while ( nTerminated < nThreadMax) {
for ( int nL = 0 ; nL < nThreadMax ; ++ nL) {
// Async terminato
if ( vRes[nL].valid() && vRes[nL].wait_for( chrono::microseconds{ 1}) == future_status::ready) {
++ nTerminated ;
bCompleted = bCompleted && vRes[nL].get() ;
}
}
}
}
// !!!! NON MULTITHREAD : SOLO PER DEBUG !!!!
else {
CreateMapPart( nG, 0, m_nNx[nG], 0, m_nNy[nG], vtLen, ptMapOrig, Surf, intPLSTM) ;
}
}
// Assegno il minimo e massimo valore di Z della mappa
m_dMinZ[0] = 0 ;
m_dMaxZ[0] = vtLen.z ;
m_dMinZ[1] = 0 ;
m_dMaxZ[1] = ( bTriDex ? vtLen.x : 0) ;
m_dMinZ[2] = 0 ;
m_dMaxZ[2] = ( bTriDex ? vtLen.y : 0) ;
m_dMinZ[0] = dExtraBox ;
m_dMaxZ[0] = vtLen.z - dExtraBox ;
m_dMinZ[1] = ( bTriDex ? dExtraBox : 0) ;
m_dMaxZ[1] = ( bTriDex ? vtLen.x - dExtraBox : 0) ;
m_dMinZ[2] = ( bTriDex ? dExtraBox : 0) ;
m_dMaxZ[2] = ( bTriDex ? vtLen.y - dExtraBox : 0) ;
// Tipologia
m_nShape = ( IsBox() ? BOX : GENERIC) ;
// Con espansione non va considerato box (calcolo trimesh va in crash)
m_nShape = ( dExtraBox <= EPS_ZERO && IsBox() ? BOX : GENERIC) ;
// Aggiornamento dello stato
m_nStatus = OK ;
+64 -17
View File
@@ -19,10 +19,12 @@
#include "MC_Tables.h"
#include "PolygonPlane.h"
#include "IntersLineBox.h"
#include "SurfTriMesh.h"
#include "/EgtDev/Include/EGkIntervals.h"
#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>
@@ -571,6 +573,35 @@ VolZmap::GetBlockTriangles( int nBlock, TRIA3DEXVECTOR& vTria) const
}
}
//----------------------------------------------------------------------------
ISurfTriMesh*
VolZmap::GetSurfTriMesh( void) const
{
// controllo che lo Zmap sia valido
if ( ! IsValid())
return nullptr ;
// inizializzo la superficie
PtrOwner<SurfTriMesh> pStm( CreateBasicSurfTriMesh()) ;
if ( IsNull( pStm) || ! pStm->Init( 3, 1))
return nullptr ;
PointGrid3d VertGrid ; VertGrid.Init( 50000) ;
// ciclo lungo i blocchi dello Zmap
for ( int nB = 0 ; nB < GetBlockCount() ; ++ nB) {
TRIA3DEXVECTOR vTria ;
GetBlockTriangles( nB, vTria) ;
if ( ! pStm->AddTriaFromZMap( vTria, VertGrid))
return nullptr ;
}
// sistemo la topologia
if ( ! pStm->AdjustTopologyFromZMap())
return nullptr ;
return ( Release( pStm)) ;
}
//----------------------------------------------------------------------------
int
VolZmap::GetBlockCount( void) const
@@ -920,25 +951,41 @@ VolZmap::UpdateTripleMapGraphics( void) const
}
}
// Calcolo i triangoli sui blocchi
int nBlockUpdated = 0 ;
vector< future<bool>> vRes ;
vRes.resize( m_nNumBlock) ;
for ( int i = 0 ; i < m_nNumBlock ; ++ i) {
// Se il blocco deve essere processato
if ( m_BlockToUpdate[i]) {
// processo ...
++ nBlockUpdated ;
vRes[i] = async( launch::async, &VolZmap::ExtMarchingCubes, this, i, ref( vVoxContainerVec[i])) ;
// Standard è multithread
constexpr bool MULTITHREAD = true ;
if ( MULTITHREAD) {
// Calcolo i triangoli sui blocchi
int nBlockUpdated = 0 ;
vector< future<bool>> vRes ;
vRes.resize( m_nNumBlock) ;
for ( int i = 0 ; i < m_nNumBlock ; ++ i) {
// Se il blocco deve essere processato
if ( m_BlockToUpdate[i]) {
// processo ...
++ nBlockUpdated ;
vRes[i] = async( launch::async, &VolZmap::ExtMarchingCubes, this, i, ref( vVoxContainerVec[i])) ;
}
}
bool bOk = true ;
int nTerminated = 0 ;
while ( nTerminated < nBlockUpdated) {
for ( int i = 0 ; i < m_nNumBlock ; ++ i) {
if ( m_BlockToUpdate[i] && vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
bOk = vRes[i].get() && bOk ;
++ nTerminated ;
}
}
}
}
bool bOk = true ;
int nTerminated = 0 ;
while ( nTerminated < nBlockUpdated) {
else {
// Calcolo i triangoli sui blocchi
bool bOk = true ;
for ( int i = 0 ; i < m_nNumBlock ; ++ i) {
if ( m_BlockToUpdate[i] && vRes[i].valid() && vRes[i].wait_for( chrono::nanoseconds{ 1}) == future_status::ready) {
bOk = vRes[i].get() && bOk ;
++ nTerminated ;
// Se il blocco deve essere processato
if ( m_BlockToUpdate[i]) {
// processo ...
bOk = ExtMarchingCubes( i, vVoxContainerVec[i]) && bOk ;
}
}
}
@@ -1142,7 +1189,7 @@ VolZmap::ExtMarchingCubes( int nBlock, VoxelContainer& vVox) const
}
// Controllo se il voxel ha una sola faccia che giace in un piano canonico e quindi ha gestione speciale
if ( m_nShape != BOX) {
if ( m_nShape != BOX && m_nShape != OFFSET) {
// Faccia XY normale Z+
if ( nIndex == 15) {
int nTool ; double dPos ;
+2806
View File
File diff suppressed because it is too large Load Diff
+1860 -432
View File
File diff suppressed because it is too large Load Diff
+189 -172
View File
@@ -21,11 +21,12 @@
#include "Voronoi.h"
#include "/EgtDev/Include/EGkDistPointCurve.h"
#include "/EgtDev/Include/EGkChainCurves.h"
#include "/EgtDev/Extern/vroni/Include/vroni_object.h"
using namespace std ;
//----------------------------------------------------------------------------
Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd)
Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd)
: m_vroni( nullptr), m_nBound( VORONOI_STD_BOUND), m_bVDComputed( false), m_bAllowAdd( true)
{
// tento di aggiungere la curva
@@ -35,7 +36,7 @@ Voronoi::Voronoi( const ICurve* pCrv, bool bAllowAdd)
}
//----------------------------------------------------------------------------
Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd)
Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd)
: m_vroni( nullptr), m_nBound( VORONOI_STD_BOUND), m_bVDComputed( false), m_bAllowAdd( true)
{
// tento di aggiungere la superficie
@@ -45,16 +46,16 @@ Voronoi::Voronoi( const ISurfFlatRegion* pSfr, bool bAllowAdd)
}
//----------------------------------------------------------------------------
Voronoi::~Voronoi( void)
Voronoi::~Voronoi( void)
{
Clear() ;
}
//----------------------------------------------------------------------------
bool
Voronoi::Clear( void)
Voronoi::Clear( void)
{
// pulizia oggetto vroni
// pulizia oggetto vroni
if ( m_vroni != nullptr)
delete m_vroni ;
m_vroni = nullptr ;
@@ -72,7 +73,7 @@ Voronoi::Clear( void)
//----------------------------------------------------------------------------
bool
Voronoi::AddCurve( const ICurve* pCrv)
Voronoi::AddCurve( const ICurve* pCrv)
{
if ( ! m_bAllowAdd)
return false ;
@@ -99,21 +100,21 @@ Voronoi::AddCurve( const ICurve* pCrv)
if ( ! vtExtr.IsSmall())
plPlane.Set( ptS, vtExtr) ;
else
plPlane.Set( ptS, Z_AX) ;
plPlane.Set( ptS, Z_AX) ;
}
else {
if ( ! pCrv->IsFlat( plPlane, false, 10 * EPS_SMALL))
return false ;
}
return false ;
}
if ( m_vpCrvs.empty()) {
// se prima curva considerata assegno il frame al Voronoi
m_Frame.Set( plPlane.GetPoint(), plPlane.GetVersN()) ;
m_Frame.Set( plPlane.GetPoint(), plPlane.GetVersN()) ;
}
else {
// altrimenti verifico sia complanare ad eventuali curve già presenti
if ( ! AreSameOrOppositeVectorApprox( m_Frame.VersZ(), plPlane.GetVersN()) || ! PointInPlaneApprox( m_Frame.Orig(), plPlane))
return false ;
return false ;
}
// creo una copia della curva e la porto in locale
@@ -128,8 +129,8 @@ Voronoi::AddCurve( const ICurve* pCrv)
m_vroni = new( nothrow) vroniObject() ;
if ( m_vroni == nullptr)
return false ;
m_vroni->apiInitializeProgram() ;
}
m_vroni->apiInitializeProgram() ;
}
// aggiungo la curva in locale all'oggetto vroni
if ( ! AddCurveToVroni( pCrvLoc))
@@ -144,61 +145,61 @@ Voronoi::AddCurve( const ICurve* pCrv)
BBox3d bBox ;
pCrvLoc->GetLocalBBox( bBox) ;
m_bBox.Add( bBox) ;
return true ;
}
//----------------------------------------------------------------------------
bool
Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr)
Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr)
{
if ( ! m_bAllowAdd)
return false ;
if ( pSfr == nullptr)
return false ;
// recupero il piano
Point3d ptCen ; pSfr->GetCentroid( ptCen) ;
Vector3d vtN = pSfr->GetNormVersor() ;
Vector3d vtN = pSfr->GetNormVersor() ;
if ( m_vpCrvs.empty()) {
// assegno il frame al Voronoi
m_Frame.Set( ptCen, vtN) ;
m_Frame.Set( ptCen, vtN) ;
}
else {
// verifico sia complanare ad eventuali curve già presenti
Plane3d plPlane ;
plPlane.Set( ptCen, pSfr->GetNormVersor()) ;
if ( ! AreSameOrOppositeVectorApprox( m_Frame.VersZ(), pSfr->GetNormVersor()) || ! PointInPlaneApprox( m_Frame.Orig(), plPlane))
return false ;
return false ;
}
try {
// verifico se oggetto vroni è stato inizializzato
if ( m_vroni == nullptr) {
m_vroni = new( nothrow) vroniObject() ;
if ( m_vroni == nullptr)
return false ;
m_vroni->apiInitializeProgram() ;
m_vroni->apiInitializeProgram() ;
}
// aggiungo le curve di loop
for ( int i = 0 ; i < pSfr->GetChunkCount() ; i ++) {
for ( int j = 0 ; j < pSfr->GetLoopCount( i) ; j ++) {
PtrOwner<ICurve> pCrvLoc( pSfr->GetLoop( i, j)) ;
if ( IsNull( pCrvLoc))
return false ;
pCrvLoc->ToLoc( m_Frame) ;
pCrvLoc->ToLoc( m_Frame) ;
if ( ! AddCurveToVroni( pCrvLoc))
return false ;
}
}
}
}
catch (...) {
LOG_ERROR( GetEGkLogger(), m_vroni->GetExceptionMessage())
return false ;
}
// aggiorno il box complessivo
BBox3d bBox ;
Frame3d frSrf = m_Frame ;
@@ -211,16 +212,16 @@ Voronoi::AddSurfFlatRegion( const ISurfFlatRegion* pSfr)
//----------------------------------------------------------------------------
bool
Voronoi::AddCurveToVroni( const ICurve* pCrv)
Voronoi::AddCurveToVroni( const ICurve* pCrv)
{
int nLoopId = m_vpCrvs.size() ;
// aggiungo il punto iniziale
Point3d ptStart ;
Point3d ptStart ;
if ( ! pCrv->GetStartPoint( ptStart))
return false ;
int nCrv = m_vroni->HandlePnt( ptStart.x, ptStart.y, {nLoopId, 0}) ;
// aggiungo la parte rimanente della curva
switch ( pCrv->GetType()) {
case CRV_LINE :
@@ -229,7 +230,7 @@ Voronoi::AddCurveToVroni( const ICurve* pCrv)
case CRV_ARC :
m_vpCrvs.emplace_back( pCrv->Clone()) ;
return AddArcToVroni( GetCurveArc( pCrv), nCrv, nLoopId) ;
case CRV_COMPO :
case CRV_COMPO :
return AddCompoToVroni( GetCurveComposite( pCrv), nCrv, nLoopId) ;
case CRV_BEZIER :
return AddBezierToVroni( GetCurveBezier( pCrv), nCrv, nLoopId) ;
@@ -242,7 +243,7 @@ Voronoi::AddCurveToVroni( const ICurve* pCrv)
//----------------------------------------------------------------------------
bool
Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd)
Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd)
{
if ( pLine == nullptr)
return false ;
@@ -250,7 +251,7 @@ Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, i
// verifico se il punto finale viene forzato oppure deve essere ricavato dalla pLine
if ( ! ptEnd.IsValid()) {
if ( ! pLine->GetEndPoint( ptEnd))
return false ;
return false ;
}
m_vroni->AddSeg( &nVroniCrv, ptEnd.x, ptEnd.y, {nLoopId, nCrvId}) ;
@@ -259,7 +260,7 @@ Voronoi::AddLineToVroni( const ICurveLine* pLine, int& nVroniCrv, int nLoopId, i
//----------------------------------------------------------------------------
bool
Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd)
Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int nCrvId, Point3d ptEnd)
{
if ( pArc == nullptr)
return false ;
@@ -285,7 +286,7 @@ Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int
// verifico se il punto finale viene forzato oppure deve essere ricavato dal pArc
if ( ! ptEnd.IsValid()) {
if ( ! pArc->GetEndPoint( ptEnd))
return false ;
return false ;
}
m_vroni->AddArc( &nVroniCrv, ptEnd.x, ptEnd.y, ptCen.x, ptCen.y, nArcSiteType, {nLoopId, nCrvId}) ;
}
@@ -295,7 +296,7 @@ Voronoi::AddArcToVroni( const ICurveArc* pArc, int& nVroniCrv, int nLoopId, int
//----------------------------------------------------------------------------
bool
Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLoopId)
Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLoopId)
{
if ( pCompo == nullptr)
return false ;
@@ -315,18 +316,18 @@ Voronoi::AddCompoToVroni( const ICurveComposite* pCompo, int& nVroniCrv, int nLo
bool bClosed = pCopy->IsClosed() ;
for ( int i = 0 ; i < pCopy->GetCurveCount() ; i++) {
Point3d ptForcedEnd = P_INVALID ;
// se curva è chiusa, forzo l'end point a coincidere con lo start ( per le tolleranze di vroni)
if ( i == pCopy->GetCurveCount() - 1 && bClosed)
pCompo->GetStartPoint( ptForcedEnd) ;
// aggiungo
const ICurve* pCrv = pCopy->GetCurve( i) ;
int nType = pCrv->GetType() ;
if ( nType == CRV_LINE)
AddLineToVroni( GetCurveLine( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ;
else if ( nType == CRV_ARC)
AddArcToVroni( GetCurveArc( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ;
AddArcToVroni( GetCurveArc( pCrv), nVroniCrv, nLoopId, i, ptForcedEnd) ;
}
// aggiungo al vettore di curve
@@ -341,7 +342,7 @@ Voronoi::AddBezierToVroni( const ICurveBezier* pBezier, int& nVroniCrv, int nLoo
{
if ( pBezier == nullptr)
return false ;
// riconduco al caso di curva composita
PtrOwner<CurveComposite> pCompo( CreateBasicCurveComposite()) ;
if ( IsNull( pCompo))
@@ -352,28 +353,28 @@ Voronoi::AddBezierToVroni( const ICurveBezier* pBezier, int& nVroniCrv, int nLoo
Vector3d vtExtr ; pBezier->GetExtrusion( vtExtr) ;
pCompo->SetExtrusion( vtExtr) ;
return AddCompoToVroni( pCompo, nVroniCrv, nLoopId) ;
}
//----------------------------------------------------------------------------
ICurve*
ICurve*
Voronoi::GetCurve( int nId) const
{
// verifico validità indice
if ( nId < 0 || nId > ( int)m_vpCrvs.size() - 1)
return nullptr ;
return nullptr ;
// ne faccio una copia
ICurve* pCrv = m_vpCrvs[nId]->Clone() ;
if ( pCrv == nullptr)
return nullptr ;
return nullptr ;
// la porto nel riferimento globale
pCrv->ToGlob( m_Frame) ;
return pCrv ;
}
//----------------------------------------------------------------------------
bool
bool
Voronoi::GetVroniPlane( Plane3d& plPlane) const
{
if ( ! IsValid())
@@ -383,13 +384,13 @@ Voronoi::GetVroniPlane( Plane3d& plPlane) const
}
//----------------------------------------------------------------------------
bool
bool
Voronoi::CalcVoronoi( int nBound)
{
{
// se già stato calcolato con lo stesso bound non devo fare nulla
if ( m_bVDComputed && nBound == m_nBound)
return true ;
// se già stato calcolato reset dei dati
if ( m_bVDComputed)
m_vroni->ResetVoronoiDiagram() ;
@@ -398,9 +399,9 @@ Voronoi::CalcVoronoi( int nBound)
m_nBound = max( nBound, VORONOI_STD_BOUND) ;
// calcolo
m_bVDComputed = true ;
m_bVDComputed = true ;
string sTmp = "" ;
m_vroni->apiComputeVD( false, true, false, m_nBound, 0, 0, &sTmp[0], false, false, false, &sTmp[0], true) ;
m_vroni->apiComputeVD( false, true, false, m_nBound, 0, 0, &sTmp[0], false, false, false, &sTmp[0], true) ;
return true ;
}
@@ -416,7 +417,7 @@ Voronoi::GetBisectorCurve( int i)
int nType = m_vroni->GetBisectorType( i) ;
// linea
if ( nType == BisectorType::LINE) {
if ( nType == BisectorType::LINE) {
// recupero i dati del bisettore da vroni
Point3d ptS, ptE ;
double dParS, dParE ;
@@ -434,7 +435,7 @@ Voronoi::GetBisectorCurve( int i)
pLine->SetTempParam( dParS, 0) ;
pLine->SetTempParam( dParE, 1) ;
pLine->ToGlob( m_Frame) ;
return pLine ;
return pLine ;
}
// degenerate hyperellipse ( arco)
@@ -454,20 +455,20 @@ Voronoi::GetBisectorCurve( int i)
pArc->SetTempParam( dParS, 0) ;
pArc->SetTempParam( dParS, 1) ; // dParE = dParS
pArc->ToGlob( m_Frame) ;
return pArc ;
return pArc ;
}
// bisettore generico
else if ( nType != BisectorType::NONE) {
// approssimo linearmente il bisettore
int nPoints = m_vroni->GetApproxedBisectorPointsNbr( i) ;
if ( nPoints < 2)
return nullptr ;
CurveComposite* pCompo = CreateBasicCurveComposite() ;
if ( pCompo == nullptr)
return nullptr ;
// verifico se devo leggere i punti del bisettore al contrario per averlo orientato dal parametro minore al maggiore
bool bInvert = false ;
double dPar1, dPar2 ;
@@ -481,13 +482,13 @@ Voronoi::GetBisectorCurve( int i)
m_vroni->GetApproxedBisectorPoint( i, bInvert ? nPoints - 1 : 0, pt.v, dParS) ;
pCompo->AddPoint( pt) ;
int nCrvCount = 0 ;
double dParPrev = dParS ;
int j = bInvert ? nPoints - 2 : 1 ;
while ( ( bInvert && j >= 0) || ( ! bInvert && j < nPoints)) {
double dPar ;
m_vroni->GetApproxedBisectorPoint( i, j, pt.v, dPar) ;
if ( pCompo->AddLine( pt)) {
if ( pCompo->AddLine( pt)) {
// setto i parametri sulla sottocurva
pCompo->SetCurveTempParam( nCrvCount, dParPrev, 0) ;
pCompo->SetCurveTempParam( nCrvCount, dPar, 1) ;
@@ -501,7 +502,7 @@ Voronoi::GetBisectorCurve( int i)
else
j ++ ;
}
// setto parametri sulla curva
pCompo->SetTempParam( dParS, 0) ;
pCompo->SetTempParam( dParPrev, 1) ;
@@ -521,12 +522,12 @@ Voronoi::CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound)
if ( ! IsValid())
return false ;
try {
// verifico se necessario calcolo Voronoi
if ( ! m_bVDComputed || nBound != m_nBound)
CalcVoronoi( nBound) ;
for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) {
// recupero la curva del bisettore
PtrOwner<ICurve> pCrv( GetBisectorCurve( i)) ;
@@ -546,7 +547,7 @@ Voronoi::CalcVoronoiDiagram( ICURVEPOVECTOR& vCrvs, int nBound)
}
//----------------------------------------------------------------------------
bool
bool
Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide)
{
vCrvs.clear() ;
@@ -561,21 +562,21 @@ Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide)
bRight = false ;
else if ( nSide == WMAT_RIGHT)
bLeft = false ;
try {
try {
if ( ! m_bVDComputed)
CalcVoronoi() ;
// calcolo medial axis
m_vroni->apiComputeWMAT( false, 0.0, 0.0, false, bLeft, bRight) ;
for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) {
// verifico se il lato appartiene al medial axis
if ( m_vroni->IsWMATEdge( i)) {
PtrOwner<ICurve> pCrv( GetBisectorCurve( i)) ;
if ( ! IsNull( pCrv) && pCrv->IsValid())
vCrvs.emplace_back( Release( pCrv)) ;
}
if ( ! IsNull( pCrv) && pCrv->IsValid())
vCrvs.emplace_back( Release( pCrv)) ;
}
}
// libero la memoria di vroni utilizzata per calcolare bisettore
@@ -590,7 +591,7 @@ Voronoi::CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide)
}
//----------------------------------------------------------------------------
bool
bool
Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType)
{
vOffs.clear() ;
@@ -603,38 +604,34 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType)
for ( auto pCrv : m_vpCrvs)
vOffs.emplace_back( pCrv->Clone()) ;
}
// calcolo offset
ICRVCOMPOPLIST OffsList ;
if ( ! CalcVroniOffset( OffsList, abs( dOffs)))
return false ;
return false ;
// sistemo le curve di offset calcolate con vroni
for ( auto pCrv : OffsList) {
// seleziono le porzioni dell'offset che si trovano dal lato richiesto
ICRVCOMPOPOVECTOR vResult = AdjustOffsetCurves( pCrv, dOffs) ;
for ( int i = 0 ; i < int( vResult.size()) ; ++ i) {
for ( int i = 0 ; i < int( vResult.size()) ; ++ i) {
// eventuale inversione
if ( dOffs > EPS_SMALL)
vResult[i]->Invert() ;
// sistemo il punto di inizio
if ( vResult[i]->IsClosed())
if ( vResult[i]->IsClosed())
AdjustOffsetStart( vResult[i]) ;
// sistemo i raccordi
if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0) {
// identifico i raccordi
if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0)
IdentifyFillets( vResult[i], dOffs) ;
AdjustCurveFillets( vResult[i], dOffs, nType) ;
}
// porto nel frame globale
vResult[i]->ToGlob( m_Frame) ;
// unisco le parti allineate
vResult[i]->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ;
vResult[i]->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ;
// aggiungo al vettore finale
vOffs.emplace_back( Release( vResult[i])) ;
}
@@ -642,11 +639,22 @@ Voronoi::CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType)
delete( pCrv) ;
}
// aggiusto i raccordi
if ( ( nType & ICurve::OFF_CHAMFER) != 0 || ( nType & ICurve::OFF_EXTEND) != 0)
if ( ! AdjustCurveFillets( vOffs, dOffs, nType)) {
vOffs.clear() ;
return false ;
}
// porto nel frame globale
for ( int i = 0 ; i < int( vOffs.size()) ; i++)
vOffs[i]->ToGlob( m_Frame) ;
return true ;
}
//----------------------------------------------------------------------------
bool
bool
Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs)
{
// calcola, se possibile, le curve di offset del valore richiesto come curve singole, andando a recuperare i tratti del
@@ -660,22 +668,22 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs)
if ( ! IsValid())
return false ;
try {
try {
if ( ! m_bVDComputed)
CalcVoronoi() ;
// individuo il lato richiesto
// individuo il lato richiesto
bool bLeft = ( dOffs < 0) ;
bool bRight = ! bLeft ;
bool bRight = ! bLeft ;
for ( int i = 0 ; i < int( m_vpCrvs.size()) ; i++) {
if ( ! m_vpCrvs[i]->IsClosed()) {
// se è presente una curva aperta il medial axis deve essere fatto sia a destra sia a sinistra
bLeft = true ;
bRight = true ;
break ;
break ;
}
}
int nSideRef = ( dOffs < 0 ? MDS_LEFT : MDS_RIGHT) ;
int nSideRef = ( dOffs < 0 ? MDS_LEFT : MDS_RIGHT) ;
// seleziono le curve del medial axis aventi parametro costante pari all'offset richiesto
m_vroni->apiComputeWMAT( false, 0.0, 0.0, false, bLeft, bRight) ;
@@ -688,7 +696,7 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs)
m_vroni->GetBisectorParams( i, dParS, dParE) ;
if ( abs( dParS - abs( dOffs)) < EPS_SMALL && abs( dParE - abs( dOffs)) < EPS_SMALL) {
PtrOwner<ICurve> pCrv( GetBisectorCurve( i)) ;
if ( ! IsNull( pCrv) && pCrv->IsValid()) {
if ( ! IsNull( pCrv) && pCrv->IsValid()) {
// se necessario verifico se dal lato corretto rispetto ai siti di riferimento
if ( bLeft && bRight) {
// recupero i siti di riferimento
@@ -700,7 +708,7 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs)
pCrv->SetTempProp( nOrigCrv1, 1) ;
int nSide = GetOffsetCurveSide( pCrv) ;
if ( nSide != nSideRef)
continue ;
continue ;
}
if ( nOrigCrv2 != -1) {
// verifico il lato rispetto al secondo sito
@@ -709,18 +717,18 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs)
int nSide = GetOffsetCurveSide( pCrv) ;
if ( nSide != nSideRef)
continue ;
}
}
}
vCrvs.emplace_back( Release( pCrv)) ;
}
}
}
vCrvs.emplace_back( Release( pCrv)) ;
}
}
}
}
// concateno le curve ottenute
if ( vCrvs.size() == 1)
vOffs.emplace_back( Release( vCrvs[0])) ;
else if ( ! vCrvs.empty()) {
else if ( ! vCrvs.empty()) {
ChainCurves chainC ;
chainC.Init( true, 10 * EPS_SMALL, int( vCrvs.size())) ;
for ( int i = 0 ; i < int( vCrvs.size()) ; ++ i) {
@@ -747,14 +755,14 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs)
vCrvs[nInd]->Invert() ;
// aggiungo alla composita
if ( ! pCrvCompo->AddCurve( Release( vCrvs[nInd])))
return false ;
return false ;
}
if ( pCrvCompo->IsValid()) {
pCrvCompo->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG) ;
vOffs.emplace_back( Release( pCrvCompo)) ;
}
}
}
}
}
// libero la memoria di vroni utilizzata per calcolare bisettore
m_vroni->apiFreeBisectorBuffer() ;
@@ -768,11 +776,11 @@ Voronoi::CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs)
}
//----------------------------------------------------------------------------
bool
bool
Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs)
{
// calcola i punti e le tangenti sui bisettori del medial axis in corrispondenza del valore di offset richiesto
vResult.clear() ;
if ( abs( dOffs) < EPS_SMALL)
@@ -785,12 +793,12 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs)
// verifico se necessario ricalcolo Voronoi
UpdateVoronoi( dOffs) ;
// indivudio lato medial axis per curve chiuse ( suppongo di chiamare la funzione dalla singola curva, quindi vale controllare
// indivudio lato medial axis per curve chiuse ( suppongo di chiamare la funzione dalla singola curva, quindi vale controllare
// la chiusura solo sulla prima curva. Eventualmente da estendere)
bool bLeft = true, bRight = true ;
if ( m_vpCrvs[0]->IsClosed()) {
bLeft = dOffs < 0 ;
bRight = ! bLeft ;
bRight = ! bLeft ;
}
// calcolo medial axis
@@ -810,6 +818,7 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs)
// calcolo il punto sul bisettore in corrispondenza dell'offset
Point3d pt ;
m_vroni->GetBisectorPointAtParam( i, abs( dOffs), pt.v) ;
pt.ToGlob( m_Frame) ;
// calcolo il vettore tangente
PtrOwner<ICurve> pCrv( GetBisectorCurve( i)) ;
@@ -818,12 +827,12 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs)
double dPar ;
Point3d ptTemp ;
Vector3d vtDir ;
if ( ! pCrv->GetParamAtPoint( pt, dPar, 100 * EPS_SMALL) || ! pCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptTemp, &vtDir))
return false ;
if ( ! pCrv->GetParamAtPoint( pt, dPar, 100 * EPS_SMALL) || ! pCrv->GetPointD1D2( dPar, ICurve::FROM_MINUS, ptTemp, &vtDir))
return false ;
vtDir.Normalize() ;
vResult.emplace_back( pt, vtDir) ;
}
}
}
// libero la memoria di vroni utilizzata per calcolare bisettori
@@ -838,22 +847,23 @@ Voronoi::CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs)
}
//----------------------------------------------------------------------------
bool
Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bool bSquareMids)
bool
Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bool bSquareMids,
bool bMergeOnlySameProps)
{
vCrvs.clear() ;
if ( ! IsValid())
return false ;
// se offset nullo errore
if ( abs( dOffs) < EPS_SMALL)
return false ;
ICRVCOMPOPLIST OffsList ;
// se offset nullo errore
if ( abs( dOffs) < EPS_SMALL)
return false ;
ICRVCOMPOPLIST OffsList ;
if ( ! CalcVroniOffset( OffsList, abs( dOffs)))
return false ;
// sistemo le curve di offset calcolate con vroni
bool bClosed = m_vpCrvs[0]->IsClosed() ;
for ( auto pCrvOffs : OffsList) {
@@ -862,11 +872,10 @@ Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bo
if ( dOffs > EPS_SMALL)
pCrvOffs->Invert() ;
// sistemo i raccordi
// identifico i raccordi da modificare
if ( bClosed && bSquareMids) {
// se curva è chiusa tutti i raccordi rispondono a bSquareMids
IdentifyFillets( pCrvOffs, dOffs) ;
AdjustCurveFillets( pCrvOffs, dOffs, ICurve::OFF_EXTEND) ;
}
else if ( ! bClosed && ( bSquareMids || bSquareEnds)) {
// se curva è aperta devo distinguere i raccordi interni da quelli relativi agli estremi e
@@ -879,22 +888,30 @@ Voronoi::CalcFatCurve( ICURVEPOVECTOR& vCrvs, double dOffs, bool bSquareEnds, bo
else
pCrvOffs->SetCurveTempParam( j, 0) ;
}
AdjustCurveFillets( pCrvOffs, dOffs, ICurve::OFF_EXTEND) ;
}
// porto nel frame globale
pCrvOffs->ToGlob( m_Frame) ;
// unisco le parti allineate
pCrvOffs->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, true) ;
pCrvOffs->MergeCurves( LIN_TOL_MIN, ANG_TOL_STD_DEG, true, bMergeOnlySameProps) ;
// aggiungo al vettore finale
vCrvs.emplace_back( pCrvOffs) ;
vCrvs.emplace_back( pCrvOffs) ;
}
// sistemo i raccordi
if ( bSquareMids || bSquareEnds)
if ( ! AdjustCurveFillets( vCrvs, dOffs, ICurve::OFF_EXTEND)) {
vCrvs.clear() ;
return false ;
}
// porto nel frame globale
for ( int i = 0 ; i < int( vCrvs.size()) ; i++)
vCrvs[i]->ToGlob( m_Frame) ;
return true ;
}
//----------------------------------------------------------------------------
bool
bool
Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
{
OffsList.clear() ;
@@ -915,21 +932,21 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
m_vroni->apiComputeOff( false, &sTmp[0], false, false, dOffs, 0.0, false, true, true) ;
// recupero le curve di offset da vroni
int nOffsCnt = m_vroni->GetOffsetCount() ;
int nOffsCnt = m_vroni->GetOffsetCount() ;
for ( int i = 0 ; i < nOffsCnt ; i++) {
Point3d ptSChain = P_INVALID ;
PtrOwner<CurveComposite> pCrvOffs ( CreateBasicCurveComposite()) ;
int nCrvCnt = m_vroni->GetOffsetCurveCount( i) ; // numero di sottocurve
for ( int j = 0 ; j < nCrvCnt ; j ++) {
// recupero la sottocurva da vroni
// recupero la sottocurva da vroni
Point3d ptS, ptE, ptC ;
int nType ;
int nOrigCrv, nOrigLoop, nOrigPnt ; // sito
m_vroni->GetOffsetCurve( i, j, nType, ptS.v, ptE.v, ptC.v, nOrigLoop, nOrigCrv, nOrigPnt) ;
if ( j == 0)
pCrvOffs->AddPoint( ptS) ;
pCrvOffs->AddPoint( ptS) ;
// se estremi coincidenti la curva va ignorata ( da vroni non possono arrivare circonferenze)
// ma controllo se appartiene ad una catena di tratti infinitesimi
@@ -938,7 +955,7 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
if ( ! AreSamePointApprox( ptSChain, ptE)) {
if ( ! pCrvOffs->AddLine( ptE))
return false ;
ptSChain = P_INVALID ;
ptSChain = P_INVALID ;
}
}
else {
@@ -954,16 +971,16 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
if ( ! pCrvOffs->AddLine( ptE))
return false ;
}
else {
else {
PtrOwner<CurveArc> pArc( CreateBasicCurveArc()) ;
if ( ! pArc->SetC2P( ptC, ptS, ptE)) {
// se raggio minore di EPS_SMALL approssimo con linea
if ( AreSamePointApprox( ptC, ptS)) {
if ( ! pCrvOffs->AddLine( ptE))
return false ;
return false ;
}
else
return false ;
return false ;
}
else {
// verifico orientamento
@@ -972,25 +989,25 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
pArc->ToExplementary() ;
// aggiungo alla composita
if ( ! pCrvOffs->AddCurve( Release( pArc)))
return false ;
}
return false ;
}
}
// setto come info la sottocurva da cui si è generata
int nCurrCrvId = pCrvOffs->GetCurveCount() - 1 ;
pCrvOffs->SetCurveTempProp( nCurrCrvId, nOrigCrv + 1, 0) ;
pCrvOffs->SetCurveTempProp( nCurrCrvId, nOrigLoop, 1) ;
// verifico se è una giunzione, ovvero un raccordo relativo agli estremi di una curva ( con distinzione fra curva
// verifico se è una giunzione, ovvero un raccordo relativo agli estremi di una curva ( con distinzione fra curva
// aperta e chiusa)
if ( nOrigCrv == -1) {
int nOrigCrvCnt = 1 ;
if ( m_vpCrvs[nOrigLoop]->GetType() == CRV_COMPO)
nOrigCrvCnt = GetBasicCurveComposite( m_vpCrvs[nOrigLoop])->GetCurveCount() ;
if ( nOrigPnt == 0 || nOrigPnt == nOrigCrvCnt) {
double dParam = m_vpCrvs[nOrigLoop]->IsClosed() ? VRONI_JUNCTION_CLOSED : VRONI_JUNCTION_OPEN ;
double dParam = m_vpCrvs[nOrigLoop]->IsClosed() ? VRONI_JUNCTION_CLOSED : VRONI_JUNCTION_OPEN ;
pCrvOffs->SetCurveTempParam( nCurrCrvId, dParam, 0) ;
}
}
}
}
// rimuovo tratti di lunghezza inferiore a 5 * EPS_SMALL
@@ -998,8 +1015,8 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
// aggiungo la curva alla lista degli offset
if ( ! IsNull( pCrvOffs) && pCrvOffs->IsValid() && pCrvOffs->GetCurveCount() > 0)
OffsList.push_back( Release( pCrvOffs)) ;
}
OffsList.push_back( Release( pCrvOffs)) ;
}
// libero la memoria di vroni dedicata agli offset
m_vroni->apiFreeOffsetData() ;
@@ -1013,11 +1030,11 @@ Voronoi::CalcVroniOffset( ICRVCOMPOPLIST& OffsList, double dOffs)
}
//----------------------------------------------------------------------------
bool
bool
Voronoi::UpdateVoronoi( double dOffs)
{
// calcolo il bound necessario per l'offset desiderato
double dNeededBound = abs( dOffs) / 0.49 / sqrt( m_bBox.GetDimX() * m_bBox.GetDimX() + m_bBox.GetDimY() * m_bBox.GetDimY()) ;
double dNeededBound = abs( dOffs) / 0.49 / sqrt( m_bBox.GetDimX() * m_bBox.GetDimX() + m_bBox.GetDimY() * m_bBox.GetDimY()) ;
if ( ! m_bVDComputed || dNeededBound > m_nBound) {
// aggiorno il valore del bound
int nBound = ( int)( ceil( dNeededBound) + 0.5) ;
@@ -1029,9 +1046,9 @@ Voronoi::UpdateVoronoi( double dOffs)
}
//----------------------------------------------------------------------------
ICRVCOMPOPOVECTOR
Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const
{
ICRVCOMPOPOVECTOR
Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const
{
ICRVCOMPOPOVECTOR vResult ;
int nSideRef = dOffs < EPS_SMALL ? MDS_LEFT : MDS_RIGHT ;
@@ -1049,13 +1066,13 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const
// controllo la curva complessiva
int nSide = GetOffsetCurveSide( pCompo->GetCurve( 0)) ;
if ( nSide == nSideRef)
vResult.emplace_back( pCompo->Clone()) ;
vResult.emplace_back( pCompo->Clone()) ;
}
else {
else {
// scorro la curva eliminando le giunzioni relative a curve aperte e le sottocurve che si trovano dal lato sbagliato
PtrOwner<CurveComposite> pCompoCurr( CreateBasicCurveComposite()) ;
for ( int i = 0 ; i < pCompo->GetCurveCount() ; i ++) {
bool bKeep = true ;
bool bKeep = true ;
double dParTmp ; pCompo->GetCurveTempParam( i, dParTmp) ;
if ( abs( dParTmp - VRONI_JUNCTION_OPEN) < EPS_SMALL)
bKeep = false ;
@@ -1071,8 +1088,8 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const
if ( pCompoCurr->IsValid()) {
vResult.emplace_back( Release( pCompoCurr)) ;
pCompoCurr.Set( CreateBasicCurveComposite()) ;
}
}
}
}
}
// salvo eventuale ultima curva
if ( pCompoCurr->IsValid())
@@ -1086,17 +1103,17 @@ Voronoi::AdjustOffsetCurves( const ICurveComposite* pCompo, double dOffs) const
vResult.pop_back() ;
}
}
return vResult ;
}
//---------------------------------------------------------------------------
int
Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const
{
int
Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const
{
if ( pCrv == nullptr)
return -1 ;
Point3d ptM ; pCrv->GetMidPoint( ptM) ;
// recupero curva e sottocurva di riferimento dalle temp prop
@@ -1105,8 +1122,8 @@ Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const
const ICurve* pCrvRef = m_vpCrvs[nOrigCrv] ;
if ( nOrigSubCrv != 0 && m_vpCrvs[nOrigCrv]->GetType() == CRV_COMPO) {
const CurveComposite* pCompoOrig = GetBasicCurveComposite( m_vpCrvs[nOrigCrv]) ;
if ( pCompoOrig != nullptr)
pCrvRef = pCompoOrig->GetCurve( nOrigSubCrv - 1) ;
if ( pCompoOrig != nullptr)
pCrvRef = pCompoOrig->GetCurve( nOrigSubCrv - 1) ;
}
DistPointCurve distPC( ptM, *pCrvRef) ;
@@ -1116,9 +1133,9 @@ Voronoi::GetOffsetCurveSide( const ICurve* pCrv) const
}
//---------------------------------------------------------------------------
bool
Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const
{
bool
Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const
{
for ( int i = 0 ; i < pCrv->GetCurveCount() ; i++) {
// cerco il tratto associato alla prima sottocurva originale
int nOrigCrv ; pCrv->GetCurveTempProp( i, nOrigCrv) ;
@@ -1138,15 +1155,15 @@ Voronoi::AdjustOffsetStart( ICurveComposite* pCrv) const
//---------------------------------------------------------------------------
bool
Voronoi::Translate( const Vector3d & vtMove)
{
Voronoi::Translate( const Vector3d & vtMove)
{
if ( ! IsValid())
return false ;
return m_Frame.Translate( vtMove) ;
}
//---------------------------------------------------------------------------
bool
bool
Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dAngDeg)
{
if ( ! IsValid())
@@ -1155,7 +1172,7 @@ Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dAngDeg)
}
//---------------------------------------------------------------------------
bool
bool
Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, double dSinAng)
{
if ( ! IsValid())
@@ -1164,7 +1181,7 @@ Voronoi::Rotate( const Point3d& ptAx, const Vector3d& vtAx, double dCosAng, doub
}
//---------------------------------------------------------------------------
bool
bool
Voronoi::ToGlob( const Frame3d& frRef)
{
if ( ! IsValid())
@@ -1173,7 +1190,7 @@ Voronoi::ToGlob( const Frame3d& frRef)
}
//---------------------------------------------------------------------------
bool
bool
Voronoi::ToLoc( const Frame3d& frRef)
{
if ( ! IsValid())
@@ -1182,7 +1199,7 @@ Voronoi::ToLoc( const Frame3d& frRef)
}
//---------------------------------------------------------------------------
bool
bool
Voronoi::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
{
if ( ! IsValid())
@@ -1191,7 +1208,7 @@ Voronoi::LocToLoc( const Frame3d& frOri, const Frame3d& frDest)
}
//---------------------------------------------------------------------------
bool
bool
Voronoi::CalcLimitOffset( int nCrv, bool bLeft, double& dOffs)
{
if ( nCrv < 0 || nCrv > int( m_vpCrvs.size()) - 1)
@@ -1205,14 +1222,14 @@ Voronoi::CalcLimitOffset( int nCrv, bool bLeft, double& dOffs)
// verifico se necessario calcolo Voronoi
if ( ! m_bVDComputed)
CalcVoronoi() ;
for ( int i = 4 ; i < m_vroni->GetNumberOfEdges() ; i ++) {
// verifico se è un bisettore relativo alla curva richiesta e dal lato opportuno
if ( m_vroni->IsRelatedEdge( i, nCrv, bLeft)) {
// calcolo i parametri del bisettore
double dParS, dParE ;
m_vroni->GetBisectorParams( i, dParS, dParE) ;
dOffs = max( { dParS, dParE, dOffs}) ;
dOffs = max( { dParS, dParE, dOffs}) ;
}
}
+7 -7
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
@@ -57,7 +57,7 @@ class Voronoi
bool CalcOffset( ICURVEPOVECTOR& vOffs, double dOffs, int nType) ;
bool CalcSingleCurvesOffset( ICURVEPOVECTOR& vOffs, double dOffs) ;
bool CalcSpecialPointOffset( PNTVECTVECTOR& vResult, double dOffs) ;
bool CalcFatCurve( ICURVEPOVECTOR& vOffs, double dOffs, bool bSquareEnds, bool bSquareMids) ;
bool CalcFatCurve( ICURVEPOVECTOR& vOffs, double dOffs, bool bSquareEnds, bool bSquareMids, bool bMergeOnlySameProps = true) ;
bool CalcMedialAxis( ICURVEPOVECTOR& vCrvs, int nSide) ;
bool CalcLimitOffset( int nCrv, bool bLeft, double& dOffs) ;