markuno_lib 1.2.64 → 1.2.65

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 CHANGED
@@ -49,7 +49,7 @@ constructor(p1,p2,x2=null,y2=null){"number"==typeof p1&&"number"==typeof p2&&nul
49
49
  /**
50
50
  * Calcola la differenza delle coordinate x dei punti
51
51
  * @returns {number} Differenza x
52
- */get dx(){return this.p2.x-this.p1.x}
52
+ */get angle(){return new Punto2(this.dx,this.dy).angle}get dx(){return this.p2.x-this.p1.x}
53
53
  /**
54
54
  * Calcola la differenza delle coordinate y dei punti
55
55
  * @returns {number} Differenza y
@@ -137,7 +137,7 @@ constructor(p1,p2,x2=null,y2=null){"number"==typeof p1&&"number"==typeof p2&&nul
137
137
  * @param {Linea2} line2 - Seconda linea
138
138
  * @param {boolean} [checkpunticomune=false] - Se true verifica anche la sovrapposizione
139
139
  * @returns {boolean} True se collineari
140
- */isCollineare(line2,checkpunticomune=!1){if(!this.isparallela(line2))return!1;const distanza=this.distanzaSegmentiParalleli(line2);if(Math.abs(distanza)>.001)return!1;if(checkpunticomune){const isPointBetween=(p,a,b)=>Math.min(a.x,b.x)<=p.x&&p.x<=Math.max(a.x,b.x)&&Math.min(a.y,b.y)<=p.y&&p.y<=Math.max(a.y,b.y),{p1:p1,p2:p2}=this,{p1:p1_2,p2:p2_2}=line2;return isPointBetween(p1_2,p1,p2)||isPointBetween(p2_2,p1,p2)||isPointBetween(p1,p1_2,p2_2)||isPointBetween(p2,p1_2,p2_2)}return!0}clone(){return new Linea2(this.p1.x,this.p1.y,this.p2.x,this.p2.y)}rotate(deg){if(!deg)return this;const r=deg*Math.PI/180,cosTheta=Math.cos(r),sinTheta=Math.sin(r);function rotate(p){return new Punto2(p.x*cosTheta-p.y*sinTheta,p.x*sinTheta+p.y*cosTheta)}return this.p1=rotate(this.p1),this.p2=rotate(this.p2),this}move(x=0,y=0){return"object"==typeof x&&x.x&&(y=x.y||0,x=x.x),this.p1.x+=x,this.p1.y+=y,this.p2.x+=x,this.p2.y+=y,this}}
140
+ */isCollineare(line2,checkpunticomune=!1){if(!this.isparallela(line2))return!1;const distanza=this.distanzaSegmentiParalleli(line2);if(Math.abs(distanza)>.001)return!1;if(checkpunticomune){function isPointBetween(p,a,b,toll=.001){const cross=(b.x-a.x)*(p.y-a.y)-(b.y-a.y)*(p.x-a.x);return!(Math.abs(cross)>toll)&&(Math.min(a.x,b.x)-toll<=p.x&&p.x<=Math.max(a.x,b.x)+toll&&Math.min(a.y,b.y)-toll<=p.y&&p.y<=Math.max(a.y,b.y)+toll)}const{p1:p1,p2:p2}=this,{p1:p1_2,p2:p2_2}=line2;return isPointBetween(p1_2,p1,p2)||isPointBetween(p2_2,p1,p2)||isPointBetween(p1,p1_2,p2_2)||isPointBetween(p2,p1_2,p2_2)}return!0}clone(){return new Linea2(this.p1.x,this.p1.y,this.p2.x,this.p2.y)}rotate(deg){if(!deg)return this;const r=deg*Math.PI/180,cosTheta=Math.cos(r),sinTheta=Math.sin(r);function rotate(p){return new Punto2(p.x*cosTheta-p.y*sinTheta,p.x*sinTheta+p.y*cosTheta)}return this.p1=rotate(this.p1),this.p2=rotate(this.p2),this}move(x=0,y=0){return"object"==typeof x&&x.x&&(y=x.y||0,x=x.x),this.p1.x+=x,this.p1.y+=y,this.p2.x+=x,this.p2.y+=y,this}}
141
141
  /**
142
142
  * Calcola i punti di offset tra due percorsi
143
143
  * Trova i punti del secondo percorso che corrispondono all'offset del primo
@@ -286,7 +286,7 @@ function sharpCorners(path,thresholdDeg=45){const result=[],n=path.length;if(n<3
286
286
  * @param {number} thresholdDeg - Angolo in gradi.
287
287
  * @returns {Array<{ index: number, point: {x:number,y:number}, angle: number }>}
288
288
  */
289
- 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)}}},orientasplitter(){-1!=orientation()&&pt.reverse();let np=pt.length;for(let i=0;i<np;i++){let lt=new Linea2(pt[(np+i-1)%np],pt[i]);if(Math.abs(Math.abs(lt.angle)-Math.PI)<.001){i&&selezionaprimo(i);break}}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=simplify(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=2==n?{x:pt[1].x+dx,y:pt[1].y+dy}: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}},swapxy(){for(let i=0;i<pt.length;i++){let q=pt[i].x;pt[i].x=-pt[i].y,pt[i].y=-q}return this},fromvec(aa){return pt=[],_addvec(aa),this},addvec(vec){return _addvec(vec),this},frompt(pts){return pt=[...pts],pt=removeduplicate(pt),this},fromdxfvec(verts){let points=[];if(verts&&verts.length)for(let i=0;i<verts.length;i++){let{x:x,y:y,bulge:bulge}=verts[i];if(points.push({x:x,y:y}),bulge){const step=1;let p1={x:x,y:y},p2=verts[(i+1)%verts.length],dx=p2.x-p1.x,dy=p2.y-p1.y,dist=Math.hypot(dx,dy);dist>step&&points.push(...dxfbulge(p1,p2,bulge,Math.floor((dist-step)/step)+1))}}return pt=points.map((e=>({x:Math.round(10*e.x)/10,y:Math.round(10*e.y)/10}))),pt=removeduplicate(pt),this},monotona(){let dxd=dims(pt),pp=pt.map((e=>({x:e.x-dxd.p2.x,y:e.y}))),xp=[];xp.push(pp[0]);let lastv=pp[0].y;for(let i=1;i<pp.length;i++)if(pp[i].y>lastv+1e-4||i==pp.length-1)xp.push(pp[i]),lastv=pp[i].y;else{const newv=lastv+1e-4;xp.push({x:pp[i].x,y:newv}),lastv=newv}return{sh:getshape().frompt(xp),...dxd}},sliceony(stag){let yvalues=stag.pt.map((e=>e.y)).slice(1,-1);const res=[],n=pt.length;let imin=0,yMin=pt[0].y;for(let i=1;i<n;i++)pt[i].y<yMin&&(yMin=pt[i].y,imin=i);const pts=[...pt.slice(imin),...pt.slice(0,imin)],m=pts.length,ymap=new Map;for(let i=0;i<m;i++)for(let y of yvalues)Math.abs(pts[i].y-y)<1e-5&&(ymap.has(y)?ymap.get(y).i2=i:ymap.set(y,{i1:i,i2:i}));const pairs=yvalues.map((y=>ymap.get(y))).filter((p=>p&&p.i1>=0&&p.i2>=0));pairs.length>0&&pairs[0].i1>0&&res.push([...pts.slice(0,pairs[0].i1+1),...pts.slice(pairs[0].i2,pairs[0].length)]);for(let i=0;i<pairs.length-1;i++){const a=pairs[i],b=pairs[i+1];res.push([...pts.slice(a.i1,b.i1+1),...pts.slice(b.i2,a.i2+1)])}const last=pairs[pairs.length-1];last.i2>last.i1&&res.push(pts.slice(last.i1,last.i2+1));return res.filter((arr=>arr.length>0))},splitshape(p,verticale=!0){const p1=verticale?{x:p.x,y:p.y-100}:{x:p.x-100,y:p.y},p2=verticale?{x:p.x,y:p.y+100}:{x:p.x+100,y:p.y},linea=this.intersectline(new Linea2(p1,p2));if(!linea)return null;const pstart=linea.p1,pend=linea.p2,findIndex=pt=>this.pt.findIndex(((v,i)=>new Linea2(v,this.pt[(i+1)%this.pt.length]).onsegment(pt))),i1=findIndex(pstart),i2=findIndex(pend);if(i1<0||i2<0)return null;const n=this.pt.length,loop=(a,b,p0,p1)=>{const res=[];for(let i=a;i!==b;i=(i+1)%n)res.push(this.pt[(i+1)%n]);return res},dx=getshape().frompt(loop(i1,i2));return{sx:getshape().frompt(loop(i2,i1)),dx:dx,linea:linea}},xfromy(y,valore0=0,maggiore=!0){const res=[],n=this.pt.length;for(let i=0;i<n-1;i++){const p1=this.pt[i],p2=this.pt[i+1];if(p1.y<=y&&p2.y>=y||p2.y<=y&&p1.y>=y){const dy=p2.y-p1.y,t=dy?(y-p1.y)/dy:0,x=p1.x+t*(p2.x-p1.x);res.push(x)}else p1.y===y&&p2.y===y&&res.push(maggiore?Math.max(p1.x,p2.x):Math.min(p1.x,p2.x))}return res.length?maggiore?Math.max(...res):Math.min(...res):valore0},yfromx(x,valore0=0,maggiore=!0){const res=[],n=this.pt.length;for(let i=0;i<n-1;i++){const p1=this.pt[i],p2=this.pt[i+1];if(p1.x<=x&&p2.x>=x||p2.x<=x&&p1.x>=x){const dx=p2.x-p1.x,t=dx?(x-p1.x)/dx:0,y=p1.y+t*(p2.y-p1.y);res.push(y)}else p1.x===x&&p2.x===x&&res.push(maggiore?Math.max(p1.y,p2.y):Math.min(p1.y,p2.y))}return res.length?maggiore?Math.max(...res):Math.min(...res):valore0},forcevalues(shape,verticale=!0,delta=1e-6){const sorted=[...new Set(shape.pt.map((e=>verticale?e.y:e.x)))].sort(((a,b)=>a-b)),newpt=[],n=pt.length;for(let i=0;i<n;i++){const p1=pt[i],p2=pt[(i+1)%n];newpt.push({...p1});let v1=verticale?p1.y:p1.x,v2=verticale?p2.y:p2.x;if(v1===v2)continue;const range=v2>v1?sorted.filter((v=>v>v1+delta&&v<v2-delta)):sorted.filter((v=>v<v1-delta&&v>v2+delta)).reverse();for(const v of range){const t=(v-v1)/(v2-v1),q={x:p1.x+t*(p2.x-p1.x),y:p1.y+t*(p2.y-p1.y)};newpt.push(q)}}return pt=newpt,this},fromrrect(w,h,r=10,sx=0,sy=0){return(r>=w/2||r>=h/2&&r<=0)&&(r=Math.round(Math.min(w/3,h/3))),fromstr(`0,0,r${r},${w},0,r${r},${w},${h},r${r},0,${h},r${r}`),(sx||sy)&&move(sx,sy),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),cl=pt.map((e=>`${pstr(e.x)};${pstr(e.y)};`)).join("");return cl&&cl.length?cl.slice(0,-1).match(/.{1,80}(;|$)/g).map((s=>s.trim())).join("\n"):""},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},truncatebefore:function truncatebefore(linea){let s=new Linea2(pt[0],pt[1]),p=linea.interseca(s);if(p){let a=pt[0],b=pt[1],dx=b.x-a.x,dy=b.y-a.y,den=dx*dx+dy*dy;if(den){if(((p.x-a.x)*dx+(p.y-a.y)*dy)/den<=1)return pt[0]=p,this}}for(let i=1;i<pt.length-1;i++){let s=new Linea2(pt[i],pt[i+1]),p=linea.interseca(s);if(p&&s.onsegment(p))return pt=pt.slice(i),pt[0]=p,this}return this},truncateafter:function truncateafter(linea){let np=pt.length,s=new Linea2(pt[np-2],pt[np-1]),p=linea.interseca(s);if(p){let a=pt[np-2],b=pt[np-1],dx=b.x-a.x,dy=b.y-a.y,den=dx*dx+dy*dy;if(den){if(((p.x-a.x)*dx+(p.y-a.y)*dy)/den>=0)return pt[np-1]=p,this}}for(let i=np-3;i>=0;i--){let s=new Linea2(pt[i],pt[i+1]),p=linea.interseca(s);if(p&&s.onsegment(p))return pt=pt.slice(0,i+1),pt.push(p),this}return this},removeduplicate(delta=.005){return pt=removeduplicate(pt,delta),this},to3d(u0,alt=0,coeffa=0,coeffb=0,open=!1,sh=null,invert=!1){let tm=function to3dcoor(path,options){let{currentU:currentU=0,c:c=0,a:a=0,b:b=0,anglemin:anglemin=30,open:open=!1,sh:sh=null,invert:invert=!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;if(sh){let t=sh.xfromy(current.y,0,!0);invert?z+=t:z-=t}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,sh:sh,invert:invert});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}}}
289
+ 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)}}},orientasplitter(){-1!=orientation()&&pt.reverse();let np=pt.length;for(let i=0;i<np;i++){let lt=new Linea2(pt[(np+i-1)%np],pt[i]);if(Math.abs(Math.abs(lt.angle)-Math.PI)<.001){i&&selezionaprimo(i);break}}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=simplify(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=2==n?{x:pt[1].x+dx,y:pt[1].y+dy}: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}},swapxy(){for(let i=0;i<pt.length;i++){let q=pt[i].x;pt[i].x=-pt[i].y,pt[i].y=-q}return this},fromvec(aa){return pt=[],_addvec(aa),this},addvec(vec){return _addvec(vec),this},frompt(pts){return pt=[...pts],pt=removeduplicate(pt),this},fromdxfvec(verts){let points=[];if(verts&&verts.length)for(let i=0;i<verts.length;i++){let{x:x,y:y,bulge:bulge}=verts[i];if(points.push({x:x,y:y}),bulge){const step=1;let p1={x:x,y:y},p2=verts[(i+1)%verts.length],dx=p2.x-p1.x,dy=p2.y-p1.y,dist=Math.hypot(dx,dy);dist>step&&points.push(...dxfbulge(p1,p2,bulge,Math.floor((dist-step)/step)+1))}}return pt=points.map((e=>({x:Math.round(10*e.x)/10,y:Math.round(10*e.y)/10}))),pt=removeduplicate(pt),this},monotona(){let dxd=dims(pt),pp=pt.map((e=>({x:e.x-dxd.p2.x,y:e.y}))),xp=[];xp.push(pp[0]);let lastv=pp[0].y;for(let i=1;i<pp.length;i++)if(pp[i].y>lastv+1e-4||i==pp.length-1)xp.push(pp[i]),lastv=pp[i].y;else{const newv=lastv+1e-4;xp.push({x:pp[i].x,y:newv}),lastv=newv}return{sh:getshape().frompt(xp),...dxd}},offsetshape(delta){let sg=[],sh=this;for(let i=0;i<sh.npt-1;i++){let l=sh.segment(i).offset(delta);sg.push(l)}let l1=sh.segment(0).perpendicolare(),s2=sh.segment(sh.npt-2),l2=s2.perpendicolare(s2.p2),pts=[l1.interseca(sg[0])];for(let i=0;i<sg.length-1;i++){let p=sg[i].interseca(sg[i+1]);p&&pts.push(p)}return pts.push(sg[sg.length-1].interseca(l2)),getshape().frompt(pts)},sliceony(stag){let yvalues=stag.pt.map((e=>e.y)).slice(1,-1);const res=[],n=pt.length;let imin=0,yMin=pt[0].y;for(let i=1;i<n;i++)pt[i].y<yMin&&(yMin=pt[i].y,imin=i);const pts=[...pt.slice(imin),...pt.slice(0,imin)],m=pts.length,ymap=new Map;for(let i=0;i<m;i++)for(let y of yvalues)Math.abs(pts[i].y-y)<1e-5&&(ymap.has(y)?ymap.get(y).i2=i:ymap.set(y,{i1:i,i2:i}));const pairs=yvalues.map((y=>ymap.get(y))).filter((p=>p&&p.i1>=0&&p.i2>=0));pairs.length>0&&pairs[0].i1>0&&res.push([...pts.slice(0,pairs[0].i1+1),...pts.slice(pairs[0].i2,pairs[0].length)]);for(let i=0;i<pairs.length-1;i++){const a=pairs[i],b=pairs[i+1];res.push([...pts.slice(a.i1,b.i1+1),...pts.slice(b.i2,a.i2+1)])}const last=pairs[pairs.length-1];last.i2>last.i1&&res.push(pts.slice(last.i1,last.i2+1));return res.filter((arr=>arr.length>0))},splitshape(p,verticale=!0){const p1=verticale?{x:p.x,y:p.y-100}:{x:p.x-100,y:p.y},p2=verticale?{x:p.x,y:p.y+100}:{x:p.x+100,y:p.y},linea=this.intersectline(new Linea2(p1,p2));if(!linea)return null;const pstart=linea.p1,pend=linea.p2,findIndex=pt=>this.pt.findIndex(((v,i)=>new Linea2(v,this.pt[(i+1)%this.pt.length]).onsegment(pt))),i1=findIndex(pstart),i2=findIndex(pend);if(i1<0||i2<0)return null;const n=this.pt.length,loop=(a,b,p0,p1)=>{const res=[];for(let i=a;i!==b;i=(i+1)%n)res.push(this.pt[(i+1)%n]);return res},dx=getshape().frompt(loop(i1,i2));return{sx:getshape().frompt(loop(i2,i1)),dx:dx,linea:linea}},xfromy(y,valore0=0,maggiore=!0){const res=[],n=this.pt.length;for(let i=0;i<n-1;i++){const p1=this.pt[i],p2=this.pt[i+1];if(p1.y<=y&&p2.y>=y||p2.y<=y&&p1.y>=y){const dy=p2.y-p1.y,t=dy?(y-p1.y)/dy:0,x=p1.x+t*(p2.x-p1.x);res.push(x)}else p1.y===y&&p2.y===y&&res.push(maggiore?Math.max(p1.x,p2.x):Math.min(p1.x,p2.x))}return res.length?maggiore?Math.max(...res):Math.min(...res):valore0},yfromx(x,valore0=0,maggiore=!0){const res=[],n=this.pt.length;for(let i=0;i<n-1;i++){const p1=this.pt[i],p2=this.pt[i+1];if(p1.x<=x&&p2.x>=x||p2.x<=x&&p1.x>=x){const dx=p2.x-p1.x,t=dx?(x-p1.x)/dx:0,y=p1.y+t*(p2.y-p1.y);res.push(y)}else p1.x===x&&p2.x===x&&res.push(maggiore?Math.max(p1.y,p2.y):Math.min(p1.y,p2.y))}return res.length?maggiore?Math.max(...res):Math.min(...res):valore0},forcevalues(shape,verticale=!0,delta=1e-6){const sorted=[...new Set(shape.pt.map((e=>verticale?e.y:e.x)))].sort(((a,b)=>a-b)),newpt=[],n=pt.length;for(let i=0;i<n;i++){const p1=pt[i],p2=pt[(i+1)%n];newpt.push({...p1});let v1=verticale?p1.y:p1.x,v2=verticale?p2.y:p2.x;if(v1===v2)continue;const range=v2>v1?sorted.filter((v=>v>v1+delta&&v<v2-delta)):sorted.filter((v=>v<v1-delta&&v>v2+delta)).reverse();for(const v of range){const t=(v-v1)/(v2-v1),q={x:p1.x+t*(p2.x-p1.x),y:p1.y+t*(p2.y-p1.y)};newpt.push(q)}}return pt=newpt,this},fromrrect(w,h,r=10,sx=0,sy=0){return(r>=w/2||r>=h/2&&r<=0)&&(r=Math.round(Math.min(w/3,h/3))),fromstr(`0,0,r${r},${w},0,r${r},${w},${h},r${r},0,${h},r${r}`),(sx||sy)&&move(sx,sy),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),cl=pt.map((e=>`${pstr(e.x)};${pstr(e.y)};`)).join("");return cl&&cl.length?cl.slice(0,-1).match(/.{1,80}(;|$)/g).map((s=>s.trim())).join("\n"):""},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},truncatebefore:function truncatebefore(linea){let s=new Linea2(pt[0],pt[1]),p=linea.interseca(s);if(p){let a=pt[0],b=pt[1],dx=b.x-a.x,dy=b.y-a.y,den=dx*dx+dy*dy;if(den){if(((p.x-a.x)*dx+(p.y-a.y)*dy)/den<=1)return pt[0]=p,this}}for(let i=1;i<pt.length-1;i++){let s=new Linea2(pt[i],pt[i+1]),p=linea.interseca(s);if(p&&s.onsegment(p))return pt=pt.slice(i),pt[0]=p,this}return this},truncateafter:function truncateafter(linea){let np=pt.length,s=new Linea2(pt[np-2],pt[np-1]),p=linea.interseca(s);if(p){let a=pt[np-2],b=pt[np-1],dx=b.x-a.x,dy=b.y-a.y,den=dx*dx+dy*dy;if(den){if(((p.x-a.x)*dx+(p.y-a.y)*dy)/den>=0)return pt[np-1]=p,this}}for(let i=np-3;i>=0;i--){let s=new Linea2(pt[i],pt[i+1]),p=linea.interseca(s);if(p&&s.onsegment(p))return pt=pt.slice(0,i+1),pt.push(p),this}return this},removeduplicate(delta=.005){return pt=removeduplicate(pt,delta),this},to3d(u0,alt=0,coeffa=0,coeffb=0,open=!1,sh=null,invert=!1){let tm=function to3dcoor(path,options){let{currentU:currentU=0,c:c=0,a:a=0,b:b=0,anglemin:anglemin=30,open:open=!1,sh:sh=null,invert:invert=!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;if(sh){let t=sh.xfromy(current.y,0,!0);invert?z+=t:z-=t}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,sh:sh,invert:invert});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}}}
290
290
  /**
291
291
  * Calcola i punti di un arco passante per tre punti
292
292
  * @param {number} segments - Numero di segmenti (punti-1)
@@ -504,7 +504,7 @@ ClipperLib.ExPolygon=function(){this.outer=null,this.holes=null},ClipperLib.JS.A
504
504
  * @property {Function} inflate - Espande o contrae una forma
505
505
  * @property {Function} unisci - Unisce più forme con gestione di fori e tagli
506
506
  */
507
- function alignByMinDist(sag1,sag2,isopen){const n1=sag1.length,n2=sag2.length;if(n1<1||n2<1)return sag2.slice();let bestOffset=0,minSum=1/0;for(let k=0;k<n2;k++){const p0=sag1[0],q0=sag2[k%n2],dx0=p0.x-q0.x,dy0=p0.y-q0.y,p1=sag1[n1-1],q1=sag2[isopen?Math.min(k+n1-1,n2-1):(k+n1-1)%n2],dx1=p1.x-q1.x,dy1=p1.y-q1.y,sum=dx0*dx0+dy0*dy0+dx1*dx1+dy1*dy1;sum<minSum&&(minSum=sum,bestOffset=k)}return[...sag2.slice(bestOffset),...sag2.slice(0,bestOffset)]}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};function _inflateopen(pts,delta){const co=new ClipperLib.ClipperOffset;co.MiterLimit=4,co.ArcTolerance=.25;const DD=1e4*delta,pshape=toclipformat(pts);co.AddPath(pshape,ClipperLib.JoinType.jtMiter,ClipperLib.EndType.etClosedPolygon);const solution=new ClipperLib.Paths;co.Execute(solution,DD);let tm=fromclipformat(solution[0]);return getshape().frompt(tm)}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:function inflate(shape,delta=2,mantainorder=!1,isopen=0){let pshape=toclipformat(shape.pt),tm=_inflate(pshape,1e4*delta);if(!tm||!tm.length)return getshape().frompt([]);let p2=getshape().frompt(fromclipformat(tm[0]));if(mantainorder){p2.orient!=shape.orient&&p2.reverse();let p3=alignByMinDist(shape.pt,p2.pt,isopen);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),q2=sh2.segment(-2).interseca(l2),q1=sh2.segment(0).interseca(l1);q1&&(sh2.pt[0]=q1),q2&&(sh2.pt[sh2.pt.length-1]=q2)}function estendi2(sh1,sh2){let lfin=sh1.segment(-1),l2=sh2.segment(0),q1=lfin.interseca(l2);q1&&(sh2.pt[0]=q1),l2=sh2.segment(-2);let q2=lfin.interseca(l2);q2&&(sh2.pt[sh2.pt.length-1]=q2)}1==isopen?estendi1(shape,p2):estendi2(shape,p2)}}return p2},inflateopen:_inflateopen,inflateclose(shape,delta){let p2=_inflateopen(shape.pt,delta);p2.orient!=shape.orient&&p2.reverse();let p3=alignByMinDist(shape.pt,p2.pt,0);return p2.frompt(p3),p2},inflatecornici(shape,delta=2,linetruncateini,linetruncateend){let p2,n=shape.npt;if(2==n){let l2=shape.segment(0).offset(delta);p2=getshape().frompt([l2.p1,l2.p2])}else if(3==n){let l1=shape.segment(0).offset(delta),l2=shape.segment(1).offset(delta);if(l1.isparallela(l2))p2=getshape().frompt([l1.p1,l2.p2]);else{let p=l1.interseca(l2);p2=getshape().frompt([l1.p1,p,l2.p2])}}else{let l1=new Linea2(shape.pt[0],shape.pt[shape.npt-1]),len1=l1.len,l2=l1.perpendicolare(l1.p1,len1),l3=l1.perpendicolare(l1.p2,len1);l2.isparallela(shape.segment(0))&&(l2=l1.perpendicolare(l1.puntot(.1),len1)),l3.isparallela(shape.segment(shape.npt-2))&&(l3=l1.perpendicolare(l1.puntot(.9),len1));let n2=Math.floor(shape.npt/2),{t:t}=l2.proiezionet(shape.pt[n2]),t2=2*(t>0?-1:1),px2=l2.puntot(t2),px3=l3.puntot(t2);p2=_inflateopen([...shape.pt,px3,px2],delta);let idx=p2.pt.reduce(((imin,p,i)=>(p.x-px2.x)**2+(p.y-px2.y)**2<(p2.pt[imin].x-px2.x)**2+(p2.pt[imin].y-px2.y)**2?i:imin),0);p2.pt=p2.pt.slice(idx+2).concat(p2.pt.slice(0,idx)),p2.orient!=shape.orient&&p2.reverse(),linetruncateini&&(shape.truncatebefore(linetruncateini),p2.truncatebefore(linetruncateini)),linetruncateend&&(p2.truncateafter(linetruncateend),shape.truncateafter(linetruncateend))}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 Vscene{constructor(x,y,info={}){this.x=x,this.y=y,this.info=info,this.clear()}addrow(o){o||(o={}),o.id=function newid(rows){let max=0;for(let x of rows)+x.id>max&&(max=+x.id);return max+1}(this.rows);let tm=new Vobject(o);return this.rows.push(tm),tm}clear(){this.curlayer=0,this.rows=[],this.clines=[]}fromjson(o){o||(o={info:{}}),this.clear(),this.x=o.x||4e3,this.y=o.y||3e3,this.info=o.info||{},this.curlayer=o.curlayer,o.clines&&(this.clines=o.clines.map((e=>new Linea2(e.p1,e.p2)))),o.rows&&(this.rows=o.rows.map((e=>new Vobject(e))))}tojson(){let{x:x,y:y,info:info,curlayer:curlayer,rows:rows,clines:clines}=this;return rows=rows.map((e=>e.tojson())),clines=clines.map((e=>({p1:e.p1,p2:e.p2}))),{x:x,y:y,curlayer:curlayer,rows:rows,clines:clines}}}class Vobject{constructor(o){o||(o={}),this.fromjson(o)}fromjson(o){this.id=o.id??1,this.layer=o.layer||0,this.hidden=!!o.hidden,this.x=o.x||100,this.y=o.y||100,this.pc=o.pc||{x:0,y:0},o.shape?this.shape=getshape().frompt(o.shape):this.shape=void 0,this.lines=(o.lines||[]).map((e=>new Linea2(e.p1,e.p2))),this.draw=new Vis2d(`d:${o.id}`),o.draw&&this.draw.fromjson(o.draw),this.info=o.info||{},this.pos=o.pos||{x:0,y:0,rot:0}}tojson(){let{id:id,layer:layer,x:x,y:y,pc:pc,shape:shape,hidden:hidden,lines:lines,info:info,pos:pos}=this;return lines=lines.map((e=>({p1:e.p1,p2:e.p2}))),shape=shape?shape.pt:void 0,{id:id,layer:layer,x:x,y:y,pc:pc,shape:shape,lines:lines,hidden:hidden,info:info,pos:pos,draw:this.draw.tojson()}}}class Vis2d{constructor(name){this.name=name,this.clear()}clear(){return this.vec=[],this.gr={},this}tojson(){let tm={};for(let x in this.gr)tm[x]=this.gr[x].tojson();return{name:this.name,rows:this.vec,groups:tm}}fromjson(n){if(!(n&&n.name&&n.rows&&n.groups))throw new Error("wrong data JSON");this.clear(),this.name=n.name,this.vec=n.rows;for(let x in n.groups)this.gr[x]=new Vis2d(x).fromjson(n.groups[x])}creategr(name="grp"){return this.gr[name]||(this.gr[name]=new Vis2d(name)),this.gr[name]}push(x=0,y=0,op={}){"number"==typeof op&&(op={rot:op}),op||(op={}),this.vec.push({type:"push",x:x,y:y,op:op})}pop(){this.vec.push({type:"pop"})}randomcolor(transp="100%"){return`hsl(${Math.floor(360*Math.random())}, 50%, 40%,${transp})`}addgr(gr){let name=gr;gr?.name&&(name=gr.name),this.gr[name]?this.vec.push({type:"group",name:name}):this.vec.push({type:"err",err:`addgroup: ${name} => missing`})}addquota(x1,y1,x2,y2,d=0,text="",scalafont=1,spessore=.25){this.vec.push({type:"quota",x1:x1,y1:y1,x2:x2,y2:y2,d:d,text:text,spessore:spessore,color:"black",scalafont:scalafont})}addqpunto(x1,y1,x2,y2,d=0,text="",scalafont=1,spessore=.25){this.vec.push({type:"qpunto",x1:x1,y1:y1,x2:x2,y2:y2,d:d,text:text,spessore:spessore,color:"black",scalafont:scalafont})}addpoint(p,id=-1,color="red",spessore=8){return p&&this.vec.push({type:"point",p:p,id:id,color:color,spessore:1*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:1*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:1*spessore}),this}addimg(l,img){return l&&this.vec.push({type:"img",l:l,img:img}),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:1*spessore}),this}addshapelin(s,color=void 0,spessore=1){return s&&this.vec.push({type:"shapelin",s:s,color:color||this.randomcolor(),spessore:1*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}}function checkoggetto(oggetti,tipo,cod,isrect){if("h"==tipo&&(tipo="o"),oggetti||(oggetti=[]),"number"==typeof cod&&!["a","as"].includes(tipo))return{cod:"__",macro:"",sps:cod};let bb=oggetti.find((e=>e.tipo.includes(tipo)&&e.cod==cod&&(e.isshape||isrect||"a"!=tipo)));return bb||(bb=oggetti.find((e=>e.tipo.includes(tipo)&&(e.isshape||isrect||"a"!=tipo)))),bb||(bb={cod:"__",macro:"",sps:0}),"a"!=tipo&&"as"!=tipo||"__"==bb.cod||bb.color||(bb.color=`hsl(${function stringToHue(str){let hash=0;for(let i=0;i<str.length;i++)hash=31*hash+str.charCodeAt(i)>>>0;return Math.floor(.6180339887*hash%1*360)}(bb.cod)}, 95%, 97%`),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.sps===bordi[0].sps))}else{let tm=checkoggetto(oggetti,"b",bordo);bordi=[tm,tm,tm,tm],uguali=!0}return{bordi:bordi,uguali:uguali,senza:!(bordi[0].sps||bordi[1].sps||bordi[2].sps||bordi[3].sps),bl:bordi[0].sps,bt:bordi[1].sps,br:bordi[2].sps,bb:bordi[3].sps}}function elaborapercorso(sh1,bordo,taglio,oggetti,countid=0){let sh2,sh3,p1h,p2h,p3h,p4h,p1v,p2v,p3v,p4v,p1s,p2s,line1,line2,i1,i2,dati=[],draws=[];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:++countid,type:`b${bordo}`,info:info};shape&&(tm.shape=s1.pt),draws.push({type:`b${bordo}`,pt:s0.pt}),dati.push(tm)}}countid=countid||0;let np=sh1.pt.length,idr=np-1;oggetti||(oggetti=[]);let{bordi:bordi,uguali:uguali,senza:senza}=getbordi(oggetti,bordo);if(uguali)if(senza||!bordi[0].sps)sh2=sh1.clone();else{let b=bordi[0].sps;sh2=shapeclip().inflate(sh1,-b,!0)}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)}if(!senza){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)}if(sh3=getshape().frompt(p2s),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{countid:countid,shape2:sh2,shapetop:sh3,bordi:bordi,dati:dati,draws:draws}}function creaprofiloesterno(ff,oggetti){let sh1,{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 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||h2)&&h1>=0&&h1<Math.min(y,x/2)&&h2>=0&&h2<Math.min(y,x/2)){let tm=getshape().fromstr(`a30;${l1||0};${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)}pts.push(x,0),ff.countid=0,sh1=getshape().fromvec(pts);let{countid:countid,shape2:shape2,shapetop:shapetop,bordi:bordi,dati:dati,draws:draws}=elaborapercorso(sh1,bordo,taglio,oggetti,ff.countid);return ff.countid=countid,{shape:sh1,internalshape:shape2,shape2:shape2,shapetop:shapetop,bordi:bordi,dati:dati,draws:draws}}
507
+ function alignByMinDist(sag1,sag2,isopen){const n1=sag1.length,n2=sag2.length;if(n1<1||n2<1)return sag2.slice();let bestOffset=0,minSum=1/0;for(let k=0;k<n2;k++){const p0=sag1[0],q0=sag2[k%n2],dx0=p0.x-q0.x,dy0=p0.y-q0.y,p1=sag1[n1-1],q1=sag2[isopen?Math.min(k+n1-1,n2-1):(k+n1-1)%n2],dx1=p1.x-q1.x,dy1=p1.y-q1.y,sum=dx0*dx0+dy0*dy0+dx1*dx1+dy1*dy1;sum<minSum&&(minSum=sum,bestOffset=k)}return[...sag2.slice(bestOffset),...sag2.slice(0,bestOffset)]}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};function _inflateopen(pts,delta){const co=new ClipperLib.ClipperOffset;co.MiterLimit=4,co.ArcTolerance=.25;const DD=1e4*delta,pshape=toclipformat(pts);co.AddPath(pshape,ClipperLib.JoinType.jtMiter,ClipperLib.EndType.etClosedPolygon);const solution=new ClipperLib.Paths;co.Execute(solution,DD);let tm=fromclipformat(solution[0]);return getshape().frompt(tm)}return{offset(shape,delta){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 getshape().frompt(tm)},inflate:function inflate(shape,delta=2,mantainorder=!1,isopen=0){let pshape=toclipformat(shape.pt),tm=_inflate(pshape,1e4*delta);if(!tm||!tm.length)return getshape().frompt([]);let p2=getshape().frompt(fromclipformat(tm[0]));if(mantainorder){p2.orient!=shape.orient&&p2.reverse();let p3=alignByMinDist(shape.pt,p2.pt,isopen);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),q2=sh2.segment(-2).interseca(l2),q1=sh2.segment(0).interseca(l1);q1&&(sh2.pt[0]=q1),q2&&(sh2.pt[sh2.pt.length-1]=q2)}function estendi2(sh1,sh2){let lfin=sh1.segment(-1),l2=sh2.segment(0),q1=lfin.interseca(l2);q1&&(sh2.pt[0]=q1),l2=sh2.segment(-2);let q2=lfin.interseca(l2);q2&&(sh2.pt[sh2.pt.length-1]=q2)}1==isopen?estendi1(shape,p2):estendi2(shape,p2)}}return p2},inflateopen:_inflateopen,inflateclose(shape,delta){let p2=_inflateopen(shape.pt,delta);p2.orient!=shape.orient&&p2.reverse();let p3=alignByMinDist(shape.pt,p2.pt,0);return p2.frompt(p3),p2},inflatecornici(shape,delta=2,linetruncateini,linetruncateend){let p2,n=shape.npt;if(2==n){let l2=shape.segment(0).offset(delta);p2=getshape().frompt([l2.p1,l2.p2])}else if(3==n){let l1=shape.segment(0).offset(delta),l2=shape.segment(1).offset(delta);if(l1.isparallela(l2))p2=getshape().frompt([l1.p1,l2.p2]);else{let p=l1.interseca(l2);p2=getshape().frompt([l1.p1,p,l2.p2])}}else{let l1=new Linea2(shape.pt[0],shape.pt[shape.npt-1]),len1=l1.len,l2=l1.perpendicolare(l1.p1,len1),l3=l1.perpendicolare(l1.p2,len1);l2.isparallela(shape.segment(0))&&(l2=l1.perpendicolare(l1.puntot(.1),len1)),l3.isparallela(shape.segment(shape.npt-2))&&(l3=l1.perpendicolare(l1.puntot(.9),len1));let n2=Math.floor(shape.npt/2),{t:t}=l2.proiezionet(shape.pt[n2]),t2=2*(t>0?-1:1),px2=l2.puntot(t2),px3=l3.puntot(t2);p2=_inflateopen([...shape.pt,px3,px2],delta);let idx=p2.pt.reduce(((imin,p,i)=>(p.x-px2.x)**2+(p.y-px2.y)**2<(p2.pt[imin].x-px2.x)**2+(p2.pt[imin].y-px2.y)**2?i:imin),0);p2.pt=p2.pt.slice(idx+2).concat(p2.pt.slice(0,idx)),p2.orient!=shape.orient&&p2.reverse(),linetruncateini&&(shape.truncatebefore(linetruncateini),p2.truncatebefore(linetruncateini)),linetruncateend&&(p2.truncateafter(linetruncateend),shape.truncateafter(linetruncateend))}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 Vscene{constructor(x,y,info={}){this.x=x,this.y=y,this.info=info,this.clear()}addrow(o){o||(o={}),o.id=function newid(rows){let max=0;for(let x of rows)+x.id>max&&(max=+x.id);return max+1}(this.rows);let tm=new Vobject(o);return this.rows.push(tm),tm}clear(){this.curlayer=0,this.rows=[],this.clines=[]}fromjson(o){let ll,l2;o||(o={info:{}}),this.clear(),this.x=o.x||4e3,this.y=o.y||3e3,this.info=o.info||{},this.curlayer=o.curlayer,o.clines&&(ll=o.clines.map((e=>new Linea2(e.p1,e.p2))));let x=this.x,y=this.y;l2=[new Linea2(0,0,100,0),new Linea2(x,0,x,100),new Linea2(x,y,x-100,y),new Linea2(0,y,0,y-100)],this.clines=[...l2,...ll],o.rows&&(this.rows=o.rows.map((e=>new Vobject(e))))}tojson(){let{x:x,y:y,info:info,curlayer:curlayer,xrows:xrows,xclines:xclines}=this,rows=xrows.map((e=>e.tojson())),clines=xclines.map((e=>({p1:e.p1,p2:e.p2})));return clines=clines.slice(4),{x:x,y:y,curlayer:curlayer,rows:rows,clines:clines}}}class Vobject{constructor(o){o||(o={}),this.fromjson(o)}fromjson(o){this.id=o.id??1,this.layer=o.layer||0,this.hidden=!!o.hidden,this.x=o.x||100,this.y=o.y||100,this.pc=o.pc||{x:0,y:0},o.shape?this.shape=getshape().frompt(o.shape):this.shape=void 0;let ll=(o.lines||[]).map((e=>new Linea2(e.p1,e.p2)));this.lines=ll,this.draw=new Vis2d(`d:${o.id}`),o.draw&&this.draw.fromjson(o.draw),this.info=o.info||{},this.pos=o.pos||{x:0,y:0,rot:0}}tojson(){let{id:id,layer:layer,x:x,y:y,pc:pc,shape:shape,hidden:hidden,lines:lines,info:info,pos:pos}=this;return lines=lines.map((e=>({p1:e.p1,p2:e.p2}))),shape=shape?shape.pt:void 0,{id:id,layer:layer,x:x,y:y,pc:pc,shape:shape,lines:lines,hidden:hidden,info:info,pos:pos,draw:this.draw.tojson()}}}class Vis2d{constructor(name){this.name=name,this.clear()}clear(){return this.vec=[],this.gr={},this}tojson(){let tm={};for(let x in this.gr)tm[x]=this.gr[x].tojson();return{name:this.name,rows:this.vec,groups:tm}}fromjson(n){if(!(n&&n.name&&n.rows&&n.groups))throw new Error("wrong data JSON");this.clear(),this.name=n.name,this.vec=n.rows;for(let x in n.groups)this.gr[x]=new Vis2d(x).fromjson(n.groups[x])}creategr(name="grp"){return this.gr[name]||(this.gr[name]=new Vis2d(name)),this.gr[name]}push(x=0,y=0,op={}){"number"==typeof op&&(op={rot:op}),op||(op={}),this.vec.push({type:"push",x:x,y:y,op:op})}pop(){this.vec.push({type:"pop"})}randomcolor(transp="100%"){return`hsl(${Math.floor(360*Math.random())}, 50%, 40%,${transp})`}addgr(gr){let name=gr;gr?.name&&(name=gr.name),this.gr[name]?this.vec.push({type:"group",name:name}):this.vec.push({type:"err",err:`addgroup: ${name} => missing`})}addquota(x1,y1,x2,y2,d=0,text="",scalafont=1,spessore=.25){this.vec.push({type:"quota",x1:x1,y1:y1,x2:x2,y2:y2,d:d,text:text,spessore:spessore,color:"black",scalafont:scalafont})}addqpunto(x1,y1,x2,y2,d=0,text="",scalafont=1,spessore=.25){this.vec.push({type:"qpunto",x1:x1,y1:y1,x2:x2,y2:y2,d:d,text:text,spessore:spessore,color:"black",scalafont:scalafont})}addpoint(p,id=-1,color="red",spessore=8){return p&&this.vec.push({type:"point",p:p,id:id,color:color,spessore:1*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:1*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:1*spessore}),this}addimg(l,img){return l&&this.vec.push({type:"img",l:l,img:img}),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:1*spessore}),this}addshapelin(s,color=void 0,spessore=1){return s&&this.vec.push({type:"shapelin",s:s,color:color||this.randomcolor(),spessore:1*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}}function checkoggetto(oggetti,tipo,cod,isrect){if("h"==tipo&&(tipo="o"),oggetti||(oggetti=[]),"number"==typeof cod&&!["a","as"].includes(tipo))return{cod:"__",macro:"",sps:cod};let bb=oggetti.find((e=>e.tipo.includes(tipo)&&e.cod==cod&&(e.isshape||isrect||"a"!=tipo)));return bb||(bb=oggetti.find((e=>e.tipo.includes(tipo)&&(e.isshape||isrect||"a"!=tipo)))),bb||(bb={cod:"__",macro:"",sps:0}),"a"!=tipo&&"as"!=tipo||"__"==bb.cod||bb.color||(bb.color=`hsl(${function stringToHue(str){let hash=0;for(let i=0;i<str.length;i++)hash=31*hash+str.charCodeAt(i)>>>0;return Math.floor(.6180339887*hash%1*360)}(bb.cod)}, 95%, 97%`),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.sps===bordi[0].sps))}else{let tm=checkoggetto(oggetti,"b",bordo);bordi=[tm,tm,tm,tm],uguali=!0}return{bordi:bordi,uguali:uguali,senza:!(bordi[0].sps||bordi[1].sps||bordi[2].sps||bordi[3].sps),bl:bordi[0].sps,bt:bordi[1].sps,br:bordi[2].sps,bb:bordi[3].sps}}function elaborapercorso(sh1,bordo,taglio,oggetti,countid=0){let sh2,sh3,p1h,p2h,p3h,p4h,p1v,p2v,p3v,p4v,p1s,p2s,line1,line2,i1,i2,dati=[],draws=[];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:++countid,type:`b${bordo}`,info:info};shape&&(tm.shape=s1.pt),draws.push({type:`b${bordo}`,pt:s0.pt}),dati.push(tm)}}countid=countid||0;let np=sh1.pt.length,idr=np-1;oggetti||(oggetti=[]);let{bordi:bordi,uguali:uguali,senza:senza}=getbordi(oggetti,bordo);if(uguali)if(senza||!bordi[0].sps)sh2=sh1.clone();else{let b=bordi[0].sps;sh2=shapeclip().inflate(sh1,-b,!0)}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)}if(!senza){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)}if(sh3=getshape().frompt(p2s),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{countid:countid,shape2:sh2,shapetop:sh3,bordi:bordi,dati:dati,draws:draws}}function creaprofiloesterno(ff,oggetti){let sh1,{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 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||h2)&&h1>=0&&h1<Math.min(y,x/2)&&h2>=0&&h2<Math.min(y,x/2)){let tm=getshape().fromstr(`a30;${l1||0};${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)}pts.push(x,0),ff.countid=0,sh1=getshape().fromvec(pts);let{countid:countid,shape2:shape2,shapetop:shapetop,bordi:bordi,dati:dati,draws:draws}=elaborapercorso(sh1,bordo,taglio,oggetti,ff.countid);return ff.countid=countid,{shape:sh1,internalshape:shape2,shape2:shape2,shapetop:shapetop,bordi:bordi,dati:dati,draws:draws}}
508
508
  /**
509
509
  * Genera segmenti basati su intervalli e punti di interruzione
510
510
  * @param {Array<{a: number, b: number}>} t1 - Array di oggetti che rappresentano intervalli con coordinate a e b
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markuno_lib",
3
- "version": "1.2.64",
3
+ "version": "1.2.65",
4
4
  "description": "Croswil Markuno Language Lib",
5
5
  "author": "Croswil SRL",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -18,7 +18,8 @@
18
18
  /**
19
19
  * Calcola la differenza delle coordinate x dei punti
20
20
  * @returns {number} Differenza x
21
- */ get dx(): number;
21
+ */ get angle(): number;
22
+ get dx(): number;
22
23
  /**
23
24
  * Calcola la differenza delle coordinate y dei punti
24
25
  * @returns {number} Differenza y
@@ -31,7 +32,6 @@
31
32
  * Calcola la lunghezza della linea
32
33
  * @returns {number} Lunghezza
33
34
  */ get len(): number;
34
- get angle(): number;
35
35
  /**
36
36
  * Estende la linea di una certa lunghezza o fino all'intersezione con un'altra linea
37
37
  * @param {number|Linea2} l - Lunghezza di estensione o linea da intersecare
@@ -348,7 +348,7 @@ export class Vscene {
348
348
  clear(): void;
349
349
  curlayer: any;
350
350
  rows: any;
351
- clines: any;
351
+ clines: any[];
352
352
  fromjson(o: any): void;
353
353
  tojson(): {
354
354
  x: any;
@@ -676,7 +676,7 @@ export const scaleunit: 0.001;
676
676
  export function setLineColorMode(white: any, isdark: any): void;
677
677
  export function setorigine(obj: any, x?: number, y?: number, z?: number): any;
678
678
  export function shapeclip(): {
679
- offset(shape: any, delta: any, full?: boolean): any;
679
+ offset(shape: any, delta: any): any;
680
680
  inflate: (shape: any, delta?: number, mantainorder?: boolean, isopen?: number) => any;
681
681
  inflateopen: (pts: any, delta: any) => any;
682
682
  inflateclose(shape: any, delta: any): any;