@expofp/floorplan
Version:
Interactive floor plan library for expos and events
2 lines (1 loc) • 2.46 kB
JavaScript
import{MercatorCoordinate as A}from"maplibre-gl";const F=1e-12,S=3.28084,b=6371e3;export function calculateTransformMatrix(n,i){const o=n.p1??_(n),s=[n.p0,o,n.p2],r=[],t=[],a=[];for(const h of s){N(h),t.push([h.x,h.y]);const p=A.fromLngLat([h.lng,h.lat],0),d=p.meterInMercatorCoordinateUnits();u(p.x),u(p.y),u(d),r.push(d),a.push([p.x,p.y])}const c=[],e=[];for(let h=0;h<3;h++){const[p,d]=t[h],[L,T]=a[h];c.push([p,d,1,0,0,0]),e.push(L),c.push([0,0,0,p,d,1]),e.push(T)}const l=k(c,e),[f,E,y,w,P,v]=l,R=i?.toLowerCase?.().trim()==="ft"?1/S:1,I=r.reduce((h,p)=>h+p,0)/r.length*R,x=[f,w,0,0,E,P,0,0,0,0,I,0,y,v,0,1];if(!x.every(Number.isFinite))throw new Error("Cannot calculate Maplibre transform: geo anchor points produced a non-finite matrix.");return x}function _(n){const i=n.p2.x-n.p0.x,o=n.p2.y-n.p0.y;if(i===0&&o===0)throw new Error("Cannot calculate Maplibre transform: p0 and p2 have identical SVG coordinates.");const s=n.p0.x-o,r=n.p0.y+i,t=D(n.p0.lat,n.p0.lng,n.p2.lat,n.p2.lng),a=Z(n.p0.lat,n.p0.lng,n.p2.lat,n.p2.lng),[c,e]=j(n.p0.lat,n.p0.lng,t,a+90);return{x:s,y:r,lat:e,lng:c}}function N(n){u(n.x),u(n.y),u(n.lat),u(n.lng)}function u(n){if(!Number.isFinite(n))throw new Error("Cannot calculate Maplibre transform: geo anchor points contain invalid coordinates.")}function M(n){return n*Math.PI/180}function m(n){return n*180/Math.PI}function D(n,i,o,s){const r=M(n),t=M(o),a=M(o-n),c=M(s-i),e=Math.sin(a/2)*Math.sin(a/2)+Math.cos(r)*Math.cos(t)*Math.sin(c/2)*Math.sin(c/2),l=2*Math.atan2(Math.sqrt(e),Math.sqrt(1-e));return b*l}function Z(n,i,o,s){const r=M(n),t=M(o),a=M(s-i),c=Math.sin(a)*Math.cos(t),e=Math.cos(r)*Math.sin(t)-Math.sin(r)*Math.cos(t)*Math.cos(a);return(m(Math.atan2(c,e))+360)%360}function j(n,i,o,s){const r=o/b,t=M(s),a=M(n),c=M(i),e=Math.asin(Math.sin(a)*Math.cos(r)+Math.cos(a)*Math.sin(r)*Math.cos(t)),l=c+Math.atan2(Math.sin(t)*Math.sin(r)*Math.cos(a),Math.cos(r)-Math.sin(a)*Math.sin(e));return[m(l),m(e)]}function k(n,i){const o=n.length,s=n.map((t,a)=>[...t,i[a]]);for(let t=0;t<o;t++){let a=t;for(let c=t+1;c<o;c++)Math.abs(s[c][t])>Math.abs(s[a][t])&&(a=c);if([s[t],s[a]]=[s[a],s[t]],Math.abs(s[t][t])<F)throw new Error("Cannot calculate Maplibre transform: geo anchor points are collinear or invalid.");for(let c=t+1;c<o;c++){const e=s[c][t]/s[t][t];for(let l=t;l<=o;l++)s[c][l]-=e*s[t][l]}}const r=new Array(o);for(let t=o-1;t>=0;t--){r[t]=s[t][o];for(let a=t+1;a<o;a++)r[t]-=s[t][a]*r[a];r[t]/=s[t][t]}return r}