markuno_lib 1.1.53 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markuno_lib",
3
- "version": "1.1.53",
3
+ "version": "1.2.2",
4
4
  "description": "Croswil Markuno Language Lib",
5
5
  "authors": [
6
6
  "Croswil <info@croswil.com>"
@@ -28,11 +28,6 @@
28
28
  "require": "./bin/markcad.js",
29
29
  "types": "./types/markcad.d.ts"
30
30
  },
31
- "./cad3d": {
32
- "import": "./bin/markcad3d.js",
33
- "require": "./bin/markcad3d.js",
34
- "types": "./types/markcad3d.d.ts"
35
- },
36
31
  "./marked": {
37
32
  "import": "./bin/marked.js",
38
33
  "require": "./bin/marked.js",
@@ -174,6 +174,7 @@ export class Punto2 {
174
174
  * @returns {Punto2} Nuovo punto con le coordinate normalizzate
175
175
  */ dir(): Punto2;
176
176
  }
177
+ export const SIDE: any;
177
178
  export var SP: Readonly<{
178
179
  __proto__: any;
179
180
  addhoriz: (ff: any, tipodim: any, dim: any, cod: any, align: any, cuts: any) => any;
@@ -267,6 +268,7 @@ export class Vis2d {
267
268
  addarea(s: any, color?: any): this;
268
269
  addoffset(x: any, y: any): this;
269
270
  }
271
+ export function addmovpivot(gcad: any, grp: any, movimento: any, op?: {}, x?: number, y?: number, z?: number): any;
270
272
  /**
271
273
  * Calcola l'angolo tra due vettori in gradi.
272
274
  * @param {Object} v1 - Primo vettore {x,y}
@@ -290,10 +292,20 @@ export namespace blocked {
290
292
  let fetch: any;
291
293
  let XMLHttpRequest: any;
292
294
  }
293
- /**
294
- * Classe per la gestione degli errori con funzionalità di accumulo e formattazione
295
- */ export function clamp(n: any, min?: number, max?: number): any;
295
+ export function calcolatasks(scena: any): {
296
+ tipo: any;
297
+ ori: any;
298
+ lavs: any[];
299
+ x: any;
300
+ y: any;
301
+ z: any;
302
+ id: any;
303
+ }[];
304
+ export function clamp(n: any, min?: number, max?: number): any;
296
305
  export function clean(k: any, locase?: boolean): any;
306
+ export function creategroup(name: any): any;
307
+ export function deletegroup(grpbase: any, name: any): void;
308
+ export function edgesfromgeometry(g1: any, layer?: number): any;
297
309
  export function elaborapercorso(sh1: any, bordo: any, taglio: any, oggetti: any, countid?: number): {
298
310
  countid: number;
299
311
  shape2: any;
@@ -302,7 +314,28 @@ export function elaborapercorso(sh1: any, bordo: any, taglio: any, oggetti: any,
302
314
  dati: any[];
303
315
  draws: any[];
304
316
  };
317
+ /**
318
+ * Crea una geometria estrusa con opzioni avanzate
319
+ * @param {string} orient - Orientamento dell'estrusione
320
+ * @param {number} hshape - Altezza dell'estrusione
321
+ * @param {Object} shape - Forma base
322
+ * @param {Array} holes - Array di fori
323
+ * @param {Array} mats - Array di materiali
324
+ * @param {Object} options - Opzioni di configurazione
325
+ * @returns {THREE.Group} Gruppo contenente la geometria estrusa
326
+ */ export function estruso(gcad: any, orient: string, hshape: number, shape: any, holes: any[], mats: any[], options: any): THREE.Group;
327
+ /**
328
+ * Crea una geometria estrusa con opzioni avanzate
329
+ * @param {string} orient - Orientamento dell'estrusione
330
+ * @param {number} hshape - Altezza dell'estrusione
331
+ * @param {Object} shape - Forma base
332
+ * @param {Array} holes - Array di fori
333
+ * @param {Array} mats - Array di materiali
334
+ * @param {Object} options - Opzioni di configurazione
335
+ * @returns {THREE.Group} Gruppo contenente la geometria estrusa
336
+ */ export function estrusopat(gcad: any, orient: string, pat: any, shape: any, mats: any[], options: any): THREE.Group;
305
337
  export function evalcustomfunction(amb: any, code: any, values: any, objects: any): Promise<any>;
338
+ export function get3dshape(punti: any, material: any, layer: any): any;
306
339
  export function getOggetto(obj: any, exclude?: any[]): any;
307
340
  export function getbordi(oggetti: any, bordo: any): {
308
341
  bordi: any[];
@@ -313,8 +346,74 @@ export function getbordi(oggetti: any, bordo: any): {
313
346
  br: any;
314
347
  bb: any;
315
348
  };
349
+ export function getbox(gcad: any, x: any, y: any, z: any, mat: any, options: any): any;
350
+ /**
351
+ * Crea un cilindro 3D con orientamento personalizzabile
352
+ * @param {string} ori - Orientamento (X/L, Y/A, Z/P)
353
+ * @param {number} h - Altezza
354
+ * @param {number} r1 - Raggio base
355
+ * @param {number} r2 - Raggio top
356
+ * @param {THREE.Material|Array} mats - Materiale/i da applicare
357
+ * @param {Object} options - Opzioni di configurazione
358
+ * @returns {Promise<THREE.Group>} Gruppo contenente il cilindro
359
+ */
360
+ export function getcilindro(gcad: any, ori: string, h: number, r1: number, r2: number, mats: THREE.Material | any[], options: any): Promise<THREE.Group>;
361
+ export function getcyl(gcad: any, height: any, radius: any, mat: any, options: any): any;
316
362
  export function getdumpmacro(nodo: any): string;
363
+ export function getemitter(data: any): any;
364
+ /**
365
+ * Crea un box 3D con linee di bordo opzionali
366
+ * @param {number} x - Larghezza
367
+ * @param {number} y - Altezza
368
+ * @param {number} z - Profondità
369
+ * @param {THREE.Material} mat - Materiale da applicare
370
+ * @param {Object} options - Opzioni di configurazione
371
+ * @returns {Promise<THREE.Group>} Gruppo contenente il box
372
+ */ export function getface(gcad: any, x: number, y: number, mat: THREE.Material, scaled?: boolean): Promise<THREE.Group>;
373
+ export function getfakeshadow(gcad: any, shape: any, alfa: any): any;
374
+ /**
375
+ * Crea una linea 3D
376
+ * @param {Object} l - Oggetto contenente punti p1 e p2
377
+ * @param {string} id - Identificatore
378
+ * @param {THREE.Material} [mat=null] - Materiale da applicare
379
+ * @returns {THREE.Line} Linea 3D
380
+ */ export function getline(l: any, id: string, mat?: THREE.Material): THREE.Line;
381
+ export function getlinesgeom(edges: any, layer?: number): any;
382
+ export function getmesh(geom: any, material: any, layer?: number, clone?: boolean): any;
383
+ /**
384
+ * Crea un gestore di movimento per animare oggetti 3D.
385
+ * @param {string} key - Chiave identificativa del movimento
386
+ * @param {Array<Object>} gtimeline - Timeline di passi di animazione. Ogni passo può contenere:
387
+ * @param {number} time - Durata del passo in millisecondi
388
+ * @param {(number|function)} [x] - Traslazione X (unità o funzione che restituisce unità)
389
+ * @param {(number|function)} [y] - Traslazione Y
390
+ * @param {(number|function)} [z] - Traslazione Z
391
+ * @param {(number|function)} [s] - Scala uniforme (moltiplicatore)
392
+ * @param {(number|function)} [sx] - Scala X
393
+ * @param {(number|function)} [sy] - Scala Y
394
+ * @param {(number|function)} [sz] - Scala Z
395
+ * @param {(number|function)} [ax] - Rotazione X (in giri)
396
+ * @param {(number|function)} [ay] - Rotazione Y
397
+ * @param {(number|function)} [az] - Rotazione Z
398
+ * @param {(number|function)} [t] - Trasparenza (0-1)
399
+ * @returns {Object} Oggetto gestore del movimento con metodi:
400
+ * @property {number} tline - Durata totale della timeline
401
+ * @property {function} clear - Pulisce la timeline
402
+ * @property {function} add - Aggiunge un passo alla timeline
403
+ * @property {string} key - Chiave del movimento
404
+ * @property {function} step - Esegue un passo dell'animazione
405
+ * @property {function} reset - Resetta l'oggetto alla posizione iniziale
406
+ */ export function getmovimento(key: string, gtimeline?: Array<any>): any;
317
407
  export function getnodebyid(id: any, nodocorrente: any): any;
408
+ export function getpannello(gcad: any, orientamento: any, x: any, y: any, z: any, mat1: any, mat2: any, options: any): any;
409
+ /**
410
+ * Crea un punto 3D rappresentato da una sfera
411
+ * @param {Object} p - Coordinate del punto
412
+ * @param {string} id - Identificatore
413
+ * @param {THREE.Material} [mat=null] - Materiale da applicare
414
+ * @param {number} [size=5] - Dimensione della sfera
415
+ * @returns {THREE.Mesh} Punto 3D
416
+ */ export function getpoint(p: any, id: string, mat?: THREE.Material, size?: number): THREE.Mesh;
318
417
  export function getprojectkeys(project: any): any;
319
418
  /**
320
419
  * Calcola i punti di offset tra due percorsi
@@ -333,6 +432,29 @@ export function getprojectkeys(project: any): any;
333
432
  x: number;
334
433
  y: number;
335
434
  }>;
435
+ export function getpunto(gcad: any, x: any, y: any, z: any, color: string, options: any): Promise<any>;
436
+ /**
437
+ * Crea una quota tra due punti in 3D sul piano XY
438
+ * @param {string} testo - Testo da visualizzare nella quota
439
+ * @param {number} x1 - Coordinata X del primo punto
440
+ * @param {number} y1 - Coordinata Y del primo punto
441
+ * @param {number} x2 - Coordinata X del secondo punto
442
+ * @param {number} y2 - Coordinata Y del secondo punto
443
+ * @param {number} sizetesto - Dimensione del testo
444
+ * @param {Object} options - Opzioni aggiuntive
445
+ * @returns {THREE.Group} Gruppo contenente la quota
446
+ */ export function getquota(gcad: any, testo: string, x1: number, y1: number, x2: number, y2: number, altezza?: number, offset?: number, options?: any): THREE.Group;
447
+ export function getreceiver(gcad: any, data: any): any;
448
+ /**
449
+ * Crea un punto di riferimento invisibile nell'albero 3D
450
+ * @param {number} x - Coordinata X
451
+ * @param {number} y - Coordinata Y
452
+ * @param {number} z - Coordinata Z
453
+ * @param {Object} dati - Dati da archiviare nell'oggetto
454
+ * @param {string} [id=null] - Identificatore opzionale
455
+ * @returns {THREE.Object3D} Oggetto di riferimento invisibile
456
+ */
457
+ export function getriferimento(dati: any, x?: number, y?: number, z?: number, id?: string): THREE.Object3D;
336
458
  /**
337
459
  * Calcola le normali e i valori UV per un percorso chiuso.
338
460
  * @param {Array<Object>} path - Array di punti {x,y}
@@ -366,6 +488,7 @@ export function getprojectkeys(project: any): any;
366
488
  * @method to3d(u0,c,a,b) - Converte in forma 3D con normali
367
489
  */
368
490
  export function getshape(): any;
491
+ export function getsprite(gcad: any, x: any, y: any, z: any, mat: any, options?: {}): any;
369
492
  export function getsubrules(nodocorrente: any): ({
370
493
  id: string;
371
494
  level: number;
@@ -380,19 +503,83 @@ export function getsubrules(nodocorrente: any): ({
380
503
  level: number;
381
504
  })[];
382
505
  /**
383
- * Esegue una semplice somma sincrona di due numeri
384
- * @param {number} a - Primo numero da sommare
385
- * @param {number} b - Secondo numero da sommare
386
- * @returns {number} La somma dei due numeri
387
- */ export function hash(obj: any): number;
506
+ * Crea una targhetta rettangolare con testo
507
+ * @param {Array|string} testo - Array di oggetti {testo, size, colore} o stringa
508
+ * @param {number} dim - Larghezza/altezza della targhetta
509
+ * @param {Object} options - Opzioni aggiuntive
510
+ * @returns {THREE.Mesh} Mesh con la targhetta
511
+ */ export function gettarghetta(gcad: any, testo: any[] | string, dim?: number, options?: any): THREE.Mesh;
512
+ export function groupfromgeometry(geometry: any, material: any, x: any, y: any, z: any, name: any, layer: any): any;
513
+ export function hash(obj: any): string;
514
+ export function infoestrudi(shape: any, hshape: any, pts: any, options: any): {
515
+ aini: any;
516
+ aini2: any;
517
+ afin: any;
518
+ afin2: any;
519
+ pts: any;
520
+ mi: any;
521
+ ma: any;
522
+ rect: {
523
+ x: any;
524
+ y: any;
525
+ }[];
526
+ dimx: number;
527
+ dimy: number;
528
+ lnom: number;
529
+ lmax: number;
530
+ lmin: number;
531
+ lmed: number;
532
+ };
388
533
  export function isfn(row: any): boolean;
389
534
  export function ismacro(row: any): any;
535
+ export let materialline1: any;
536
+ export let materialline2: any;
537
+ export const mblack: any;
538
+ export const mblue: any;
539
+ export const mgray1: any;
540
+ export const mgray2: any;
541
+ export const mgreen: any;
542
+ export const mred: any;
543
+ export const mwhite: any;
544
+ export function newgcad(P: any, _cat: any, islog?: boolean): {
545
+ clearmatricole: () => void;
546
+ islog: boolean;
547
+ clear: () => Promise<void>;
548
+ getScript: (file: any) => Promise<any>;
549
+ checkScripts: (files: any) => Promise<void>;
550
+ gmats: {};
551
+ scripts: () => string[];
552
+ geo: {};
553
+ movs: {};
554
+ textures: {};
555
+ smats: {};
556
+ dump(): void;
557
+ readonly cat: any;
558
+ pushcat(cat: any): void;
559
+ popcat: () => any;
560
+ tex(file: any, sx: number, sy: any, rot: any): Promise<any>;
561
+ get3ds(file: any, callback: any, ky?: string): Promise<any>;
562
+ getglb(file: any, textures: any, callback?: any, ky?: string): Promise<any>;
563
+ };
390
564
  /**
391
565
  * Calcola il vettore normale unitario di un segmento di linea.
392
566
  * @param {Object} p1 - Punto iniziale {x,y}
393
567
  * @param {Object} p2 - Punto finale {x,y}
394
568
  * @returns {Object} Vettore normale unitario {nx,ny}
395
569
  */ export function normal2(p1: any, p2: any): any;
570
+ export function posiziona(grp: any, pos?: {}): any;
571
+ /**
572
+ * Esegue la semplificazione di un poligono (array di punti) combinando
573
+ * l’algoritmo di distanza radiale e l’algoritmo di Ramer–Douglas–Peucker.
574
+ *
575
+ * @param {Array<{x:number,y:number}>} points - Array di punti {x,y} da semplificare.
576
+ * @param {number} [tolerance=1] - Tolleranza di semplificazione: distanza minima consentita
577
+ * (in unità lineari) tra i punti; internamente usata al quadrato per il calcolo
578
+ * (`sqTolerance = tolerance * tolerance`). Valori più grandi rimuovono più punti.
579
+ * @param {boolean} [highestQuality=false] - Se `true`, salta il passaggio di
580
+ * semplificazione radiale e usa solo Douglas–Peucker per massima qualità.
581
+ * @returns {Array<{x:number,y:number}>} Nuovo array di punti semplificato.
582
+ */
396
583
  /**
397
584
  * Crea una curva di Bézier quadratica tra due segmenti di linea.
398
585
  * @param {Object} a1 - Punto iniziale del primo segmento {x,y}
@@ -403,6 +590,10 @@ export function ismacro(row: any): any;
403
590
  * @returns {Array<Object>} Array di punti {x,y} che formano la curva
404
591
  */
405
592
  export function raccordabezier(a1: any, a2: any, b1: any, b2: any, subdivisions?: number): Array<any>;
593
+ export function randombasemat(): any;
594
+ export function revolve(gcad: any, shape: any, orient: any, mat: any, options: any): any;
595
+ export const scaleunit: 0.001;
596
+ export function setLineColorMode(white: any): void;
406
597
  /**
407
598
  * Crea un oggetto per operazioni booleane e manipolazione di forme 2D usando la libreria Clipper
408
599
  * @returns {Object} Oggetto con metodi per operazioni su forme
@@ -411,6 +602,9 @@ export function raccordabezier(a1: any, a2: any, b1: any, b2: any, subdivisions?
411
602
  * @property {Function} unisci - Unisce più forme con gestione di fori e tagli
412
603
  */
413
604
  export function shapeclip(): any;
605
+ export function smat(gcad: any, file: any, op?: {}): Promise<any>;
606
+ export function spritemat(gcad: any, file: any): Promise<any>;
607
+ export function svuotanodo(n: any): void;
414
608
  export function valutagrafica(amb: any, startmacro: any, rulespec: any, progetto: any, fnreload: any): Promise<{
415
609
  oo: any;
416
610
  vari: any;
package/bin/markcad3d.js DELETED
@@ -1,113 +0,0 @@
1
- import*as THREE from"three";import{PIF,hash,clean,getshape,raccordabezier}from"#markuno_cad";export{clamp}from"#markuno_cad";import{clean as clean$1,getcolonne,muClComments}from"#markuno_lib";const SIDE=THREE.DoubleSide;let materialline1=new THREE.LineBasicMaterial({color:3158064}),materialline2=new THREE.LineBasicMaterial({color:5263440});const mwhite=new THREE.MeshStandardMaterial({color:16777215,roughness:.5,metalness:.4,side:SIDE}),mgray1=new THREE.MeshStandardMaterial({color:8421504,roughness:.5,metalness:.4,side:SIDE}),mgray2=new THREE.MeshStandardMaterial({color:11579568,roughness:.5,metalness:.4,side:SIDE}),mred=new THREE.MeshStandardMaterial({color:16711680,roughness:.5,metalness:.4,side:SIDE}),mblue=new THREE.MeshStandardMaterial({color:1982639,roughness:.5,metalness:.4,side:SIDE}),mgreen=new THREE.MeshStandardMaterial({color:36864,roughness:.5,metalness:.4,side:SIDE}),mblack=new THREE.MeshStandardMaterial({color:0,roughness:.5,metalness:.4,side:SIDE}),scaleunit=.001;function groupfromgeometry(geometry,material,x,y,z,name,layer){let child=new THREE.Group;child.position.set(x,y,z),child.name=name;const mesh=new THREE.Mesh(geometry,material);mesh.name=name,mesh.castShadow=!0,mesh.receiveShadow=!0,mesh.layers.set(layer);const edges=new THREE.EdgesGeometry(geometry),lineSegments=new THREE.LineSegments(edges,materialline1);return lineSegments.layers.set(30),child.add(mesh),child.add(lineSegments),child}function posiziona(grp,pos={}){let tm=new THREE.Group;if(grp){let g2=grp.clone(),tm2=g2,{sl:sl=0,sa:sa=0,sp:sp=0,ax:ax=0,ay:ay=0,az:az=0,ul:ul=0,ua:ua=0,up:up=0,scale:scale=1,scx:scx=scale,scy:scy=scale,scz:scz=scale,emitters:emitters,emittersname:emittersname}=pos;if(tm.position.set(sl,sa,sp),tm.rotation.set(ax*PIF,ay*PIF,az*PIF),(ul||ua||up)&&(tm2=new THREE.Group,tm2.add(g2),tm2.position.set(ul,ua,up)),tm.scale.set(scx,scy,scz),tm.add(tm2),emitters&&emitters.length)for(let e of emitters)e.name=e.name||emittersname,tm.add(getemitter(e))}return tm}function edgesfromgeometry(g1,layer=30){return getlinesgeom(new THREE.EdgesGeometry(g1,40),layer)}function getlinesgeom(edges,layer=30){const lineSegments=new THREE.LineSegments(edges,materialline1);return lineSegments.layers.set(layer),lineSegments}function getmesh(geom,material,layer=1,clone=!1){let m=new THREE.Mesh(geom,clone?material.clone():material);return m.castShadow=!0,m.receiveShadow=!0,m.layers.set(layer),m}function get3dshape(punti,material,layer){if(!punti||punti.length<3)return new THREE.BufferGeometry;const vertices=[];for(let i=0;i<punti.length;i++){const p1=punti[i],p2=punti[(i+1)%punti.length];vertices.push(p1.x,0,p1.y),vertices.push(p2.x,0,p2.y)}const geometry=new THREE.BufferGeometry;geometry.setAttribute("position",new THREE.Float32BufferAttribute(vertices,3));let m=new THREE.LineSegments(geometry,material);return m.layers.set(layer),m}function creategroup(name){let g=new THREE.Group;return g.name=name||"$$",g}function svuotanodo(n){!function _dispose(node){if(node.children.length){[...node.children].forEach((child=>{_dispose(child),node.remove(child)}))}node.geometry&&node.geometry.dispose(),node.material&&(Array.isArray(node.material)?node.material.forEach((m=>m.dispose())):node.material.dispose())}(n)}function deletegroup(grpbase,name){if(!grpbase?.children)return;let gr=grpbase.children.find((e=>e.name==name));if(gr){for(;gr.children.length>0;){const child=gr.children[0];gr.remove(child)}gr.parent&&gr.parent.remove(gr),gr=null}}function randombasemat(){const material=new THREE.LineBasicMaterial,color=new THREE.Color;return color.setHSL(Math.random(),.7,.4),material.color=color,material}
2
- /**
3
- * Crea una linea 3D
4
- * @param {Object} l - Oggetto contenente punti p1 e p2
5
- * @param {string} id - Identificatore
6
- * @param {THREE.Material} [mat=null] - Materiale da applicare
7
- * @returns {THREE.Line} Linea 3D
8
- */function getline(l,id,mat=null){const lineGeometry=(new THREE.BufferGeometry).setFromPoints([new THREE.Vector3(l.p1.x,0,l.p1.y),new THREE.Vector3(l.p2.x,0,l.p2.y)]);return new THREE.Line(lineGeometry,mat||randombasemat())}
9
- /**
10
- * Crea un punto 3D rappresentato da una sfera
11
- * @param {Object} p - Coordinate del punto
12
- * @param {string} id - Identificatore
13
- * @param {THREE.Material} [mat=null] - Materiale da applicare
14
- * @param {number} [size=5] - Dimensione della sfera
15
- * @returns {THREE.Mesh} Punto 3D
16
- */function getpoint(p,id,mat=null,size=5){const pointgeom=new THREE.SphereGeometry(size,8,8);let tm=new THREE.Mesh(pointgeom,mat||randombasemat());return tm.position.set(p.x,0,p.y),tm}const suffissoMap={"":{prop:"map",extra:null},n:{prop:"normalMap",extra:null},h:{prop:"displacementMap",extra:"displacementScale"},a:{prop:"aoMap",extra:"aoMapIntensity"},r:{prop:"roughnessMap",extra:null},b:{prop:"bumpMap",extra:"bumpScale"},m:{prop:"metalnessMap",extra:null},e:{prop:"emissiveMap",extra:["emissive","emissiveIntensity"]}};async function smat(gcad,file,op={}){op||(op={});let ky=hash(file+JSON.stringify(op));return gcad.smats[ky]||(gcad.smats[ky]=await async function smat0(gcad,file,op={}){let paramstr="",isColore=!1;file.startsWith("#")&&(isColore=!0,/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})(?=$|[\[(])/.test(file)||(file=file.slice(1)));let basefile=file;const paramMatch=file.match(/^(.*)\[([^\]]+)\]$/);paramMatch&&(basefile=paramMatch[1],paramstr=paramMatch[2]);const p={};paramstr&&paramstr.split(/[,;]/).forEach((kv=>{let[k,v]=kv.split("=").map((x=>x.trim()));void 0!==v&&(["e"].includes(k)?p[k]=v.startsWith("0x")?parseInt(v):v:isNaN(parseFloat(v))?p[k]=v:p[k]=parseFloat(v))}));const mappaParam={s:["sx","sy"],sx:["sx"],sy:["sy"],rot:["rot"],r:["roughness"],m:["metalness"],h:["displacementScale"],d:["bumpScale"],b:["bumpScale"],e:["emissive"],ei:["emissiveIntensity"],ao:["aoMapIntensity"],env:["envMapIntensity"],o:["opacity"],t:["transparent"],at:["alphaTest"]};let optot={...op};for(let k in p)if(mappaParam[k])for(let t of mappaParam[k])optot[t]=p[k];let sx=(optot.sx??1)*(p.sx??p.s??1),sy=(optot.sy??1)*(p.sy??p.s??1),rot=((optot.rot??0)+(p.rot??0))*PIF;try{let tm={roughness:optot.roughness??.7,metalness:optot.metalness??.3,side:THREE.DoubleSide,envMapIntensity:optot.env??1};if(file.includes("(")||isColore){let{base:base,files:files}=function getFilesToLoad(isColore,basefile){let files=[],m=basefile.match(/^([^(]+)\((([a-zA-Z0-9_\-]+)_([a-z]+)|([a-z]+))\)$/);if(!m)return{base:basefile,files:files};let base=m[1],mapalias=m[3]||base,suffstr=m[4]||m[5]||"";isColore||files.push({suff:"",file:`${base}.webp`});for(let s of suffstr)suffissoMap[s]&&files.push({suff:s,file:`${mapalias}_${s}.webp`});return{base:base,files:files}}(isColore,basefile);if(files&&files.length){let textures=await Promise.all(files.map((f=>gcad.tex(f.file,sx,sy,rot).catch((()=>null)))));for(let i=0;i<files.length;i++){let t=textures[i];if(!t)continue;let suff=files[i].suff,{prop:prop,extra:extra}=suffissoMap[suff];tm[prop]=t,extra&&("displacementScale"===extra?tm.displacementScale=optot.displacementScale??.1:"bumpScale"===extra?tm.bumpScale=optot.bumpScale??.05:"aoMapIntensity"===extra?tm.aoMapIntensity=optot.aoMapIntensity??1:Array.isArray(extra)&&extra.includes("emissive")&&(tm.emissive=optot.emissive??16777215,tm.emissiveIntensity=optot.emissiveIntensity??1))}}isColore&&(tm.color=base)}else if(basefile.includes(".")){let tx=await gcad.tex(basefile,sx,sy,rot);if(!tx)return mwhite;tm.map=tx}return["opacity","alphaTest"].forEach((k=>{void 0!==optot[k]&&(tm[k]=optot[k])})),(void 0!==tm.opacity&&tm.opacity<1||optot.transparent)&&(tm.transparent=!0),new THREE.MeshStandardMaterial(tm)}catch(error){return mwhite}}(gcad,file,op)),gcad.smats[ky]}function getfakeshadow(gcad,shape,alfa){let ky=`fk${shape.key}${alfa}`,{p1:p1,width:width,height:height}=shape.dims();gcad.texture||(gcad.texture={});let tm=gcad.texture[ky];tm||(tm=function createBlurredShadowTextureFromPoints(mshape,size=256,blurPx=32,alpha=.2,p1,width,height){if(!width||!height||!mshape.pt||mshape.pt.length<2)return;const minX=p1.x,minY=p1.y,shapeWidth=width,shapeHeight=height,points=mshape.pt,extra=2*blurPx,canvas=document.createElement("canvas");canvas.width=size+2*extra,canvas.height=size+2*extra;const ctx=canvas.getContext("2d");ctx.save(),ctx.translate(extra,extra),ctx.scale(size/shapeWidth,size/shapeHeight),ctx.translate(-minX,-minY),ctx.filter=`blur(${blurPx}px)`,ctx.beginPath(),ctx.moveTo(points[0].x,points[0].y);for(let i=1;i<points.length;i++)ctx.lineTo(points[i].x,points[i].y);ctx.closePath(),ctx.fillStyle=`rgba(0,0,0,${alpha})`,ctx.fill(),ctx.restore();const texture=new THREE.CanvasTexture(canvas);return texture.needsUpdate=!0,texture}(shape,256,32,alfa,p1,width,height),gcad.texture[ky]=tm);const fakeShape=function pointsToShape(points){const fakeShape=new THREE.Shape;fakeShape.moveTo(points[0].x,points[0].y);for(let i=1;i<points.length;i++)fakeShape.lineTo(points[i].x,points[i].y);return fakeShape}(shape.pt),shadowGeometry=new THREE.ShapeGeometry(fakeShape);!function applyUVtoShapeGeometry(geometry,minX,minY,width,height){const pos=geometry.attributes.position,uv=[];for(let i=0;i<pos.count;i++){const x=pos.getX(i),y=pos.getY(i);uv.push((x-minX)/width,(y-minY)/height)}geometry.setAttribute("uv",new THREE.Float32BufferAttribute(uv,2))}(shadowGeometry,p1.x,p1.y,width,height);const shadowMaterial=new THREE.MeshBasicMaterial({map:tm,transparent:!0,depthWrite:!1,side:THREE.DoubleSide});let ms=new THREE.Mesh(shadowGeometry,shadowMaterial);return ms.layers.set(9),ms.rotation.x=Math.PI/2,ms}function addmovpivot(gcad,grp,movimento,op={},x=0,y=0,z=0){if(movimento=clean(movimento,!0),!gcad.movs[movimento])return grp;gcad.movs[movimento];const pivotLocal=new THREE.Vector3(x,y,z),isZeroPivot=0===pivotLocal.lengthSq(),pivotGroup=new THREE.Group;pivotGroup.name=`pivot_${movimento}`;const movimentoGroup=new THREE.Group;if(movimentoGroup.name=`mov_${movimento}`,isZeroPivot)pivotGroup.position.copy(grp.position),pivotGroup.quaternion.copy(grp.quaternion),grp.position.set(0,0,0),grp.rotation.set(0,0,0);else{const pivotWorld=pivotLocal.clone().applyMatrix4(grp.matrixWorld);pivotGroup.position.copy(pivotWorld);const offset=pivotLocal.clone().negate();grp.position.add(offset),pivotGroup.quaternion.copy(grp.getWorldQuaternion(new THREE.Quaternion)),grp.rotation.set(0,0,0)}return movimentoGroup.add(grp),pivotGroup.add(movimentoGroup),op||(op={}),op.inmov=!1,op.key=movimento,op.dt=0,op.dtstart=!1,movimentoGroup.userData.mov={...op},pivotGroup}
17
- /**
18
- * Crea un gestore di movimento per animare oggetti 3D.
19
- * @param {string} key - Chiave identificativa del movimento
20
- * @param {Array<Object>} gtimeline - Timeline di passi di animazione. Ogni passo può contenere:
21
- * @param {number} time - Durata del passo in millisecondi
22
- * @param {(number|function)} [x] - Traslazione X (unità o funzione che restituisce unità)
23
- * @param {(number|function)} [y] - Traslazione Y
24
- * @param {(number|function)} [z] - Traslazione Z
25
- * @param {(number|function)} [s] - Scala uniforme (moltiplicatore)
26
- * @param {(number|function)} [sx] - Scala X
27
- * @param {(number|function)} [sy] - Scala Y
28
- * @param {(number|function)} [sz] - Scala Z
29
- * @param {(number|function)} [ax] - Rotazione X (in giri)
30
- * @param {(number|function)} [ay] - Rotazione Y
31
- * @param {(number|function)} [az] - Rotazione Z
32
- * @param {(number|function)} [t] - Trasparenza (0-1)
33
- * @returns {Object} Oggetto gestore del movimento con metodi:
34
- * @property {number} tline - Durata totale della timeline
35
- * @property {function} clear - Pulisce la timeline
36
- * @property {function} add - Aggiunge un passo alla timeline
37
- * @property {string} key - Chiave del movimento
38
- * @property {function} step - Esegue un passo dell'animazione
39
- * @property {function} reset - Resetta l'oggetto alla posizione iniziale
40
- */function getmovimento(key,gtimeline=[]){let totale=0,timeline=[];const _cleartimeline=()=>{timeline=[],totale=0},_add=(t,op={})=>{t&&timeline.push({...op,time:t}),totale=timeline.reduce(((t,e)=>t+(e.time||0)),0)};_cleartimeline(),gtimeline&&gtimeline.length&&gtimeline.forEach((e=>_add(e.time,e)));const _resetmov=grp=>{const{mov:mov}=grp?.userData||{};mov&&(mov.inmov=!1,grp.position.set(0,0,0),grp.scale.set(1,1,1),grp.rotation.set(0,0,0))};return{get tline(){return totale},clear:_cleartimeline,add:_add,key:key,step:(grp,callback)=>{if(!grp||!grp.userData?.mov||!totale)return;const{mov:mov}=grp.userData;if(!mov.inmov)return;let dt=mov.dt-mov.dtstart;if(mov.ripeti)dt%=totale;else if(dt>totale)return void _resetmov(grp);let x=0,y=0,z=0,ax=0,ay=0,az=0,sx=1,sy=1,sz=1,t=null,accumTime=0;for(let step of timeline){if(accumTime+=step.time,dt<accumTime){const c=step.time>0?(dt-(accumTime-step.time))/step.time:1,_calc=(f,def=0)=>"function"==typeof f?f(mov)*c:(f||def)*c;x+=_calc(step.x),y+=_calc(step.y),z+=_calc(step.z),sx*=1+_calc(step.sx??step.s,0),sy*=1+_calc(step.sy??step.s,0),sz*=1+_calc(step.sz??step.s,0),ax+=_calc(step.ax)*PIF,ay+=_calc(step.ay)*PIF,az+=_calc(step.az)*PIF,void 0!==step.t&&(t="function"==typeof step.t?step.t(mov)*c:step.t*c);break}{const _calc=(f,def=0)=>"function"==typeof f?f(mov):f||def;x+=_calc(step.x),y+=_calc(step.y),z+=_calc(step.z),sx*=1+_calc(step.sx??step.s,0),sy*=1+_calc(step.sy??step.s,0),sz*=1+_calc(step.sz??step.s,0),ax+=_calc(step.ax)*PIF,ay+=_calc(step.ay)*PIF,az+=_calc(step.az)*PIF,void 0!==step.t&&(t="function"==typeof step.t?step.t(mov):step.t)}}grp.position.set(x,y,z),grp.scale.set(sx,sy,sz),grp.rotation.set(ax,ay,az),null!==t&&grp.traverse((obj=>{if(obj.material){(Array.isArray(obj.material)?obj.material:[obj.material]).forEach((mat=>{mat.transparent&&(mat.opacity=1-t)}))}})),callback&&callback(grp,dt)},reset:_resetmov}}function getorientate(ori,x,y,z){switch(x=x||0,y=y||0,z=z||0,ori.trim().toLowerCase()){case"alp":return{x:y,y:x,z:z};case"apl":return{x:y,y:z,z:x};case"pla":return{x:z,y:x,z:y};case"pal":return{x:z,y:y,z:x};case"lpa":return{x:x,y:z,z:y};default:return{x:x,y:y,z:z}}}function parselavs(ori,id,x=0,y=0,z=0,lavorazioni="",facce="",def=""){let lavcods=muClComments(lavorazioni),rets=[];for(let lavcod of lavcods){var rr=/^([({}):$\w.\\/]+)[\s;,]*(.*)?$/im.exec(lavcod);if(rr&&rr[1]){let lav={name:rr[1].trim().toLowerCase(),...getorientate(ori,x,y,z),id:id,facce:facce};if(rr[2]){let aa=getcolonne(rr[2]);for(let a of aa){let i=a.indexOf("=");i>0&&(lav[a.slice(0,i).trim()]=a.slice(i+1).trim())}}rets.push(lav)}}return!rets.length&&def&&rets.push({name:def,...getorientate(ori,x,y,z),id:id,facce:facce}),rets}function getemitter(data){let{d:d,name:name,x:x,y:y,z:z,lavs:lavs="",ids:ids="",faces:faces=null,size:size=5}=data;ids=getcolonne(clean$1(ids,!0));const emitter=new THREE.Object3D;if(emitter.position.set(x,y,z),emitter.userData={emitter:!0,lavs:lavs,ids:ids,faces:faces,size:size,name:name},d){const geometry=new THREE.SphereGeometry(size||5,8,8),material=new THREE.MeshBasicMaterial({color:16711680}),mesh=new THREE.Mesh(geometry,material);emitter.add(mesh)}return emitter}function getreceiver(gcad,data){gcad.gmats.__istask=1;let{d:d,ori:ori="LAP",x:x=0,y:y=0,z:z=0,tipo:tipo="",start:start="",end:end=""}=data;tipo=clean$1(tipo,!0);const receiver=new THREE.Object3D;if(receiver.position.set(x/2,y/2,z/2),receiver.userData={receiver:!0,ori:(ori||"").trim().toLowerCase(),x:x,y:y,z:z,tipo:tipo,start:start,end:end},d){const geometry=new THREE.BoxGeometry(x,y,z),mesh=new THREE.Mesh(geometry,mgreen);mesh.position.set(0,0,0),receiver.add(mesh)}return receiver}function calcolatasks(scena){const emitterWorldPosition=new WeakMap,receiverWorldMatrixInverse=new WeakMap;function boxBoxIntersects(pos,l,x,y,z){return pos.x+l>0&&pos.x-l<x&&pos.y+l>0&&pos.y-l<y&&pos.z+l>0&&pos.z-l<z}function getFacceToccate(pos,sogliafaccia,x,y,z,filtra){const facce=[];function addfaccia(f){filtra&&!filtra.includes(f)||facce.push(f)}return Math.abs(pos.x-0)<sogliafaccia&&addfaccia("s"),Math.abs(pos.x-x)<sogliafaccia&&addfaccia("d"),Math.abs(pos.y-0)<sogliafaccia&&addfaccia("b"),Math.abs(pos.y-y)<sogliafaccia&&addfaccia("a"),Math.abs(pos.z-0)<sogliafaccia&&addfaccia("z"),Math.abs(pos.z-z)<sogliafaccia&&addfaccia("f"),facce.join("")}function getEmitterWorldPosition(emitter){if(!emitterWorldPosition.has(emitter)){const pos=new THREE.Vector3;emitter.getWorldPosition(pos),emitterWorldPosition.set(emitter,pos)}return emitterWorldPosition.get(emitter)}function getReceiverWorldMatrixInverse(receiver){if(!receiverWorldMatrixInverse.has(receiver)){const inv=receiver.matrixWorld.clone().invert();receiverWorldMatrixInverse.set(receiver,inv)}return receiverWorldMatrixInverse.get(receiver)}scena.updateMatrixWorld(!0);const receivers=[],emitters=[];!function scan(obj){obj.userData?.receiver&&receivers.push(obj),obj.userData?.emitter&&emitters.push(obj),obj.children&&obj.children.forEach(scan)}(scena);let tasks=[];for(const receiver of receivers){const{mat:mat,ori:ori,x:x,y:y,z:z,start:start,end:end,tipo:tipo,size:size}=receiver.userData;let singletask={id:mat,...getorientate(ori,x,y,z),tipo:tipo,ori:ori,lavs:[]};start&&singletask.lavs.push(...parselavs(ori,"_start",0,0,0,start,"",""));const matrixInverse=getReceiverWorldMatrixInverse(receiver);for(const emitter of emitters){if("string"==typeof tipo&&""!==tipo){const idx=emitter.userData.ids;if(Array.isArray(idx)&&idx.length>0&&!idx.includes("*")&&!idx.includes(tipo))continue}const posLocalAdj=getEmitterWorldPosition(emitter).clone().applyMatrix4(matrixInverse).clone().add(new THREE.Vector3(x/2,y/2,z/2));if(!boxBoxIntersects(posLocalAdj,emitter.userData.size??0,x,y,z))continue;const facceToccate=getFacceToccate(posLocalAdj,emitter.userData.soglia??2,x,y,z,emitter.userData.faces);facceToccate&&facceToccate.length&&singletask.lavs.push(...parselavs(ori,emitter.userData.name,posLocalAdj.x,posLocalAdj.y,posLocalAdj.z,emitter.userData.lavs,facceToccate,"nd"))}end&&singletask.lavs.push(...parselavs(ori,"_end",0,0,0,end,"","")),singletask.lavs.length&&tasks.push(singletask)}return tasks}let globalLabelCanvas=null,globalLabelContext=null;
41
- /**
42
- * Crea un punto di riferimento invisibile nell'albero 3D
43
- * @param {number} x - Coordinata X
44
- * @param {number} y - Coordinata Y
45
- * @param {number} z - Coordinata Z
46
- * @param {Object} dati - Dati da archiviare nell'oggetto
47
- * @param {string} [id=null] - Identificatore opzionale
48
- * @returns {THREE.Object3D} Oggetto di riferimento invisibile
49
- */
50
- function getriferimento(dati,x=0,y=0,z=0,id="rif"){"string"==typeof dati&&(dati={testo:dati});let riferimento=new THREE.Object3D;return riferimento.position.set(x,y,z),id&&(riferimento.name=id),riferimento.userData={tipo:"rif",...dati},riferimento}
51
- /**
52
- * Crea una targhetta rettangolare con testo
53
- * @param {Array|string} testo - Array di oggetti {testo, size, colore} o stringa
54
- * @param {number} dim - Larghezza/altezza della targhetta
55
- * @param {Object} options - Opzioni aggiuntive
56
- * @returns {THREE.Mesh} Mesh con la targhetta
57
- */function gettarghetta(gcad,testo,dim=100,options={}){const{noSfondo:noSfondo=!1,forcey:forcey=!1,coloreSfondo:coloreSfondo="white",coloreBordo:coloreBordo="darkgray",spessoreBordo:spessoreBordo=3,padding:padding=8,layer:layer=21,fontFamily:fontFamily="Arial",raggioAngoli:raggioAngoli=20}=options;let tt=hash(`T:${coloreSfondo}|${coloreBordo}|${padding}|${spessoreBordo}|${raggioAngoli}|${noSfondo}|${testo}`);testo=testo.split("\n").map((e=>{let size=12,color="black";e=e.trim();let rr=/^\s*#(\w)(\d*),(.*)$/.exec(e);if(rr)switch(size=parseInt(rr[2]||12),e=rr[3],rr[1].toLowerCase()){case"r":color="red";break;case"g":color="green";break;case"b":color="blue";break;case"c":color="cyan"}return{testo:e,size:size,color:color}})).filter((e=>e.testo));const{canvas:canvas,context:context}=function getGlobalCanvas(){return globalLabelCanvas||(globalLabelCanvas=document.createElement("canvas"),globalLabelContext=globalLabelCanvas.getContext("2d",{willReadFrequently:!0})),{canvas:globalLabelCanvas,context:globalLabelContext}}();let maxWidth=0,totalHeight=2*padding;testo.forEach(((riga,i)=>{const{testo:testoRiga,size:size=12}=riga,fontSize=2*size;context.font=`${fontSize}px ${fontFamily}`;const textWidth=context.measureText(testoRiga).width,textHeight=fontSize*(i==testo.length-1?1:1.2);maxWidth=Math.max(maxWidth,textWidth),totalHeight+=textHeight})),maxWidth+=2*padding;const aspectRatio=totalHeight/maxWidth||1;let dimx,dimy;if(forcey?(dimy=dim,dimx=Math.ceil(dimy/aspectRatio)):(dimx=dim,dimy=Math.ceil(dimx*aspectRatio)),!gcad.textures[tt]){const canvasWidth=maxWidth+2*spessoreBordo,canvasHeight=totalHeight+2*spessoreBordo;(canvas.width<canvasWidth||canvas.height<canvasHeight)&&(canvas.width=Math.max(canvas.width,canvasWidth),canvas.height=Math.max(canvas.height,canvasHeight)),context.clearRect(0,0,canvasWidth,canvasHeight);const bgColor=new THREE.Color(coloreSfondo),bgColorStyle=`rgb(${Math.floor(255*bgColor.r)}, ${Math.floor(255*bgColor.g)}, ${Math.floor(255*bgColor.b)})`,borderColor=new THREE.Color(coloreBordo),borderColorStyle=`rgb(${Math.floor(255*borderColor.r)}, ${Math.floor(255*borderColor.g)}, ${Math.floor(255*borderColor.b)})`,radius=raggioAngoli;context.beginPath(),noSfondo||(drawRoundedRect(context,0,0,canvasWidth,canvasHeight,radius+spessoreBordo/2),context.fillStyle=borderColorStyle,context.fill(),context.beginPath(),drawRoundedRect(context,spessoreBordo,spessoreBordo,canvasWidth-2*spessoreBordo,canvasHeight-2*spessoreBordo,radius-spessoreBordo/2),context.fillStyle=bgColorStyle,context.fill());let yPosition=padding+spessoreBordo;testo.forEach((riga=>{const{testo:testoRiga,size:size=12,color:color="black"}=riga,fontSize=2*size;context.font=`${fontSize}px ${fontFamily}`,context.fillStyle=color,context.textAlign="center",context.textBaseline="top",context.fillText(testoRiga,canvasWidth/2,yPosition),yPosition+=1.2*fontSize}));const imageData=context.getImageData(0,0,canvasWidth,canvasHeight),texture=new THREE.DataTexture(imageData.data,imageData.width,imageData.height,THREE.RGBAFormat);texture.needsUpdate=!0,texture.flipY=!0,texture.minFilter=THREE.LinearFilter,texture.magFilter=THREE.LinearFilter,gcad.textures[tt]=texture}const materialeTesto=new THREE.MeshBasicMaterial({map:gcad.textures[tt],transparent:!0,side:SIDE}),geometriaTesto=new THREE.PlaneGeometry(dimx,dimy),meshTesto=new THREE.Mesh(geometriaTesto,materialeTesto);return meshTesto.layers.set(layer),meshTesto.userData={dimx:dimx,dimy:dimy},meshTesto}function drawRoundedRect(ctx,x,y,width,height,radius){radius=Math.min(radius,Math.min(width/2,height/2)),ctx.moveTo(x+radius,y),ctx.lineTo(x+width-radius,y),ctx.quadraticCurveTo(x+width,y,x+width,y+radius),ctx.lineTo(x+width,y+height-radius),ctx.quadraticCurveTo(x+width,y+height,x+width-radius,y+height),ctx.lineTo(x+radius,y+height),ctx.quadraticCurveTo(x,y+height,x,y+height-radius),ctx.lineTo(x,y+radius),ctx.quadraticCurveTo(x,y,x+radius,y),ctx.closePath()}
58
- /**
59
- * Crea una quota tra due punti in 3D sul piano XY
60
- * @param {string} testo - Testo da visualizzare nella quota
61
- * @param {number} x1 - Coordinata X del primo punto
62
- * @param {number} y1 - Coordinata Y del primo punto
63
- * @param {number} x2 - Coordinata X del secondo punto
64
- * @param {number} y2 - Coordinata Y del secondo punto
65
- * @param {number} sizetesto - Dimensione del testo
66
- * @param {Object} options - Opzioni aggiuntive
67
- * @returns {THREE.Group} Gruppo contenente la quota
68
- */function getquota(gcad,testo,x1,y1,x2,y2,altezza=30,offset=0,options={}){const{piano:piano="xy",layer:layer=22,delta:delta=5,spessoreLinea:spessoreLinea=3}=options,pp=(x,y)=>"xz"===piano?[x,0,y]:"yz"===piano?[0,x,y]:[x,y,0],quotaGroup=new THREE.Group;quotaGroup.name="quota";const dx=x2-x1,dy=y2-y1,distanza=Math.sqrt(dx*dx+dy*dy),angolo=Math.atan2(dy,dx),offsetX=-Math.sin(angolo)*offset,offsetY=Math.cos(angolo)*offset,targhetta=gettarghetta(gcad,testo||`${distanza.toFixed(1)}`,2*altezza,{noSfondo:!0,layer:layer,forcey:!0}),{dimx:dimx,dimy:dimy}=targhetta.userData;function getCilindro(puntoInizio,puntoFine,spessore){const direzione=(new THREE.Vector3).subVectors(puntoFine,puntoInizio),lunghezza=direzione.length();let geometria,ky=hash(`c:${spessore}|${lunghezza}`);gcad.geo[ky]?geometria=gcad.geo[ky]:(geometria=new THREE.CylinderGeometry(spessore/2,spessore/2,lunghezza,3,1,!0),gcad.geo[ky]=geometria);const cilindro=new THREE.Mesh(geometria,mblack);cilindro.position.copy(puntoInizio).add(direzione.multiplyScalar(.5));const punto=(new THREE.Vector3).copy(puntoFine);return cilindro.lookAt(punto),cilindro.rotateX(Math.PI/2),cilindro}if(dimx>distanza-delta){targhetta.position.set(distanza/2,altezza,0);const lineaOrizzontale=getCilindro(new THREE.Vector3(...pp(0,0)),new THREE.Vector3(...pp(distanza,0)),spessoreLinea);quotaGroup.add(lineaOrizzontale)}else{const spazioTarghetta=dimx+delta,inizioTarghetta=(distanza-spazioTarghetta)/2,fineTarghetta=inizioTarghetta+spazioTarghetta,lineaOrizzontale1=getCilindro(new THREE.Vector3(...pp(0,0)),new THREE.Vector3(...pp(inizioTarghetta,0)),spessoreLinea);quotaGroup.add(lineaOrizzontale1);const lineaOrizzontale2=getCilindro(new THREE.Vector3(...pp(fineTarghetta,0)),new THREE.Vector3(...pp(distanza,0)),spessoreLinea);quotaGroup.add(lineaOrizzontale2),targhetta.position.set(...pp(distanza/2,0))}const h1=offset>altezza/2?-offset:-altezza/2,h2=-offset>altezza/2?-offset:altezza/2,puntoInizioV1=new THREE.Vector3(...pp(0,h1)),puntoFineV1=new THREE.Vector3(...pp(0,h2)),puntoInizioV2=new THREE.Vector3(...pp(distanza,h1)),puntoFineV2=new THREE.Vector3(...pp(distanza,h2)),lineaVerticale1=getCilindro(puntoInizioV1,puntoFineV1,spessoreLinea);quotaGroup.add(lineaVerticale1);const lineaVerticale2=getCilindro(puntoInizioV2,puntoFineV2,spessoreLinea);return quotaGroup.add(lineaVerticale2),targhetta.userData.updateOrientation=function(camera){camera&&this.quaternion.copy(camera.quaternion)},quotaGroup.add(targhetta),"xy"===piano?(quotaGroup.position.set(x1+offsetX,y1+offsetY,0),quotaGroup.rotation.z=angolo):"xz"===piano?(quotaGroup.position.set(x1+offsetX,0,y1+offsetY),quotaGroup.rotation.y=-angolo):"yz"===piano&&(quotaGroup.position.set(0,x1+offsetX,y1+offsetY),quotaGroup.rotation.x=angolo),quotaGroup.traverse((function(object){object.layers.set(layer)})),quotaGroup}
69
- /**
70
- * Crea un cilindro 3D con orientamento personalizzabile
71
- * @param {string} ori - Orientamento (X/L, Y/A, Z/P)
72
- * @param {number} h - Altezza
73
- * @param {number} r1 - Raggio base
74
- * @param {number} r2 - Raggio top
75
- * @param {THREE.Material|Array} mats - Materiale/i da applicare
76
- * @param {Object} options - Opzioni di configurazione
77
- * @returns {Promise<THREE.Group>} Gruppo contenente il cilindro
78
- */
79
- function getcilindro(gcad,ori,h,r1,r2,mats=mwhite,options){options||(options={}),Array.isArray(mats)||(mats=[mats]);const cyl=function cylgeometry(gcad,h,r,rtop,segments=16){if(!r||!h)return null;let ky=hash(`cy${h}|${r}|${rtop||r}|${segments}`);if(!gcad.geo[ky]){const geometry=new THREE.CylinderGeometry(rtop||r,r,h,segments);gcad.geo[ky]=geometry}return gcad.geo[ky]}(gcad,h,r1,r2,options.sides||16);let grp=new THREE.Group;switch((ori||"").trim().toUpperCase()){case"X":case"L":grp.position.set(h/2,0,0),grp.rotation.z=Math.PI/2;break;case"Z":case"P":grp.position.set(0,0,h/2),grp.rotation.x=Math.PI/2;break;default:grp.position.set(0,h/2,0)}if(cyl){if(!options.nolines){let segments=edgesfromgeometry(cyl);grp.add(segments)}const matTop=mats[0]||mwhite,matBottom=mats[1]||matTop,matSides=mats[2]||matTop;grp.add(getmesh(cyl,[matTop,matBottom,matSides]))}return grp}
80
- /**
81
- * Crea un box 3D con linee di bordo opzionali
82
- * @param {number} x - Larghezza
83
- * @param {number} y - Altezza
84
- * @param {number} z - Profondità
85
- * @param {THREE.Material} mat - Materiale da applicare
86
- * @param {Object} options - Opzioni di configurazione
87
- * @returns {Promise<THREE.Group>} Gruppo contenente il box
88
- */function getface(gcad,x,y,mat,scaled=!1){let ky=hash(`f:${x}|${y}|${scaled?1:0}`);if(!gcad.geo[ky]){const geometry=new THREE.PlaneGeometry(x,y),uvs=geometry.attributes.uv;if(!scaled)for(let i=0;i<uvs.count;i++)uvs.setXY(i,uvs.getX(i)*x,uvs.getY(i)*y);gcad.geo[ky]=geometry}const plane=new THREE.Mesh(gcad.geo[ky],mat);return plane.position.set(x/2,y/2,0),mat?.transparent&&plane.layers.set(2),plane}function getcyl(gcad,height,radius,mat,options){options||(options={});let{center:center=!1,nolines:nolines=!1,segments:segments=16,radiusBottom:radiusBottom=-1}=options;radiusBottom<0&&(radiusBottom=radius);let grp=new THREE.Group;const cylinder=new THREE.CylinderGeometry(radius,radiusBottom,height,segments);if(grp.position.set(0,center?0:height/2,0),!nolines){let segments=edgesfromgeometry(cylinder);grp.add(segments)}return grp.add(getmesh(cylinder,mat||mwhite)),grp}function getbox(gcad,x,y,z,mat,options){options||(options={});let{center:center,nolines:nolines}=options,grp=new THREE.Group;const box=function boxgeometry(gcad,x,y,z){let ky=hash(`b:${x}|${y}|${z}`);if(!gcad.geo[ky]){const bx=new THREE.BoxGeometry(x,y,z);gcad.geo[ky]=bx}return gcad.geo[ky]}(gcad,x,y,z);if(grp.position.set(center?0:x/2,y/2,center?0:z/2),!nolines){let segments=edgesfromgeometry(box);grp.add(segments)}return grp.add(getmesh(box,mat||mwhite)),grp}
89
- /**
90
- * @param {BufferGeometry} geometry
91
- * @param {number} tolerance
92
- * @return {BufferGeometry}
93
- */function pannellogeometry(gcad,l,a,p,r1=0,r2=0,r3=0,r4=0,b=0,npt=2){let ky=hash(`pg--${l}|${a}|${p}|${r1}|${r2}|${r3}|${r4}|${b}|${npt}`);if(l-=.01,a-=.01,p-=.01,!gcad.geo[ky]){l-=2*b,a-=2*b,p-=2*b;let tm=getshape();const vv=[{x:r4,y:0},{x:a-r1,y:0},{x:a,y:r1},{x:a,y:p-r2},{x:a-r2,y:p},{x:r3,y:p},{x:0,y:p-r3},{x:0,y:r4}];tm.addpt(vv[0]),tm.addpt(vv[1]),r1&&tm.addpt(raccordabezier(vv[0],vv[1],vv[2],vv[3],npt)),tm.addpt(vv[2]),tm.addpt(vv[3]),r2&&tm.addpt(raccordabezier(vv[2],vv[3],vv[4],vv[5],npt)),tm.addpt(vv[4]),tm.addpt(vv[5]),r3&&tm.addpt(raccordabezier(vv[4],vv[5],vv[6],vv[7],npt)),tm.addpt(vv[6]),tm.addpt(vv[7]),r2&&tm.addpt(raccordabezier(vv[6],vv[7],vv[0],vv[1],npt)),tm.removeduplicate(.01);let pts=tm.pt;const shape=new THREE.Shape;shape.moveTo(pts[0].x,pts[0].y);for(let i=1;i<pts.length;i++)shape.lineTo(pts[i].x,pts[i].y);shape.lineTo(pts[0].x,pts[0].y);const extrudeSettings={depth:l,bevelEnabled:b>0,bevelThickness:b,bevelSize:b,bevelSegments:1};let xgeo=new THREE.ExtrudeGeometry(shape,extrudeSettings);xgeo=function mergeVertices(geometry,tolerance=1e-4){tolerance=Math.max(tolerance,Number.EPSILON);const hashToIndex={},indices=geometry.getIndex(),positions=geometry.getAttribute("position"),vertexCount=indices?indices.count:positions.count;let nextIndex=0;const attributeNames=Object.keys(geometry.attributes),tmpAttributes={},tmpMorphAttributes={},newIndices=[],getters=["getX","getY","getZ","getW"],setters=["setX","setY","setZ","setW"];for(let i=0,l=attributeNames.length;i<l;i++){const name=attributeNames[i],attr=geometry.attributes[name];tmpAttributes[name]=new attr.constructor(new attr.array.constructor(attr.count*attr.itemSize),attr.itemSize,attr.normalized);const morphAttributes=geometry.morphAttributes[name];morphAttributes&&(tmpMorphAttributes[name]||(tmpMorphAttributes[name]=[]),morphAttributes.forEach(((morphAttr,i)=>{const array=new morphAttr.array.constructor(morphAttr.count*morphAttr.itemSize);tmpMorphAttributes[name][i]=new morphAttr.constructor(array,morphAttr.itemSize,morphAttr.normalized)})))}const halfTolerance=.5*tolerance,exponent=Math.log10(1/tolerance),hashMultiplier=Math.pow(10,exponent),hashAdditive=halfTolerance*hashMultiplier;for(let i=0;i<vertexCount;i++){const index=indices?indices.getX(i):i;let hash="";for(let j=0,l=attributeNames.length;j<l;j++){const name=attributeNames[j],attribute=geometry.getAttribute(name),itemSize=attribute.itemSize;for(let k=0;k<itemSize;k++)hash+=~~(attribute[getters[k]](index)*hashMultiplier+hashAdditive)+","}if(hash in hashToIndex)newIndices.push(hashToIndex[hash]);else{for(let j=0,l=attributeNames.length;j<l;j++){const name=attributeNames[j],attribute=geometry.getAttribute(name),morphAttributes=geometry.morphAttributes[name],itemSize=attribute.itemSize,newArray=tmpAttributes[name],newMorphArrays=tmpMorphAttributes[name];for(let k=0;k<itemSize;k++){const getterFunc=getters[k],setterFunc=setters[k];if(newArray[setterFunc](nextIndex,attribute[getterFunc](index)),morphAttributes)for(let m=0,ml=morphAttributes.length;m<ml;m++)newMorphArrays[m][setterFunc](nextIndex,morphAttributes[m][getterFunc](index))}}hashToIndex[hash]=nextIndex,newIndices.push(nextIndex),nextIndex++}}const result=geometry.clone();for(const name in geometry.attributes){const tmpAttribute=tmpAttributes[name];if(result.setAttribute(name,new tmpAttribute.constructor(tmpAttribute.array.slice(0,nextIndex*tmpAttribute.itemSize),tmpAttribute.itemSize,tmpAttribute.normalized)),name in tmpMorphAttributes)for(let j=0;j<tmpMorphAttributes[name].length;j++){const tmpMorphAttribute=tmpMorphAttributes[name][j];result.morphAttributes[name][j]=new tmpMorphAttribute.constructor(tmpMorphAttribute.array.slice(0,nextIndex*tmpMorphAttribute.itemSize),tmpMorphAttribute.itemSize,tmpMorphAttribute.normalized)}}return result.setIndex(newIndices),result}(xgeo),xgeo.computeVertexNormals();const uv=xgeo.attributes.uv;let x1=Math.random()*l,y1=Math.random()*(a+p);for(let i=0;i<uv.count;i++)uv.setXY(i,uv.getX(i)+x1,uv.getY(i)+y1);uv.needsUpdate=!0,gcad.geo[ky]=xgeo}return gcad.geo[ky]}function getpannello(gcad,orientamento,x,y,z,mat1,mat2,options){options||(options={});let l,a,p,{r:r,r1:r1,r2:r2,r3:r3,r4:r4,b:b,npt:npt}=options;r1=r1||r||0,r2=r2||r||0,r3=r3||r||0,r4=r4||r||0,npt=npt||2,b=b||0,(b>=x/2||b>=y/2||b>=z/2)&&(b=0),l="L"==(orientamento=orientamento.trim().toUpperCase())[0]?x:"A"==orientamento[0]?y:z,a="L"==orientamento[1]?x:"A"==orientamento[1]?y:z,p="L"==orientamento[2]?x:"A"==orientamento[2]?y:z;let grp=new THREE.Group;if(!options.nolines){let segments=edgesfromgeometry(new THREE.BoxGeometry(x,y,z));segments.position.set(x/2,y/2,z/2),grp.add(segments)}let mesh=getmesh(pannellogeometry(gcad,l,a,p,r1,r2,r3,r4,b,npt),[mat2||mgreen,mat1||mwhite]);mesh.name="pannello",mesh.layers.set(1);let m2=mesh;return b&&(mesh.position.set(b,b,b),m2=new THREE.Group,m2.add(mesh)),mesh=function meshrotate(orientamento,mesh,x=0,y=0,z=0){switch(orientamento.trim().toUpperCase()){case"LPA":mesh.rotation.y=Math.PI/2,mesh.rotation.x=Math.PI,mesh.position.set(0,z,0);break;case"ALP":mesh.rotation.x=Math.PI/2,mesh.position.set(0,x,0);break;case"APL":mesh.rotation.x=-Math.PI/2,mesh.rotation.z=-Math.PI/2;break;case"PLA":break;case"PAL":mesh.rotation.z=Math.PI/2,mesh.position.set(z,0,0);break;case"LAP":mesh.rotation.y=Math.PI/2,mesh.rotation.z=Math.PI/2}return mesh}(orientamento,m2,l,a,p),grp.add(mesh),grp}function earcut(data,holeIndices,dim=2){const hasHoles=holeIndices&&holeIndices.length,outerLen=hasHoles?holeIndices[0]*dim:data.length;let outerNode=linkedList(data,0,outerLen,dim,!0);const triangles=[];if(!outerNode||outerNode.next===outerNode.prev)return triangles;let minX,minY,invSize;if(hasHoles&&(outerNode=function eliminateHoles(data,holeIndices,outerNode,dim){const queue=[];for(let i=0,len=holeIndices.length;i<len;i++){const list=linkedList(data,holeIndices[i]*dim,i<len-1?holeIndices[i+1]*dim:data.length,dim,!1);list===list.next&&(list.steiner=!0),queue.push(getLeftmost(list))}queue.sort(compareXYSlope);for(let i=0;i<queue.length;i++)outerNode=eliminateHole(queue[i],outerNode);return outerNode}(data,holeIndices,outerNode,dim)),data.length>80*dim){minX=1/0,minY=1/0;let maxX=-1/0,maxY=-1/0;for(let i=dim;i<outerLen;i+=dim){const x=data[i],y=data[i+1];x<minX&&(minX=x),y<minY&&(minY=y),x>maxX&&(maxX=x),y>maxY&&(maxY=y)}invSize=Math.max(maxX-minX,maxY-minY),invSize=0!==invSize?32767/invSize:0}return earcutLinked(outerNode,triangles,dim,minX,minY,invSize,0),triangles}function linkedList(data,start,end,dim,clockwise){let last;if(clockwise===function signedArea(data,start,end,dim){let sum=0;for(let i=start,j=end-dim;i<end;i+=dim)sum+=(data[j]-data[i])*(data[i+1]+data[j+1]),j=i;return sum}(data,start,end,dim)>0)for(let i=start;i<end;i+=dim)last=insertNode(i/dim|0,data[i],data[i+1],last);else for(let i=end-dim;i>=start;i-=dim)last=insertNode(i/dim|0,data[i],data[i+1],last);return last&&equals(last,last.next)&&(removeNode(last),last=last.next),last}function filterPoints(start,end){if(!start)return start;end||(end=start);let again,p=start;do{if(again=!1,p.steiner||!equals(p,p.next)&&0!==area(p.prev,p,p.next))p=p.next;else{if(removeNode(p),p=end=p.prev,p===p.next)break;again=!0}}while(again||p!==end);return end}function earcutLinked(ear,triangles,dim,minX,minY,invSize,pass){if(!ear)return;!pass&&invSize&&function indexCurve(start,minX,minY,invSize){let p=start;do{0===p.z&&(p.z=zOrder(p.x,p.y,minX,minY,invSize)),p.prevZ=p.prev,p.nextZ=p.next,p=p.next}while(p!==start);p.prevZ.nextZ=null,p.prevZ=null,function sortLinked(list){let numMerges,inSize=1;do{let e,p=list;list=null;let tail=null;for(numMerges=0;p;){numMerges++;let q=p,pSize=0;for(let i=0;i<inSize&&(pSize++,q=q.nextZ,q);i++);let qSize=inSize;for(;pSize>0||qSize>0&&q;)0!==pSize&&(0===qSize||!q||p.z<=q.z)?(e=p,p=p.nextZ,pSize--):(e=q,q=q.nextZ,qSize--),tail?tail.nextZ=e:list=e,e.prevZ=tail,tail=e;p=q}tail.nextZ=null,inSize*=2}while(numMerges>1);return list}(p)}(ear,minX,minY,invSize);let stop=ear;for(;ear.prev!==ear.next;){const prev=ear.prev,next=ear.next;if(invSize?isEarHashed(ear,minX,minY,invSize):isEar(ear))triangles.push(prev.i,ear.i,next.i),removeNode(ear),ear=next.next,stop=next.next;else if((ear=next)===stop){pass?1===pass?earcutLinked(ear=cureLocalIntersections(filterPoints(ear),triangles),triangles,dim,minX,minY,invSize,2):2===pass&&splitEarcut(ear,triangles,dim,minX,minY,invSize):earcutLinked(filterPoints(ear),triangles,dim,minX,minY,invSize,1);break}}}function isEar(ear){const a=ear.prev,b=ear,c=ear.next;if(area(a,b,c)>=0)return!1;const ax=a.x,bx=b.x,cx=c.x,ay=a.y,by=b.y,cy=c.y,x0=Math.min(ax,bx,cx),y0=Math.min(ay,by,cy),x1=Math.max(ax,bx,cx),y1=Math.max(ay,by,cy);let p=c.next;for(;p!==a;){if(p.x>=x0&&p.x<=x1&&p.y>=y0&&p.y<=y1&&pointInTriangleExceptFirst(ax,ay,bx,by,cx,cy,p.x,p.y)&&area(p.prev,p,p.next)>=0)return!1;p=p.next}return!0}function isEarHashed(ear,minX,minY,invSize){const a=ear.prev,b=ear,c=ear.next;if(area(a,b,c)>=0)return!1;const ax=a.x,bx=b.x,cx=c.x,ay=a.y,by=b.y,cy=c.y,x0=Math.min(ax,bx,cx),y0=Math.min(ay,by,cy),x1=Math.max(ax,bx,cx),y1=Math.max(ay,by,cy),minZ=zOrder(x0,y0,minX,minY,invSize),maxZ=zOrder(x1,y1,minX,minY,invSize);let p=ear.prevZ,n=ear.nextZ;for(;p&&p.z>=minZ&&n&&n.z<=maxZ;){if(p.x>=x0&&p.x<=x1&&p.y>=y0&&p.y<=y1&&p!==a&&p!==c&&pointInTriangleExceptFirst(ax,ay,bx,by,cx,cy,p.x,p.y)&&area(p.prev,p,p.next)>=0)return!1;if(p=p.prevZ,n.x>=x0&&n.x<=x1&&n.y>=y0&&n.y<=y1&&n!==a&&n!==c&&pointInTriangleExceptFirst(ax,ay,bx,by,cx,cy,n.x,n.y)&&area(n.prev,n,n.next)>=0)return!1;n=n.nextZ}for(;p&&p.z>=minZ;){if(p.x>=x0&&p.x<=x1&&p.y>=y0&&p.y<=y1&&p!==a&&p!==c&&pointInTriangleExceptFirst(ax,ay,bx,by,cx,cy,p.x,p.y)&&area(p.prev,p,p.next)>=0)return!1;p=p.prevZ}for(;n&&n.z<=maxZ;){if(n.x>=x0&&n.x<=x1&&n.y>=y0&&n.y<=y1&&n!==a&&n!==c&&pointInTriangleExceptFirst(ax,ay,bx,by,cx,cy,n.x,n.y)&&area(n.prev,n,n.next)>=0)return!1;n=n.nextZ}return!0}function cureLocalIntersections(start,triangles){let p=start;do{const a=p.prev,b=p.next.next;!equals(a,b)&&intersects(a,p,p.next,b)&&locallyInside(a,b)&&locallyInside(b,a)&&(triangles.push(a.i,p.i,b.i),removeNode(p),removeNode(p.next),p=start=b),p=p.next}while(p!==start);return filterPoints(p)}function splitEarcut(start,triangles,dim,minX,minY,invSize){let a=start;do{let b=a.next.next;for(;b!==a.prev;){if(a.i!==b.i&&isValidDiagonal(a,b)){let c=splitPolygon(a,b);return a=filterPoints(a,a.next),c=filterPoints(c,c.next),earcutLinked(a,triangles,dim,minX,minY,invSize,0),void earcutLinked(c,triangles,dim,minX,minY,invSize,0)}b=b.next}a=a.next}while(a!==start)}function compareXYSlope(a,b){let result=a.x-b.x;if(0===result&&(result=a.y-b.y,0===result)){result=(a.next.y-a.y)/(a.next.x-a.x)-(b.next.y-b.y)/(b.next.x-b.x)}return result}function eliminateHole(hole,outerNode){const bridge=function findHoleBridge(hole,outerNode){let p=outerNode;const hx=hole.x,hy=hole.y;let m,qx=-1/0;if(equals(hole,p))return p;do{if(equals(hole,p.next))return p.next;if(hy<=p.y&&hy>=p.next.y&&p.next.y!==p.y){const x=p.x+(hy-p.y)*(p.next.x-p.x)/(p.next.y-p.y);if(x<=hx&&x>qx&&(qx=x,m=p.x<p.next.x?p:p.next,x===hx))return m}p=p.next}while(p!==outerNode);if(!m)return null;const stop=m,mx=m.x,my=m.y;let tanMin=1/0;p=m;do{if(hx>=p.x&&p.x>=mx&&hx!==p.x&&pointInTriangle(hy<my?hx:qx,hy,mx,my,hy<my?qx:hx,hy,p.x,p.y)){const tan=Math.abs(hy-p.y)/(hx-p.x);locallyInside(p,hole)&&(tan<tanMin||tan===tanMin&&(p.x>m.x||p.x===m.x&&sectorContainsSector(m,p)))&&(m=p,tanMin=tan)}p=p.next}while(p!==stop);return m}(hole,outerNode);if(!bridge)return outerNode;const bridgeReverse=splitPolygon(bridge,hole);return filterPoints(bridgeReverse,bridgeReverse.next),filterPoints(bridge,bridge.next)}function sectorContainsSector(m,p){return area(m.prev,m,p.prev)<0&&area(p.next,m,m.next)<0}function zOrder(x,y,minX,minY,invSize){return(x=1431655765&((x=858993459&((x=252645135&((x=16711935&((x=(x-minX)*invSize|0)|x<<8))|x<<4))|x<<2))|x<<1))|(y=1431655765&((y=858993459&((y=252645135&((y=16711935&((y=(y-minY)*invSize|0)|y<<8))|y<<4))|y<<2))|y<<1))<<1}function getLeftmost(start){let p=start,leftmost=start;do{(p.x<leftmost.x||p.x===leftmost.x&&p.y<leftmost.y)&&(leftmost=p),p=p.next}while(p!==start);return leftmost}function pointInTriangle(ax,ay,bx,by,cx,cy,px,py){return(cx-px)*(ay-py)>=(ax-px)*(cy-py)&&(ax-px)*(by-py)>=(bx-px)*(ay-py)&&(bx-px)*(cy-py)>=(cx-px)*(by-py)}function pointInTriangleExceptFirst(ax,ay,bx,by,cx,cy,px,py){return!(ax===px&&ay===py)&&pointInTriangle(ax,ay,bx,by,cx,cy,px,py)}function isValidDiagonal(a,b){return a.next.i!==b.i&&a.prev.i!==b.i&&!function intersectsPolygon(a,b){let p=a;do{if(p.i!==a.i&&p.next.i!==a.i&&p.i!==b.i&&p.next.i!==b.i&&intersects(p,p.next,a,b))return!0;p=p.next}while(p!==a);return!1}(a,b)&&(locallyInside(a,b)&&locallyInside(b,a)&&function middleInside(a,b){let p=a,inside=!1;const px=(a.x+b.x)/2,py=(a.y+b.y)/2;do{p.y>py!=p.next.y>py&&p.next.y!==p.y&&px<(p.next.x-p.x)*(py-p.y)/(p.next.y-p.y)+p.x&&(inside=!inside),p=p.next}while(p!==a);return inside}(a,b)&&(area(a.prev,a,b.prev)||area(a,b.prev,b))||equals(a,b)&&area(a.prev,a,a.next)>0&&area(b.prev,b,b.next)>0)}function area(p,q,r){return(q.y-p.y)*(r.x-q.x)-(q.x-p.x)*(r.y-q.y)}function equals(p1,p2){return p1.x===p2.x&&p1.y===p2.y}function intersects(p1,q1,p2,q2){const o1=sign(area(p1,q1,p2)),o2=sign(area(p1,q1,q2)),o3=sign(area(p2,q2,p1)),o4=sign(area(p2,q2,q1));return o1!==o2&&o3!==o4||(!(0!==o1||!onSegment(p1,p2,q1))||(!(0!==o2||!onSegment(p1,q2,q1))||(!(0!==o3||!onSegment(p2,p1,q2))||!(0!==o4||!onSegment(p2,q1,q2)))))}function onSegment(p,q,r){return q.x<=Math.max(p.x,r.x)&&q.x>=Math.min(p.x,r.x)&&q.y<=Math.max(p.y,r.y)&&q.y>=Math.min(p.y,r.y)}function sign(num){return num>0?1:num<0?-1:0}function locallyInside(a,b){return area(a.prev,a,a.next)<0?area(a,b,a.next)>=0&&area(a,a.prev,b)>=0:area(a,b,a.prev)<0||area(a,a.next,b)<0}function splitPolygon(a,b){const a2=createNode(a.i,a.x,a.y),b2=createNode(b.i,b.x,b.y),an=a.next,bp=b.prev;return a.next=b,b.prev=a,a2.next=an,an.prev=a2,b2.next=a2,a2.prev=b2,bp.next=b2,b2.prev=bp,b2}function insertNode(i,x,y,last){const p=createNode(i,x,y);return last?(p.next=last.next,p.prev=last,last.next.prev=p,last.next=p):(p.prev=p,p.next=p),p}function removeNode(p){p.next.prev=p.prev,p.prev.next=p.next,p.prevZ&&(p.prevZ.nextZ=p.nextZ),p.nextZ&&(p.nextZ.prevZ=p.prevZ)}function createNode(i,x,y){return{i:i,x:x,y:y,prev:null,next:null,z:0,prevZ:null,nextZ:null,steiner:!1}}function infoestrudi(shape,hshape,pts,options){options||(options={}),pts||(pts=[]);let p0=options.p0||0,coeffbase1=Math.tan(options.coeffbase1*PIF||0),coeffbase2=Math.tan(options.coeffbase2*PIF||0),p1=hshape||options.p1||20,coefftop1=Math.tan(options.coefftop1*PIF||0),coefftop2=Math.tan(options.coefftop2*PIF||0),{mi:mi,ma:ma}=shape.pt.reduce(((t,e)=>(t.mi.x=Math.min(t.mi.x,e.x),t.mi.y=Math.min(t.mi.y,e.y),t.ma.x=Math.max(t.ma.x,e.x),t.ma.y=Math.max(t.ma.y,e.y),t)),{mi:{x:1e9,y:1e9},ma:{x:-1e9,y:-1e9}}),lmax=0,lmin=1e9;function getpars(p){p.z1=getzeta(p.x,p.y,p0,coeffbase1,coeffbase2),p.z2=getzeta(p.x,p.y,p1,coefftop1,coefftop2),p.l=Math.abs(p.z2-p.z1)}for(let p of pts)getpars(p);getpars(mi),getpars(ma);let rect=[{x:mi.x,y:mi.y},{x:ma.x,y:mi.y},{x:ma.x,y:ma.y},{x:mi.x,y:ma.y}];for(let r of rect)getpars(r),r.l>lmax&&(lmax=r.l),r.l<lmin&&(lmin=r.l);return{aini:options.coeffbase1||0,aini2:options.coeffbase2||0,afin:options.coefftop1||0,afin2:options.coefftop2||0,pts:pts,mi:mi,ma:ma,rect:rect,dimx:ma.x-mi.x,dimy:ma.y-mi.y,lnom:p1-p0,lmax:lmax,lmin:lmin,lmed:(lmax+lmin)/2}}function getzeta(x,y,zbase,cx,cy){return x*cx+y*cy+zbase}function sidegeomfromshapes(gcad,ky,s1,s2,invert=!1){if(s1&&s2){if(s1.length!==s2.length)throw new Error("shapes with different length");if(s1.length<2)throw new Error("I percorsi devono contenere almeno due punti ciascuno.");if(!gcad.geo[ky]){const positions=[],uvs=[],indices=[],np=s1.length,addpts=ss=>{for(const s of ss)positions.push(s.x,s.y,s.z),uvs.push(s.u,s.v)},equalpos=(p1,p2)=>p1.x===p2.x&&p1.y===p2.y&&p1.z===p2.z,addindexquad=(i1,i2,i3,i4)=>{invert?indices.push(i1,i3,i2,i3,i4,i2):indices.push(i1,i2,i3,i3,i2,i4)};addpts(s1),addpts(s2);for(let i=0;i<np-1;i++){const j=i+1;equalpos(s1[i],s1[j])||addindexquad(i,j,i+np,j+np)}const geometry=new THREE.BufferGeometry;geometry.setAttribute("position",new THREE.Float32BufferAttribute(positions,3)),geometry.setAttribute("uv",new THREE.Float32BufferAttribute(uvs,2)),geometry.setIndex(indices),geometry.computeVertexNormals(),gcad.geo[ky]=geometry}return gcad.geo[ky]}}function bottomgeomfromshape(gcad,inverti,outer,holes,c=0,a=0,b=0){let ky=`bg:${c}|${a}${b}|${outer.key}|${inverti}`;for(let h of holes)ky=`${ky}|${h.key}`;if(ky=hash(ky),!gcad.geo[ky]){let triangles,pos=[],hl=[],cc=outer.pt.length;if(pos=outer.vec,Array.isArray(holes)){for(let h of holes)hl.push(cc),cc+=h.pt.length,pos=[...pos,...h.vec];triangles=earcut(pos,hl)}else triangles=earcut(pos);const geometry=new THREE.BufferGeometry,vertices=[],uvs=[],indices=[];for(let i=0;i<triangles.length;i++){const index=triangles[i],x=pos[2*index],y=-pos[2*index+1],z=getzeta(x,y,c,a,b);vertices.push(x,y,z),uvs.push(y,x)}for(let i=0;i<triangles.length;i+=3)inverti?indices.push(i,i+2,i+1):indices.push(i,i+1,i+2);geometry.setAttribute("position",new THREE.Float32BufferAttribute(vertices,3)),geometry.setAttribute("uv",new THREE.Float32BufferAttribute(uvs,2)),geometry.setIndex(indices),geometry.computeVertexNormals(),gcad.geo[ky]=geometry}return gcad.geo[ky]}function estrusorotate(orientamento,mesh,z=0){switch(orientamento.trim().toUpperCase().slice(0,1)){case"A":mesh.rotation.x=-Math.PI/2;break;case"L":mesh.rotation.y=Math.PI/2,mesh.rotation.z=Math.PI;break;case"P":mesh.rotation.z=Math.PI/2}return mesh}
94
- /**
95
- * Crea una geometria estrusa con opzioni avanzate
96
- * @param {string} orient - Orientamento dell'estrusione
97
- * @param {number} hshape - Altezza dell'estrusione
98
- * @param {Object} shape - Forma base
99
- * @param {Array} holes - Array di fori
100
- * @param {Array} mats - Array di materiali
101
- * @param {Object} options - Opzioni di configurazione
102
- * @returns {THREE.Group} Gruppo contenente la geometria estrusa
103
- */function estruso(gcad,orient,hshape,shape,holes,mats,options){options||(options={}),mats||(mats=[]),Array.isArray(mats)||(mats=[mats,mats,mats]);let p0=options.p0||0,coeffbase1=Math.tan(options.coeffbase1*PIF||0),coeffbase2=Math.tan(options.coeffbase2*PIF||0),p1=hshape||options.p1||20,coefftop1=Math.tan(options.coefftop1*PIF||0),coefftop2=Math.tan(options.coefftop2*PIF||0),open=options.open||!1,grp=new THREE.Group;if(shape){if(!options.nobase){let g1=bottomgeomfromshape(gcad,!1,shape,open?[]:holes,p0,coeffbase1,coeffbase2);options.nolines||grp.add(edgesfromgeometry(g1)),grp.add(getmesh(g1,mats[0]||mwhite))}if(!options.notop){let g3=bottomgeomfromshape(gcad,!0,shape,open?[]:holes,p1,coefftop1,coefftop2);grp.add(getmesh(g3,mats[1]||mats[0]||mwhite)),options.nolines||grp.add(edgesfromgeometry(g3))}if(!options.nosides){let pat1=shape.to3d(0,p0,coeffbase1,-coeffbase2,open),pat2=shape.to3d(1,p1,coefftop1,-coefftop2,open),ky=`${shape.key}|${p0}|${p1}|${coeffbase1}|${coeffbase2}|${coefftop1}|${coefftop2}|${open}`,geo1=sidegeomfromshapes(gcad,ky,pat1,pat2,!1);if(options.nolines||options.nosidelines||grp.add(edgesfromgeometry(geo1)),grp.add(getmesh(geo1,mats[2]||mats[0]||mwhite)),holes&&!open)for(var h of holes){pat1=h.to3d(0,p0,coeffbase1,coeffbase2),pat2=h.to3d(0,p1,coefftop1,coefftop2),ky=`${h.key}|${p0}|${p1}|${coeffbase1}|${coeffbase2}|${coefftop1}|${coefftop2}`;let geo2=sidegeomfromshapes(gcad,ky,pat1,pat2,!0);options.nolines||options.nosidelines||grp.add(edgesfromgeometry(geo2)),grp.add(getmesh(geo2,mats[3]||mats[0]||mwhite))}}return estrusorotate(orient,grp,hshape)}return grp}function revolve(gcad,shape,orient,mat,options){options||(options={});let segmenti=options.segmenti??12,ky=hash(`rev|${shape.key}|${orient}|${segmenti}`),geometria=gcad.geo[ky],grp=new THREE.Group;if(!geometria){const punti3D=shape.pt.map((p=>new THREE.Vector3(p.x,p.y,0)));geometria=new THREE.LatheGeometry(punti3D,segmenti,0,2*Math.PI),gcad.geo[ky]=geometria}const mesh=new THREE.Mesh(geometria,mat);return grp.add(mesh),options.nolines||options.nosidelines||grp.add(edgesfromgeometry(geometria)),grp}
104
- /**
105
- * Crea una geometria estrusa con opzioni avanzate
106
- * @param {string} orient - Orientamento dell'estrusione
107
- * @param {number} hshape - Altezza dell'estrusione
108
- * @param {Object} shape - Forma base
109
- * @param {Array} holes - Array di fori
110
- * @param {Array} mats - Array di materiali
111
- * @param {Object} options - Opzioni di configurazione
112
- * @returns {THREE.Group} Gruppo contenente la geometria estrusa
113
- */function estrusopat(gcad,orient,pat,shape,mats,options){options||(options={});let invert=options.invert;mats||(mats=[]);let open=options.open;if(!pat.pt?.length)return;let pbase=shape.to3d(0,0,0,0,open),grp=new THREE.Group;if(!options.nobase){let gb=new THREE.Group,g1=bottomgeomfromshape(gcad,!1,shape,[],0,0,0);gb.add(getmesh(g1,mats[0]||mwhite)),gb.add(edgesfromgeometry(g1));let seg1=pat.infosegmento(0,!0);grp.add(posiziona(gb,{sl:seg1.x,sp:seg1.y,sa:0,ay:90-seg1.ang}))}if(!options.notop){let gt=new THREE.Group,g2=bottomgeomfromshape(gcad,!0,shape,[],0,0,0);gt.add(getmesh(g2,mats[1]||mats[0]||mwhite)),gt.add(edgesfromgeometry(g2));let seg1=pat.infosegmento(pat.pt.length-1,!0);grp.add(posiziona(gt,{sl:seg1.x,sp:seg1.y,sa:0,ay:90-seg1.ang}))}const geo1=function sidegeomfrompat(gcad,pbase,pat,invert){let ky=`bsg:${pbase.key}|${pat.key}|${invert}`;if(ky=hash(ky),!gcad.geo[ky]){const positions=[],uvs=[],indices=[],np=pbase.length,lp=pat.pt.length,equalpos=(p1,p2)=>p1.x===p2.x&&p1.y===p2.y&&p1.z===p2.z;let l0=0;for(let ii=0;ii<lp;ii++){const addpts=(ss,mat,deltav)=>{for(const s of ss){let p=new THREE.Vector3(s.x,s.y,s.z);p.applyMatrix4(mat),positions.push(p.x,p.y,p.z),uvs.push(s.u,s.v+deltav)}};let seg1=pat.infosegmento(ii,!0),obj=new THREE.Object3D;obj.position.set(seg1.x,0,seg1.y),obj.rotation.set(0,(90-seg1.ang)*PIF,0),obj.updateMatrix(),addpts(pbase,obj.matrix,l0),l0+=seg1.l}for(let li=0;li<lp-1;li++)for(let i=0;i<np-1;i++){const addindexquad=(i1,i2,i3,i4)=>{invert?indices.push(i1,i3,i2,i3,i4,i2):indices.push(i1,i2,i3,i3,i2,i4)},j=i+1;equalpos(pbase[i],pbase[j])||addindexquad(i+li*np,j+li*np,i+(li+1)*np,j+(li+1)*np)}const geometry=new THREE.BufferGeometry;geometry.setAttribute("position",new THREE.Float32BufferAttribute(positions,3)),geometry.setAttribute("uv",new THREE.Float32BufferAttribute(uvs,2)),geometry.setIndex(indices),geometry.computeVertexNormals(),gcad[ky]=geometry}return gcad[ky]}(gcad,pbase,pat,invert);return options.nolines||options.nosidelines||grp.add(edgesfromgeometry(geo1)),grp.add(getmesh(geo1,mats[2]||mats[0]||mwhite)),estrusorotate(orient,grp,0)}async function spritemat(gcad,file){try{let tm={transparent:!0,depthTest:!1,depthWrite:!1,fog:!1,toneMapped:!1};if(file.startsWith("#"))tm.color=file;else{let tx=await gcad.tex(file,1e3,1e3);tx?tm.map=tx:tm.color="black"}return new THREE.SpriteMaterial(tm)}catch(error){return mwhite}}function getsprite0(ispunto,x,y,z,mat,options={}){options||(options={});let{size:size=50,pick:pick=!1,screen:screen=!1,sizex:sizex,sizey:sizey}=options;const sprite=new THREE.Sprite(mat);sprite.position.set(0,0,0),sprite.userData.issprite=!0,sprite.userData.ispunto=ispunto,sprite.userData.ispick=pick,sprite.userData.isScreen=screen,sprite.renderOrder=999,sprite.layers.set(29),sprite.name=ispunto?"_punto":"_sprite";let gr=new THREE.Group;return gr.position.set(x,y,z),gr.scale.set(sizex||size,sizey||sizex||size,1),gr.add(sprite),gr.traverse((obj=>{obj.material&&(obj.material.depthTest=!1,obj.material.depthWrite=!1)})),gr.renderOrder=999,gr}async function getpunto(gcad,x,y,z,color="yellow",options){options||(options={size:20}),options.screen=!0;const texture=await function createCircleTexture(gcad,size=64,color="rgba(255,0,0,1)"){const ky=`ct|${size}|${color}`;if(!gcad.textures[ky]){const canvas=document.createElement("canvas");canvas.width=canvas.height=size;const ctx=canvas.getContext("2d"),radius=size/2;ctx.clearRect(0,0,size,size),ctx.fillStyle=color,ctx.beginPath(),ctx.arc(radius,radius,radius,0,2*Math.PI),ctx.fill();const texture=new THREE.CanvasTexture(canvas);texture.needsUpdate=!0,gcad.textures[ky]=texture}return gcad.textures[ky]}(gcad,64,color);return getsprite0(!0,x,y,z,new THREE.SpriteMaterial({map:texture,transparent:!0,fog:!1,toneMapped:!1}),options)}function getsprite(gcad,x,y,z,mat,options={}){return getsprite0(!1,x,y,z,mat,options)}function setLineColorMode(white){white?(materialline1.color.set(16777215),materialline2.color.set(16777215)):(materialline1.color.set(3158064),materialline2.color.set(5263440)),materialline1.needsUpdate=!0,materialline2.needsUpdate=!0}export{SIDE,addmovpivot,calcolatasks,creategroup,deletegroup,edgesfromgeometry,estruso,estrusopat,get3dshape,getbox,getcilindro,getcyl,getemitter,getface,getfakeshadow,getline,getlinesgeom,getmesh,getmovimento,getpannello,getpoint,getpunto,getquota,getreceiver,getriferimento,getsprite,gettarghetta,groupfromgeometry,infoestrudi,materialline1,materialline2,mblack,mblue,mgray1,mgray2,mgreen,mred,mwhite,posiziona,randombasemat,revolve,scaleunit,setLineColorMode,smat,spritemat,svuotanodo};