markuno_lib 1.1.36 → 1.1.38
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 +35 -7
- package/bin/markcad3d.js +2 -2
- package/bin/markuno.js +3 -2
- package/package.json +1 -1
- package/types/markcad.d.ts +106 -60
- package/types/markcad3d.d.ts +1 -0
- package/types/markuno.d.ts +2 -1
package/bin/markcad.js
CHANGED
|
@@ -154,7 +154,19 @@ constructor(p1,p2,x2=null,y2=null){"number"==typeof p1&&"number"==typeof p2&&nul
|
|
|
154
154
|
*/function hash(obj){let str="";if("string"==typeof obj||"number"==typeof obj)str=obj+"";else if("object"==typeof obj&&obj){const chiaviOrdinati=Object.keys(obj).sort(),separatore="\0";str=chiaviOrdinati.map((key=>`${key}${separatore}${String(obj[key])}`)).join(separatore)}let h1=2166136261,h2=2218511855;for(let i=0;i<str.length;i++){const char=str.charCodeAt(i);h1^=char,h1+=h1<<5^2779096485,h2^=h1,h2=((h2<<3)+char^2134516169)>>>0}return h1>>>=0,h1.toString(16)+h2.toString(16)}
|
|
155
155
|
/**
|
|
156
156
|
* Classe per la gestione degli errori con funzionalità di accumulo e formattazione
|
|
157
|
-
*/function clamp(n,min=-1/0,max=1/0){return(n=Number(n)||0)<min&&(n=min),n>max&&(n=max),n}function getSqSegDist(p,p1,p2){var x=p1.x,y=p1.y,dx=p2.x-x,dy=p2.y-y;if(0!==dx||0!==dy){var t=((p.x-x)*dx+(p.y-y)*dy)/(dx*dx+dy*dy);t>1?(x=p2.x,y=p2.y):t>0&&(x+=dx*t,y+=dy*t)}return(dx=p.x-x)*dx+(dy=p.y-y)*dy}function simplifyDPStep(points,first,last,sqTolerance,simplified){for(var index,maxSqDist=sqTolerance,i=first+1;i<last;i++){var sqDist=getSqSegDist(points[i],points[first],points[last]);sqDist>maxSqDist&&(index=i,maxSqDist=sqDist)}maxSqDist>sqTolerance&&(index-first>1&&simplifyDPStep(points,first,index,sqTolerance,simplified),simplified.push(points[index]),last-index>1&&simplifyDPStep(points,index,last,sqTolerance,simplified))}function simplifyDouglasPeucker(points,sqTolerance){var last=points.length-1,simplified=[points[0]];return simplifyDPStep(points,0,last,sqTolerance,simplified),simplified.push(points[last]),simplified}
|
|
157
|
+
*/function clamp(n,min=-1/0,max=1/0){return(n=Number(n)||0)<min&&(n=min),n>max&&(n=max),n}function getSqSegDist(p,p1,p2){var x=p1.x,y=p1.y,dx=p2.x-x,dy=p2.y-y;if(0!==dx||0!==dy){var t=((p.x-x)*dx+(p.y-y)*dy)/(dx*dx+dy*dy);t>1?(x=p2.x,y=p2.y):t>0&&(x+=dx*t,y+=dy*t)}return(dx=p.x-x)*dx+(dy=p.y-y)*dy}function simplifyDPStep(points,first,last,sqTolerance,simplified){for(var index,maxSqDist=sqTolerance,i=first+1;i<last;i++){var sqDist=getSqSegDist(points[i],points[first],points[last]);sqDist>maxSqDist&&(index=i,maxSqDist=sqDist)}maxSqDist>sqTolerance&&(index-first>1&&simplifyDPStep(points,first,index,sqTolerance,simplified),simplified.push(points[index]),last-index>1&&simplifyDPStep(points,index,last,sqTolerance,simplified))}function simplifyDouglasPeucker(points,sqTolerance){var last=points.length-1,simplified=[points[0]];return simplifyDPStep(points,0,last,sqTolerance,simplified),simplified.push(points[last]),simplified}
|
|
158
|
+
/**
|
|
159
|
+
* Esegue la semplificazione di un poligono (array di punti) combinando
|
|
160
|
+
* l’algoritmo di distanza radiale e l’algoritmo di Ramer–Douglas–Peucker.
|
|
161
|
+
*
|
|
162
|
+
* @param {Array<{x:number,y:number}>} points - Array di punti {x,y} da semplificare.
|
|
163
|
+
* @param {number} [tolerance=1] - Tolleranza di semplificazione: distanza minima consentita
|
|
164
|
+
* (in unità lineari) tra i punti; internamente usata al quadrato per il calcolo
|
|
165
|
+
* (`sqTolerance = tolerance * tolerance`). Valori più grandi rimuovono più punti.
|
|
166
|
+
* @param {boolean} [highestQuality=false] - Se `true`, salta il passaggio di
|
|
167
|
+
* semplificazione radiale e usa solo Douglas–Peucker per massima qualità.
|
|
168
|
+
* @returns {Array<{x:number,y:number}>} Nuovo array di punti semplificato.
|
|
169
|
+
*/new class Errori{constructor(){this.azzera()}
|
|
158
170
|
/**
|
|
159
171
|
* Azzera la lista degli errori
|
|
160
172
|
*/azzera(){this.err=[]}
|
|
@@ -259,7 +271,7 @@ function getshape(){let pt=[];
|
|
|
259
271
|
/**
|
|
260
272
|
* Converte i punti in array di coordinate
|
|
261
273
|
* @returns {Array<number>} Array [x1,y1,x2,y2,...]
|
|
262
|
-
*/function tovec(){
|
|
274
|
+
*/function tovec(){return pt.flatMap((p=>[p.x,p.y]))}
|
|
263
275
|
/**
|
|
264
276
|
* Verifica se un punto è interno al poligono usando ray casting
|
|
265
277
|
* @param {Object} P - Punto da verificare {x,y}
|
|
@@ -269,7 +281,23 @@ function getshape(){let pt=[];
|
|
|
269
281
|
* Aggiunge punti da array di coordinate
|
|
270
282
|
* @param {Array<number>} aa - Array [x1,y1,x2,y2,...]
|
|
271
283
|
*/
|
|
272
|
-
function _addvec(aa){for(let i=0;i<aa.length;i+=2)pt.push({x:aa[i],y:aa[i+1]})}function dims(pts){let{p1:p1,p2:p2}=pts.reduce(((m,p)=>(m.p1.x=Math.min(m.p1.x,p.x),m.p2.x=Math.max(m.p2.x,p.x),m.p1.y=Math.min(m.p1.y,p.y),m.p2.y=Math.max(m.p2.y,p.y),m)),{p1:new Punto2(1/0,1/0),p2:new Punto2(-1/0,-1/0)}),isrect=!1;if(4==pts.length){const TOLL=.001;function findpunto(x,y){return!!pts.find((p=>Math.abs(p.x-x)<TOLL&&Math.abs(p.y-y)<TOLL))}findpunto(p1.x,p1.y)&&findpunto(p1.x,p2.y)&&findpunto(p2.x,p1.y)&&findpunto(p2.x,p2.y)&&(isrect=!0)}return{p1:p1,p2:p2,isrect:isrect,width:p2.x-p1.x,height:p2.y-p1.y}}return{get key(){return hash(tovec().join("\t"))},orienta:function orienta(p0,p1){if(!p0||!p1)return null;const dx=p1.x-p0.x,dy=p1.y-p0.y,angolo=180*Math.atan2(dy,dx)/Math.PI,matrix=new Matrix3D;matrix.rotateZ(-angolo),matrix.translate(-p0.x,-p0.y,0);const ptTrasformati=pt.map((p=>matrix.transform(p.x,p.y)));let mm=ptTrasformati.reduce(((m,p)=>(m.p1.x=Math.min(m.p1.x,p.x),m.p2.x=Math.max(m.p2.x,p.x),m.p1.y=Math.min(m.p1.y,p.y),m.p2.y=Math.max(m.p2.y,p.y),m)),{p1:new Punto2(1/0,1/0),p2:new Punto2(-1/0,-1/0)});return{shape:getshape().frompt(ptTrasformati),origine:new Punto2(p0.x,p0.y),angolo:angolo,mm:mm,width:mm.p2.x-mm.p1.x,height:mm.p2.y-mm.p1.y}},rebase:function rebase(angolo,forceorigin=!1,ox=0,oy=0){const matrix=new Matrix3D;matrix.rotateZ(-angolo);let ptTrasformati=pt.map((p=>matrix.transform(p.x,p.y))),{p1:p1,p2:p2,width:width,height:height}=dims(ptTrasformati);return forceorigin||(ox=p1.x,oy=p1.y),ptTrasformati=ptTrasformati.map((p=>new Punto2(p.x-ox,p.y-oy))),{shape:getshape().frompt(ptTrasformati),origine:new Punto2(ox,oy),angolo:angolo,width:width,height:height}},get pt(){return pt},get vec(){return tovec()},toJSON:()=>({vec:tovec(),orient:orientation()}),get orient(){return orientation()},clone:()=>getshape().frompt(pt),dims:()=>dims(pt),rotate(deg){if(!deg)return this;const r=deg*Math.PI/180,cosTheta=Math.cos(r),sinTheta=Math.sin(r);for(let p of pt){const xNew=p.x*cosTheta-p.y*sinTheta,yNew=p.x*sinTheta+p.y*cosTheta;p.x=xNew,p.y=yNew}return this},selezionaprimo:function selezionaprimo(idprimopunto){return(idprimopunto%=pt.length)>0&&(pt=[...pt.slice(idprimopunto),...pt.slice(0,idprimopunto)]),this},segment(i,inverse=!1){let n=pt.length;return i<0&&(i+=n),new Linea2(pt[i%n],pt[(i+(inverse?-1:1))%n])},lineoffset(i1,i2,offset){if((i1=(i1||0)%pt.length)!=(i2=(i2||0)%pt.length)){let l2=new Linea2(pt[i1],pt[i2]);if(l2){return l2=l2.offsetline(-offset),this.intersectline(l2)}}},move(x=0,y=0){for(let p of pt)p.x+=x,p.y+=y;return this},mirrorx(value=0){for(let p of pt)p.x=2*value-p.x;return this},mirrory(value=0){for(let p of pt)p.y=2*value-p.y;return this},simplify(tolerance,hq){return pt=function simplify(points,tolerance,highestQuality){if(points.length<=2)return points;var sqTolerance=void 0!==tolerance?tolerance*tolerance:1;return simplifyDouglasPeucker(points=highestQuality?points:function simplifyRadialDist(points,sqTolerance){for(var point,p1,p2,dx,dy,prevPoint=points[0],newPoints=[prevPoint],i=1,len=points.length;i<len;i++)p2=prevPoint,dx=void 0,dy=void 0,(dx=(p1=point=points[i]).x-p2.x)*dx+(dy=p1.y-p2.y)*dy>sqTolerance&&(newPoints.push(point),prevPoint=point);return prevPoint!==point&&newPoints.push(point),newPoints}(points,sqTolerance),sqTolerance)}(pt,tolerance,hq),this},fromclip(vv){pt=[];for(let p of vv)pt.push({x:p.x/1e3,y:p.y/1e3});return this},infosegmento(i,open=!1){const n=pt.length;function clampIndex(idx){return(idx+n)%n}function angle(p1,p2){return Math.atan2(p2.y-p1.y,p2.x-p1.x)}function angleDiff(a,b){let diff=a-b;for(;diff>Math.PI;)diff-=2*Math.PI;for(;diff<-Math.PI;)diff+=2*Math.PI;return diff}const p1=pt[i];let p0,p2,p3;if(open)if(0===i){const dx=pt[1].x-pt[0].x,dy=pt[1].y-pt[0].y;p0={x:pt[0].x-dx,y:pt[0].y-dy},p2=pt[1],p3=pt[2]}else if(i===n-1){const dx=pt[n-1].x-pt[n-2].x,dy=pt[n-1].y-pt[n-2].y;p0=pt[n-2],p2={x:pt[n-1].x+dx,y:pt[n-1].y+dy},p3={x:p2.x+dx,y:p2.y+dy}}else p0=pt[i-1],p2=pt[i+1],p3=i+2<n?pt[i+2]:{x:pt[i+1].x+(pt[i+1].x-pt[i].x),y:pt[i+1].y+(pt[i+1].y-pt[i].y)};else{const i0=clampIndex(i-1),i2=clampIndex(i+1),i3=clampIndex(i+2);p0=pt[i0],p2=pt[i2],p3=pt[i3]}const ang12=angle(p1,p2),ang01=angle(p0,p1),ang23=angle(p2,p3);return{x:p1.x,y:p1.y,l:function length(p1,p2){const dx=p2.x-p1.x,dy=p2.y-p1.y;return Math.sqrt(dx*dx+dy*dy)}(p1,p2),ang:ang12/PIF,a1:angleDiff(ang12,ang01)/PIF,a2:angleDiff(ang23,ang12)/PIF}},fromvec(aa){return pt=[],_addvec(aa),this},addvec(vec){return _addvec(vec),this},frompt(pts){return pt=[...pts],pt=removeduplicate(pt),this},fromstr(str){return pt=removeduplicate(function processTokens(tokens){const points=[];for(let i=0;i<tokens.length;i++){const token=tokens[i];if("point"===token.type)points.push(token.point);else if("command"===token.type)switch(token.cmd){case"b":{if(points.length<2)continue;const npt=parseInt(token.params[0])||5,p1=points[points.length-2],p2=points[points.length-1];let p3="point"===tokens[i+1]?.type?tokens[i+1].point:void 0,p4="point"===tokens[i+2]?.type?tokens[i+2].point:void 0;p3?p4||(p4=points[0]):(p3=points[0],p4=points[1]);const raccordo=raccordabezier(p1,p2,p3,p4,npt);points.push(...raccordo),i+=1;break}case"r":{if(points.length<1)continue;const dist=parseFloat(token.params[0])||5,npt=parseInt(token.params[1])||10,p1=points[points.length-1];let p2="point"===tokens[i+1]?.type?tokens[i+1].point:void 0,p3="point"===tokens[i+2]?.type?tokens[i+2].point:"point"===tokens[i+3]?.type?tokens[i+3].point:void 0;p2?p3||(p3=points[0]):(p2=points[0],p3=points[1],points.splice(0,1));const raccordo=raccordabezier3(p1,p2,p3,dist,npt);points.push(...raccordo),i+=1;break}case"c":{const radius=parseFloat(token.params[0])||50,segments=parseInt(token.params[1])||12,center="point"===tokens[i+1]?.type?tokens[i+1].point:new Punto2(0,0);for(let j=0;j<segments;j++)points.push(new Punto2(center.x+radius*Math.cos(j/segments*Math.PI*2),center.y+radius*Math.sin(j/segments*Math.PI*2)));i+=1;break}case"a":{let npt,p1="point"===tokens[i+1]?.type?tokens[i+1].point:void 0,p2="point"===tokens[i+2]?.type?tokens[i+2].point:void 0,p3="point"===tokens[i+3]?.type?tokens[i+3].point:void 0;if(!p1||!p3)continue;if(p2)if(token.params[0])npt=clamp(parseInt(token.params[0]),1,24);else{const chord=Math.hypot(p3.x-p1.x,p3.y-p1.y),sagitta=Math.abs((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))/(2*chord);npt=Math.round(chord*Math.sqrt(sagitta/(chord+.1))*10),npt=clamp(npt,1,24),npt=1}else p2=p3,npt=0;const arcoPoints=arcfrom3point(npt,p1,p2,p3);points.push(...arcoPoints),i+=3;break}}}return points}(function tokenize(str){const tokens=[],values=str.toLowerCase().replace(/[\n\s]+/gm," ").split(/[,;]/).map((s=>s.trim()));for(let i=0;i<values.length;){const current=values[i];["b","r","c","a"].includes(current[0])?(tokens.push({type:"command",cmd:current[0],params:current.slice(1).split(":")}),i++):/[a-zA-Z]/.test(current[0])||(i<values.length-1?(tokens.push({type:"point",point:new Punto2(parseFloat(values[i]),parseFloat(values[i+1]))}),i+=2):i++)}return tokens}(str))),this},fromrect(w,h,sx,sy,bordo){w||(w=10),h||(h=10),bordo||(bordo=0),bordo=Math.min(Math.abs(bordo),Math.abs(.4*w),Math.abs(.4*h));let b1=w>0?bordo:-bordo,b2=h>0?bordo:-bordo;return pt=bordo?[{x:b1,y:0},{x:w-b1,y:0},{x:w,y:b2},{x:w,y:h-b2},{x:w-b1,y:h},{x:b1,y:h},{x:0,y:h-b2},{x:0,y:b2}]:[{x:0,y:0},{x:w,y:0},{x:w,y:h},{x:0,y:h}],this},intersectline:l=>function _intersectline(shape,p3,p4){let n=shape.length,l=new Linea2(p3,p4);const intersezioni=[];for(let i=0;i<shape.length;i++){let l2=new Linea2(shape[i],shape[(i+1)%n]),p=l2.interseca(l);p&&l2.onsegment(p)&&intersezioni.push(p)}if(intersezioni.length<2)return null;const{dx:dx,dy:dy}=l;intersezioni.sort(((a,b)=>(a.x-p3.x)*dx+(a.y-p3.y)*dy-((b.x-p3.x)*dx+(b.y-p3.y)*dy)));let pstart=new Punto2(intersezioni[0].x,intersezioni[0].y),pend=new Punto2(intersezioni[intersezioni.length-1].x,intersezioni[intersezioni.length-1].y);const vx1=pend.x-pstart.x,vy1=pend.y-pstart.y;return vx1*dx+vy1*dy<0&&([pstart,pend]=[pend,pstart]),new Linea2(pstart,pend)}(pt,l.p1,l.p2),addpt(pts){return pts?(Array.isArray(pts)||(pts=[pts]),pt=removeduplicate([...pt,...pts]),this):this},addracc(v1,v2,suddivisioni=2,addv1v2=!0){if(Array.isArray(v1)&&(v2={x:v1[2]||0,y:v1[3]||0},v1={x:v1[0]||0,y:v1[1]||0}),pt.length>=2){let tm=raccordabezier(pt[pt.length-2],pt[pt.length-1],v1,v2,suddivisioni);pt=[...pt,...tm],addv1v2&&(pt.push(v1),pt.push(v2))}return pt=removeduplicate(pt),this},setorient(mode){let p=orientation();return(1==p&&-1==mode||-1==p&&1==mode)&&pt.reverse(),this},reverse(){return pt.reverse(),this},pointinshape:p=>function isPointInPolygon(P){let x=P.x,y=P.y,inside=!1;for(let i=0,j=pt.length-1;i<pt.length;j=i++){let xi=pt[i].x,yi=pt[i].y,xj=pt[j].x,yj=pt[j].y;yi>y!=yj>y&&x<(xj-xi)*(y-yi)/(yj-yi)+xi&&(inside=!inside)}return inside}(p),azzera(){return pt=[],this},removeduplicate(delta=.005){return pt=removeduplicate(pt,delta),this},to3d(u0,alt=0,coeffa=0,coeffb=0,open=!1){pt=removeduplicate(pt);let tm=function genuvnormal(path,options){let{currentU:currentU=0,c:c=0,a:a=0,b:b=0,anglemin:anglemin=30,open:open=!1}=options;const pointsWithNormals=[],n=path.length;for(let i=0;i<n;i++){const prev=path[(i-1+n)%n],current=path[i],next=path[(i+1)%n],vPrev={x:current.x-prev.x,y:current.y-prev.y},vNext={x:next.x-current.x,y:next.y-current.y},normalPrev=normal2(prev,current),normalNext=normal2(current,next),angle=angle2vec(vPrev,vNext);let z=a*current.x+b*current.y+c;Math.abs(angle-180)<=anglemin?(normalPrev.nx,normalNext.nx,normalPrev.ny,normalNext.ny,pointsWithNormals.push({x:current.x,y:-current.y,z:z,u:currentU,v:z})):(pointsWithNormals.push({x:current.x,y:-current.y,z:z,u:currentU,v:z}),pointsWithNormals.push({x:current.x,y:-current.y,z:z,u:currentU,v:z}));const dx=next.x-current.x,dy=next.y-current.y;currentU+=Math.sqrt(dx*dx+dy*dy)}if(!open){let p=pointsWithNormals[0],pf=pointsWithNormals[pointsWithNormals.length-1];p.x==pf.x&&p.y==pf.y||pointsWithNormals.push({x:p.x,y:p.y,z:p.z,nx:p.nx,ny:p.ny,nz:p.nz,u:currentU,v:p.z})}return pointsWithNormals}(pt,{open:open,currentU:u0,c:alt,a:coeffa,b:coeffb,anglemin:30});return tm},getboundbox:()=>pt.length?pt.reduce(((box,p)=>(box.p1.x=Math.min(box.p1.x,p.x),box.p1.y=Math.min(box.p1.y,p.y),box.p2.x=Math.max(box.p2.x,p.x),box.p2.y=Math.max(box.p2.y,p.y),box)),{p1:new Punto2(1/0,1/0),p2:new Punto2(-1/0,-1/0)}):{p1:new Punto2(0,0),p2:new Punto2(0,0)},fittobox(p1,p2){if(!pt.length)return this;const currentBox=this.getboundbox(),currentWidth=currentBox.p2.x-currentBox.p1.x,currentHeight=currentBox.p2.y-currentBox.p1.y,targetWidth=p2.x-p1.x,targetHeight=p2.y-p1.y,scale=Math.min(targetWidth/(currentWidth||1),targetHeight/(currentHeight||1));for(let p of pt)p.x=(p.x-currentBox.p1.x)*scale,p.y=(p.y-currentBox.p1.y)*scale,p.x+=p1.x,p.y+=p1.y;return this}}}
|
|
284
|
+
function _addvec(aa){for(let i=0;i<aa.length;i+=2)pt.push({x:aa[i],y:aa[i+1]})}function dims(pts){let{p1:p1,p2:p2}=pts.reduce(((m,p)=>(m.p1.x=Math.min(m.p1.x,p.x),m.p2.x=Math.max(m.p2.x,p.x),m.p1.y=Math.min(m.p1.y,p.y),m.p2.y=Math.max(m.p2.y,p.y),m)),{p1:new Punto2(1/0,1/0),p2:new Punto2(-1/0,-1/0)}),isrect=!1;if(4==pts.length){const TOLL=.001;function findpunto(x,y){return!!pts.find((p=>Math.abs(p.x-x)<TOLL&&Math.abs(p.y-y)<TOLL))}findpunto(p1.x,p1.y)&&findpunto(p1.x,p2.y)&&findpunto(p2.x,p1.y)&&findpunto(p2.x,p2.y)&&(isrect=!0)}return{p1:p1,p2:p2,isrect:isrect,width:p2.x-p1.x,height:p2.y-p1.y}}return{get key(){return hash(tovec().join("\t"))},orienta:function orienta(p0,p1){if(!p0||!p1)return null;const dx=p1.x-p0.x,dy=p1.y-p0.y,angolo=180*Math.atan2(dy,dx)/Math.PI,matrix=new Matrix3D;matrix.rotateZ(-angolo),matrix.translate(-p0.x,-p0.y,0);const ptTrasformati=pt.map((p=>matrix.transform(p.x,p.y)));let mm=ptTrasformati.reduce(((m,p)=>(m.p1.x=Math.min(m.p1.x,p.x),m.p2.x=Math.max(m.p2.x,p.x),m.p1.y=Math.min(m.p1.y,p.y),m.p2.y=Math.max(m.p2.y,p.y),m)),{p1:new Punto2(1/0,1/0),p2:new Punto2(-1/0,-1/0)});return{shape:getshape().frompt(ptTrasformati),origine:new Punto2(p0.x,p0.y),angolo:angolo,mm:mm,width:mm.p2.x-mm.p1.x,height:mm.p2.y-mm.p1.y}},rebase:function rebase(angolo,forceorigin=!1,ox=0,oy=0){const matrix=new Matrix3D;matrix.rotateZ(-angolo);let ptTrasformati=pt.map((p=>matrix.transform(p.x,p.y))),{p1:p1,p2:p2,width:width,height:height}=dims(ptTrasformati);return forceorigin||(ox=p1.x,oy=p1.y),ptTrasformati=ptTrasformati.map((p=>new Punto2(p.x-ox,p.y-oy))),{shape:getshape().frompt(ptTrasformati),origine:new Punto2(ox,oy),angolo:angolo,width:width,height:height}},get pt(){return pt},get vec(){return tovec()},toJSON:()=>({vec:tovec(),orient:orientation()}),get orient(){return orientation()},corners:(angolo=45)=>
|
|
285
|
+
/**
|
|
286
|
+
* Trova i punti in cui l’angolo interno è maggiore di `thresholdDeg`.
|
|
287
|
+
*
|
|
288
|
+
* @param {Array<{x:number,y:number}>} path - Array di punti chiuso.
|
|
289
|
+
* @param {number} thresholdDeg - Angolo in gradi.
|
|
290
|
+
* @returns {Array<{ index: number, point: {x:number,y:number}, angle: number }>}
|
|
291
|
+
*/
|
|
292
|
+
function sharpCorners(path,thresholdDeg=45){const result=[],n=path.length;if(n<3)return result;for(let i=0;i<n;i++){const prev=path[(i-1+n)%n],curr=path[i],next=path[(i+1)%n],ux=curr.x-prev.x,uy=curr.y-prev.y,vx=next.x-curr.x,vy=next.y-curr.y,magU=Math.hypot(ux,uy),magV=Math.hypot(vx,vy);if(0===magU||0===magV)continue;let cosTheta=(ux*vx+uy*vy)/(magU*magV);cosTheta=Math.max(-1,Math.min(1,cosTheta));const angleDeg=180*Math.acos(cosTheta)/Math.PI;angleDeg>thresholdDeg&&result.push({i:i,x:curr.x,y:curr.y,a:angleDeg})}return result}(pt,45),clone:()=>getshape().frompt(pt),dims:()=>dims(pt),alignline(p1,p2){return pt=function stretchShapeToLine(shapePts,p1,p2){if(!shapePts?.length||!p1||!p2)return[];const first=shapePts[0],last=shapePts[shapePts.length-1],dx=last.x-first.x,dy=last.y-first.y,ang=Math.atan2(dy,dx);let pts1=shapePts.map((p=>({x:p.x-first.x,y:p.y-first.y}))).map((p=>({x:p.x*Math.cos(-ang)-p.y*Math.sin(-ang),y:p.x*Math.sin(-ang)+p.y*Math.cos(-ang)})));const linea={dx:p2.x-p1.x,dy:p2.y-p1.y},scaleX=Math.sqrt(linea.dx*linea.dx+linea.dy*linea.dy)/(pts1[pts1.length-1].x||1e-8);let pts2=pts1.map((p=>({x:p.x*scaleX,y:p.y})));const angDest=Math.atan2(linea.dy,linea.dx);return pts2.map((p=>({x:p.x*Math.cos(angDest)-p.y*Math.sin(angDest),y:p.x*Math.sin(angDest)+p.y*Math.cos(angDest)}))).map((p=>({x:p.x+p1.x,y:p.y+p1.y})))}(pt,p1,p2),this},rotate(deg){if(!deg)return this;const r=deg*Math.PI/180,cosTheta=Math.cos(r),sinTheta=Math.sin(r);for(let p of pt){const xNew=p.x*cosTheta-p.y*sinTheta,yNew=p.x*sinTheta+p.y*cosTheta;p.x=xNew,p.y=yNew}return this},selezionaprimo:function selezionaprimo(idprimopunto){return(idprimopunto%=pt.length)>0&&(pt=[...pt.slice(idprimopunto),...pt.slice(0,idprimopunto)]),this},
|
|
293
|
+
/**
|
|
294
|
+
* Trova i punti in cui l’angolo interno è maggiore di `thresholdDeg`.
|
|
295
|
+
*
|
|
296
|
+
* @param {Array<{x:number,y:number}>} path - Array di punti chiuso.
|
|
297
|
+
* @param {number} thresholdDeg - Angolo in gradi.
|
|
298
|
+
* @returns {Array<{ index: number, point: {x:number,y:number}, angle: number }>}
|
|
299
|
+
*/
|
|
300
|
+
segment(i,inverse=!1){let n=pt.length;return i<0&&(i+=n),new Linea2(pt[i%n],pt[(i+(inverse?-1:1))%n])},lineoffset(i1,i2,offset){if((i1=(i1||0)%pt.length)!=(i2=(i2||0)%pt.length)){let l2=new Linea2(pt[i1],pt[i2]);if(l2){return l2=l2.offsetline(-offset),this.intersectline(l2)}}},move(x=0,y=0){for(let p of pt)p.x+=x,p.y+=y;return this},mirrorx(value=0){for(let p of pt)p.x=2*value-p.x;return this},mirrory(value=0){for(let p of pt)p.y=2*value-p.y;return this},simplify(tolerance,hq){return pt=function simplify(points,tolerance,highestQuality){if(points.length<=2)return points;var sqTolerance=void 0!==tolerance?tolerance*tolerance:1;return simplifyDouglasPeucker(points=highestQuality?points:function simplifyRadialDist(points,sqTolerance){for(var point,p1,p2,dx,dy,prevPoint=points[0],newPoints=[prevPoint],i=1,len=points.length;i<len;i++)p2=prevPoint,dx=void 0,dy=void 0,(dx=(p1=point=points[i]).x-p2.x)*dx+(dy=p1.y-p2.y)*dy>sqTolerance&&(newPoints.push(point),prevPoint=point);return prevPoint!==point&&newPoints.push(point),newPoints}(points,sqTolerance),sqTolerance)}(pt,tolerance,hq),this},fromclip(vv){pt=[];for(let p of vv)pt.push({x:p.x/1e3,y:p.y/1e3});return this},infosegmento(i,open=!1){const n=pt.length;function clampIndex(idx){return(idx+n)%n}function angle(p1,p2){return Math.atan2(p2.y-p1.y,p2.x-p1.x)}function angleDiff(a,b){let diff=a-b;for(;diff>Math.PI;)diff-=2*Math.PI;for(;diff<-Math.PI;)diff+=2*Math.PI;return diff}const p1=pt[i];let p0,p2,p3;if(open)if(0===i){const dx=pt[1].x-pt[0].x,dy=pt[1].y-pt[0].y;p0={x:pt[0].x-dx,y:pt[0].y-dy},p2=pt[1],p3=pt[2]}else if(i===n-1){const dx=pt[n-1].x-pt[n-2].x,dy=pt[n-1].y-pt[n-2].y;p0=pt[n-2],p2={x:pt[n-1].x+dx,y:pt[n-1].y+dy},p3={x:p2.x+dx,y:p2.y+dy}}else p0=pt[i-1],p2=pt[i+1],p3=i+2<n?pt[i+2]:{x:pt[i+1].x+(pt[i+1].x-pt[i].x),y:pt[i+1].y+(pt[i+1].y-pt[i].y)};else{const i0=clampIndex(i-1),i2=clampIndex(i+1),i3=clampIndex(i+2);p0=pt[i0],p2=pt[i2],p3=pt[i3]}const ang12=angle(p1,p2),ang01=angle(p0,p1),ang23=angle(p2,p3);return{x:p1.x,y:p1.y,l:function length(p1,p2){const dx=p2.x-p1.x,dy=p2.y-p1.y;return Math.sqrt(dx*dx+dy*dy)}(p1,p2),ang:ang12/PIF,a1:angleDiff(ang12,ang01)/PIF,a2:angleDiff(ang23,ang12)/PIF}},fromvec(aa){return pt=[],_addvec(aa),this},addvec(vec){return _addvec(vec),this},frompt(pts){return pt=[...pts],pt=removeduplicate(pt),this},fromstr(str){return pt=removeduplicate(function processTokens(tokens){const points=[];for(let i=0;i<tokens.length;i++){const token=tokens[i];if("point"===token.type)points.push(token.point);else if("command"===token.type)switch(token.cmd){case"b":{if(points.length<2)continue;const npt=parseInt(token.params[0])||5,p1=points[points.length-2],p2=points[points.length-1];let p3="point"===tokens[i+1]?.type?tokens[i+1].point:void 0,p4="point"===tokens[i+2]?.type?tokens[i+2].point:void 0;p3?p4||(p4=points[0]):(p3=points[0],p4=points[1]);const raccordo=raccordabezier(p1,p2,p3,p4,npt);points.push(...raccordo),i+=1;break}case"r":{if(points.length<1)continue;const dist=parseFloat(token.params[0])||5,npt=parseInt(token.params[1])||10,p1=points[points.length-1];let p2="point"===tokens[i+1]?.type?tokens[i+1].point:void 0,p3="point"===tokens[i+2]?.type?tokens[i+2].point:"point"===tokens[i+3]?.type?tokens[i+3].point:void 0;p2?p3||(p3=points[0]):(p2=points[0],p3=points[1],points.splice(0,1));const raccordo=raccordabezier3(p1,p2,p3,dist,npt);points.push(...raccordo),i+=1;break}case"c":{const radius=parseFloat(token.params[0])||50,segments=parseInt(token.params[1])||12,center="point"===tokens[i+1]?.type?tokens[i+1].point:new Punto2(0,0);for(let j=0;j<segments;j++)points.push(new Punto2(center.x+radius*Math.cos(j/segments*Math.PI*2),center.y+radius*Math.sin(j/segments*Math.PI*2)));i+=1;break}case"a":{let npt,p1="point"===tokens[i+1]?.type?tokens[i+1].point:void 0,p2="point"===tokens[i+2]?.type?tokens[i+2].point:void 0,p3="point"===tokens[i+3]?.type?tokens[i+3].point:void 0;if(!p1||!p3)continue;if(p2)if(token.params[0])npt=clamp(parseInt(token.params[0]),1,24);else{const chord=Math.hypot(p3.x-p1.x,p3.y-p1.y),sagitta=Math.abs((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))/(2*chord);npt=Math.round(chord*Math.sqrt(sagitta/(chord+.1))*10),npt=clamp(npt,1,24),npt=1}else p2=p3,npt=0;const arcoPoints=arcfrom3point(npt,p1,p2,p3);points.push(...arcoPoints),i+=3;break}}}return points}(function tokenize(str){const tokens=[],values=str.toLowerCase().replace(/[\n\s]+/gm," ").split(/[,;]/).map((s=>s.trim()));for(let i=0;i<values.length;){const current=values[i];["b","r","c","a"].includes(current[0])?(tokens.push({type:"command",cmd:current[0],params:current.slice(1).split(":")}),i++):/[a-zA-Z]/.test(current[0])||(i<values.length-1?(tokens.push({type:"point",point:new Punto2(parseFloat(values[i]),parseFloat(values[i+1]))}),i+=2):i++)}return tokens}(str))),this},fromrect(w,h,sx,sy,bordo){w||(w=10),h||(h=10),bordo||(bordo=0),bordo=Math.min(Math.abs(bordo),Math.abs(.4*w),Math.abs(.4*h));let b1=w>0?bordo:-bordo,b2=h>0?bordo:-bordo;return pt=bordo?[{x:b1,y:0},{x:w-b1,y:0},{x:w,y:b2},{x:w,y:h-b2},{x:w-b1,y:h},{x:b1,y:h},{x:0,y:h-b2},{x:0,y:b2}]:[{x:0,y:0},{x:w,y:0},{x:w,y:h},{x:0,y:h}],this},intersectline:l=>function _intersectline(shape,p3,p4){let n=shape.length,l=new Linea2(p3,p4);const intersezioni=[];for(let i=0;i<shape.length;i++){let l2=new Linea2(shape[i],shape[(i+1)%n]),p=l2.interseca(l);p&&l2.onsegment(p)&&intersezioni.push(p)}if(intersezioni.length<2)return null;const{dx:dx,dy:dy}=l;intersezioni.sort(((a,b)=>(a.x-p3.x)*dx+(a.y-p3.y)*dy-((b.x-p3.x)*dx+(b.y-p3.y)*dy)));let pstart=new Punto2(intersezioni[0].x,intersezioni[0].y),pend=new Punto2(intersezioni[intersezioni.length-1].x,intersezioni[intersezioni.length-1].y);const vx1=pend.x-pstart.x,vy1=pend.y-pstart.y;return vx1*dx+vy1*dy<0&&([pstart,pend]=[pend,pstart]),new Linea2(pstart,pend)}(pt,l.p1,l.p2),tostr(dec=2){let dd=10**dec,pstr=x=>String(Math.round(x*dd)/dd);return pt.map((e=>pstr(e.x)+";"+pstr(e.y))).join(";")},addpt(pts){return pts?(Array.isArray(pts)||(pts=[pts]),pt=removeduplicate([...pt,...pts]),this):this},addracc(v1,v2,suddivisioni=2,addv1v2=!0){if(Array.isArray(v1)&&(v2={x:v1[2]||0,y:v1[3]||0},v1={x:v1[0]||0,y:v1[1]||0}),pt.length>=2){let tm=raccordabezier(pt[pt.length-2],pt[pt.length-1],v1,v2,suddivisioni);pt=[...pt,...tm],addv1v2&&(pt.push(v1),pt.push(v2))}return pt=removeduplicate(pt),this},setorient(mode){let p=orientation();return(1==p&&-1==mode||-1==p&&1==mode)&&pt.reverse(),this},reverse(){return pt.reverse(),this},pointinshape:p=>function isPointInPolygon(P){let x=P.x,y=P.y,inside=!1;for(let i=0,j=pt.length-1;i<pt.length;j=i++){let xi=pt[i].x,yi=pt[i].y,xj=pt[j].x,yj=pt[j].y;yi>y!=yj>y&&x<(xj-xi)*(y-yi)/(yj-yi)+xi&&(inside=!inside)}return inside}(p),azzera(){return pt=[],this},removeduplicate(delta=.005){return pt=removeduplicate(pt,delta),this},to3d(u0,alt=0,coeffa=0,coeffb=0,open=!1){pt=removeduplicate(pt);let tm=function genuvnormal(path,options){let{currentU:currentU=0,c:c=0,a:a=0,b:b=0,anglemin:anglemin=30,open:open=!1}=options;const pointsWithNormals=[],n=path.length;for(let i=0;i<n;i++){const prev=path[(i-1+n)%n],current=path[i],next=path[(i+1)%n],vPrev={x:current.x-prev.x,y:current.y-prev.y},vNext={x:next.x-current.x,y:next.y-current.y},normalPrev=normal2(prev,current),normalNext=normal2(current,next),angle=angle2vec(vPrev,vNext);let z=a*current.x+b*current.y+c;Math.abs(angle-180)<=anglemin?(normalPrev.nx,normalNext.nx,normalPrev.ny,normalNext.ny,pointsWithNormals.push({x:current.x,y:-current.y,z:z,u:currentU,v:z})):(pointsWithNormals.push({x:current.x,y:-current.y,z:z,u:currentU,v:z}),pointsWithNormals.push({x:current.x,y:-current.y,z:z,u:currentU,v:z}));const dx=next.x-current.x,dy=next.y-current.y;currentU+=Math.sqrt(dx*dx+dy*dy)}if(!open){let p=pointsWithNormals[0],pf=pointsWithNormals[pointsWithNormals.length-1];p.x==pf.x&&p.y==pf.y||pointsWithNormals.push({x:p.x,y:p.y,z:p.z,nx:p.nx,ny:p.ny,nz:p.nz,u:currentU,v:p.z})}return pointsWithNormals}(pt,{open:open,currentU:u0,c:alt,a:coeffa,b:coeffb,anglemin:30});return tm},getboundbox:()=>pt.length?pt.reduce(((box,p)=>(box.p1.x=Math.min(box.p1.x,p.x),box.p1.y=Math.min(box.p1.y,p.y),box.p2.x=Math.max(box.p2.x,p.x),box.p2.y=Math.max(box.p2.y,p.y),box)),{p1:new Punto2(1/0,1/0),p2:new Punto2(-1/0,-1/0)}):{p1:new Punto2(0,0),p2:new Punto2(0,0)},fittobox(p1,p2){if(!pt.length)return this;const currentBox=this.getboundbox(),currentWidth=currentBox.p2.x-currentBox.p1.x,currentHeight=currentBox.p2.y-currentBox.p1.y,targetWidth=p2.x-p1.x,targetHeight=p2.y-p1.y,scale=Math.min(targetWidth/(currentWidth||1),targetHeight/(currentHeight||1));for(let p of pt)p.x=(p.x-currentBox.p1.x)*scale,p.y=(p.y-currentBox.p1.y)*scale,p.x+=p1.x,p.y+=p1.y;return this}}}
|
|
273
301
|
/**
|
|
274
302
|
* Calcola i punti di un arco passante per tre punti
|
|
275
303
|
* @param {number} segments - Numero di segmenti (punti-1)
|
|
@@ -277,7 +305,7 @@ function _addvec(aa){for(let i=0;i<aa.length;i+=2)pt.push({x:aa[i],y:aa[i+1]})}f
|
|
|
277
305
|
* @param {Punto2} p2 - Punto intermedio
|
|
278
306
|
* @param {Punto2} p3 - Punto finale
|
|
279
307
|
* @returns {Array<Punto2>} Array di punti che formano l'arco
|
|
280
|
-
*/function arcfrom3point(segments,p1,p2,p3){if(segments<=0)return[p1,p3];if(1===segments)return[p1,p2,p3];const center=function findCircleCenter(p1,p2,p3){const
|
|
308
|
+
*/function arcfrom3point(segments,p1,p2,p3){if(segments<=0)return[p1,p3];if(1===segments)return[p1,p2,p3];const center=function findCircleCenter(p1,p2,p3){const t=p2.x*p2.x+p2.y*p2.y,bc=(p1.x*p1.x+p1.y*p1.y-t)/2,cd=(t-p3.x*p3.x-p3.y*p3.y)/2,det=(p1.x-p2.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p2.y);return Math.abs(det)<1e-10?null:new Punto2((bc*(p2.y-p3.y)-cd*(p1.y-p2.y))/det,((p1.x-p2.x)*cd-(p2.x-p3.x)*bc)/det)}(p1,p2,p3);if(!center){const pts=[];for(let i=0;i<=segments;i++){const t=i/segments;pts.push(new Punto2(p1.x+(p3.x-p1.x)*t,p1.y+(p3.y-p1.y)*t))}return pts}let start=Math.atan2(p1.y-center.y,p1.x-center.x);Math.atan2(p2.y-center.y,p2.x-center.x);let end=Math.atan2(p3.y-center.y,p3.x-center.x);const cross=(p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x),norm=a=>(a+2*Math.PI)%(2*Math.PI);start=norm(start),end=norm(end),cross>0?end<start&&(end+=2*Math.PI):end>start&&(end-=2*Math.PI);const radius=Math.hypot(p1.x-center.x,p1.y-center.y),delta=(end-start)/segments,points=[];for(let i=0;i<=segments;i++){const angle=start+delta*i;points.push(new Punto2(center.x+radius*Math.cos(angle),center.y+radius*Math.sin(angle)))}return points}function getDefaultExportFromCjs(x){return x&&x.__esModule&&Object.prototype.hasOwnProperty.call(x,"default")?x.default:x}var module,clipper={exports:{}};
|
|
281
309
|
/*******************************************************************************
|
|
282
310
|
* *
|
|
283
311
|
* Author : Angus Johnson *
|
|
@@ -487,7 +515,7 @@ ClipperLib.ExPolygon=function(){this.outer=null,this.holes=null},ClipperLib.JS.A
|
|
|
487
515
|
* @property {Function} inflate - Espande o contrae una forma
|
|
488
516
|
* @property {Function} unisci - Unisce più forme con gestione di fori e tagli
|
|
489
517
|
*/
|
|
490
|
-
function shapeclip(){function toclipformat(pts){let tm=pts.map((e=>({X:Math.round(1e4*e.x),Y:Math.round(1e4*e.y)})));return ensureOrientation(tm)}function fromclipformat(pts){return pts.map((e=>({x:e.X/1e4,y:e.Y/1e4})))}const ensureOrientation=poly=>ClipperLib.Clipper.Orientation(poly)?poly:poly.slice().reverse();function orientation(pt){if(!pt.length)return 0;let area=0;const n=pt.length;for(let i=0;i<n;i++){const current=pt[i],next=pt[(i+1)%n];area+=current.X*next.Y-next.X*current.Y}return area>0?1:area<0?-1:0}const _inflate=(pt,delta,cut=!1)=>{const co=new ClipperLib.ClipperOffset;co.MiterLimit=4,co.AddPath(pt,ClipperLib.JoinType.jtMiter,cut||2==pt.length?ClipperLib.EndType.etOpenButt:ClipperLib.EndType.etClosedPolygon);const solution=new ClipperLib.Paths;return co.Execute(solution,delta),solution};return{offset(shape,delta,full=!1){const co=new ClipperLib.ClipperOffset;co.MiterLimit=4,co.ArcTolerance=.25;const DD=1e4*Math.abs(delta),pshape=toclipformat(shape.pt);co.AddPath(pshape,ClipperLib.JoinType.jtMiter,ClipperLib.EndType.etOpenButt);const solution=new ClipperLib.Paths;co.Execute(solution,DD);let tm=fromclipformat(solution[0]);return full?getshape().frompt(tm):getshape().frompt(getptsoffset(shape.pt,tm,delta))},inflate(shape,delta=2,mantainorder=!1,isopen=0){let pshape=toclipformat(shape.pt),tm=_inflate(pshape,1e4*delta);let p2=getshape().frompt(fromclipformat(tm[0]));if(mantainorder&&shape.pt.length==p2.pt.length){p2.orient!=shape.orient&&p2.reverse();let p3=function alignByMinDist(sag1,sag2){const N=sag1.length;let bestOffset=0,minSum=1/0;for(let k=0;k<N;k++){let sum=0;for(let i=0;i<N;i++){const p=sag1[i],q=sag2[(i+k)%N],dx=p.x-q.x,dy=p.y-q.y;sum+=dx*dx+dy*dy}sum<minSum&&(minSum=sum,bestOffset=k)}return[...sag2.slice(bestOffset),...sag2.slice(0,bestOffset)]}(shape.pt,p2.pt);if(p2.frompt(p3),isopen>0&&shape.pt.length>=3){function estendi1(sh1,sh2){let l1=sh1.segment(0).ruotata(-Math.PI/2,200,!0),l2=sh1.segment(-2).ruotata(-Math.PI/2,200),p2=sh2.segment(-2).interseca(l2),p1=sh2.segment(0).interseca(l1);p1&&(sh2.pt[0]=p1),p2&&(sh2.pt[sh2.pt.length-1]=p2)}function estendi2(sh1,sh2){let lfin=sh1.segment(-1),l2=sh2.segment(0),p1=lfin.interseca(l2);p1&&(sh2.pt[0]=p1),l2=sh2.segment(-2);let p2=lfin.interseca(l2);p2&&(sh2.pt[sh2.pt.length-1]=p2)}1==isopen?estendi1(shape,p2):estendi2(shape,p2)}}return p2},intersecasplitter(areabase,forma1){const clipper=new ClipperLib.Clipper,pt1=[toclipformat(forma1.pt)],pt2=[toclipformat(areabase.pt)];clipper.AddPaths(pt1,ClipperLib.PolyType.ptSubject,!0),clipper.AddPaths(pt2,ClipperLib.PolyType.ptClip,!0);const solution=new ClipperLib.Paths;let res;if(clipper.Execute(ClipperLib.ClipType.ctIntersection,solution,ClipperLib.PolyFillType.pftNonZero,ClipperLib.PolyFillType.pftNonZero)&&solution.length>0){const path=solution[0];if(1===orientation(path)){res=getshape().frompt(fromclipformat(path)),res.orient!=forma1.orient&&res.reverse();for(let iu=0;iu<forma1.pt.length;iu++){let p2=forma1.pt[iu],id=res.pt.findIndex((p=>Math.abs(p.x-p2.x)<.01&&Math.abs(p.y-p2.y)<.01));if(id>0){id-=iu,0!=id&&res.selezionaprimo(id);break}}}}return res},offsetpts(pts,delta=.01){const DELTA=1e4*delta;let tm=_inflate(toclipformat(pts),DELTA);if(tm&&tm.length)return fromclipformat(tm[0])},areesplitter(shapept,clipspt,useInflatedClipping=!0){if(!Array.isArray(shapept)||shapept.length<3)return;if(!clipspt||0==clipspt.length)return[shapept];const subj=new ClipperLib.Paths,clip=new ClipperLib.Paths;let shape_in=useInflatedClipping?_inflate(toclipformat(shapept),-100):[toclipformat(shapept)],clips_in=useInflatedClipping?clipspt.flatMap((c=>_inflate(toclipformat(c),100))):clipspt.map((c=>toclipformat(c)));for(let s of shape_in)subj.push(s);for(let c of clips_in)clip.push(c);const clipper=new ClipperLib.Clipper;clipper.AddPaths(subj,ClipperLib.PolyType.ptSubject,!0),clipper.AddPaths(clip,ClipperLib.PolyType.ptClip,!0);const solution=new ClipperLib.Paths;if(!clipper.Execute(ClipperLib.ClipType.ctDifference,solution,ClipperLib.PolyFillType.pftNonZero,ClipperLib.PolyFillType.pftNonZero))return;let res=[];for(let x of solution)if(useInflatedClipping){const restored=_inflate(x,100);for(const r of restored)1===orientation(r)&&res.push(fromclipformat(r))}else if(x.length>4&&1==orientation(x)){const cleaned=_inflate(x,-100);if(cleaned.length>0)for(let cc of cleaned){const restored=_inflate(cc,100);for(const rr of restored)1===orientation(rr)&&res.push(fromclipformat(rr))}}else 1==orientation(x)&&res.push(fromclipformat(x));return res},unisci(shapes,holes,cuts){const subj=new ClipperLib.Paths,clip=new ClipperLib.Paths;for(let hh of shapes){let h2=[toclipformat(hh.pt)];for(let h of h2)subj.push(h)}if(holes&&holes.length)for(let hh of holes){let h1=toclipformat(hh.pt);clip.push(h1)}if(cuts&&cuts.length)for(let hh of cuts){let h1=toclipformat(hh.pt),h2=_inflate(h1,1,!0);for(let h of h2)clip.push(h)}const clipper=new ClipperLib.Clipper;clipper.AddPaths(subj,ClipperLib.PolyType.ptSubject,!0),clipper.AddPaths(clip,ClipperLib.PolyType.ptClip,!0);const solution=new ClipperLib.Paths;if(clipper.Execute(ClipperLib.ClipType.ctDifference,solution,ClipperLib.PolyFillType.pftNonZero,ClipperLib.PolyFillType.pftNonZero)){let res=[],holes=[];for(let x of solution)if(1==orientation(x)){let yy=[x];for(let y of yy)res.push({shape:getshape().frompt(fromclipformat(y)),holes:[]})}else holes.push(getshape().frompt(fromclipformat(x)));for(let h of holes)for(let s of res)if(s.shape.pointinshape(h.pt[0])){s.holes.push(h);break}return res}return[]}}}class Vis2d{constructor(name,p1,p2){this.name=name,this.clear(p1,p2)}clear(p1,p2){return this.vec=[],this.xp1=p1||new Punto2(-10,-10),this.xp2=p2||new Punto2(100,100),this}push(x,y,rot=0){this.vec.push({type:"push",x:x,y:y,rot:rot})}pop(){this.vec.push({type:"pop"})}randomcolor(transp="100%"){return`hsl(${Math.floor(360*Math.random())}, 50%, 40%,${transp})`}addpoint(p,id=-1,color="red",spessore=8){return p&&this.vec.push({type:"point",p:p,id:id,color:color,spessore:spessore}),this}addline(l,id=-1,color=void 0,spessore=1){return l&&this.vec.push({type:"line",l:l,id:id,color:color,spessore:spessore}),this}addrect(l,id=-1,color=void 0,spessore=1){return l&&this.vec.push({type:"rect",l:l,id:id,color:color,spessore:spessore}),this}addrecta(l,id=-1,color=void 0){return l&&this.vec.push({type:"recta",l:l,id:id,color:color,spessore:0}),this}addshape(s,color=void 0,spessore=1){return s&&this.vec.push({type:"shape",s:s,color:color||this.randomcolor(),spessore:spessore}),this}addshapelin(s,color=void 0,spessore=1){return s&&this.vec.push({type:"shapelin",s:s,color:color||this.randomcolor(),spessore:spessore}),this}addarea(s,color=void 0){return s&&this.vec.push({type:"area",s:s,color:color||this.randomcolor()}),this}addoffset(x,y){return this.vec.push({type:"offset",x:x||0,y:y||0}),this}}
|
|
518
|
+
function shapeclip(){function toclipformat(pts){let tm=pts.map((e=>({X:Math.round(1e4*e.x),Y:Math.round(1e4*e.y)})));return ensureOrientation(tm)}function fromclipformat(pts){return pts.map((e=>({x:e.X/1e4,y:e.Y/1e4})))}const ensureOrientation=poly=>ClipperLib.Clipper.Orientation(poly)?poly:poly.slice().reverse();function orientation(pt){if(!pt.length)return 0;let area=0;const n=pt.length;for(let i=0;i<n;i++){const current=pt[i],next=pt[(i+1)%n];area+=current.X*next.Y-next.X*current.Y}return area>0?1:area<0?-1:0}const _inflate=(pt,delta,cut=!1)=>{const co=new ClipperLib.ClipperOffset;co.MiterLimit=4,co.AddPath(pt,ClipperLib.JoinType.jtMiter,cut||2==pt.length?ClipperLib.EndType.etOpenButt:ClipperLib.EndType.etClosedPolygon);const solution=new ClipperLib.Paths;return co.Execute(solution,delta),solution};return{offset(shape,delta,full=!1){const co=new ClipperLib.ClipperOffset;co.MiterLimit=4,co.ArcTolerance=.25;const DD=1e4*Math.abs(delta),pshape=toclipformat(shape.pt);co.AddPath(pshape,ClipperLib.JoinType.jtMiter,ClipperLib.EndType.etOpenButt);const solution=new ClipperLib.Paths;co.Execute(solution,DD);let tm=fromclipformat(solution[0]);return full?getshape().frompt(tm):getshape().frompt(getptsoffset(shape.pt,tm,delta))},inflate(shape,delta=2,mantainorder=!1,isopen=0){let pshape=toclipformat(shape.pt),tm=_inflate(pshape,1e4*delta);let p2=getshape().frompt(fromclipformat(tm[0]));if(mantainorder&&shape.pt.length==p2.pt.length){p2.orient!=shape.orient&&p2.reverse();let p3=function alignByMinDist(sag1,sag2){const N=sag1.length;let bestOffset=0,minSum=1/0;for(let k=0;k<N;k++){let sum=0;for(let i=0;i<N;i++){const p=sag1[i],q=sag2[(i+k)%N],dx=p.x-q.x,dy=p.y-q.y;sum+=dx*dx+dy*dy}sum<minSum&&(minSum=sum,bestOffset=k)}return[...sag2.slice(bestOffset),...sag2.slice(0,bestOffset)]}(shape.pt,p2.pt);if(p2.frompt(p3),isopen>0&&shape.pt.length>=3){function estendi1(sh1,sh2){let l1=sh1.segment(0).ruotata(-Math.PI/2,200,!0),l2=sh1.segment(-2).ruotata(-Math.PI/2,200),p2=sh2.segment(-2).interseca(l2),p1=sh2.segment(0).interseca(l1);p1&&(sh2.pt[0]=p1),p2&&(sh2.pt[sh2.pt.length-1]=p2)}function estendi2(sh1,sh2){let lfin=sh1.segment(-1),l2=sh2.segment(0),p1=lfin.interseca(l2);p1&&(sh2.pt[0]=p1),l2=sh2.segment(-2);let p2=lfin.interseca(l2);p2&&(sh2.pt[sh2.pt.length-1]=p2)}1==isopen?estendi1(shape,p2):estendi2(shape,p2)}}return p2},intersecasplitter(areabase,forma1){const clipper=new ClipperLib.Clipper,pt1=[toclipformat(forma1.pt)],pt2=[toclipformat(areabase.pt)];clipper.AddPaths(pt1,ClipperLib.PolyType.ptSubject,!0),clipper.AddPaths(pt2,ClipperLib.PolyType.ptClip,!0);const solution=new ClipperLib.Paths;let res;if(clipper.Execute(ClipperLib.ClipType.ctIntersection,solution,ClipperLib.PolyFillType.pftNonZero,ClipperLib.PolyFillType.pftNonZero)&&solution.length>0){const path=solution[0];if(1===orientation(path)){res=getshape().frompt(fromclipformat(path)),res.orient!=forma1.orient&&res.reverse();for(let iu=0;iu<forma1.pt.length;iu++){let p2=forma1.pt[iu],id=res.pt.findIndex((p=>Math.abs(p.x-p2.x)<.01&&Math.abs(p.y-p2.y)<.01));if(id>0){id-=iu,0!=id&&res.selezionaprimo(id);break}}}}return res},offsetpts(pts,delta=.01){const DELTA=1e4*delta;let tm=_inflate(toclipformat(pts),DELTA);if(tm&&tm.length)return fromclipformat(tm[0])},areesplitter(shapept,clipspt,useInflatedClipping=!0){if(!Array.isArray(shapept)||shapept.length<3)return;if(!clipspt||0==clipspt.length)return[shapept];const subj=new ClipperLib.Paths,clip=new ClipperLib.Paths;let shape_in=useInflatedClipping?_inflate(toclipformat(shapept),-100):[toclipformat(shapept)],clips_in=useInflatedClipping?clipspt.flatMap((c=>_inflate(toclipformat(c),100))):clipspt.map((c=>toclipformat(c)));for(let s of shape_in)subj.push(s);for(let c of clips_in)clip.push(c);const clipper=new ClipperLib.Clipper;clipper.AddPaths(subj,ClipperLib.PolyType.ptSubject,!0),clipper.AddPaths(clip,ClipperLib.PolyType.ptClip,!0);const solution=new ClipperLib.Paths;if(!clipper.Execute(ClipperLib.ClipType.ctDifference,solution,ClipperLib.PolyFillType.pftNonZero,ClipperLib.PolyFillType.pftNonZero))return;let res=[];for(let x of solution)if(useInflatedClipping){const restored=_inflate(x,100);for(const r of restored)1===orientation(r)&&res.push(fromclipformat(r))}else if(x.length>4&&1==orientation(x)){const cleaned=_inflate(x,-100);if(cleaned.length>0)for(let cc of cleaned){const restored=_inflate(cc,100);for(const rr of restored)1===orientation(rr)&&res.push(fromclipformat(rr))}}else 1==orientation(x)&&res.push(fromclipformat(x));return res},unisci(shapes,holes,cuts){const subj=new ClipperLib.Paths,clip=new ClipperLib.Paths;for(let hh of shapes){let h2=[toclipformat(hh.pt)];for(let h of h2)subj.push(h)}if(holes&&holes.length)for(let hh of holes){let h1=toclipformat(hh.pt);clip.push(h1)}if(cuts&&cuts.length)for(let hh of cuts){let h1=toclipformat(hh.pt),h2=_inflate(h1,1,!0);for(let h of h2)clip.push(h)}const clipper=new ClipperLib.Clipper;clipper.AddPaths(subj,ClipperLib.PolyType.ptSubject,!0),clipper.AddPaths(clip,ClipperLib.PolyType.ptClip,!0);const solution=new ClipperLib.Paths;if(clipper.Execute(ClipperLib.ClipType.ctDifference,solution,ClipperLib.PolyFillType.pftNonZero,ClipperLib.PolyFillType.pftNonZero)){let res=[],holes=[];for(let x of solution)if(1==orientation(x)){let yy=[x];for(let y of yy)res.push({shape:getshape().frompt(fromclipformat(y)),holes:[]})}else holes.push(getshape().frompt(fromclipformat(x)));for(let h of holes)for(let s of res)if(s.shape.pointinshape(h.pt[0])){s.holes.push(h);break}return res}return[]}}}class Vis2d{constructor(name,scalalinea=1){this.name=name,this.clear(scalalinea)}clear(scalalinea=1){return this.vec=[],this._sl=scalalinea,this}push(x,y,rot=0){this.vec.push({type:"push",x:x,y:y,rot:rot})}pop(){this.vec.push({type:"pop"})}randomcolor(transp="100%"){return`hsl(${Math.floor(360*Math.random())}, 50%, 40%,${transp})`}addpoint(p,id=-1,color="red",spessore=8){return p&&this.vec.push({type:"point",p:p,id:id,color:color,spessore:spessore*this._sl}),this}addline(l,id=-1,color=void 0,spessore=1){return l&&this.vec.push({type:"line",l:l,id:id,color:color,spessore:spessore*this._sl}),this}addrect(l,id=-1,color=void 0,spessore=1){return l&&this.vec.push({type:"rect",l:l,id:id,color:color,spessore:spessore*this._sl}),this}addrecta(l,id=-1,color=void 0){return l&&this.vec.push({type:"recta",l:l,id:id,color:color,spessore:0}),this}addshape(s,color=void 0,spessore=1){return s&&this.vec.push({type:"shape",s:s,color:color||this.randomcolor(),spessore:spessore*this._sl}),this}addshapelin(s,color=void 0,spessore=1){return s&&this.vec.push({type:"shapelin",s:s,color:color||this.randomcolor(),spessore:spessore*this._sl}),this}addarea(s,color=void 0){return s&&this.vec.push({type:"area",s:s,color:color||this.randomcolor()}),this}addoffset(x,y){return this.vec.push({type:"offset",x:x||0,y:y||0}),this}}function checkoggetto(oggetti,tipo,cod){"h"==tipo&&(tipo="o"),oggetti||(oggetti=[]);let bb=oggetti.find((e=>e.tipo.includes(tipo)&&e.cod==cod));return bb||(bb={cod:"__",macro:"",sps:0}),bb}function getbordi(oggetti,bordo){let bordi,uguali=!1;if(Array.isArray(bordo)){bordo.length=4;let b0=bordo[0]||"";bordi=bordo.map((b=>checkoggetto(oggetti,"b",b||b0))),uguali=bordi.every((b=>b.cod===bordi[0].cod))}else{"number"==typeof bordo&&(bordo=String(bordo));let tm=checkoggetto(oggetti,"b","string"==typeof bordo?bordo:"");bordi=[tm,tm,tm,tm],uguali=!0}return{bordi:bordi,uguali:uguali,bl:bordi[0].sps,bt:bordi[1].sps,br:bordi[2].sps,bb:bordi[3].sps}}function creaprofiloesterno(ff,oggetti){let dati=[],draws=[];function newcount(){return ff.countid++,ff.countid}function eseguipezzo(l1,l2,bordo,shape){let info=l1.infoquad(l2);if(info&&info.distanza){let s0=getshape().frompt(shape||[l1.p1,l1.p2,l2.p2,l2.p1]),s1=s0.clone();(info.sx||info.sy)&&s1.move(-info.sx||0,-info.sy||0),info.angle&&s1.rotate(-info.angle||0);let tm={id:newcount,type:`b${bordo}`,info:info};shape&&(tm.shape=s1.pt),draws.push({type:`b${bordo}`,pt:s0.pt}),dati.push(tm)}}ff.countid=ff.countid||0;let sh1,sh2,p1h,p2h,p3h,p4h,p1v,p2v,p3v,p4v,p1s,p2s,line1,line2,i1,i2,{x:x,y:y,tipo:tipo,bordo:bordo,taglio:taglio,h1:h1,h2:h2,l1:l1,l2:l2,forma:forma}=ff;x=x<50?50:x,y=y<50?50:y,l1=l1||0,l2=l2||0,h1=h1||0,h2=h2||0;let idr=0,pts=[0,0];switch(tipo){case"i":case"d":pts.push(l1>0&&l1<x?l1:0,h1>0&&h1<y?y-h1:y),pts.push(l2>0&&l2<x-l1?x-l2:x,h2>0&&h2<y&&h2!=h1?y-h2:y);break;case"a":if(forma){let tm=getshape().fromstr(forma);tm.alignline({x:l1,y:y-h1},{x:x-l2,y:y-h2}),pts.push(...tm.vec)}else if(h1>=0&&h1<y-x/2||h2>=0&&h2>y-x/2){let tm=getshape().fromstr(`a30;${l1};${y-h1};${x/2};${y};${x-l2};${y-h2}`);pts.push(...tm.vec)}else pts.push(0,y,x,y);break;case"s":l1>0&&h1>0?pts.push(0,y-h1,l1,y):pts.push(0,y),l2&&l2<x-l1&&h2>0&&h2<y?pts.push(x-l2,y,x,y-h2):pts.push(x,y);break;default:pts.push(0,y,x,y)}idr=pts.length/2,pts.push(x,0),sh1=getshape().fromvec(pts);let np=sh1.pt.length,{bordi:bordi,uguali:uguali}=getbordi(oggetti,bordo);if(uguali){let b=bordi[0].sps;sh2=b?shapeclip().inflate(sh1,-b,!0):sh1.clone()}else{let b,ll=[],pp=[];for(let i=0;i<np;i++){b=0==i?bordi[0].sps:i==idr-1?bordi[2].sps:i==idr?bordi[3].sps:bordi[1].sps,"number"!=typeof b&&(b=0);let l=sh1.segment(i).offset(-b);ll.push(l)}for(let i=0;i<np;i++){let p=ll[i].interseca(ll[(i-1+np)%np]);pp.push(p)}sh2=getshape().frompt(pp)}p1h=sh2.segment(idr).interseca(sh1.segment(0)),p2h=sh2.segment(1).interseca(sh1.segment(0)),p3h=sh1.segment(idr-1).interseca(sh2.segment(idr-2)),p4h=sh1.segment(idr-1).interseca(sh2.segment(idr)),p1v=sh1.segment(idr).interseca(sh2.segment(0)),p2v=sh1.segment(1).interseca(sh2.segment(0)),p3v=sh1.segment(idr-2).interseca(sh2.segment(idr-1)),p4v=sh1.segment(idr).interseca(sh2.segment(idr-1)),i1=1,i2=idr-2,line1=sh2.segment(0),line2=sh2.segment(idr-1);for(let i=1;i<idr-1;i++){let l=sh1.segment(i),p=l.interseca(line1);p&&l.onsegment(p)&&(i1=i,p2v=p),p=l.interseca(line2),p&&l.onsegment(p)&&(i2=i,p3v=p)}i1-=1,i2=idr-2-i2;let p1=sh1.pt[0],p2=sh2.pt[0],p3=sh2.pt[idr],p4=sh1.pt[idr];switch(taglio[0]){case"v":eseguipezzo(new Linea2(p4v,p1v),sh2.segment(idr),3),p2=p1v,p3=p4v;break;case"o":eseguipezzo(sh1.segment(idr),new Linea2(p4h,p1h),3),p1=p1h,p4=p4h;break;default:eseguipezzo(sh1.segment(idr),sh2.segment(idr),3)}switch(p1s=sh1.pt.slice(1,idr),p2s=sh2.pt.slice(1,idr),taglio[1]){case"v":eseguipezzo(new Linea2(p1,sh1.pt[1]),new Linea2(p2,p2v),0),eseguipezzo(new Linea2(sh1.pt[idr-1],p4),new Linea2(p3v,p3),2),i1&&(p1s=p1s.slice(i1)),i2&&(p1s=p1s.slice(0,-i2)),p1s[0]=p2v,p1s[p1s.length-1]=p3v;break;case"o":eseguipezzo(new Linea2(p1,p2h),new Linea2(p2,sh2.pt[1]),0),eseguipezzo(new Linea2(p3h,p4),new Linea2(sh2.pt[idr-1],p3),2),p2s[0]=p2h,p2s[p2s.length-1]=p3h;break;default:eseguipezzo(new Linea2(p1,sh1.pt[1]),new Linea2(p2,sh2.pt[1]),0),eseguipezzo(new Linea2(sh1.pt[idr-1],p4),new Linea2(sh2.pt[idr-1],p3),2)}let sh3=getshape().frompt(p2s);if(p1s.length<8&&p1s.length==p2s.length)for(let i=0;i<p1s.length-1;i++)eseguipezzo(new Linea2(p1s[i],p1s[i+1]),new Linea2(p2s[i],p2s[i+1]),1);else{let sh3=getshape().frompt([...p1s,...p2s.reverse()]),l3=new Linea2(p1s[0],p1s[p1s.length-1]),l4=l3.offset(-bordo[1]);eseguipezzo(l3,l4,1,sh3.pt)}return{shape:sh1,internalshape:sh2,shape2:sh2,shapetop:sh3,bordi:bordi,dati:dati,draws:draws}}
|
|
491
519
|
/**
|
|
492
520
|
* Genera segmenti basati su intervalli e punti di interruzione
|
|
493
521
|
* @param {Array<{a: number, b: number}>} t1 - Array di oggetti che rappresentano intervalli con coordinate a e b
|
|
@@ -495,7 +523,7 @@ function shapeclip(){function toclipformat(pts){let tm=pts.map((e=>({X:Math.roun
|
|
|
495
523
|
* @param {boolean} [interna=false] - Se true, usa i bordi interni degli intervalli
|
|
496
524
|
* @param {boolean} [allbreak=false] - Se true, considera ogni punto degli intervalli come una rottura
|
|
497
525
|
* @returns {Array<{a: number, b: number}>} Array di segmenti generati
|
|
498
|
-
*/function generatesegments(t1,t2,interna=!1,allbreak=!1){let t3=[];if(t1?.length>=2){if(allbreak){let tm=[];for(let t of t1)tm.push({a:t.a,b:t.a}),t.a!=t.b&&tm.push({a:t.b,b:t.b});t1=tm}if(t1=t1.sort(((a,b)=>a.a-b.a)),t2?.length){let j=0;for(let i=1;i<t1.length;i++){const ε=1e-6;t2.find((e=>e>t1[i-1].b+ε&&e<t1[i].a-ε))&&(i-1>j&&(interna?t3.push({a:t1[j].b,b:t1[i-1].a}):t3.push({a:t1[j].a,b:t1[i-1].b})),j=i)}j<t1.length-1&&(interna?t3.push({a:t1[j].b,b:t1[t1.length-1].a}):t3.push({a:t1[j].a,b:t1[t1.length-1].b}))}else t3.push({a:t1[0].b,b:t1[t1.length-1].a})}return t3}function
|
|
526
|
+
*/const tipi={i:"inclinato",a:"arco",d:"diagonali",s:"smussato",x:"normale"},tagli={dd:"diagonale",vv:"verticale",oo:"orizzontale",vo:"verticale+orizzontale",vd:"verticale+diagonale",ov:"orizzontale+verticale",od:"orizzontale+diagonale"},tipocut={d:"dist. positiva","d-":"dist. negativa",p:"perc. positiva","p-":"perc negativa"},tipoalign={l:"left",c:"center",r:"right"};function findareacod(areacodes,x,y){let mindist=1/0,minkey="";for(let k of areacodes){let dist=(k.x-x)**2+(k.y-y)**2;dist<mindist&&(mindist=dist,minkey=k.k)}return minkey}function generatesegments(t1,t2,interna=!1,allbreak=!1){let t3=[];if(t1?.length>=2){if(allbreak){let tm=[];for(let t of t1)tm.push({a:t.a,b:t.a}),t.a!=t.b&&tm.push({a:t.b,b:t.b});t1=tm}if(t1=t1.sort(((a,b)=>a.a-b.a)),t2?.length){let j=0;for(let i=1;i<t1.length;i++){const ε=1e-6;t2.find((e=>e>t1[i-1].b+ε&&e<t1[i].a-ε))&&(i-1>j&&(interna?t3.push({a:t1[j].b,b:t1[i-1].a}):t3.push({a:t1[j].a,b:t1[i-1].b})),j=i)}j<t1.length-1&&(interna?t3.push({a:t1[j].b,b:t1[t1.length-1].a}):t3.push({a:t1[j].a,b:t1[t1.length-1].b}))}else t3.push({a:t1[0].b,b:t1[t1.length-1].a})}return t3}function makedivisions(ff,shape2,oggetti){let draws=[],areas=[],dati=[],lines=[],{x:dx,y:dy,oriz:oriz,vert:vert,tipo:tipo,minvano:minvano,minvanox:minvanox,minvanoy:minvanoy}=ff,{bb:bb,bt:bt,bl:bl,br:br}=getbordi(oggetti,ff.bordo);minvanox=minvanox||minvano||50,minvanoy=minvanoy||minvano||50;let{dati:h1,punti:ph}=ordinabase(oggetti,"o",oriz,dy,minvanoy,bb,bt,tipo),{dati:v1,punti:pv}=ordinabase(oggetti,"v",vert,dx,minvanox,bl,br),shapecontorno=shape2.clone();function adddatilin(type,cod,l0,l1,sp,id){if("l"==type)areas.push([l0.p1,l0.p2]);else{let ptx=[l0.p1,l0.p2,l1.p2,l1.p1];areas.push(ptx);let s1=getshape().frompt(ptx);if(shapecontorno?.pt&&(s1.orient!=shapecontorno.orient&&s1.reverse(),s1=shapeclip().intersecasplitter(shapecontorno,s1)),s1){4==s1.pt.length&&(l0.p1=s1.pt[0],l0.p2=s1.pt[1],l1.p1=s1.pt[3],l1.p2=s1.pt[2]),lines.push([l0.p1.x+("v"==type?sp:0),l0.p1.y+("v"!=type?sp:0),l0.p2.x+("v"==type?sp:0),l0.p2.y+("v"!=type?sp:0)]);let info=l0.infoquad(l1);if(info&&info.distanza){let s2=s1.clone(),c2=checkoggetto(oggetti,type,cod);(info.sx||info.sy)&&s2.move(-info.sx||0,-info.sy||0),info.angle&&s2.rotate(-info.angle||0);let tm={id:id,type:type,cod:cod,c2:c2,shape:s2.pt,info:info};dati.push(tm),tm?.shape&&draws.push({type:type,sx:tm.info.sx,sy:tm.info.sy,rot:tm.info.angle,pt:tm.shape})}}}}function isinseg(segs,v){return!!segs.find((e=>e.a<=v&&e.b>=v))}for(var h of(v1.forEach(((v,i)=>{v.segs=generatesegments(ph,v.cuts,!0),v.segs.forEach(((s,j)=>{let l0=new Linea2({x:v.x,y:s.a},{x:v.x,y:s.b}),l1=new Linea2({x:v.x+v.sp,y:s.a},{x:v.x+v.sp,y:s.b});adddatilin(v.sp?"v":"l",v.cod,l0,l1,v.sp/2,v.id)}))})),h1)){let cuts=[...h.cuts],pv1=[...pv];for(var v of v1)pv1.push({a:v.x,b:v.x+v.sp}),isinseg(v.segs,h.x+h.sp/2)&&cuts.push(v.x+v.sp/2);h.segs=generatesegments(pv1,cuts,!0,!0);for(let s of h.segs){let l1=new Linea2({x:s.b,y:h.x+h.sp},{x:s.a,y:h.x+h.sp}),l0=new Linea2({x:s.b,y:h.x},{x:s.a,y:h.x});adddatilin(h.sp?"o":"l",h.cod,l0,l1,h.sp,h.id)}}let res=shapeclip().areesplitter(shape2.pt,areas),areacodes=function getareacodes(ff){let k1,x1,k2,x2,out=[];for(let i=0;i<=ff.vert.length;i++){if(0==i)k1="v0",x1=0;else{let t=ff.vert[i-1];k1=`${t.dir}${t.id}`,x1=t._v}for(let j=0;j<=ff.oriz.length;j++){if(0==j)k2="o0",x2=0;else{let t=ff.oriz[j-1];k2=`${t.dir}${t.id}`,x2=t._v}out.push({k:k1+k2,x:x1,y:x2})}}return out}(ff);for(let d of res){let s=getshape().frompt(d),{p1:p1,width:width,height:height,isrect:isrect}=s.dims(),ix=s.pt.findIndex((p=>Math.abs(p.x-p1.x)<.001&&Math.abs(p.y-p1.y)<.001));ix>0&&s.selezionaprimo(ix),s.pt.length&&(s.move(-p1.x,-p1.y),1==s.orient&&s.reverse());let k=findareacod(areacodes,p1.x,p1.y),cod=ff.aree[k]||ff.area||"",c2=checkoggetto(oggetti,"a",cod);dati.push({id:k,cod:cod,c2:c2,type:"a",shape:isrect?null:s.pt,info:{isrect:isrect?1:0,sx:p1.x,sy:p1.y,rot:0,width:width,height:height}}),draws.push({type:isrect?"a":"as",sx:p1.x,sy:p1.y,dx:width,dy:height,id:k,cod:cod,rot:0,pt:s.pt})}return{ff:ff,h1:h1,ph:ph,v1:v1,pv:pv,draws:draws,lines:lines,dati:dati}}function ordinabase(oggetti,dir,hh,dd,minvano,b1,b2,tipo){let d1=[];if(hh){for(var h of hh){let sp=checkoggetto(oggetti,dir,h.cod).sps||0,x=0;switch(h.tipo){case"d-":x=dd-h.v;break;case"p":x=dd*h.v/100;break;case"p-":x=dd*(100-h.v)/100;break;default:x=h.v}if(sp&&"c"==h.align?x-=sp/2:sp&&"r"==h.align&&(x-=sp),x=Math.round(10*x)/10,h._x0=x,h._x1=x+sp,h._v=x+sp/2,h._valid=x>0&&x<dd,x>b1&&x<dd-b2){let cuts=[];h.cuts&&h.cuts.length&&h.cuts.forEach((c=>{cuts.push(c<0?dd+c:c)})),d1.push({id:h.id,x:x,sp:sp,cuts:cuts,cod:h.cod})}}d1.sort(((a,b)=>a.x-b.x))}let d2=[],p0=b1;"a"==tipo&&(dd*=1.3);for(let i=0;i<d1.length;i++){let d=d1[i];d.x>=p0+minvano&&d.x+d.sp<=dd-b2-minvano&&(d.min=p0+minvano,d.max=dd-b2-minvano,d2.length>0&&(d2[d2.length-1].max=d.x-minvano),d2.push(d),p0=d.x+d.sp)}let d3=[];d3.push({a:b1,b:b1});for(let d of d2)d3.push({a:d.x,b:d.x+d.sp});return d3.push({a:dd-b2,b:dd-b2}),{dati:d2,punti:d3}}function newcount(ff){return ff.countid++,ff.countid}function addtaglio(ff,dir,tipodim,dim,cod,align="c",cuts=[]){return{dir:dir,id:newcount(ff),tipo:tipocut[tipodim]?tipodim:"d",align:tipoalign[align]?align:"c",v:dim,cod:cod,cuts:cuts||[]}}function addoriz(ff,tipodim,dim,cod,align,cuts){Array.isArray(align)&&(cuts=align,align="c");let tm=addtaglio(ff,"o",tipodim,dim,cod,align,cuts);return ff.oriz.push(tm),ff}var SP=Object.freeze({__proto__:null,addhoriz:function addhoriz(ff,tipodim,dim,cod,align,cuts){return addoriz(ff,tipodim,dim,cod,align,cuts)},addoriz:addoriz,addvert:function addvert(ff,tipodim,dim,cod,align,cuts){Array.isArray(align)&&(cuts=align,align="c");let tm=addtaglio(ff,"v",tipodim,dim,cod,align,cuts);return ff.vert.push(tm),ff},calcoladivisioni:
|
|
499
527
|
/**
|
|
500
528
|
* Ordina e calcola le posizioni di taglio lungo una dimensione, gestendo bordi e spazi minimi
|
|
501
529
|
* @param {Array<Object>} hh - Array di oggetti che definiscono i tagli
|
|
@@ -506,4 +534,4 @@ function shapeclip(){function toclipformat(pts){let tm=pts.map((e=>({X:Math.roun
|
|
|
506
534
|
* - dati: Array di oggetti con le posizioni elaborate dei tagli
|
|
507
535
|
* - punti: Array di oggetti {a,b} che definiscono inizio e fine di ogni segmento
|
|
508
536
|
*/
|
|
509
|
-
function calcoladivisioni(ff,
|
|
537
|
+
function calcoladivisioni(ff,notused,shape2,oggetti){return makedivisions(ff,shape2,oggetti)},checkoggetto:checkoggetto,creaprofiloesterno:creaprofiloesterno,create:function create(x,y,bordo,options){options||(options={});let{minvano:minvano,priority:priority,taglio:taglio,tipo:tipo,h1:h1,h2:h2,d1:d1,d2:d2,l1:l1,l2:l2,x1:x1,x2:x2,y1:y1,y2:y2,forma:forma,area:area}=options;(x=x||1e3)<200&&(x=200),(y=y||1e3)<200&&(y=200),h1=h1||y1||0,h2=h2||y2||0,l1=l1||d1||x1||0,l2=l2||d2||x2||0,h1<0&&h1>y-100&&(h1=0),h2<0&&h2>y-100&&(h2=0),(l2<0||l2>x-l1)&&(l2=0),(l1<0||l1>x-l2)&&(l1=0),minvano||(minvano=50),taglio||(taglio="d"),forma&&(tipo="a");let ff={x:x,y:y,area:area||"__",bordo:bordo||"__",priority:priority||"v",minvano:minvano||50,taglio:tagli[taglio]?taglio:"dd",tipo:tipi[tipo]?tipo:"x",h1:h1,h2:h2,l1:l1,l2:l2,vert:[],oriz:[],aree:{},countid:1};return delete options.x1,delete options.x2,delete options.d1,delete options.d2,delete options.y1,delete options.y2,ff={...options,...ff},ff},getbordi:getbordi,makedivisions:makedivisions,makeshape:function makeshape(ff,oggetti){return creaprofiloesterno(ff,oggetti)},priorita:{v:"verticale",h:"orizzontale"},tagli:tagli,tipi:tipi,tipoalign:tipoalign,tipocut:tipocut});async function valutagrafica(amb,startmacro,rulespec,progetto,fnreload){let{getcolonne:getcolonne,muCalc:muCalc,muEval:muEval,tipifree:tipifree}=amb.muvalutatore;rulespec||(rulespec={});for(let x of["l","a","p"]){!amb.vari.var(x)&&startmacro.dims&&amb.vari.add(x,String(startmacro.dims[x].val||100))}let fnlist=new Set;const PARSGLOBAL=["sl","sa","sp","ul","ua","up","ax","ay","az","scx","scy","scz","scale"];let isfnreload=!1,oo=await muEval(amb,startmacro,startmacro.codice,{leveleval:0,checkheader:op=>{let{variante:variante}=op;if(Array.isArray(startmacro.head)){let ff=startmacro.head.find((e=>e.cod==variante));isfnreload=!!ff}},grafica:async _op=>{let p2,cadv,iscad,des,fatti,{id:id,pars:pars,parametri:parametri,macro:macro,options:options,vari:vari}=_op,isheader=!!(macro&¯o.head&¯o.head.length),sv={l:amb.vari.var("l"),a:amb.vari.var("a"),p:amb.vari.var("p")};const varcad=["l","a","p","#d",...PARSGLOBAL];for(let x of varcad){let tm=amb.vari.dictionary[x];tm&&(sv[x]=tm)}async function _parsepars(x,head){let k,v,r9=/^#(d|des|descrizione)\s*=\s*(.*)\s*$/im.exec(x);if(r9)k="#d",v=await amb.vari.valuta(r9[2]);else{let result=await vari.parametrokeyval(x);k=result.k,v=result.v}k&&!fatti[k]&&(fatti[k]=!0,varcad.includes(k)?"#d"==k?des=v:("string"==typeof v&&(v=muCalc(v)),["l","a","p"].includes(k)&&amb.vari.add(k,String(v)),cadv[k]=v,iscad=!0):"string"==typeof v?p2.push(`${k}=${v}`):amb.vari.add(k,v))}if(p2=[],cadv={},iscad=!1,des="",fatti={},progetto&&progetto.keys&&progetto.keys[id]){let px=progetto.keys[id].pars;if(px)for(let t in px){let t1=amb.vari.dictionary[t];t1&&(sv[t]=t1),await _parsepars(`${t}=${px[t]}`)}}if(pars&&pars.length)for(const par of pars)await _parsepars(par);if(parametri&¶metri.length)for(const param of parametri)await _parsepars(param);if(macro&¯o.head&¯o.head.length){let tm=macro.head.filter((e=>!["g"].includes(e.t)));for(const h of tm)await _parsepars(h.cod)}let out={iscad:iscad,isheader:isheader,name:macro.name,des:des,leveleval:options.leveleval};isheader&&id&&(out.id=id),iscad&&(cadv.l?amb.vari.add("l",String(cadv.l)):cadv.l=muCalc(amb.vari.var("l")),cadv.a?amb.vari.add("a",String(cadv.a)):cadv.a=muCalc(amb.vari.var("a")),cadv.p?amb.vari.add("p",String(cadv.p)):cadv.p=muCalc(amb.vari.var("p")),out.cadv=cadv),await macro.impostaparametri(parametri,p2,!0);let ruleid=rulespec[id];if(id&&isheader&&ruleid&&ruleid.pars&&(out.pars=ruleid.pars,options.leveleval++,await macro.setparametri(ruleid.pars)),out.rows=await muEval(amb,macro,macro.codice,options),id&&isheader&&(out.spars=macro.getparametri()),iscad)for(let x in sv)amb.vari.dictionary[x]=sv[x];return out},parsefnpunto:async _op=>{let{dati:dati,vari:vari,id:id,output:output}=_op;dati=dati.trim();let q=dati.indexOf(" "),q2=dati.indexOf(",");q2>0&&q>0&&q2<q&&(q=q2);let fn,pp,pars={},p2={};q>1?(fn=dati.slice(1,q),pp=getcolonne(dati.slice(q+1))):(fn=dati.slice(1),pp=[]),fnlist.has(fn)||fnlist.add(fn);for(let p of pp){let{k:k,v:v}=await vari.parametrokeyval(p);k&&/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(k)&&(pars[k]=v||"")}for(let l of["l","a","p"])pars[l]||(pars[l]=vari.var(l));let tm=Object.keys(pars);for(let l of PARSGLOBAL)tm.includes(l)&&(p2[l]=muCalc(pars[l]),delete pars[l]);output.push({t:"fn",fn:fn,id:id,pars:pars,p2:p2})}});return isfnreload&&"function"==typeof fnreload&&await fnreload(),{oo:oo,vari:amb.vari.dump(!0),fnlist:[...fnlist]}}function ismacro(row){return"object"==typeof row&&row?.name&&row.rows}function isfn(row){return"object"==typeof row&&"fn"==row?.t}function getnodebyid(id,nodocorrente){let res;return nodocorrente&&nodocorrente.rows&&function _getnode(rows){for(let x of rows){if(ismacro(x)){if(x.id==id)return void(res=x);x.rows&&_getnode(x.rows)}if(res)return}}(nodocorrente.rows),res}function getsubrules(nodocorrente){let res=[];return res.push({id:"",level:0,name:"home"}),function _xfiltrati(rr,level){if(rr.rows&&rr.rows.length)for(let x of rr.rows)ismacro(x)&&(x.id&&x.isheader?(res.push({id:x.id,name:x.name,des:x.des||"",spec:x.pars?1:0,level:level}),_xfiltrati(x,level+1)):_xfiltrati(x,level))}(nodocorrente,1),res}function getprojectkeys(project){return project.keys={},function _getkeys(node){if(node.rows&&node.rows.length)for(let x of node.rows)ismacro(x)&&(x.id&&x.isheader&&x.pars&&(project.keys[x.id]={name:x.name,des:x.des||"",pars:x.pars}),_getkeys(x))}(project),project}function getdumpmacro(nodo){let cl=[];return function _dumpnodo(node){if(node.rows&&node.rows.length)for(let x of node.rows)if(ismacro(x)){x.name;let c=[];if(x.iscad&&x.cadv)for(let k in x.cadv){let t=x.cadv[k];"number"==typeof t&&t&&c.push(`${k}=${t}`)}if(x.pars)for(let k in x.pars){let t=x.pars[k];c.push(`${k}=${t}`)}c.length&&cl.push(`--\x3e ${x.name} ${c.join(",")}`),_dumpnodo(x),c.length&&cl.push("<--")}else isfn(x)?cl.push(`FN: ${x.fn} ${JSON.stringify(x.pars)}`):"string"==typeof x&&x.length&&cl.push(x)}(nodo),cl.join("\n")}function clean(k,locase=!1){return locase?(k||"").trim().toLowerCase():(k||"").trim()}function TODEG(a,dec=1){let C=10**dec;return Math.round(180*a*C/Math.PI)/C}function TORAD(a,dec=3){let C=10**dec;return Math.round(a*PIF*C)/C}const blocked={window:void 0,self:void 0,globalThis:void 0,document:void 0,Function:void 0,eval:void 0,fetch:void 0,XMLHttpRequest:void 0};function getOggetto(obj,exclude=[]){if(Array.isArray(obj))return obj.map((item=>getOggetto(item,exclude)));if(obj&&"object"==typeof obj){const result={};for(const[key,value]of Object.entries(obj))"function"==typeof value||exclude&&exclude.includes(key)||(result[key]=getOggetto(value,exclude));return result}return obj}async function evalcustomfunction(amb,code,values,objects){try{values||(values={}),objects||(objects={});const params={GCAD:!1,...values,A:amb,V:amb.vari,amb:amb,log:function addlog(...pars){const sanitized=pars.map((p=>getOggetto(p)));console.log(...sanitized)},Math:Math,clean:clean,SP:SP,Punto2:Punto2,Linea2:Linea2,clamp:clamp,hash:hash,PIF:PIF,getshape:getshape,shapeclip:shapeclip,...objects},paramNames=[...Object.keys(params),...Object.keys(blocked)],paramValues=[...Object.values(params),...Object.values(blocked)],fn=new Function(...paramNames,`\n try {\n return (async () => {\n ${code}\n })();\n } catch (err) {\n err.stack = '[SCRIPT] ' + err.stack;\n throw err;\n }`);return await fn(...paramValues)}catch(error){throw console.error("Errore durante l'esecuzione:",error),error}}export{Linea2,Matrix3D,PIF,Punto2,SP,TODEG,TORAD,Vis2d,angle2vec,angle3point,blocked,clamp,clean,evalcustomfunction,getOggetto,getdumpmacro,getnodebyid,getprojectkeys,getptsoffset,getshape,getsubrules,hash,isfn,ismacro,normal2,raccordabezier,shapeclip,valutagrafica};
|
package/bin/markcad3d.js
CHANGED
|
@@ -108,7 +108,7 @@ function getcilindro(gcad,ori,h,r1,r2,mats=mwhite,options){options||(options={})
|
|
|
108
108
|
* @param {Array} mats - Array di materiali
|
|
109
109
|
* @param {Object} options - Opzioni di configurazione
|
|
110
110
|
* @returns {THREE.Group} Gruppo contenente la geometria estrusa
|
|
111
|
-
*/function estruso(gcad,orient,hshape,shape,holes,mats,options){options||(options={}),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(!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)}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}
|
|
111
|
+
*/function estruso(gcad,orient,hshape,shape,holes,mats,options){options||(options={}),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}
|
|
112
112
|
/**
|
|
113
113
|
* Crea una geometria estrusa con opzioni avanzate
|
|
114
114
|
* @param {string} orient - Orientamento dell'estrusione
|
|
@@ -118,4 +118,4 @@ function getcilindro(gcad,ori,h,r1,r2,mats=mwhite,options){options||(options={})
|
|
|
118
118
|
* @param {Array} mats - Array di materiali
|
|
119
119
|
* @param {Object} options - Opzioni di configurazione
|
|
120
120
|
* @returns {THREE.Group} Gruppo contenente la geometria estrusa
|
|
121
|
-
*/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)}export{SIDE,addmovpivot,calcolatasks,creategroup,deletegroup,edgesfromgeometry,estruso,estrusopat,get3dshape,getbox,getcilindro,getcyl,getface,getline,getlinesgeom,getmesh,getmovimento,getpannello,getpoint,getpunto,getquota,getriferimento,getsprite,gettarghetta,groupfromgeometry,infoestrudi,materialline1,materialline2,mblack,mblue,mgray1,mgray2,mgreen,mred,mwhite,posiziona,randombasemat,revolve,scaleunit,spritemat,svuotanodo,tasklav,taskpannello};
|
|
121
|
+
*/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,getface,getline,getlinesgeom,getmesh,getmovimento,getpannello,getpoint,getpunto,getquota,getriferimento,getsprite,gettarghetta,groupfromgeometry,infoestrudi,materialline1,materialline2,mblack,mblue,mgray1,mgray2,mgreen,mred,mwhite,posiziona,randombasemat,revolve,scaleunit,setLineColorMode,spritemat,svuotanodo,tasklav,taskpannello};
|
package/bin/markuno.js
CHANGED
|
@@ -52,9 +52,10 @@ function testsync(a,b){return a+b}
|
|
|
52
52
|
/**
|
|
53
53
|
* Valida un identificatore verificando che contenga solo caratteri permessi
|
|
54
54
|
* @param {string} id - Identificatore da validare
|
|
55
|
+
* @param {boolean} vuoto - Default false: Accetta valori vuoti!
|
|
55
56
|
* @throws {Error} Se l'identificatore contiene caratteri non validi
|
|
56
57
|
* @returns {string} Identificatore validato in minuscolo
|
|
57
|
-
*/function checkname(id){if(
|
|
58
|
+
*/function checkname(id,vuoto=!1){if(id=(id||"").trim(),vuoto&&!id)return"";if(!id||!/^[a-zA-Z_][a-z0-9A-Z_-]*$/gim.test(id))throw new Error(`nome non valido: "${id}" \n deve contenere solo lettere, _, -, e numeri`);return id.toLowerCase()}
|
|
58
59
|
/**
|
|
59
60
|
* Converte una stringa in array di colonne, gestendo diversi formati
|
|
60
61
|
* @param {string} value - Stringa da convertire
|
|
@@ -83,7 +84,7 @@ function setOggetto(objDestinazione,objSorgente){"object"==typeof objDestinazion
|
|
|
83
84
|
* @param {Object} obj - Oggetto da cui estrarre le proprietà
|
|
84
85
|
* @param {string[]} [exclude] - Array di chiavi da escludere
|
|
85
86
|
* @returns {Object} Nuovo oggetto con le proprietà estratte
|
|
86
|
-
*/function getOggetto(obj,exclude){
|
|
87
|
+
*/function getOggetto(obj,exclude=[]){if(Array.isArray(obj))return obj.map((item=>getOggetto(item,exclude)));if(obj&&"object"==typeof obj){const result={};for(const[key,value]of Object.entries(obj))"function"==typeof value||exclude&&exclude.includes(key)||(result[key]=getOggetto(value,exclude));return result}return obj}
|
|
87
88
|
/**
|
|
88
89
|
* Converte una stringa in un oggetto JSON, gestendo errori e restituendo un valore di default se non valido
|
|
89
90
|
* @param {string|Array|Object} str - Stringa da convertire in JSON, array o oggetto da restituire direttamente
|
package/package.json
CHANGED
package/types/markcad.d.ts
CHANGED
|
@@ -176,49 +176,53 @@ export class Punto2 {
|
|
|
176
176
|
}
|
|
177
177
|
export var SP: Readonly<{
|
|
178
178
|
__proto__: any;
|
|
179
|
-
addhoriz: (ff: any, tipodim: any, dim: any,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
calcoladivisioni: (ff: any,
|
|
183
|
-
|
|
179
|
+
addhoriz: (ff: any, tipodim: any, dim: any, cod: any, align: any, cuts: any) => any;
|
|
180
|
+
addoriz: typeof addoriz;
|
|
181
|
+
addvert: (ff: any, tipodim: any, dim: any, cod: any, align: any, cuts: any) => any;
|
|
182
|
+
calcoladivisioni: (ff: any, notused: any, shape2: any, oggetti: any) => any;
|
|
183
|
+
checkoggetto: typeof checkoggetto;
|
|
184
|
+
creaprofiloesterno: typeof creaprofiloesterno;
|
|
184
185
|
create: (x: any, y: any, bordo: any, options: any) => {
|
|
185
186
|
x: any;
|
|
186
187
|
y: any;
|
|
188
|
+
area: any;
|
|
187
189
|
bordo: any;
|
|
188
|
-
minvano: any;
|
|
189
190
|
priority: any;
|
|
191
|
+
minvano: any;
|
|
190
192
|
taglio: any;
|
|
191
|
-
tagliov: any;
|
|
192
193
|
tipo: any;
|
|
193
194
|
h1: any;
|
|
194
195
|
h2: any;
|
|
195
196
|
l1: any;
|
|
196
197
|
l2: any;
|
|
197
198
|
vert: any[];
|
|
198
|
-
|
|
199
|
-
|
|
199
|
+
oriz: any[];
|
|
200
|
+
aree: {};
|
|
200
201
|
countid: number;
|
|
201
202
|
};
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
generatesegments: typeof generatesegments;
|
|
206
|
-
internalshape: typeof internalshape;
|
|
207
|
-
makeshape: (ff: any) => {
|
|
203
|
+
getbordi: typeof getbordi;
|
|
204
|
+
makedivisions: typeof makedivisions;
|
|
205
|
+
makeshape: (ff: any, oggetti: any) => {
|
|
208
206
|
shape: any;
|
|
209
207
|
internalshape: any;
|
|
208
|
+
shape2: any;
|
|
209
|
+
shapetop: any;
|
|
210
|
+
bordi: any[];
|
|
211
|
+
dati: any[];
|
|
212
|
+
draws: any[];
|
|
210
213
|
};
|
|
211
214
|
priorita: {
|
|
212
215
|
v: string;
|
|
213
216
|
h: string;
|
|
214
217
|
};
|
|
215
|
-
pushlineare: typeof pushlineare;
|
|
216
|
-
pushshape: typeof pushshape;
|
|
217
218
|
tagli: {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
219
|
+
dd: string;
|
|
220
|
+
vv: string;
|
|
221
|
+
oo: string;
|
|
222
|
+
vo: string;
|
|
223
|
+
vd: string;
|
|
224
|
+
ov: string;
|
|
225
|
+
od: string;
|
|
222
226
|
};
|
|
223
227
|
tipi: {
|
|
224
228
|
i: string;
|
|
@@ -242,12 +246,11 @@ export var SP: Readonly<{
|
|
|
242
246
|
export function TODEG(a: any, dec?: number): number;
|
|
243
247
|
export function TORAD(a: any, dec?: number): number;
|
|
244
248
|
export class Vis2d {
|
|
245
|
-
constructor(name: any,
|
|
249
|
+
constructor(name: any, scalalinea?: number);
|
|
246
250
|
name: any;
|
|
247
|
-
clear(
|
|
251
|
+
clear(scalalinea?: number): this;
|
|
248
252
|
vec: any[];
|
|
249
|
-
|
|
250
|
-
xp2: any;
|
|
253
|
+
_sl: number;
|
|
251
254
|
push(x: any, y: any, rot?: number): void;
|
|
252
255
|
pop(): void;
|
|
253
256
|
randomcolor(transp?: string): string;
|
|
@@ -273,11 +276,22 @@ export class Vis2d {
|
|
|
273
276
|
* @param {Object} p3 - Terzo punto {x,y}
|
|
274
277
|
* @returns {number} Angolo in radianti
|
|
275
278
|
*/ export function angle3point(p1: any, p2: any, p3: any): number;
|
|
279
|
+
export namespace blocked {
|
|
280
|
+
let window: any;
|
|
281
|
+
let self: any;
|
|
282
|
+
let globalThis: any;
|
|
283
|
+
let document: any;
|
|
284
|
+
let Function: any;
|
|
285
|
+
let eval: any;
|
|
286
|
+
let fetch: any;
|
|
287
|
+
let XMLHttpRequest: any;
|
|
288
|
+
}
|
|
276
289
|
/**
|
|
277
290
|
* Classe per la gestione degli errori con funzionalità di accumulo e formattazione
|
|
278
291
|
*/ export function clamp(n: any, min?: number, max?: number): any;
|
|
279
292
|
export function clean(k: any, locase?: boolean): any;
|
|
280
293
|
export function evalcustomfunction(amb: any, code: any, values: any, objects: any): Promise<any>;
|
|
294
|
+
export function getOggetto(obj: any, exclude?: any[]): any;
|
|
281
295
|
export function getdumpmacro(nodo: any): string;
|
|
282
296
|
export function getnodebyid(id: any, nodocorrente: any): any;
|
|
283
297
|
export function getprojectkeys(project: any): any;
|
|
@@ -381,43 +395,75 @@ export function valutagrafica(amb: any, startmacro: any, rulespec: any, progetto
|
|
|
381
395
|
vari: any;
|
|
382
396
|
fnlist: any[];
|
|
383
397
|
}>;
|
|
384
|
-
declare function
|
|
385
|
-
|
|
386
|
-
|
|
398
|
+
declare function addoriz(ff: any, tipodim: any, dim: any, cod: any, align: any, cuts: any): any;
|
|
399
|
+
declare function checkoggetto(oggetti: any, tipo: any, cod: any): any;
|
|
400
|
+
declare function creaprofiloesterno(ff: any, oggetti: any): {
|
|
401
|
+
shape: any;
|
|
402
|
+
internalshape: any;
|
|
403
|
+
shape2: any;
|
|
404
|
+
shapetop: any;
|
|
405
|
+
bordi: any[];
|
|
406
|
+
dati: any[];
|
|
407
|
+
draws: any[];
|
|
408
|
+
};
|
|
409
|
+
declare function getbordi(oggetti: any, bordo: any): {
|
|
410
|
+
bordi: any[];
|
|
411
|
+
uguali: boolean;
|
|
387
412
|
bl: any;
|
|
413
|
+
bt: any;
|
|
388
414
|
br: any;
|
|
415
|
+
bb: any;
|
|
389
416
|
};
|
|
390
|
-
declare function
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
417
|
+
declare function makedivisions(ff: any, shape2: any, oggetti: any): {
|
|
418
|
+
ff: any;
|
|
419
|
+
h1: {
|
|
420
|
+
id: any;
|
|
421
|
+
x: number;
|
|
422
|
+
sp: any;
|
|
423
|
+
cuts: any[];
|
|
424
|
+
cod: any;
|
|
425
|
+
}[];
|
|
426
|
+
ph: {
|
|
427
|
+
a: any;
|
|
428
|
+
b: any;
|
|
429
|
+
}[];
|
|
430
|
+
v1: {
|
|
431
|
+
id: any;
|
|
432
|
+
x: number;
|
|
433
|
+
sp: any;
|
|
434
|
+
cuts: any[];
|
|
435
|
+
cod: any;
|
|
436
|
+
}[];
|
|
437
|
+
pv: {
|
|
438
|
+
a: any;
|
|
439
|
+
b: any;
|
|
440
|
+
}[];
|
|
441
|
+
draws: {
|
|
442
|
+
type: string;
|
|
443
|
+
sx: any;
|
|
444
|
+
sy: any;
|
|
445
|
+
dx: any;
|
|
446
|
+
dy: any;
|
|
447
|
+
id: string;
|
|
448
|
+
cod: any;
|
|
449
|
+
rot: number;
|
|
450
|
+
pt: any;
|
|
451
|
+
}[];
|
|
452
|
+
lines: any[];
|
|
453
|
+
dati: {
|
|
454
|
+
id: string;
|
|
455
|
+
cod: any;
|
|
456
|
+
c2: any;
|
|
457
|
+
type: string;
|
|
458
|
+
shape: any;
|
|
459
|
+
info: {
|
|
460
|
+
isrect: number;
|
|
461
|
+
sx: any;
|
|
462
|
+
sy: any;
|
|
463
|
+
rot: number;
|
|
464
|
+
width: any;
|
|
465
|
+
height: any;
|
|
466
|
+
};
|
|
467
|
+
}[];
|
|
422
468
|
};
|
|
423
469
|
export {};
|
package/types/markcad3d.d.ts
CHANGED
|
@@ -173,6 +173,7 @@ export function posiziona(grp: any, pos?: {}): any;
|
|
|
173
173
|
export function randombasemat(): any;
|
|
174
174
|
export function revolve(gcad: any, shape: any, orient: any, mat: any, options: any): any;
|
|
175
175
|
export const scaleunit: 0.001;
|
|
176
|
+
export function setLineColorMode(white: any): void;
|
|
176
177
|
export function spritemat(gcad: any, file: any): Promise<any>;
|
|
177
178
|
export function svuotanodo(n: any): void;
|
|
178
179
|
export function tasklav(x: any, y: any, z: any, op: any, ids: any, faces: any): any;
|
package/types/markuno.d.ts
CHANGED
|
@@ -280,9 +280,10 @@ export class Variabile {
|
|
|
280
280
|
/**
|
|
281
281
|
* Valida un identificatore verificando che contenga solo caratteri permessi
|
|
282
282
|
* @param {string} id - Identificatore da validare
|
|
283
|
+
* @param {boolean} vuoto - Default false: Accetta valori vuoti!
|
|
283
284
|
* @throws {Error} Se l'identificatore contiene caratteri non validi
|
|
284
285
|
* @returns {string} Identificatore validato in minuscolo
|
|
285
|
-
*/ export function checkname(id: string): string;
|
|
286
|
+
*/ export function checkname(id: string, vuoto?: boolean): string;
|
|
286
287
|
export function clamp(n: any, min?: number, max?: number): any;
|
|
287
288
|
export function clean(k: any, locase?: boolean): any;
|
|
288
289
|
export function dammivariante(amb: any, macro: any, ky: any): Promise<any>;
|