feat: add manual lasso wall splitting with magnetic edge-snapping and active contour refinement
- New magneticLasso module: Sobel energy map + Dijkstra shortest-path + Douglas-Peucker
- New activeContour module: greedy snake + balloon force for polygon-to-edge refinement
- wallTextureSplit: edge barrier mask, morphological mask hole closing, Moore boundary tracing, simplified polygon contours, manual pick map patching, gap absorption
- MaskSegmentCanvas: full lasso gesture pipeline (tap vertices, drag, magnetic paths, close polygon, endLasso/cancelLasso/deleteLasso)
- New maskConfig options: splitWallsEdgeBarrierThreshold, splitWallsCloseMaskRadius, manualSplitWalls, manualSplitWallsMaxCount, manualSplitWallsGapAbsorbDilatePx, magneticLasso, activeContourRefine
- New ref methods: startLasso, endLasso, cancelLasso, getManualRegions, deleteLasso
- New exported types: LassoPolygon, ManualWallPartition
- RegionMaskData carries indexToName and wallSemanticIdx through downsample
- Simplify README to point to documentation site
- Update documentation site (EN + ZH-CN) with all new APIs and interaction guide
- Example app: lasso mode toggles and operation buttons
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 03:23:57 +00:00
|
|
|
"use strict";var D=Object.defineProperty;var fn=Object.getOwnPropertyDescriptor;var bn=Object.getOwnPropertyNames;var mn=Object.prototype.hasOwnProperty;var ln=(n,e)=>{for(var o in e)D(n,o,{get:e[o],enumerable:!0})},sn=(n,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of bn(e))!mn.call(n,a)&&a!==o&&D(n,a,{get:()=>e[a],enumerable:!(i=fn(e,a))||i.enumerable});return n};var yn=n=>sn(D({},"__esModule",{value:!0}),n);var On={};ln(On,{WALL_SUB_LABEL_NONE:()=>_,absorbSmallWallGapsForLassoPolygons:()=>Fn,buildPickMapAfterWallSplit:()=>tn,dilatePickBuffer1px:()=>rn,isWallSubRegionName:()=>Ln,patchPickMapForManualWallSplit:()=>Wn,splitWallRegionsByTexture:()=>En});module.exports=yn(On);var Z=require("./freqLayerPrep"),nn=require("./maskSegmentRuntime"),en=require("./maskSemanticPalette");const _=255;function H(){return(0,nn.getMaskSegmentRuntimeConfig)().mask}function dn(n,e,o){let i=-1,a=-1;for(let b=0;b<o;b++){for(let m=0;m<e;m++)if(n[b*e+m]){i=m,a=b;break}if(i>=0)break}if(i<0)return[];const u=[[1,0],[1,-1],[0,-1],[-1,-1],[-1,0],[-1,1],[0,1],[1,1]],r=[];let l=i,f=a,c=7;for(let b=0;b<e*o;b++){r.push({x:l,y:f});let m=!1;for(let t=0;t<8;t++){const d=(c+1+t)%8,s=l+u[d][0],A=f+u[d][1];if(!(s<0||s>=e||A<0||A>=o)&&n[A*e+s]){l=s,f=A,c=(d+4)%8,m=!0;break}}if(!m||r.length>2&&l===i&&f===a)break}return r}function xn(n,e){if(n.length<=2)return[...n];const o=new Uint8Array(n.length);o[0]=1,o[n.length-1]=1;const i=(a,u)=>{if(u-a<=1)return;const r=n[u].x-n[a].x,l=n[u].y-n[a].y,f=r*r+l*l;let c=0,b=a;for(let m=a+1;m<u;m++){let t;if(f===0)t=Math.hypot(n[m].x-n[a].x,n[m].y-n[a].y);else{const d=Math.max(0,Math.min(1,((n[m].x-n[a].x)*r+(n[m].y-n[a].y)*l)/f));t=Math.hypot(n[m].x-(n[a].x+d*r),n[m].y-(n[a].y+d*l))}t>c&&(c=t,b=m)}c>e&&(o[b]=1,i(a,b),i(b,u))};return i(0,n.length-1),n.filter((a,u)=>o[u])}const An=2.5;function gn(n,e,o){const i=e*o,a=new Uint8Array(i),u=new Uint8Array(i);for(let r=0;r<i;r++){const l=r*3,f=(0,Z.bgrToLab)(n[l],n[l+1],n[l+2]);a[r]=f.a,u[r]=f.b}return{aMap:a,bMap:u}}function pn(n,e,o,i,a,u,r){const l=e*o,f=new Uint8Array(l);if(r<=0)return f;const c=e;for(let b=1;b<o-1;b++){const m=(b-1)*c,t=b*c,d=(b+1)*c;for(let s=1;s<c-1;s++){const A=t+s;if(a[A]!==i||u[A])continue;const h=m+(s-1),k=m+s,y=m+(s+1),p=t+(s-1),g=t+(s+1),U=d+(s-1),M=d+s,P=d+(s+1);let I=0;for(let B=0;B<3;B++){const E=n[h*3+B],z=n[k*3+B],F=n[y*3+B],L=n[p*3+B],R=n[g*3+B],w=n[U*3+B],G=n[M*3+B],N=n[P*3+B],W=-E+F-2*L+2*R-w+N,v=-E-2*z-F+w+2*G+N,q=Math.sqrt(W*W+v*v);q>I&&(I=q)}I>r&&(f[A]=1)}}return X(f,e,o)}function X(n,e,o){const i=new Uint8Array(n);for(let a=1;a<o-1;a++){const u=a*e;for(let r=1;r<e-1;r++){const l=u+r;n[l]||(n[l-1]||n[l+1]||n[(a-1)*e+r]||n[(a+1)*e+r])&&(i[l]=1)}}return i}function J(n,e){const o=n-128,i=e-128;return Math.sqrt(o*o+i*i)}function hn(n,e,o,i){const a=n-o,u=e-i;return a*a+u*u}function Un(n,e,o,i,a){const u=J(n,e),r=J(o,i),l=a*2.2;if(u<=a&&r>l||r<=a&&u>l)return!0;if(u>a&&r>a){const f=Math.atan2(e-128,n-128),c=Math.atan2(i-128,o-128);let b=Math.abs(f-c);if(b>Math.PI&&(b=2*Math.PI-b),b>Math.PI/4)return!0}return!1}function j(n,e,o,i,a,u){return Un(n,e,o,i,u)?!1:hn(n,e,o,i)<=a}function Mn(){return H().semanticColors.findIndex(e=>e.name==="wall")}function K(n,e,o,i){return e[i]?!1:n[i]===o}function Cn(n,e,o,i,a,u){const r=i*a,l=new Uint8Array(r);for(let t=0;t<r;t++)n[t]===o&&!e[t]&&(l[t]=1);let f=l;for(let t=0;t<u;t++)f=X(f,i,a);let c=f;for(let t=0;t<u;t++)c=Bn(c,i,a);const b=new Uint8Array(n);for(let t=0;t<r;t++)c[t]&&n[t]!==o&&!e[t]&&(b[t]=o);const m=new Uint8Array(e);for(let t=0;t<r;t++)c[t]&&n[t]!==o&&e[t]&&(b[t]=o,m[t]=0);return{labels:b,baseboardBinary:m}}function Bn(n,e,o){const i=new Uint8Array(n);for(let a=1;a<o-1;a++){const u=a*e;for(let r=1;r<e-1;r++){const l=u+r;n[l]&&(!n[u+(r-1)]||!n[u+(r+1)]||!n[(a-1)*e+r]||!n[(a+1)*e+r])&&(i[l]=0)}}return i}function kn(n,e,o,i,a,u,r,l,f,c){const b=r*l,m=new Int32Array(b);m.fill(-1);let t=0;const d=new Int32Array(b);for(let s=0;s<l;s++)for(let A=0;A<r;A++){const h=s*r+A;if(!K(n,e,o,h)||m[h]>=0)continue;const k=t;t+=1;const y=i[h],p=a[h];let g=y,U=p,M=1,P=0,I=0;for(d[I++]=h,m[h]=k;P<I;
|