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/bin/markcad.js +573 -42
- package/package.json +1 -6
- package/types/markcad.d.ts +202 -8
- package/bin/markcad3d.js +0 -113
- package/types/markcad3d.d.ts +0 -169
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markuno_lib",
|
|
3
|
-
"version": "1.
|
|
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",
|
package/types/markcad.d.ts
CHANGED
|
@@ -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
|
-
|
|
295
|
-
|
|
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
|
-
*
|
|
384
|
-
* @param {
|
|
385
|
-
* @param {number}
|
|
386
|
-
* @
|
|
387
|
-
|
|
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&¶mstr.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&>imeline.length&>imeline.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&§orContainsSector(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};
|