@rr0/ufoathome 0.121.0 → 0.123.0
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/README.md +3 -2
- package/dist-embed-interview/InterviewMessages_es-D5d2JVA3.js +1 -0
- package/dist-embed-interview/InterviewMessages_fr-CmScqfza.js +1 -0
- package/dist-embed-interview/InterviewMessages_it-2SNw5xMp.js +1 -0
- package/dist-embed-interview/rr0-interview.mjs +34 -0
- package/dist-embed-scene/rr0-scene.mjs +2 -2
- package/dist-embed-sighting/rr0-sighting.mjs +27 -27
- package/dist-embed-sighting-editor/{AdsbLolArchiveProvider-fy3504GB.js → AdsbLolArchiveProvider-CDtWnd9O.js} +1 -1
- package/dist-embed-sighting-editor/{BodyEditor-CzR-jvO7.js → BodyEditor-ChwDW_Ws.js} +1 -1
- package/dist-embed-sighting-editor/CaseEditorMessages_es-CNLEMPjy.js +1 -0
- package/dist-embed-sighting-editor/CaseEditorMessages_fr-DN3xxn9o.js +1 -0
- package/dist-embed-sighting-editor/CaseEditorMessages_it-B6aG-baK.js +1 -0
- package/dist-embed-sighting-editor/{ContrailSystem-DPqcSIVY.js → ContrailSystem-C1ugmbHe.js} +1 -1
- package/dist-embed-sighting-editor/{CoverageAssessor-Cvcqlzqm.js → CoverageAssessor-CmEo7iZm.js} +1 -1
- package/dist-embed-sighting-editor/GLTFLoader-C8s-rYg8.js +1 -0
- package/dist-embed-sighting-editor/HeadlightSystem-NhpS6K9T.js +34 -0
- package/dist-embed-sighting-editor/{HynekAssessor-EGYF4GLv.js → HynekAssessor-BzyMfAGm.js} +1 -1
- package/dist-embed-sighting-editor/InterviewEditorElement-CT26rBmp.js +101 -0
- package/dist-embed-sighting-editor/InterviewMedia-CvAxC62V.js +1 -0
- package/dist-embed-sighting-editor/InterviewMessages_en-cs-wWpmz.js +1 -0
- package/dist-embed-sighting-editor/InterviewMessages_es-D5d2JVA3.js +1 -0
- package/dist-embed-sighting-editor/InterviewMessages_fr-CmScqfza.js +1 -0
- package/dist-embed-sighting-editor/InterviewMessages_it-2SNw5xMp.js +1 -0
- package/dist-embed-sighting-editor/{LaunchEditor-V2d95SPb.js → LaunchEditor-BCbplrLt.js} +1 -1
- package/dist-embed-sighting-editor/{ModelSource-BsUEhu3K.js → ModelSource-C3dP1aBw.js} +1 -1
- package/dist-embed-sighting-editor/{ModelThumbnails-Bxh0kDEJ.js → ModelThumbnails-B2MXsKrk.js} +1 -1
- package/dist-embed-sighting-editor/{ModelViewer-8GDjRszL.js → ModelViewer-BltV6g37.js} +1 -1
- package/dist-embed-sighting-editor/{RoadMarkings-DgTkyJ3L.js → RoadMarkings-B3u94pIv.js} +1 -1
- package/dist-embed-sighting-editor/{TraceSystem-B432m_Cj.js → TraceSystem-CZFR0soj.js} +2 -2
- package/dist-embed-sighting-editor/interviewImport-C-TiARLK.js +4 -0
- package/dist-embed-sighting-editor/interviewJson-CfwBPiuG.js +8 -0
- package/dist-embed-sighting-editor/interviewSchema-CMRZUnRy.js +1 -0
- package/dist-embed-sighting-editor/rr0-sighting-editor.mjs +341 -364
- package/dist-embed-sighting-editor/surroundingsSources-CvhFXPJx.js +1 -0
- package/dist-embed-sighting-editor/{trafficRuntime-j3m3LpCc.js → trafficRuntime-XVgt3vom.js} +2 -2
- package/package.json +10 -6
- package/dist-embed-sighting-editor/CaseEditorMessages_es-D73IC39g.js +0 -1
- package/dist-embed-sighting-editor/CaseEditorMessages_fr-Ct3RkRag.js +0 -1
- package/dist-embed-sighting-editor/CaseEditorMessages_it-DLJsrUtH.js +0 -1
- package/dist-embed-sighting-editor/GLTFLoader-7CUTWiMy.js +0 -1
- package/dist-embed-sighting-editor/HeadlightSystem-BSokhsgi.js +0 -34
- package/dist-embed-sighting-editor/InterviewMessages_es-TjWn41kX.js +0 -1
- package/dist-embed-sighting-editor/InterviewMessages_fr-BY_iezXh.js +0 -1
- package/dist-embed-sighting-editor/InterviewMessages_it-DkQ8uaNR.js +0 -1
- package/dist-embed-sighting-editor/interviewSchema-DcJWoqJZ.js +0 -1
- package/dist-embed-sighting-editor/surroundingsSources-CCnNDL0o.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{d as S,O as k,e as R,f as F}from"./rr0-sighting-editor.mjs";class K{constructor(t){if(this.candidates=t,t.length===0)throw new Error("A survey needs at least one candidate");this.current=t[0]}current;get id(){return this.current.id}get name(){return this.current.name}get attribution(){return this.current.attribution}get creditUrl(){return this.current.creditUrl}get contemporary(){return this.current.contemporary}covers(t,e){return this.candidates.some(o=>o.covers(t,e))}async getSurroundings(t,e){let o;for(const n of this.candidates)if(n.covers(t.lat,t.lng))try{const s=await n.getSurroundings(t,e);return this.current=n,s}catch(s){if(o??=s,!(s instanceof S))throw s}throw o??new S("no-coverage","No survey reaches this place")}}class w{constructor(t,e,o,n){this.heights=t,this.building=e,this.width=o,this.height=n}static ROOF_PERCENTILE=.9;static STEP_M=.9;static RECTANGLE_FILL=.72;static MIN_DEPTH_M=2.5;static MAX_PARTS=24;static MAX_CELLS=640;buildings(t){const e=t.metresPerPixel,o=t.minAreaM2??12,n=new Uint8Array(this.width*this.height),s=[];for(let r=0;r<this.building.length;r++){if(!this.building[r]||n[r])continue;const a=this.patchFrom(r,n);if(!(a.length*e*e<o))for(const i of this.buildingsOf(a,e,o))Math.hypot(i.eastM,i.northM)<=t.radiusM&&s.push(i)}return s.sort((r,a)=>Math.hypot(r.eastM,r.northM)-Math.hypot(a.eastM,a.northM)),s.slice(0,t.maxBuildings??60)}patchFrom(t,e){const o=[],n=[t];for(e[t]=1;n.length>0;){const s=n.pop();o.push(s);const r=s%this.width,a=Math.floor(s/this.width);for(const[i,c]of[[1,0],[-1,0],[0,1],[0,-1]]){const l=r+i,h=a+c;if(l<0||h<0||l>=this.width||h>=this.height)continue;const u=h*this.width+l;this.building[u]&&!e[u]&&Math.abs(this.heights[u]-this.heights[s])<=w.STEP_M&&(e[u]=1,n.push(u))}}return o}buildingsOf(t,e,o){const n=this.width/2,s=this.height/2,r=[],a=[],i=[];for(const c of t){const l=c%this.width,h=Math.floor(c/this.width);r.push((l+.5-n)*e),a.push((s-h-.5)*e),i.push(this.heights[c])}return w.ofPoints(r,a,i,e,o)}static ofPoints(t,e,o,n,s,r=w.RECTANGLE_FILL,a=[]){const i=[];for(let m=0;m<t.length;m++)for(const[E,P]of[[-.5,-.5],[.5,-.5],[-.5,.5],[.5,.5]])i.push([t[m]+E*n,e[m]+P*n]);const c=w.hull(i),{angle:l,rectangle:h}=w.smallestRectangle(c),u=t.length*n*n,M=(h.maxU-h.minU)*(h.maxV-h.minV);if(u/M>=r||u<4*s)return[w.building(h,l,w.roof(o))];const f=c.map((m,E)=>({from:{east:m[0],north:m[1]},to:{east:c[(E+1)%c.length][0],north:c[(E+1)%c.length][1]}})),d=w.dominantAngles([...a,...f]);return w.parts(t,e,o,d.length>0?d:[l],n,s)}static dominantAngles(t,e=3){const o=new Map;for(const n of t){const s=Math.hypot(n.to.east-n.from.east,n.to.north-n.from.north);if(s<1e-6)continue;const r=(Math.atan2(n.to.north-n.from.north,n.to.east-n.from.east)%(Math.PI/2)+Math.PI/2)%(Math.PI/2),a=Math.round(r/(Math.PI/60));o.set(a,(o.get(a)??0)+s)}return[...o.entries()].sort((n,s)=>s[1]-n[1]).slice(0,e).map(([n])=>n*Math.PI/60)}static parts(t,e,o,n,s,r){let a=t.map((c,l)=>l);const i=[];for(let c=0;c<w.MAX_PARTS&&a.length>0;c++){let l;for(const M of n){const f=w.largestIn(t,e,a,M,s);f&&(l===void 0||f.area>l.area)&&(l=f)}if(l===void 0||l.area<r)break;const h=l.covered;Math.min(l.rectangle.maxU-l.rectangle.minU,l.rectangle.maxV-l.rectangle.minV)>=w.MIN_DEPTH_M&&i.push(w.building(l.rectangle,l.angle,w.roof([...h].map(M=>o[M])))),a=a.filter(M=>!h.has(M))}return i}static largestIn(t,e,o,n,s){const r=Math.cos(n),a=Math.sin(n);let i=1/0,c=-1/0,l=1/0,h=-1/0;const u=[],M=[];for(const D of o){const y=t[D]*r+e[D]*a,b=-t[D]*a+e[D]*r;u.push(y),M.push(b),i=Math.min(i,y),c=Math.max(c,y),l=Math.min(l,b),h=Math.max(h,b)}const f=Math.max(s*Math.SQRT2,Math.max(c-i,h-l)/w.MAX_CELLS),d=Math.max(1,Math.ceil((c-i)/f+1e-9)),m=Math.max(1,Math.ceil((h-l)/f+1e-9)),E=new Uint8Array(d*m),P=o.map((D,y)=>{const b=Math.min(d-1,Math.max(0,Math.floor((u[y]-i)/f))),T=Math.min(m-1,Math.max(0,Math.floor((M[y]-l)/f)));return E[T*d+b]=1,T*d+b}),p=w.largestRectangle(E,d,m);if(p===void 0)return;const O=new Set;return o.forEach((D,y)=>{const b=P[y]%d,T=Math.floor(P[y]/d);b>=p.column&&b<p.column+p.columns&&T>=p.row&&T<p.row+p.rows&&O.add(D)}),{area:p.area*f*f,angle:n,covered:O,rectangle:{minU:i+p.column*f,maxU:i+(p.column+p.columns)*f,minV:l+p.row*f,maxV:l+(p.row+p.rows)*f}}}static largestRectangle(t,e,o){const n=new Array(e).fill(0);let s;for(let r=0;r<o;r++){for(let i=0;i<e;i++)n[i]=t[r*e+i]?n[i]+1:0;const a=[];for(let i=0;i<=e;i++){const c=i===e?0:n[i];for(;a.length>0&&n[a[a.length-1]]>=c;){const l=a.pop(),h=a.length===0?i:i-a[a.length-1]-1,u=n[l]*h;(s===void 0||u>s.area)&&(s={column:i-h,row:r-n[l]+1,columns:h,rows:n[l],area:u})}a.push(i)}}return s}static roof(t){const e=[...t].sort((o,n)=>o-n);return Math.max(2,e[Math.min(e.length-1,Math.floor(e.length*w.ROOF_PERCENTILE))])}static building(t,e,o){const n=Math.cos(e),s=Math.sin(e),r=t.maxU-t.minU,a=t.maxV-t.minV,i=(t.minU+t.maxU)/2,c=(t.minV+t.maxV)/2,h=((90-(r<a?e:e+Math.PI/2)*180/Math.PI)%180+180)%180;return{eastM:w.tenth(i*n-c*s),northM:w.tenth(i*s+c*n),widthM:w.tenth(Math.max(r,a)),lengthM:w.tenth(Math.min(r,a)),heightM:w.tenth(o),headingDeg:Math.round(h*10)/10}}static smallestRectangle(t){let e={area:1/0,angle:0,rectangle:{minU:0,maxU:0,minV:0,maxV:0}};for(let o=0;o<Math.max(1,t.length);o++){const[n,s]=t[o]??[0,0],[r,a]=t[(o+1)%t.length]??[1,0],i=Math.atan2(a-s,r-n),c=Math.cos(i),l=Math.sin(i);let h=1/0,u=-1/0,M=1/0,f=-1/0;for(const[m,E]of t){const P=m*c+E*l,p=-m*l+E*c;h=Math.min(h,P),u=Math.max(u,P),M=Math.min(M,p),f=Math.max(f,p)}const d=(u-h)*(f-M);d<e.area&&(e={area:d,angle:i,rectangle:{minU:h,maxU:u,minV:M,maxV:f}})}return e}static hull(t){const e=[...t].sort((a,i)=>a[0]-i[0]||a[1]-i[1]),o=e.filter((a,i)=>i===0||a[0]!==e[i-1][0]||a[1]!==e[i-1][1]);if(o.length<3)return o;const n=(a,i,c)=>(i[0]-a[0])*(c[1]-a[1])-(i[1]-a[1])*(c[0]-a[0]),s=[];for(const a of o){for(;s.length>=2&&n(s[s.length-2],s[s.length-1],a)<=0;)s.pop();s.push(a)}const r=[];for(const a of[...o].reverse()){for(;r.length>=2&&n(r[r.length-2],r[r.length-1],a)<=0;)r.pop();r.push(a)}return[...s.slice(0,-1),...r.slice(0,-1)]}static tenth(t){return Math.round(t*10)/10}}class x{constructor(t,e,o,n){this.heights=t,this.vegetation=e,this.width=o,this.height=n}static SUMMIT_RADIUS_M=2.5;static CROWN_REACH_M=8;static MAX_WIDTH_M=16;static MIN_WIDTH_M=2;static tenth(t){return Math.round(t*10)/10}trees(t){const e=t.metresPerPixel,o=t.minHeightM??4,n=t.eyeM??1.6,s=t.minElevationDeg??2,r=Math.max(1,Math.round(x.SUMMIT_RADIUS_M/e)),a=Math.round(x.CROWN_REACH_M/e),i=this.width/2,c=this.height/2,l=[];for(let h=0;h<this.height;h++)for(let u=0;u<this.width;u++){const M=this.canopy(u,h);if(M<o)continue;const f=(u+.5-i)*e,d=(c-h-.5)*e,m=Math.hypot(f,d);if(m>t.radiusM||!this.isSummit(u,h,M,r))continue;const E=Math.atan2(M-n,Math.max(m,1))*180/Math.PI;E<s||l.push({tree:{eastM:x.tenth(f),northM:x.tenth(d),heightM:x.tenth(M),widthM:x.tenth(this.crownWidth(u,h,M,e,a))},elevation:E})}return l.sort((h,u)=>u.elevation-h.elevation),l.slice(0,t.maxTrees??150).map(h=>h.tree)}canopy(t,e){if(t<0||e<0||t>=this.width||e>=this.height)return 0;const o=e*this.width+t;return this.vegetation[o]?this.heights[o]:0}isSummit(t,e,o,n){for(let s=-n;s<=n;s++)for(let r=-n;r<=n;r++){if(r===0&&s===0)continue;const a=this.canopy(t+r,e+s);if(a>o||a===o&&(s<0||s===0&&r<0))return!1}return!0}crownWidth(t,e,o,n,s){let r=0;for(let i=-s;i<=s;i++)for(let c=-s;c<=s;c++)Math.hypot(c,i)*n<=x.CROWN_REACH_M&&this.canopy(t+c,e+i)>=o*.5&&r++;const a=2*Math.sqrt(r*n*n/Math.PI);return Math.max(x.MIN_WIDTH_M,Math.min(a,x.MAX_WIDTH_M))}}class A{static WALLS={1:"stone",2:"meuliere",3:"concrete",4:"brick",5:"block",6:"wood",9:"other"};static ROOFS={1:"tile",2:"slate",3:"zinc",4:"concrete",9:"other"};static WALL_COLOURS={stone:"#b9ae9b",meuliere:"#b8a78a",concrete:"#b4b2ac",brick:"#a65f48",block:"#d0c6b2",wood:"#7d5c3e",other:"#c9c0ae"};static PLASTER="#d3cab8";static ROOF_COLOURS={tile:"#a0583f",slate:"#4a5059",zinc:"#8d969c",concrete:"#8f8e8a",other:"#7a7872"};static VARIATION=.12;static of(t,e){const o=String(t??"").trim();if(!/^\d{1,2}$/.test(o))return;const n=Number(o),s=n%10!==0?n%10:Math.floor(n/10);return(e==="wall"?A.WALLS:A.ROOFS)[String(s)]}static roofColor(t){return t?A.ROOF_COLOURS[t]:void 0}static fit(t){return t.map(e=>{if(e.facade)return e;const o={color:A.wallColor(e)};return{...e,facade:o}})}static wallColor(t){const e=t.wallMaterial?A.WALL_COLOURS[t.wallMaterial]:A.PLASTER,o=Math.sin(t.eastM*12.9898+t.northM*78.233)*43758.5453,n=1+(o-Math.floor(o)-.5)*2*A.VARIATION,s=r=>Math.max(0,Math.min(255,Math.round(parseInt(e.slice(r,r+2),16)*n))).toString(16).padStart(2,"0");return`#${s(1)}${s(3)}${s(5)}`}}class g{static MIN_RISE_M=1.2;static MIN_EAVES_M=2.5;static MIN_SEEN=.35;static NO_DATA=-9999;static BANDS=7;static INSET_M=.9;static LIFT=1.18;static PEAK=.3;static LEVEL=.45;static fit(t,e,o){return!e&&!o&&!t.some(n=>n.roofMaterial)?t:t.map(n=>{const s=e?g.shapeOf(n,e):void 0,r=(o?g.colorOf(n,o):void 0)??A.roofColor(n.roofMaterial);if(!s&&!r)return n;const a={shape:s?.shape??"flat",...s?.ridge==="depth"?{ridge:"depth"}:{},riseM:s?.riseM??0,...r?{color:r}:{}},i=s&&s.shape!=="flat"?s.topM:n.heightM;return{...n,heightM:i,roof:a}})}static world(t,e,o){const n=t.headingDeg*Math.PI/180;return{east:t.eastM+e*Math.cos(n)+o*Math.sin(n),north:t.northM-e*Math.sin(n)+o*Math.cos(n)}}static shapeOf(t,e){const o=g.BANDS,n=Math.max(e.metresPerPixel,.5),s=t.widthM/2-g.INSET_M,r=t.lengthM/2-g.INSET_M;if(s<=0||r<=0)return;const a=[],i=Array.from({length:o},()=>({sum:0,n:0})),c=Array.from({length:o},()=>({sum:0,n:0}));let l=0;for(let y=-s;y<=s;y+=n)for(let b=-r;b<=r;b+=n){l++;const{east:T,north:X}=g.world(t,y,b),C=Math.floor(T/e.metresPerPixel+e.size/2),z=Math.floor(e.size/2-X/e.metresPerPixel);if(C<0||z<0||C>=e.size||z>=e.size)continue;const V=z*e.size+C,U=e.heights[V];if(e.vegetation[V]||U===g.NO_DATA||!(U>0))continue;a.push(U);const W=i[Math.min(o-1,Math.floor((y+s)/(2*s)*o))],$=c[Math.min(o-1,Math.floor((b+r)/(2*r)*o))];W.sum+=U,W.n++,$.sum+=U,$.n++}if(l===0||a.length/l<g.MIN_SEEN)return;a.sort((y,b)=>y-b);const h=g.percentile(a,.08),u=g.percentile(a,.92),M=u-h;if(h<g.MIN_EAVES_M||M>Math.min(t.widthM,t.lengthM))return;if(M<g.MIN_RISE_M)return{shape:"flat",riseM:0,topM:u};const f=g.profile(i),d=g.profile(c);if(!f||!d)return;const m=g.peak(d)/M,E=g.peak(f)/M,P=g.spread(f)/M,p=g.spread(d)/M,O=m>=g.PEAK&&P<=g.LEVEL,D=E>=g.PEAK&&p<=g.LEVEL;if(O&&(!D||m>=E))return{shape:"gable",ridge:"width",riseM:M,topM:u};if(D)return{shape:"gable",ridge:"depth",riseM:M,topM:u};if(m>=g.PEAK&&E>=g.PEAK/2)return{shape:"hip",ridge:"width",riseM:M,topM:u}}static profile(t){const e=t.map(o=>o.n>0?o.sum/o.n:NaN);return e.filter(Number.isFinite).length>=t.length-1?e.map((o,n)=>Number.isFinite(o)?o:g.neighbour(e,n)):void 0}static neighbour(t,e){return Number.isFinite(t[e-1])?t[e-1]:t[e+1]}static peak(t){const e=Math.max(1,Math.floor(t.length/3)),o=s=>s.reduce((r,a)=>r+a,0)/s.length,n=[...t.slice(0,e),...t.slice(t.length-e)];return o(t.slice(e,t.length-e))-o(n)}static spread(t){return Math.max(...t)-Math.min(...t)}static percentile(t,e){return t[Math.min(t.length-1,Math.floor(t.length*e))]}static colorOf(t,e){const o=Math.max(e.metresPerPixel,.5),n=Math.max(t.widthM/2-g.INSET_M,o),s=Math.max(t.lengthM/2-g.INSET_M,o),r=[],a=[],i=[];for(let h=-n;h<=n;h+=o)for(let u=-s;u<=s;u+=o){const{east:M,north:f}=g.world(t,h,u),d=Math.floor(M/e.metresPerPixel+e.size/2),m=Math.floor(e.size/2-f/e.metresPerPixel);if(d<0||m<0||d>=e.size||m>=e.size)continue;const E=(m*e.size+d)*e.samples,P=e.values[E],p=e.values[E+1],O=e.values[E+2];p>P&&p>O||(r.push(P),a.push(p),i.push(O))}if(r.length===0)return;const c=h=>h.sort((u,M)=>u-M)[Math.floor(h.length/2)],l=h=>Math.min(255,Math.round(h*g.LIFT)).toString(16).padStart(2,"0");return`#${l(c(r))}${l(c(a))}${l(c(i))}`}}class v{static DEFAULT_HEIGHT_M=6;static METRES_PER_DEGREE=111320;static STREET_SPACING_M=35;static KERB_OFFSET_M=1;static DEFAULT_WIDTH_M=5.5;static PATIENCE_MS=15e3;static MAX=150;client;constructor(t={}){this.client=new k(t)}static today(){return new Date().toISOString().slice(0,10)}async near(t,e){const o=e/v.METRES_PER_DEGREE,n=e/(v.METRES_PER_DEGREE*Math.cos(t.lat*Math.PI/180)),s=[t.lat-o,t.lng-n,t.lat+o,t.lng+n].map(i=>i.toFixed(6)).join(",");let r;const a=new Promise(i=>{r=setTimeout(()=>i(void 0),v.PATIENCE_MS)});try{const i=await Promise.race([this.client.query(`[out:json][timeout:25];(node["highway"="street_lamp"](${s});way["highway"]["lit"="yes"](${s}););out geom;`),a]);return i?v.lampsFrom(i,t,e):[]}catch{return[]}finally{clearTimeout(r)}}static lampsFrom(t,e,o){const n=[];for(const r of t.elements??[]){if(r.type==="way"){v.alongStreet(r,e,n);continue}if(typeof r.lat!="number"||typeof r.lon!="number")continue;const a=(r.lon-e.lng)*v.METRES_PER_DEGREE*Math.cos(e.lat*Math.PI/180),i=(r.lat-e.lat)*v.METRES_PER_DEGREE;if(Math.hypot(a,i)>o)continue;const c=Number.parseFloat(r.tags?.height??"");n.push({eastM:Math.round(a*10)/10,northM:Math.round(i*10)/10,...Number.isFinite(c)&&c>=2&&c<=20?{heightM:c}:{}})}const s=n.filter(r=>Math.hypot(r.eastM,r.northM)<=o);return n.length=0,n.push(...s),n.sort((r,a)=>Math.hypot(r.eastM,r.northM)-Math.hypot(a.eastM,a.northM)),n.slice(0,v.MAX)}static alongStreet(t,e,o){const n=t.geometry;if(!n||n.length<2)return;const s=f=>[(f.lon-e.lng)*v.METRES_PER_DEGREE*Math.cos(e.lat*Math.PI/180),(f.lat-e.lat)*v.METRES_PER_DEGREE],r=n.map(s),a=Number.parseFloat(t.tags?.width??""),i=Number.parseInt(t.tags?.lanes??"",10),l=(Number.isFinite(a)&&a>0?a:Number.isFinite(i)&&i>0?i*3.5:v.DEFAULT_WIDTH_M)/2+v.KERB_OFFSET_M;let h=1,u=v.STREET_SPACING_M/2,M=0;for(let f=1;f<r.length;f++){const[d,m]=r[f-1],[E,P]=r[f],p=Math.hypot(E-d,P-m);if(p===0)continue;const O=(E-d)/p,D=(P-m)/p;for(;u<=M+p;u+=v.STREET_SPACING_M){const y=u-M;o.push({eastM:Math.round((d+O*y+D*l*h)*10)/10,northM:Math.round((m+D*y-O*l*h)*10)/10}),h=-h}M+=p}}}class j{id="ign-lidar-hd";name="IGN LiDAR HD";attribution="Canopy and roofs © IGN, LiDAR HD (Licence Ouverte 2.0), as surveyed on a day the service does not give";creditUrl="https://geoservices.ign.fr/lidarhd";contemporary=!0;platform;lamps;constructor(t={},e){this.platform=new R(t),this.lamps=e}covers(t,e){return R.covers(t,e)}async getSurroundings(t,e){if(!this.covers(t.lat,t.lng))throw new S("no-coverage","The LiDAR HD survey covers France only");const o=R.lidarRadius(e),[n,s,r,a,i]=await Promise.all([this.platform.lidar(t,o),this.platform.photo(t,o).catch(()=>{}),this.lamps?.near(t,e),this.platform.laserDate(t),this.platform.photoDate(t)]);return{trees:new x(n.heights,n.vegetation,n.size,n.size).trees({metresPerPixel:n.metresPerPixel,radiusM:o}),buildings:A.fit(g.fit(new w(n.heights,n.building,n.size,n.size).buildings({metresPerPixel:n.metresPerPixel,radiusM:o,maxBuildings:300}),n,s)),bridges:[],lines:[],...r?{lamps:r}:{},dates:{...a?{laser:a}:{},...s&&i?{photo:i}:{},...r?.length?{lamps:v.today()}:{}}}}}class I{static METRES_PER_DEGREE=111320;static NAMED_NATURES={Silo:"Silo"};static DEFAULT_HEIGHT_M=6;static FLOOR_HEIGHT_M=3;static FINE_M=.5;static COARSE_M=1;static MAX_CELLS=4e4;static RECTANGLE_FILL=.9;static buildings(t,e,o,n=12,s=300){const r=[];for(const i of t){const c=I.rings(i,e);if(c.length===0)continue;const l=Number(i.properties.nombre_d_etages),h=Number(i.properties.hauteur),u=Number.isFinite(h)&&h>0?h:Number.isFinite(l)&&l>0?l*I.FLOOR_HEIGHT_M:I.DEFAULT_HEIGHT_M;for(const M of I.rectanglesOf(c,u,n)){if(Math.hypot(M.eastM,M.northM)>o)continue;const f=A.of(i.properties.materiaux_des_murs,"wall"),d=A.of(i.properties.materiaux_de_la_toiture,"roof"),m=I.NAMED_NATURES[String(i.properties.nature??"")];r.push({...M,...m?{name:m}:{},...Number.isFinite(l)&&l>0?{floors:l}:{},...f?{wallMaterial:f}:{},...d?{roofMaterial:d}:{}})}}const a=i=>Math.hypot(i.eastM,i.northM);if(r.length>s){const i=c=>(c.heightM+6)*Math.sqrt(c.widthM*c.lengthM)/Math.max(a(c),50);r.sort((c,l)=>i(l)-i(c)),r.length=s}return r.sort((i,c)=>a(i)-a(c)),r}static named(t,e,o){const n=e.map(s=>({name:typeof s.properties.toponyme=="string"?s.properties.toponyme:"",rings:I.rings(s,o)})).filter(s=>s.name.length>0&&s.rings.length>0);return n.length===0?t:t.map(s=>{const r=n.find(a=>I.inside(s.eastM,s.northM,a.rings));return r?{...s,name:r.name}:s})}static inside(t,e,o){let n=0;for(const s of o)for(let r=0;r+1<s.length;r++){const a=s[r],i=s[r+1];a.north<=e!=i.north<=e&&a.east+(e-a.north)/(i.north-a.north)*(i.east-a.east)>t&&n++}return n%2===1}static rings(t,e){const o=t.geometry,n=o.type==="Polygon"?[o.coordinates]:o.type==="MultiPolygon"?o.coordinates:[],s=Math.cos(e.lat*Math.PI/180),r=[];for(const a of n)for(const i of a)r.push(i.map(([c,l])=>({east:(c-e.lng)*I.METRES_PER_DEGREE*s,north:(l-e.lat)*I.METRES_PER_DEGREE})));return r}static rectanglesOf(t,e,o){let n=1/0,s=-1/0,r=1/0,a=-1/0;for(const u of t)for(const M of u)n=Math.min(n,M.east),s=Math.max(s,M.east),r=Math.min(r,M.north),a=Math.max(a,M.north);let i=I.FINE_M;(s-n)*(a-r)/(i*i)>I.MAX_CELLS&&(i=I.COARSE_M);const c=[],l=[];for(let u=r+i/2;u<a;u+=i){const M=[];for(const f of t)for(let d=0;d+1<f.length;d++){const m=f[d],E=f[d+1];m.north<=u!=E.north<=u&&M.push(m.east+(u-m.north)/(E.north-m.north)*(E.east-m.east))}M.sort((f,d)=>f-d);for(let f=0;f+1<M.length;f+=2)for(let d=Math.ceil((M[f]-i/2)/i)*i+i/2;d<M[f+1];d+=i)c.push(d),l.push(u)}if(c.length*i*i<o)return[];const h=t.flatMap(u=>u.slice(0,-1).map((M,f)=>({from:M,to:u[f+1]})));return w.ofPoints(c,l,new Array(c.length).fill(e),i,o,I.RECTANGLE_FILL,h)}}class q{id="ign-lidar-topo";name="IGN LiDAR HD + BD TOPO";attribution="Canopy © IGN, LiDAR HD; buildings, bridges and lines © IGN, BD TOPO (Licence Ouverte 2.0), as surveyed on days the services do not give";creditUrl="https://geoservices.ign.fr/lidarhd";contemporary=!0;platform;lamps;constructor(t={},e){this.platform=new R(t),this.lamps=e}covers(t,e){return R.covers(t,e)}async getSurroundings(t,e){if(!this.covers(t.lat,t.lng))throw new S("no-coverage","The IGN's surveys cover France only");const o=R.radius(e),[n,s,r,a,i,c]=await Promise.allSettled([this.platform.lidar(t,o),this.platform.vectors(t,o,!0),this.platform.photo(t,o),this.lamps?.near(t,e)??Promise.resolve(void 0),this.platform.laserDate(t),this.platform.photoDate(t)]),l=R.lidarRadius(o);if(n.status==="rejected"&&s.status==="rejected")throw n.reason;const h=n.status==="fulfilled"?n.value:void 0,u=s.status==="fulfilled"?s.value:void 0,M=u!==void 0&&u.buildings.length===0&&u.bridges.length===0&&u.lines.length===0;if(n.status==="rejected"&&n.reason instanceof S&&n.reason.reason==="no-coverage"&&M)throw n.reason;return{trees:h?new x(h.heights,h.vegetation,h.size,h.size).trees({metresPerPixel:h.metresPerPixel,radiusM:l}):[],buildings:this.roofed(this.buildings(h,u,t,o),h,r.status==="fulfilled"?r.value:void 0),bridges:u?F.bridges(u,t,o,h?.structures):[],lines:u?F.lines(u,t,o,h?.structures):[],...a.status==="fulfilled"&&a.value?{lamps:a.value}:{},dates:{...n.status==="fulfilled"&&i.status==="fulfilled"&&i.value?{laser:i.value}:{},...r.status==="fulfilled"&&c.status==="fulfilled"&&c.value?{photo:c.value}:{},...u?.mapDate?{map:u.mapDate}:{},...a.status==="fulfilled"&&a.value?.length?{lamps:v.today()}:{}}}}roofed(t,e,o){return A.fit(g.fit(t,e,o))}buildings(t,e,o,n){const s=e?I.buildings(e.buildings,o,n):[],r=s.length>0||t===void 0?s:new w(t.heights,t.building,t.size,t.size).buildings({metresPerPixel:t.metresPerPixel,radiusM:R.lidarRadius(n),maxBuildings:300});return e?I.named(r,e.zones,o):r}}class Y{id="ign-bd-topo";name="IGN BD TOPO";attribution="Buildings, bridges and lines © IGN, BD TOPO (Licence Ouverte 2.0), as drawn on a day the service does not give";creditUrl="https://geoservices.ign.fr/bdtopo";contemporary=!0;platform;lamps;constructor(t={},e){this.platform=new R(t),this.lamps=e}covers(t,e){return R.covers(t,e)}async getSurroundings(t,e){if(!this.covers(t.lat,t.lng))throw new S("no-coverage","BD TOPO covers France only");const o=R.radius(e),[n,s,r,a]=await Promise.all([this.platform.vectors(t,o,!0),this.platform.photo(t,o).catch(()=>{}),this.lamps?.near(t,e),this.platform.photoDate(t)]);return{trees:[],buildings:A.fit(g.fit(I.named(I.buildings(n.buildings,t,o),n.zones,t),void 0,s)),bridges:F.bridges(n,t,o,void 0),lines:F.lines(n,t,o,void 0),...r?{lamps:r}:{},dates:{...n.mapDate?{map:n.mapDate}:{},...s&&a?{photo:a}:{},...r?.length?{lamps:v.today()}:{}}}}}class N{static ROOF_SHAPES={flat:"flat",gabled:"gable",gambrel:"gable",saltbox:"gable","half-hipped":"hip",hipped:"hip",pyramidal:"hip",mansard:"hip",round:"gable"};static WALL_MATERIALS={brick:"brick",stone:"stone",granite:"stone",sandstone:"stone",limestone:"stone",concrete:"concrete",cement_block:"block",block:"block",wood:"wood",timber_framing:"wood"};static ROOF_MATERIALS={roof_tiles:"tile",tiles:"tile",tile:"tile",slate:"slate",metal:"zinc",zinc:"zinc",tin:"zinc",copper:"zinc",concrete:"concrete",eternit:"other"};static COLOURS={white:"#e8e6e0",grey:"#8c8c8a",gray:"#8c8c8a",black:"#3a3a3a",red:"#a8483a",brown:"#6e4f38",beige:"#d6c9a8",yellow:"#d8c070",orange:"#c9773a",green:"#5f7a52",blue:"#506a8a",tan:"#c0a37a",cream:"#e6dcc0",pink:"#c99a96",silver:"#b4b6b6"};static height(t){const e=Number.parseFloat((t??"").replace(",","."));return Number.isFinite(e)&&e>=2&&e<=500?e:void 0}static levels(t){const e=Number.parseInt(t??"",10);return Number.isFinite(e)&&e>=1&&e<=150?e:void 0}static roofShape(t){return N.ROOF_SHAPES[(t??"").trim().toLowerCase()]}static wallMaterial(t){return N.WALL_MATERIALS[(t??"").trim().toLowerCase()]}static roofMaterial(t){return N.ROOF_MATERIALS[(t??"").trim().toLowerCase()]}static colour(t){const e=(t??"").trim().toLowerCase();return/^#[0-9a-f]{6}$/.test(e)?e:/^#[0-9a-f]{3}$/.test(e)?`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`:N.COLOURS[e]}}class L{id="osm-buildings";name="OpenStreetMap buildings";attribution="Buildings © OpenStreetMap contributors (ODbL), as drawn on the day of the data, which a recording is not";creditUrl="https://www.openstreetmap.org/copyright";contemporary=!0;static MAX_RADIUS_M=1500;static MIN_AREA_M2=12;static MAX_BUILDINGS=300;client;lamps;constructor(t={},e){this.client=new k(t),this.lamps=e}covers(){return!0}async getSurroundings(t,e){const o=Math.min(e,L.MAX_RADIUS_M);let n;try{n=await this.client.query(`[out:json][timeout:30];(way["building"](around:${o},${t.lat},${t.lng});relation["building"]["type"="multipolygon"](around:${o},${t.lat},${t.lng}););out geom;`)}catch(a){throw new S("unreachable",a instanceof Error?a.message:String(a))}const s=await this.lamps?.near(t,e),r=(n.osm3s?.timestamp_osm_base??"").slice(0,10);return{trees:[],buildings:A.fit(L.buildings(n,t,o)),bridges:[],lines:[],...s?{lamps:s}:{},dates:{.../^\d{4}-\d{2}-\d{2}$/.test(r)?{map:r}:{},...s?.length?{lamps:v.today()}:{}}}}static buildings(t,e,o){const n=[];for(const s of t.elements??[]){const r=L.ringsOf(s);if(r.length===0)continue;const a=s.tags??{},i=N.levels(a["building:levels"]),c=N.height(a.height),l={geometry:{type:"Polygon",coordinates:r},properties:{...c?{hauteur:c}:{},...i?{nombre_d_etages:i}:{}}};for(const h of I.buildings([l],e,o,L.MIN_AREA_M2,50))n.push(L.described(h,a,c!==void 0))}return n.sort((s,r)=>Math.hypot(s.eastM,s.northM)-Math.hypot(r.eastM,r.northM)),n.slice(0,L.MAX_BUILDINGS)}static ringsOf(t){const e=n=>{if(!n||n.length<4)return;const s=n.map(i=>[i.lon,i.lat]),r=s[0],a=s[s.length-1];return r[0]===a[0]&&r[1]===a[1]?s:void 0};if(t.type==="way"){const n=e(t.geometry);return n?[n]:[]}return(t.members??[]).filter(n=>n.role==="outer").map(n=>e(n.geometry)).filter(n=>n!==void 0).slice(0,1)}static described(t,e,o){const n=N.wallMaterial(e["building:material"]),s=N.roofMaterial(e["roof:material"]),r=N.colour(e["building:colour"]),a=N.colour(e["roof:colour"])??A.roofColor(s),i=N.roofShape(e["roof:shape"]),c=r?{color:r}:void 0;let l,h=t.heightM;if(i==="gable"||i==="hip"){const u=N.height(e["roof:height"]),M=Math.round((u??Math.min(5,Math.max(1.5,.29*Math.min(t.widthM,t.lengthM))))*10)/10;o||(h=Math.round((t.heightM+M)*10)/10),l={shape:i,riseM:M,...e["roof:orientation"]==="across"?{ridge:"depth"}:{},...a?{color:a}:{}}}else(i==="flat"||a)&&(l={shape:"flat",riseM:0,...a?{color:a}:{}});return{...t,heightM:h,...e.name?{name:e.name}:{},...n?{wallMaterial:n}:{},...s?{roofMaterial:s}:{},...c?{facade:c}:{},...l?{roof:l}:{}}}}const _=[{id:"ign-lidar-topo",name:"IGN LiDAR HD + BD TOPO",credit:"© IGN, LiDAR HD and BD TOPO, Licence Ouverte 2.0; street lamps © OpenStreetMap contributors",creditUrl:"https://geoservices.ign.fr/lidarhd",create:()=>new q({},new v)},{id:"ign-lidar-hd",name:"IGN LiDAR HD",credit:"© IGN, LiDAR HD, Licence Ouverte 2.0; street lamps © OpenStreetMap contributors",creditUrl:"https://geoservices.ign.fr/lidarhd",create:()=>new j({},new v)},{id:"ign-bd-topo",name:"IGN BD TOPO",credit:"© IGN, BD TOPO, Licence Ouverte 2.0; street lamps © OpenStreetMap contributors",creditUrl:"https://geoservices.ign.fr/bdtopo",create:()=>new Y({},new v)},{id:"osm-buildings",name:"OpenStreetMap buildings",credit:"Buildings and street lamps © OpenStreetMap contributors (ODbL)",creditUrl:"https://www.openstreetmap.org/copyright",create:()=>new L({},new v)}];class G{static DEFAULT_ID=_[0].id;static WORLD_ID="osm-buildings";static NONE="none";static byId(t){return t===G.NONE?void 0:_.find(e=>e.id===t)??_[0]}static providerFor(t,e,o){const n=G.byId(t)?.create();if(t!==void 0&&t!==G.DEFAULT_ID)return n?.covers(e,o)?n:void 0;const s=_.find(a=>a.id===G.WORLD_ID).create(),r=[n,s].filter(a=>a!==void 0&&a.covers(e,o));return r.length>1?new K(r):r[0]}}export{_ as SURROUNDINGS_SOURCES,G as SurroundingsSources};
|
package/dist-embed-sighting-editor/{trafficRuntime-j3m3LpCc.js → trafficRuntime-XVgt3vom.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{A as ct,e as lt,T as U,R as L,f as P,r as ht,g as ut}from"./rr0-sighting-editor.mjs";import{C as Y}from"./ContrailGrowth-CuAzwIoc.js";class A{static OCTAVES=[63,125,250,500,1e3,2e3,4e3,8e3];static STANDARD={temperatureC:15,relativeHumidity:.7,pressureKPa:101.325};static REFERENCE_PRESSURE_KPA=101.325;static REFERENCE_TEMPERATURE_K=293.15;static TRIPLE_POINT_K=273.16;static speedOfSound(t){return 20.0468*Math.sqrt(t+273.15)}static absorptionDbPerKm(t,e=A.STANDARD){const a=e.temperatureC+273.15,n=A.REFERENCE_TEMPERATURE_K,i=e.pressureKPa/A.REFERENCE_PRESSURE_KPA,r=10**(-6.8346*(A.TRIPLE_POINT_K/a)**1.261+4.6151),s=e.relativeHumidity*100*r/i,o=i*(24+40400*s*(.02+s)/(.391+s)),l=i*(a/n)**-.5*(9+280*s*Math.exp(-4.17*((a/n)**(-1/3)-1))),c=t*t;return 8.686*c*(184e-13*(1/i)*Math.sqrt(a/n)+(a/n)**-2.5*(.01275*Math.exp(-2239.1/a)/(o+c/o)+.1068*Math.exp(-3352/a)/(l+c/l)))*1e3}static aWeightingDb(t){const e=t*t,a=12194**2*e*e/((e+20.6**2)*Math.sqrt((e+107.7**2)*(e+737.9**2))*(e+12194**2));return 20*Math.log10(a)+2}static sumDb(t){return 10*Math.log10(t.reduce((e,a)=>e+10**(a/10),0))}}const dt=.25,$=.4,J=6,j=12,pt=3,x=.2,mt=.2,gt=24,At=3,Et=12,Z=1,ft=.7,Mt=1.5,bt=.8,Dt=1.3,Q=.9,tt=5,St=25,Rt=.5,Bt=.12,et=[.13,.31],vt=.16,Ot=1.6,It=3.6,at=1.1,Tt=.3,_t=1e3,nt=.7;class V{context;noiseBuffer;roughBuffers=new Map;voices=new Map;bus;reverb;reverbOut;level=1;master;paused=!0;requested=[];headingDeg=0;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(t){console.warn("AircraftAudio: Web Audio unavailable, aircraft stay silent:",t);return}}ct.unlock(this.context),this.apply()}setLevel(t){this.level=t,this.master&&(this.master.gain.value=t)}setPaused(t){t!==this.paused&&(this.paused=t,this.apply())}setVoices(t,e=0){this.requested=t,this.headingDeg=e,this.apply()}dispose(){for(const t of[...this.voices.keys()])this.release(t);this.context?.close(),this.context=void 0,this.master=void 0,this.bus=void 0}apply(){const t=this.context;if(!t)return;const e=this.paused?[]:this.requested,a=new Set(e.map(n=>n.id));for(const n of[...this.voices.keys()])a.has(n)||this.release(n);for(const n of e){const i=this.voices.get(n.id)??this.build(t,n);this.retarget(t,i,n)}}build(t,e){const a=t.createGain();a.gain.value=0;let n;const i=this.busOf(t);typeof t.createStereoPanner=="function"?(n=t.createStereoPanner(),a.connect(n).connect(i)):a.connect(i);const r=t.createGain(),s=e.character?.modulationDepth??0;r.gain.value=1-s/2;const o=t.createOscillator();o.type="sine";const l=t.createGain();l.gain.value=s/2,o.connect(l).connect(r.gain),r.connect(a);const c=t.createBufferSource();c.buffer=this.noise(t),c.loop=!0,c.loopStart=Math.random()*J*.5;const d=[],u=[],h=[];for(const D of A.OCTAVES){const v=t.createBiquadFilter();v.type="bandpass",v.frequency.value=D,v.Q.value=Z;const C=t.createBiquadFilter();C.type="bandpass",C.frequency.value=D,C.Q.value=Z;const w=t.createGain();w.gain.value=0,c.connect(v).connect(C).connect(w).connect(r),d.push(v),u.push(C),h.push(w)}const p=[];for(const[D,v]of[[e.character?.toneHz,e.character?.toneShare],[e.character?.humHz,e.character?.humShare]])if(D!==void 0)for(let C=1;C<=At;C++){const w=t.createOscillator();w.type="sine",w.frequency.value=D*C;const W=t.createGain();W.gain.value=0,w.connect(W).connect(a),p.push({oscillator:w,gain:W,harmonic:C,baseHz:D,share:v??0})}const m=t.createGain();m.gain.value=0,m.connect(a.gain);const f=et.map(D=>{const v=t.createOscillator();return v.type="sine",v.frequency.value=D,v.connect(m),v}),b=t.createGain();b.gain.value=e.character?.roughness??x;const N=t.createBufferSource();N.buffer=this.roughTable(t,pt),N.loop=!0,N.loopStart=Math.random()*j*.5,N.connect(b).connect(r.gain);const _=t.createGain();_.gain.value=(e.character?.roughness??x)*mt;const R=t.createBufferSource();R.buffer=this.roughTable(t,gt),R.loop=!0,R.loopStart=Math.random()*j*.5,R.connect(_).connect(r.gain);let O;const G=this.busOf(t)&&this.reverb;G&&(O=t.createGain(),O.gain.value=0,a.connect(O).connect(G));const z=[c,N,R,o,...p.map(D=>D.oscillator),...f];for(const D of z)D.start();const q={nodes:[a,r,l,b,_,m,...p.map(D=>D.gain),...d,...u,...h,...O?[O]:[],...n?[n]:[],...z],sources:z,filters:d,seconds:u,gains:h,tones:p,lfo:o,lfoDepth:l,wander:f,wanderDepth:m,roughDepth:b,crackleDepth:_,beat:r,output:a,panner:n,send:O};return this.voices.set(e.id,q),q}retarget(t,e,a){const n=t.currentTime,i=(p,m)=>p.setTargetAtTime(m,n,dt),r=Math.min(Mt,Math.max(ft,a.dopplerRatio)),s=Math.min(Dt,Math.max(bt,Math.sqrt(a.dopplerRatio))),o=t.sampleRate*.45,l=a.bandAmplitudes.map((p,m)=>p*V.unweighting(A.OCTAVES[m])),c=Math.sqrt(l.reduce((p,m)=>p+m*m,0)),d=Math.min(1,Math.max(0,(a.distanceKm-tt)/(St-tt)));A.OCTAVES.forEach((p,m)=>{i(e.filters[m].frequency,Math.min(o,p*s)),i(e.seconds[m].frequency,Math.min(o,p*s)),i(e.gains[m].gain,l[m]*Math.sqrt(_t/p))});const u=a.character;for(const{oscillator:p,gain:m,harmonic:f,baseHz:b,share:N}of e.tones){const _=b*f;i(p.frequency,_*r);const R=_*r;i(m.gain,R<o?N*vt*l[V.bandOf(R)]/f:0)}u?.modulationHz!==void 0&&i(e.lfo.frequency,u.modulationHz*r);const h=c>0?nt*(1-Math.exp(-c/nt))/c:1;if(i(e.output.gain,h*(1-Tt*d)),i(e.wanderDepth.gain,h*Bt*d/et.length),e.send&&i(e.send.gain,Ot*d),e.panner){const p=(a.azimuthDeg-this.headingDeg)*Math.PI/180;i(e.panner.pan,Math.max(-Q,Math.min(Q,Math.sin(p)))*(1-Rt*d))}}static unweighting(t){return 10**(Math.min(Et,Math.max(0,-A.aWeightingDb(t)))/20)}static bandOf(t){let e=0;return A.OCTAVES.forEach((a,n)=>{Math.abs(Math.log(t/a))<Math.abs(Math.log(t/A.OCTAVES[e]))&&(e=n)}),e}roughTable(t,e){const a=this.roughBuffers.get(e);if(a)return a;const n=Math.floor(t.sampleRate*j),i=t.createBuffer(1,n,t.sampleRate),r=i.getChannelData(0),s=Array.from({length:j*e},()=>(Math.random()*2-1)**3),o=t.sampleRate/e;for(let l=0;l<r.length;l++){const c=l/o,d=Math.floor(c),u=c-d,h=u*u*(3-2*u);r[l]=s[d%s.length]*(1-h)+s[(d+1)%s.length]*h}return this.roughBuffers.set(e,i),i}roomImpulse(t){const e=Math.floor(t.sampleRate*It),a=t.createBuffer(2,e,t.sampleRate);for(let n=0;n<2;n++){const i=a.getChannelData(n);let r=0;for(let s=0;s<e;s++){const o=s/t.sampleRate,l=.6*Math.exp(-o/(at*2))+.04;r+=l*(Math.random()*2-1-r),i[s]=r*Math.exp(-o/at)}}return a}busOf(t){if(this.bus)return this.bus;const e=t.createGain();if(e.gain.value=this.level,e.connect(t.destination),this.master=e,typeof t.createConvolver=="function"){const a=t.createConvolver();a.buffer=this.roomImpulse(t);const n=t.createGain();n.gain.value=.9,a.connect(n),this.reverb=a,this.reverbOut=n}if(typeof t.createDynamicsCompressor=="function"){const a=t.createDynamicsCompressor();a.threshold.value=-6,a.knee.value=3,a.ratio.value=4,a.attack.value=.005,a.release.value=.25,a.connect(e),this.bus=a}else this.bus=e;return this.reverbOut?.connect(this.bus),this.bus}release(t){const e=this.voices.get(t);if(!e)return;this.voices.delete(t);const a=this.context;a&&(e.output.gain.setTargetAtTime(0,a.currentTime,$/3),setTimeout(()=>{for(const n of e.sources)try{n.stop()}catch{}for(const n of e.nodes)n.disconnect()},$*1e3*3))}noise(t){if(this.noiseBuffer)return this.noiseBuffer;const e=t.createBuffer(1,t.sampleRate*J,t.sampleRate),a=e.getChannelData(0);for(let n=0;n<a.length;n++)a[n]=Math.random()*2-1;return this.noiseBuffer=e,e}}class I{static BASE_DB_A=30;static WIND_DB_A=[[0,10],[1,28],[2,36],[3,40],[5,46],[8,52],[12,58],[20,66]];static RAIN_DB_A=[[0,0],[.1,42],[.3,50],[.6,58],[1,65]];static BED_RMS=.2;static MINIMUM_REFERENCE=.008;static WIND_BED_MIN_MS=1;static WIND_BED_FULL_MS=20;static dbA(t){const e=[I.BASE_DB_A,I.along(I.WIND_DB_A,t.windSpeed)];return(t.precipitationType==="rain"||t.precipitationType==="hail")&&e.push(I.along(I.RAIN_DB_A,t.precipitationIntensity)),10*Math.log10(e.filter(a=>a>0).reduce((a,n)=>a+10**(n/10),0))}static bedVolume(t){const e=t.windSpeed>I.WIND_BED_MIN_MS?Math.min(t.windSpeed/I.WIND_BED_FULL_MS,1):0,a=t.precipitationType==="hail"?Math.min(1,t.precipitationIntensity*1.3+.2):t.precipitationType==="rain"?t.precipitationIntensity:0;return Math.hypot(e,a)}static referenceAmplitude(t){return Math.max(I.BED_RMS*I.bedVolume(t),I.MINIMUM_REFERENCE)}static along(t,e){if(e<=t[0][0])return t[0][1];for(let a=1;a<t.length;a++)if(e<=t[a][0]){const[n,i]=t[a-1],[r,s]=t[a];return i+(s-i)*(e-n)/(r-n)}return t[t.length-1][1]}}class y{static TYPES={A318:["Airbus A318","airliner-narrow",34.1,31.4],A319:["Airbus A319","airliner-narrow",34.1,33.8],A320:["Airbus A320","airliner-narrow",34.1,37.6],A321:["Airbus A321","airliner-narrow",34.1,44.5],A19N:["Airbus A319neo","airliner-narrow",35.8,33.8],A20N:["Airbus A320neo","airliner-narrow",35.8,37.6],A21N:["Airbus A321neo","airliner-narrow",35.8,44.5],B737:["Boeing 737-700","airliner-narrow",34.3,33.6],B738:["Boeing 737-800","airliner-narrow",35.8,39.5],B739:["Boeing 737-900","airliner-narrow",35.8,42.1],B38M:["Boeing 737 MAX 8","airliner-narrow",35.9,39.5],B39M:["Boeing 737 MAX 9","airliner-narrow",35.9,42.2],B752:["Boeing 757-200","airliner-narrow",38,47.3],B753:["Boeing 757-300","airliner-narrow",38,54.4],B762:["Boeing 767-200","airliner-wide",47.6,48.5],B763:["Boeing 767-300","airliner-wide",47.6,54.9],B764:["Boeing 767-400","airliner-wide",51.9,61.4],B772:["Boeing 777-200","airliner-wide",60.9,63.7],B77L:["Boeing 777-200LR","airliner-wide",64.8,63.7],B77W:["Boeing 777-300ER","airliner-wide",64.8,73.9],B788:["Boeing 787-8","airliner-wide",60.1,56.7],B789:["Boeing 787-9","airliner-wide",60.1,62.8],B78X:["Boeing 787-10","airliner-wide",60.1,68.3],B744:["Boeing 747-400","airliner-wide",64.4,70.7],B748:["Boeing 747-8","airliner-wide",68.4,76.3],A306:["Airbus A300-600","airliner-wide",44.8,54.1],A310:["Airbus A310","airliner-wide",43.9,46.7],A332:["Airbus A330-200","airliner-wide",60.3,58.8],A333:["Airbus A330-300","airliner-wide",60.3,63.7],A338:["Airbus A330-800","airliner-wide",64,58.8],A339:["Airbus A330-900","airliner-wide",64,63.7],A343:["Airbus A340-300","airliner-wide",60.3,63.7],A346:["Airbus A340-600","airliner-wide",63.5,75.4],A359:["Airbus A350-900","airliner-wide",64.8,66.8],A35K:["Airbus A350-1000","airliner-wide",64.8,73.8],A388:["Airbus A380-800","airliner-wide",79.8,72.7],E170:["Embraer 170","regional-jet",26,29.9],E75L:["Embraer 175","regional-jet",26,31.7],E75S:["Embraer 175","regional-jet",26,31.7],E190:["Embraer 190","regional-jet",28.7,36.2],E195:["Embraer 195","regional-jet",28.7,38.7],E290:["Embraer 190-E2","regional-jet",33.7,36.2],E295:["Embraer 195-E2","regional-jet",33.7,41.5],CRJ2:["Bombardier CRJ200","regional-jet",21.2,26.8],CRJ7:["Bombardier CRJ700","regional-jet",23.2,32.3],CRJ9:["Bombardier CRJ900","regional-jet",24.9,36.2],CRJX:["Bombardier CRJ1000","regional-jet",26.2,39.1],AT72:["ATR 72","regional-turboprop",27.1,27.2],AT76:["ATR 72-600","regional-turboprop",27.1,27.2],AT45:["ATR 42","regional-turboprop",24.6,22.7],DH8D:["Dash 8 Q400","regional-turboprop",28.4,32.8],DH8C:["Dash 8-300","regional-turboprop",27.4,25.7],SF34:["Saab 340","regional-turboprop",21.4,19.7],B190:["Beechcraft 1900","regional-turboprop",17.7,17.6],C25A:["Cessna CitationJet CJ2","business-jet",14.3,14.4],C56X:["Cessna Citation Excel","business-jet",17.2,16],C68A:["Cessna Citation Latitude","business-jet",22,18.9],C550:["Cessna Citation II","business-jet",15.8,14.4],E55P:["Embraer Phenom 300","business-jet",15.9,15.6],E50P:["Embraer Phenom 100","business-jet",12.3,12.8],GLF5:["Gulfstream G550","business-jet",28.5,29.4],FA7X:["Dassault Falcon 7X","business-jet",26.2,23.4],CL60:["Bombardier Challenger 600","business-jet",19.6,20.9],LJ45:["Learjet 45","business-jet",14.6,17.7],H25B:["Hawker 800","business-jet",15.7,15.6],C172:["Cessna 172","light-piston",11,8.3],C152:["Cessna 152","light-piston",10.2,7.3],C182:["Cessna 182","light-piston",10.9,8.8],P28A:["Piper Cherokee","light-piston",10.7,7.2],PA34:["Piper Seneca","light-piston",11.8,8.7],SR20:["Cirrus SR20","light-piston",10.9,7.9],SR22:["Cirrus SR22","light-piston",11.7,7.9],S22T:["Cirrus SR22T","light-piston",11.7,7.9],DA40:["Diamond DA40","light-piston",11.6,8.1],DA42:["Diamond DA42","light-piston",13.4,8.6],BE20:["Beechcraft King Air 200","turboprop-light",16.6,13.3],BE58:["Beechcraft Baron","light-piston",11.5,9.1],C208:["Cessna Caravan","turboprop-light",15.9,11.5],PC12:["Pilatus PC-12","turboprop-light",16.3,14.4],TBM9:["Daher TBM 900","turboprop-light",12.8,10.7],EC35:["Airbus H135","helicopter-light",10.2,12.1],EC45:["Airbus H145","helicopter-medium",11,13.6],AS50:["Airbus H125","helicopter-light",10.7,12.9],EC30:["Airbus H130","helicopter-light",10.7,12.6],B407:["Bell 407","helicopter-light",10.7,12.7],B06:["Bell 206","helicopter-light",10.2,12],B429:["Bell 429","helicopter-medium",10.9,13],B505:["Bell 505","helicopter-light",10.4,11.9],R44:["Robinson R44","helicopter-light",10.1,11.7],R22:["Robinson R22","helicopter-light",7.7,8.8],A109:["Agusta A109","helicopter-medium",11,13],A139:["Leonardo AW139","helicopter-medium",13.8,16.7],S92:["Sikorsky S-92","helicopter-heavy",17.2,20.9],H60:["Sikorsky UH-60 Black Hawk","helicopter-heavy",16.4,19.8],T38:["Northrop T-38 Talon","military-jet",7.7,14.1],HAWK:["BAE Hawk","military-jet",9.4,11.9],GLID:["Glider","glider",17,7],BALL:["Balloon","balloon",15,20],ULAC:["Ultralight","ultralight",9.5,6],C42:["Ikarus C42","ultralight",9.4,6.3],DRON:["Drone","unmanned",1,.6]};static CATEGORIES={A1:["Light aircraft","light-piston",11,8.3],A2:["Small aircraft","business-jet",15,15],A3:["Large aircraft","airliner-narrow",34.1,37.6],A4:["High-vortex large aircraft","airliner-narrow",38,47.3],A5:["Heavy aircraft","airliner-wide",60.3,63.7],A6:["High-performance aircraft","military-jet",8,14],A7:["Rotorcraft","helicopter-medium",10.7,12.7],B1:["Glider","glider",17,7],B2:["Lighter-than-air","balloon",15,20],B4:["Ultralight","ultralight",9.5,6],B6:["Unmanned aircraft","unmanned",1.5,1]};static GENERIC={name:"Airliner",kind:"airliner-narrow",spanM:34.1,lengthM:37.6,basis:"nothing"};static of(t){const e=t?.type?.toUpperCase(),a=e?y.TYPES[e]:void 0;if(a)return{code:e,name:a[0],kind:a[1],spanM:a[2],lengthM:a[3],basis:"type"};const n=t?.category?y.CATEGORIES[t.category]:void 0;return n?{name:n[0],kind:n[1],spanM:n[2],lengthM:n[3],basis:"category"}:{...y.GENERIC}}static isHelicopter(t){return t.kind.startsWith("helicopter")}}class k{static DUSK_SUN_ELEVATION_DEG=-.83;static ALWAYS=new Set(["airliner-narrow","airliner-wide","regional-turboprop","regional-jet","business-jet"]);static NONE=new Set(["glider","balloon"]);static BRIGHTNESS={"light-piston":[.5,.2,.5],"turboprop-light":[.7,.4,.8],ultralight:[.4,.2,.4],unmanned:[0,.05,0],"helicopter-light":[1,1,1],"helicopter-medium":[1,1,1],"helicopter-heavy":[1,1,1],"military-jet":[1,1,1]};static lampsOn(t,e){if(k.NONE.has(t))return{navigation:!1,beacon:!1,strobes:!1};if(k.ALWAYS.has(t))return{navigation:!0,beacon:!0,strobes:!0};const a=e<k.DUSK_SUN_ELEVATION_DEG;return t==="unmanned"?{navigation:!1,beacon:!1,strobes:a}:{navigation:a,beacon:a,strobes:a}}static lights(t,e){const a=k.lampsOn(t.kind,e),n=t.kind.startsWith("helicopter"),i=lt.find(h=>h.id===(n?"helicopter":"airliner")).create(),[r,s]=n?[5,7]:[17,18],o=t.spanM/2/r,l=t.lengthM/2/s,[c,d,u]=k.BRIGHTNESS[t.kind]??[1,1,1];return i.filter(h=>h.id.startsWith("nav")?a.navigation:h.id.startsWith("strobe")?a.strobes:h.id.startsWith("beacon")?a.beacon:!0).filter(h=>!(h.id.startsWith("beacon")&&!a.beacon)).map(h=>{const p=h.id.startsWith("nav")?c:h.id.startsWith("strobe")?d:u;return{...h,offsetM:{x:h.offsetM.x*o,y:h.offsetM.y,z:h.offsetM.z*l},intensity:(h.intensity??1)*p}}).filter(h=>(h.intensity??1)>0)}static bodyColor(t){return t.kind==="military-jet"?"#8a8e94":t.kind.startsWith("helicopter")?"#c8ccd1":t.kind==="unmanned"?"#2c2e33":"#dde0e4"}}class F{static FAMILIES={"amvlab-a320":["A318","A319","A320","A321","A19N","A20N","A21N"],"amvlab-b737":["B732","B733","B734","B735","B736","B737","B738","B739","B37M","B38M","B39M","B3XM"],"amvlab-a350":["A359","A35K"],"amvlab-a380":["A388"],"amvlab-b787":["B788","B789","B78X"]};static BY_TYPE=new Map(Object.entries(F.FAMILIES).flatMap(([t,e])=>e.map(a=>[a,t])));static idOf(t){return t?F.BY_TYPE.get(t.toUpperCase()):void 0}}class M{static ID_PREFIX=U.ID_PREFIX;static MAX_OBJECTS=40;static FT_TO_M=.3048;static DEG=Math.PI/180;static from(t,e,a,n=M.MAX_OBJECTS,i={}){return new Ct(t,e,a,n,i).build()}static idOf(t,e){return U.idOf(t,e)}static keyOf(t){return U.keyOf(t)}static HEIGHT_OVER_LENGTH=.29;static sizeOf(t){return{widthM:t.spanM,lengthM:t.lengthM,heightM:t.lengthM*M.HEIGHT_OVER_LENGTH}}static offsetOf(t,e){const a=L.seenFrom(t,{lat:e.lat,lng:e.lng,heightM:e.altitudeFt*M.FT_TO_M}),n=a.distanceKm*1e3,i=n*Math.cos(a.altitudeDeg*M.DEG);return{eastM:i*Math.sin(a.azimuthDeg*M.DEG),northM:i*Math.cos(a.azimuthDeg*M.DEG),upM:n*Math.sin(a.altitudeDeg*M.DEG),altitudeDeg:a.altitudeDeg,distanceKm:a.distanceKm}}static segments(t){const e=[];let a=[];for(const n of t.points){const i=a[a.length-1];i&&n.t-i.t>P.MAX_GAP_S*1e3&&(e.push(a),a=[]),a.push(n)}return e.push(a),e.filter(n=>n.length>=2)}static bearingDeg(t,e){return(Math.atan2(e.eastM-t.eastM,e.northM-t.northM)/M.DEG+360)%360}}class Ct{constructor(t,e,a,n,i){this.tracks=t,this.observer=e,this.startMs=a,this.maxObjects=n,this.options=i}build(){const t=[];for(const a of this.tracks){const n=M.keyOf(a),i=this.options.models?.get(n)??y.of(void 0);M.segments(a).forEach((r,s)=>{const o=r.map(h=>({point:h,at:M.offsetOf(this.observer,h)}));if(!o.some(h=>h.at.altitudeDeg>=0))return;const l=o.map((h,p)=>({t:h.point.t-this.startMs,eastM:h.at.eastM,northM:h.at.northM,altitudeM:h.at.upM,headingDeg:h.point.trackDeg??(p+1<o.length?M.bearingDeg(h.at,o[p+1].at):M.bearingDeg(o[p-1].at,h.at))})),c=M.idOf(a,s),d=o[Math.floor(o.length/2)].point,u=this.options.sunElevationAt?.(d)??90;t.push({object:{id:c,kind:"aircraft",eastM:l[0].eastM,northM:l[0].northM,headingDeg:l[0].headingDeg,sizeM:M.sizeOf(i),model:F.idOf(i.code)?{id:F.idOf(i.code)}:void 0,color:k.bodyColor(i),lights:k.lights(i,u),track:l},presence:{fromMs:l[0].t,untilMs:l[l.length-1].t},flight:{icao:a.icao,nonIcao:a.nonIcao,points:r},closestKm:Math.min(...o.map(h=>h.at.distanceKm))})})}t.sort((a,n)=>a.closestKm-n.closestKm);const e=t.slice(0,this.maxObjects);return{objects:e.map(a=>a.object),presence:new Map(e.map(a=>[a.object.id,a.presence])),flights:new Map(e.map(a=>[a.object.id,a.flight])),total:t.length,shown:e.length}}}const ot=[{id:"turbofan-narrow-body",name:"Turbofan airliner, narrow-body",kinds:["airliner-narrow"],totalDbA:148,shapeDb:[-32,-17,-9,-6,-5,-7,-12,-22],character:{toneHz:1800,toneShare:.3,humHz:90,humShare:.7}},{id:"turbofan-wide-body",name:"Turbofan airliner, wide-body",kinds:["airliner-wide"],totalDbA:151,shapeDb:[-28,-14,-7,-4,-3,-6,-12,-22],character:{toneHz:1200,toneShare:.3,humHz:70,humShare:.7}},{id:"regional-jet",name:"Regional jet",kinds:["regional-jet"],totalDbA:144,shapeDb:[-32,-17,-9,-5,-4,-6,-11,-21],character:{toneHz:1900,toneShare:.3,humHz:95,humShare:.7}},{id:"business-jet",name:"Business jet",kinds:["business-jet"],totalDbA:141,shapeDb:[-30,-15,-8,-4,-3,-4,-9,-19],character:{toneHz:2500,toneShare:.25,humHz:110,humShare:.7}},{id:"turboprop",name:"Turboprop",kinds:["regional-turboprop","turboprop-light"],totalDbA:138,shapeDb:[-14,-9,-8,-6,-8,-13,-20,-28],character:{toneHz:80,toneShare:.5}},{id:"light-piston",name:"Light piston aircraft",kinds:["light-piston"],totalDbA:130,shapeDb:[-18,-9,-5,-4,-8,-14,-22,-30],character:{toneHz:80,toneShare:.4}},{id:"ultralight",name:"Ultralight",kinds:["ultralight"],totalDbA:124,shapeDb:[-16,-8,-5,-4,-9,-15,-23,-31],character:{toneHz:140,toneShare:.4}},{id:"helicopter-light",name:"Light helicopter",kinds:["helicopter-light"],totalDbA:134,shapeDb:[-15,-8,-4,-3,-6,-10,-16,-24],character:{modulationHz:20,modulationDepth:.5}},{id:"helicopter-medium",name:"Medium helicopter",kinds:["helicopter-medium"],totalDbA:138,shapeDb:[-14,-7,-4,-3,-6,-10,-16,-24],character:{modulationHz:22,modulationDepth:.5}},{id:"helicopter-heavy",name:"Heavy helicopter",kinds:["helicopter-heavy"],totalDbA:144,shapeDb:[-12,-6,-4,-4,-7,-11,-17,-25],character:{modulationHz:17,modulationDepth:.5}},{id:"military-jet",name:"Military jet",kinds:["military-jet"],totalDbA:152,shapeDb:[-26,-12,-6,-3,-2,-3,-7,-15]},{id:"glider",name:"Glider",kinds:["glider"],totalDbA:85,shapeDb:[-30,-22,-15,-10,-8,-8,-14,-22]},{id:"balloon",name:"Hot-air balloon",kinds:["balloon"],totalDbA:100,shapeDb:[-25,-15,-9,-5,-3,-6,-12,-20]},{id:"unmanned",name:"Unmanned aircraft",kinds:["unmanned"],totalDbA:88,shapeDb:[-40,-30,-20,-12,-6,-3,-3,-8],character:{toneHz:450,toneShare:1}}],it=ot.map(T=>({id:T.id,name:T.name,soundPowerA:T.shapeDb.map(t=>t+T.totalDbA-A.sumDb(T.shapeDb)),character:T.character}));class g{static DEFAULT_AMBIENT_DB_A=35;static DETECTION_MARGIN_DB=3;static AMBIENT_SHAPE_DB=[-12,-7,-5,-5,-7,-11,-17,-25];static HEARING_FLOOR_DB_A=0;static ITERATIONS=30;static CONVERGED_MS=.5;static VELOCITY_STEP_MS=500;static noiseOfKind(t){const e=ot.find(a=>a.kinds.includes(t));return it.find(a=>a.id===(e?.id??"turbofan-narrow-body"))}static bandsAt(t,e,a=A.STANDARD){const n=20*Math.log10(Math.max(e*1e3,1))+11;return A.OCTAVES.map((i,r)=>t.soundPowerA[r]-n-A.absorptionDbPerKm(i,a)*e)}static couldBeHeard(t,e,a=g.DEFAULT_AMBIENT_DB_A,n=A.STANDARD){const i=g.ambientBands(a);return g.bandsAt(t,e,n).some((r,s)=>r>=Math.max(i[s]+g.DETECTION_MARGIN_DB,g.HEARING_FLOOR_DB_A))}static ambientBands(t){const e=g.AMBIENT_SHAPE_DB,a=A.sumDb(e);return e.map(n=>t+n-a)}static heardAt(t,e,a,n={}){const i=n.air??A.STANDARD,r=A.speedOfSound(i.temperatureC),s=t.points[t.points.length-1]?.t;if(s===void 0)return;let o=Math.min(a,s),l=P.positionAt(t,o);if(!l)return;let c=L.seenFrom(e,l.geo);for(let R=0;R<g.ITERATIONS;R++){const O=a-c.distanceKm*1e3*1e3/r,G=Math.abs(O-o);if(o=O,l=P.positionAt(t,o),!l)return;if(c=L.seenFrom(e,l.geo),G<g.CONVERGED_MS)break}const d=P.positionAt(t,a),u=d?L.seenFrom(e,d.geo):c,h=n.noise??it[0],p=n.ambientDbA??g.DEFAULT_AMBIENT_DB_A,m=g.ambientBands(p),f=g.bandsAt(h,c.distanceKm,i),b=f.map((R,O)=>R>=Math.max(m[O]+g.DETECTION_MARGIN_DB,g.HEARING_FLOOR_DB_A)),N=f.indexOf(Math.max(...f)),_=b.lastIndexOf(!0);return{track:t,audible:b.some(Boolean),levelDbA:A.sumDb(f),bandsDbA:f,ambientDbA:p,delayS:(a-o)/1e3,emittedAtMs:o,sound:c,seen:u,lagDeg:g.angleBetween(c,u),dopplerRatio:g.doppler(t,e,o,r),dominantHz:A.OCTAVES[N],cutoffHz:_<0?void 0:A.OCTAVES[_]}}static profile(t,e,a,n,i=2e3,r={}){const s=[];let o,l,c=a;for(let d=a;d<=n;d+=i){const u=g.heardAt(t,e,d,r);u&&(!l||u.levelDbA>l.levelDbA)&&(l=u,c=d),u?.audible?o?o.untilMs=d:s.push(o={fromMs:d,untilMs:d}):o=void 0}return{track:t,audible:s,peakDbA:l?.levelDbA??-1/0,peakAtMs:c,peakDelayS:l?.delayS??0}}static angleBetween(t,e){const a=c=>{const d=c.altitudeDeg*Math.PI/180,u=c.azimuthDeg*Math.PI/180;return[Math.cos(d)*Math.sin(u),Math.cos(d)*Math.cos(u),Math.sin(d)]},[n,i,r]=a(t),[s,o,l]=a(e);return Math.acos(Math.min(1,Math.max(-1,n*s+i*o+r*l)))*180/Math.PI}static doppler(t,e,a,n){const i=g.VELOCITY_STEP_MS,r=P.positionAt(t,a-i),s=P.positionAt(t,a+i);if(!r||!s)return 1;const o=L.seenFrom(e,r.geo).distanceKm*1e3,l=L.seenFrom(e,s.geo).distanceKm*1e3;return 1/(1-(o-l)/(2*i/1e3)/n)}}class Lt{static at(t,e,a,n,i={}){const r=P.seenFrom(t,a,n);if(!r)return;const s=y.of(e),o=g.heardAt(t,a,n,{noise:g.noiseOfKind(s.kind),...i});return{hex:`${t.nonIcao?"~":""}${t.icao.toString(16).padStart(6,"0")}`,registration:e?.registration,typeCode:s.code??e?.type,name:s.basis==="nothing"?void 0:s.name,kind:s.kind,basis:s.basis,military:e?.military===!0,restricted:e?.restricted===!0,altitudeFt:r.altitudeFt,groundSpeedKt:r.groundSpeedKt,trackDeg:r.trackDeg,sky:r.sky,angularRateDegPerS:r.angularRateDegPerS,hearing:o&&{audible:o.audible,levelDbA:o.levelDbA,ambientDbA:o.ambientDbA,delayS:o.delayS,lagDeg:o.lagDeg,dopplerRatio:o.dopplerRatio,cutoffHz:o.cutoffHz,dominantHz:o.dominantHz}}}}class S{static REFERENCE_AMPLITUDE=.02;static MASKING_RANGE_DB=6;static KNEE_DB=20;static COMPRESSION_RATIO=1.5;static EXPANSION_RATIO=1.8;static DEFAULT_MAX_VOICES=4;static candidates(t,e,a,n,i={}){const r=new Set;for(const[s,o]of t){const l=g.noiseOfKind(y.of(e.get(a(o))).kind);let c=1/0;for(const d of o.points)c=Math.min(c,L.seenFrom(n,{lat:d.lat,lng:d.lng,heightM:d.altitudeFt*.3048}).distanceKm);g.couldBeHeard(l,c,i.ambientDbA,i.air)&&r.add(s)}return r}static voices(t,e,a,n,i,r,s={}){const o=[];for(const l of t){const c=e.get(l);if(!c||s.only?.(l)===!1)continue;const d=s.kindOf?.(l)??y.of(a.get(n(c))).kind,u=g.noiseOfKind(d),h=g.heardAt(c,i,r,{...s,noise:u});h?.audible&&o.push({id:l,kind:d,bandAmplitudes:S.bandAmplitudes(h.bandsDbA,h.ambientDbA,s.referenceAmplitude),levelDbA:h.levelDbA,distanceKm:h.sound.distanceKm,dopplerRatio:h.dopplerRatio,azimuthDeg:h.sound.azimuthDeg,elevationDeg:h.sound.altitudeDeg,character:u.character})}return o.sort((l,c)=>c.levelDbA-l.levelDbA).slice(0,s.maxVoices??S.DEFAULT_MAX_VOICES)}static bandAmplitudes(t,e,a=S.REFERENCE_AMPLITUDE){const n=g.ambientBands(e),i=g.DETECTION_MARGIN_DB,r=A.sumDb(t),s=r-e,o=s>=S.KNEE_DB?S.KNEE_DB+(s-S.KNEE_DB)/S.COMPRESSION_RATIO:S.KNEE_DB-(S.KNEE_DB-s)*S.EXPANSION_RATIO,l=a*10**(o/20);return t.map((c,d)=>{const u=Math.min(1,Math.max(0,(c-n[d]-i+S.MASKING_RANGE_DB)/(2*S.MASKING_RANGE_DB)));return u*u*(3-2*u)*l*10**((c-r)/20)})}static BANDS_HZ=A.OCTAVES}class K{static ENGLISH={unnamed:"Aircraft {hex}",altitude:"{value} ft",speed:"{value} kt",heading:"heading {value}°",position:"{distance} km away, {elevation}° above the horizon, {bearing}",heard:"Heard at {level} dB(A), left the aircraft {delay} s ago, {lag}° behind it: {character}{pitch}",rumble:"a low rumble, nothing above {cutoff} Hz",muffled:"a dull noise, nothing above {cutoff} Hz",broad:"a broad roar",pitchHigher:", pitch {percent} % higher",pitchLower:", pitch {percent} % lower",inaudible:"Not audible here: {level} dB(A) against {ambient} dB(A) of ambient noise",soundUnknown:"Its sound cannot be worked out: the aircraft was not recorded yet when it left",contrailPersistent:"Leaves a trail that lasts: the air is supersaturated over ice ({rhi} % over ice)",contrailShort:"Leaves a short-lived trail: the air is dry over ice ({rhi} % over ice)",military:"military",restricted:"identity withheld by its owner",candidate:"A compatible candidate, not an identification"};static RUMBLE_BELOW_HZ=500;static DULL_BELOW_HZ=2e3;static PITCH_NOTICED=.03;static text(t,e,a,n){const i=(u,h=0)=>u.toLocaleString(n,{maximumFractionDigits:h}),r=(u,h)=>u.replace(/\{(\w+)\}/g,(p,m)=>h[m]??`{${m}}`),s=[],o=[t.registration,t.name].filter(Boolean).join(" · ");s.push(o||r(e.unnamed,{hex:t.hex}));const l=[r(e.altitude,{value:i(Math.round(t.altitudeFt/100)*100)}),t.groundSpeedKt===void 0?void 0:r(e.speed,{value:i(Math.round(t.groundSpeedKt))}),t.trackDeg===void 0?void 0:r(e.heading,{value:i(Math.round(t.trackDeg))})].filter(Boolean);s.push(l.join(" · ")),s.push(r(e.position,{distance:i(t.sky.distanceKm,t.sky.distanceKm<10?1:0),elevation:i(Math.round(t.sky.altitudeDeg)),bearing:a(t.sky.azimuthDeg)}));const c=t.hearing;if(!c)s.push(e.soundUnknown);else if(!c.audible)s.push(r(e.inaudible,{level:i(Math.round(c.levelDbA)),ambient:i(Math.round(c.ambientDbA))}));else{const u=c.cutoffHz??0,h=u<=K.RUMBLE_BELOW_HZ?e.rumble:u<=K.DULL_BELOW_HZ?e.muffled:e.broad,p=c.dopplerRatio-1,m=Math.abs(p)<K.PITCH_NOTICED?"":r(p>0?e.pitchHigher:e.pitchLower,{percent:i(Math.round(Math.abs(p)*100))});s.push(r(e.heard,{level:i(Math.round(c.levelDbA)),delay:i(Math.round(c.delayS)),lag:i(Math.round(c.lagDeg)),character:r(h,{cutoff:i(u)}),pitch:m}))}t.contrail&&s.push(r(t.contrail.persistent?e.contrailPersistent:e.contrailShort,{rhi:i(Math.round(t.contrail.iceRelativeHumidity*100))}));const d=[t.military?e.military:void 0,t.restricted?e.restricted:void 0].filter(Boolean);return d.length>0&&s.push(d.join(" · ")),s.push(e.candidate),s.join(`
|
|
2
|
-
`)}}class X{static EFFICIENCY={"airliner-narrow":.34,"airliner-wide":.38,"regional-jet":.32,"business-jet":.3,"military-jet":.22,unknown:.34};static efficiencyOf(t){return X.EFFICIENCY[t]}}class E{static EMISSION_INDEX_WATER=1.25;static COMBUSTION_HEAT=432e5;static AIR_HEAT_CAPACITY=1004;static MOLAR_MASS_RATIO=.622;static FT_TO_M=.3048;static TROPOPAUSE_M=11e3;static TROPOPAUSE_HPA=226.32;static ISOTHERMAL_SCALE_HEIGHT_M=6341.62;static pressureAtAltitudeFt(t){const e=t*E.FT_TO_M;return e<=E.TROPOPAUSE_M?1013.25*(1-225577e-10*e)**5.25588:E.TROPOPAUSE_HPA*Math.exp(-(e-E.TROPOPAUSE_M)/E.ISOTHERMAL_SCALE_HEIGHT_M)}static saturationOverWaterPa(t){const e=t+273.15;return Math.exp(54.842763-6763.22/e-4.21*Math.log(e)+367e-6*e+Math.tanh(.0415*(e-218.8))*(53.878-1331.22/e-9.44523*Math.log(e)+.014025*e))}static saturationOverIcePa(t){const e=t+273.15;return Math.exp(9.550426-5723.265/e+3.53068*Math.log(e)-.00728332*e)}static iceRelativeHumidity(t,e){return e*E.saturationOverWaterPa(t)/E.saturationOverIcePa(t)}static mixingSlope(t,e){return E.EMISSION_INDEX_WATER*E.AIR_HEAT_CAPACITY*t*100/(E.MOLAR_MASS_RATIO*E.COMBUSTION_HEAT*(1-e))}static criticalTemperatureC(t,e){const a=Math.log(E.mixingSlope(t,e)-.053);return-46.46+9.43*a+.72*a*a}static requiredHumidity(t,e,a){const n=E.criticalTemperatureC(t,e);return(E.mixingSlope(t,e)*(a-n)+E.saturationOverWaterPa(n))/E.saturationOverWaterPa(a)}static evaluate(t,e){const a=E.criticalTemperatureC(t.pressureHpa,e),n=E.requiredHumidity(t.pressureHpa,e,t.temperatureC),i=E.iceRelativeHumidity(t.temperatureC,t.relativeHumidity),r=t.temperatureC<a&&t.relativeHumidity>=n;return{forms:r,persistent:r&&i>=1,criticalTemperatureC:a,requiredHumidity:n,iceRelativeHumidity:i}}}class
|
|
1
|
+
import{A as ct,k as lt,T as U,R as L,m as P,r as ht,n as ut}from"./rr0-sighting-editor.mjs";import{C as Y}from"./ContrailGrowth-CuAzwIoc.js";class A{static OCTAVES=[63,125,250,500,1e3,2e3,4e3,8e3];static STANDARD={temperatureC:15,relativeHumidity:.7,pressureKPa:101.325};static REFERENCE_PRESSURE_KPA=101.325;static REFERENCE_TEMPERATURE_K=293.15;static TRIPLE_POINT_K=273.16;static speedOfSound(t){return 20.0468*Math.sqrt(t+273.15)}static absorptionDbPerKm(t,e=A.STANDARD){const a=e.temperatureC+273.15,n=A.REFERENCE_TEMPERATURE_K,i=e.pressureKPa/A.REFERENCE_PRESSURE_KPA,r=10**(-6.8346*(A.TRIPLE_POINT_K/a)**1.261+4.6151),s=e.relativeHumidity*100*r/i,o=i*(24+40400*s*(.02+s)/(.391+s)),l=i*(a/n)**-.5*(9+280*s*Math.exp(-4.17*((a/n)**(-1/3)-1))),c=t*t;return 8.686*c*(184e-13*(1/i)*Math.sqrt(a/n)+(a/n)**-2.5*(.01275*Math.exp(-2239.1/a)/(o+c/o)+.1068*Math.exp(-3352/a)/(l+c/l)))*1e3}static aWeightingDb(t){const e=t*t,a=12194**2*e*e/((e+20.6**2)*Math.sqrt((e+107.7**2)*(e+737.9**2))*(e+12194**2));return 20*Math.log10(a)+2}static sumDb(t){return 10*Math.log10(t.reduce((e,a)=>e+10**(a/10),0))}}const dt=.25,$=.4,J=6,j=12,pt=3,x=.2,mt=.2,gt=24,At=3,Et=12,Z=1,ft=.7,Mt=1.5,bt=.8,Dt=1.3,Q=.9,tt=5,St=25,Rt=.5,Bt=.12,et=[.13,.31],vt=.16,Ot=1.6,It=3.6,at=1.1,Tt=.3,_t=1e3,nt=.7;class V{context;noiseBuffer;roughBuffers=new Map;voices=new Map;bus;reverb;reverbOut;level=1;master;paused=!0;requested=[];headingDeg=0;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(t){console.warn("AircraftAudio: Web Audio unavailable, aircraft stay silent:",t);return}}ct.unlock(this.context),this.apply()}setLevel(t){this.level=t,this.master&&(this.master.gain.value=t)}setPaused(t){t!==this.paused&&(this.paused=t,this.apply())}setVoices(t,e=0){this.requested=t,this.headingDeg=e,this.apply()}dispose(){for(const t of[...this.voices.keys()])this.release(t);this.context?.close(),this.context=void 0,this.master=void 0,this.bus=void 0}apply(){const t=this.context;if(!t)return;const e=this.paused?[]:this.requested,a=new Set(e.map(n=>n.id));for(const n of[...this.voices.keys()])a.has(n)||this.release(n);for(const n of e){const i=this.voices.get(n.id)??this.build(t,n);this.retarget(t,i,n)}}build(t,e){const a=t.createGain();a.gain.value=0;let n;const i=this.busOf(t);typeof t.createStereoPanner=="function"?(n=t.createStereoPanner(),a.connect(n).connect(i)):a.connect(i);const r=t.createGain(),s=e.character?.modulationDepth??0;r.gain.value=1-s/2;const o=t.createOscillator();o.type="sine";const l=t.createGain();l.gain.value=s/2,o.connect(l).connect(r.gain),r.connect(a);const c=t.createBufferSource();c.buffer=this.noise(t),c.loop=!0,c.loopStart=Math.random()*J*.5;const d=[],u=[],h=[];for(const D of A.OCTAVES){const v=t.createBiquadFilter();v.type="bandpass",v.frequency.value=D,v.Q.value=Z;const C=t.createBiquadFilter();C.type="bandpass",C.frequency.value=D,C.Q.value=Z;const w=t.createGain();w.gain.value=0,c.connect(v).connect(C).connect(w).connect(r),d.push(v),u.push(C),h.push(w)}const p=[];for(const[D,v]of[[e.character?.toneHz,e.character?.toneShare],[e.character?.humHz,e.character?.humShare]])if(D!==void 0)for(let C=1;C<=At;C++){const w=t.createOscillator();w.type="sine",w.frequency.value=D*C;const W=t.createGain();W.gain.value=0,w.connect(W).connect(a),p.push({oscillator:w,gain:W,harmonic:C,baseHz:D,share:v??0})}const m=t.createGain();m.gain.value=0,m.connect(a.gain);const f=et.map(D=>{const v=t.createOscillator();return v.type="sine",v.frequency.value=D,v.connect(m),v}),b=t.createGain();b.gain.value=e.character?.roughness??x;const N=t.createBufferSource();N.buffer=this.roughTable(t,pt),N.loop=!0,N.loopStart=Math.random()*j*.5,N.connect(b).connect(r.gain);const _=t.createGain();_.gain.value=(e.character?.roughness??x)*mt;const R=t.createBufferSource();R.buffer=this.roughTable(t,gt),R.loop=!0,R.loopStart=Math.random()*j*.5,R.connect(_).connect(r.gain);let O;const G=this.busOf(t)&&this.reverb;G&&(O=t.createGain(),O.gain.value=0,a.connect(O).connect(G));const z=[c,N,R,o,...p.map(D=>D.oscillator),...f];for(const D of z)D.start();const q={nodes:[a,r,l,b,_,m,...p.map(D=>D.gain),...d,...u,...h,...O?[O]:[],...n?[n]:[],...z],sources:z,filters:d,seconds:u,gains:h,tones:p,lfo:o,lfoDepth:l,wander:f,wanderDepth:m,roughDepth:b,crackleDepth:_,beat:r,output:a,panner:n,send:O};return this.voices.set(e.id,q),q}retarget(t,e,a){const n=t.currentTime,i=(p,m)=>p.setTargetAtTime(m,n,dt),r=Math.min(Mt,Math.max(ft,a.dopplerRatio)),s=Math.min(Dt,Math.max(bt,Math.sqrt(a.dopplerRatio))),o=t.sampleRate*.45,l=a.bandAmplitudes.map((p,m)=>p*V.unweighting(A.OCTAVES[m])),c=Math.sqrt(l.reduce((p,m)=>p+m*m,0)),d=Math.min(1,Math.max(0,(a.distanceKm-tt)/(St-tt)));A.OCTAVES.forEach((p,m)=>{i(e.filters[m].frequency,Math.min(o,p*s)),i(e.seconds[m].frequency,Math.min(o,p*s)),i(e.gains[m].gain,l[m]*Math.sqrt(_t/p))});const u=a.character;for(const{oscillator:p,gain:m,harmonic:f,baseHz:b,share:N}of e.tones){const _=b*f;i(p.frequency,_*r);const R=_*r;i(m.gain,R<o?N*vt*l[V.bandOf(R)]/f:0)}u?.modulationHz!==void 0&&i(e.lfo.frequency,u.modulationHz*r);const h=c>0?nt*(1-Math.exp(-c/nt))/c:1;if(i(e.output.gain,h*(1-Tt*d)),i(e.wanderDepth.gain,h*Bt*d/et.length),e.send&&i(e.send.gain,Ot*d),e.panner){const p=(a.azimuthDeg-this.headingDeg)*Math.PI/180;i(e.panner.pan,Math.max(-Q,Math.min(Q,Math.sin(p)))*(1-Rt*d))}}static unweighting(t){return 10**(Math.min(Et,Math.max(0,-A.aWeightingDb(t)))/20)}static bandOf(t){let e=0;return A.OCTAVES.forEach((a,n)=>{Math.abs(Math.log(t/a))<Math.abs(Math.log(t/A.OCTAVES[e]))&&(e=n)}),e}roughTable(t,e){const a=this.roughBuffers.get(e);if(a)return a;const n=Math.floor(t.sampleRate*j),i=t.createBuffer(1,n,t.sampleRate),r=i.getChannelData(0),s=Array.from({length:j*e},()=>(Math.random()*2-1)**3),o=t.sampleRate/e;for(let l=0;l<r.length;l++){const c=l/o,d=Math.floor(c),u=c-d,h=u*u*(3-2*u);r[l]=s[d%s.length]*(1-h)+s[(d+1)%s.length]*h}return this.roughBuffers.set(e,i),i}roomImpulse(t){const e=Math.floor(t.sampleRate*It),a=t.createBuffer(2,e,t.sampleRate);for(let n=0;n<2;n++){const i=a.getChannelData(n);let r=0;for(let s=0;s<e;s++){const o=s/t.sampleRate,l=.6*Math.exp(-o/(at*2))+.04;r+=l*(Math.random()*2-1-r),i[s]=r*Math.exp(-o/at)}}return a}busOf(t){if(this.bus)return this.bus;const e=t.createGain();if(e.gain.value=this.level,e.connect(t.destination),this.master=e,typeof t.createConvolver=="function"){const a=t.createConvolver();a.buffer=this.roomImpulse(t);const n=t.createGain();n.gain.value=.9,a.connect(n),this.reverb=a,this.reverbOut=n}if(typeof t.createDynamicsCompressor=="function"){const a=t.createDynamicsCompressor();a.threshold.value=-6,a.knee.value=3,a.ratio.value=4,a.attack.value=.005,a.release.value=.25,a.connect(e),this.bus=a}else this.bus=e;return this.reverbOut?.connect(this.bus),this.bus}release(t){const e=this.voices.get(t);if(!e)return;this.voices.delete(t);const a=this.context;a&&(e.output.gain.setTargetAtTime(0,a.currentTime,$/3),setTimeout(()=>{for(const n of e.sources)try{n.stop()}catch{}for(const n of e.nodes)n.disconnect()},$*1e3*3))}noise(t){if(this.noiseBuffer)return this.noiseBuffer;const e=t.createBuffer(1,t.sampleRate*J,t.sampleRate),a=e.getChannelData(0);for(let n=0;n<a.length;n++)a[n]=Math.random()*2-1;return this.noiseBuffer=e,e}}class I{static BASE_DB_A=30;static WIND_DB_A=[[0,10],[1,28],[2,36],[3,40],[5,46],[8,52],[12,58],[20,66]];static RAIN_DB_A=[[0,0],[.1,42],[.3,50],[.6,58],[1,65]];static BED_RMS=.2;static MINIMUM_REFERENCE=.008;static WIND_BED_MIN_MS=1;static WIND_BED_FULL_MS=20;static dbA(t){const e=[I.BASE_DB_A,I.along(I.WIND_DB_A,t.windSpeed)];return(t.precipitationType==="rain"||t.precipitationType==="hail")&&e.push(I.along(I.RAIN_DB_A,t.precipitationIntensity)),10*Math.log10(e.filter(a=>a>0).reduce((a,n)=>a+10**(n/10),0))}static bedVolume(t){const e=t.windSpeed>I.WIND_BED_MIN_MS?Math.min(t.windSpeed/I.WIND_BED_FULL_MS,1):0,a=t.precipitationType==="hail"?Math.min(1,t.precipitationIntensity*1.3+.2):t.precipitationType==="rain"?t.precipitationIntensity:0;return Math.hypot(e,a)}static referenceAmplitude(t){return Math.max(I.BED_RMS*I.bedVolume(t),I.MINIMUM_REFERENCE)}static along(t,e){if(e<=t[0][0])return t[0][1];for(let a=1;a<t.length;a++)if(e<=t[a][0]){const[n,i]=t[a-1],[r,s]=t[a];return i+(s-i)*(e-n)/(r-n)}return t[t.length-1][1]}}class y{static TYPES={A318:["Airbus A318","airliner-narrow",34.1,31.4],A319:["Airbus A319","airliner-narrow",34.1,33.8],A320:["Airbus A320","airliner-narrow",34.1,37.6],A321:["Airbus A321","airliner-narrow",34.1,44.5],A19N:["Airbus A319neo","airliner-narrow",35.8,33.8],A20N:["Airbus A320neo","airliner-narrow",35.8,37.6],A21N:["Airbus A321neo","airliner-narrow",35.8,44.5],B737:["Boeing 737-700","airliner-narrow",34.3,33.6],B738:["Boeing 737-800","airliner-narrow",35.8,39.5],B739:["Boeing 737-900","airliner-narrow",35.8,42.1],B38M:["Boeing 737 MAX 8","airliner-narrow",35.9,39.5],B39M:["Boeing 737 MAX 9","airliner-narrow",35.9,42.2],B752:["Boeing 757-200","airliner-narrow",38,47.3],B753:["Boeing 757-300","airliner-narrow",38,54.4],B762:["Boeing 767-200","airliner-wide",47.6,48.5],B763:["Boeing 767-300","airliner-wide",47.6,54.9],B764:["Boeing 767-400","airliner-wide",51.9,61.4],B772:["Boeing 777-200","airliner-wide",60.9,63.7],B77L:["Boeing 777-200LR","airliner-wide",64.8,63.7],B77W:["Boeing 777-300ER","airliner-wide",64.8,73.9],B788:["Boeing 787-8","airliner-wide",60.1,56.7],B789:["Boeing 787-9","airliner-wide",60.1,62.8],B78X:["Boeing 787-10","airliner-wide",60.1,68.3],B744:["Boeing 747-400","airliner-wide",64.4,70.7],B748:["Boeing 747-8","airliner-wide",68.4,76.3],A306:["Airbus A300-600","airliner-wide",44.8,54.1],A310:["Airbus A310","airliner-wide",43.9,46.7],A332:["Airbus A330-200","airliner-wide",60.3,58.8],A333:["Airbus A330-300","airliner-wide",60.3,63.7],A338:["Airbus A330-800","airliner-wide",64,58.8],A339:["Airbus A330-900","airliner-wide",64,63.7],A343:["Airbus A340-300","airliner-wide",60.3,63.7],A346:["Airbus A340-600","airliner-wide",63.5,75.4],A359:["Airbus A350-900","airliner-wide",64.8,66.8],A35K:["Airbus A350-1000","airliner-wide",64.8,73.8],A388:["Airbus A380-800","airliner-wide",79.8,72.7],E170:["Embraer 170","regional-jet",26,29.9],E75L:["Embraer 175","regional-jet",26,31.7],E75S:["Embraer 175","regional-jet",26,31.7],E190:["Embraer 190","regional-jet",28.7,36.2],E195:["Embraer 195","regional-jet",28.7,38.7],E290:["Embraer 190-E2","regional-jet",33.7,36.2],E295:["Embraer 195-E2","regional-jet",33.7,41.5],CRJ2:["Bombardier CRJ200","regional-jet",21.2,26.8],CRJ7:["Bombardier CRJ700","regional-jet",23.2,32.3],CRJ9:["Bombardier CRJ900","regional-jet",24.9,36.2],CRJX:["Bombardier CRJ1000","regional-jet",26.2,39.1],AT72:["ATR 72","regional-turboprop",27.1,27.2],AT76:["ATR 72-600","regional-turboprop",27.1,27.2],AT45:["ATR 42","regional-turboprop",24.6,22.7],DH8D:["Dash 8 Q400","regional-turboprop",28.4,32.8],DH8C:["Dash 8-300","regional-turboprop",27.4,25.7],SF34:["Saab 340","regional-turboprop",21.4,19.7],B190:["Beechcraft 1900","regional-turboprop",17.7,17.6],C25A:["Cessna CitationJet CJ2","business-jet",14.3,14.4],C56X:["Cessna Citation Excel","business-jet",17.2,16],C68A:["Cessna Citation Latitude","business-jet",22,18.9],C550:["Cessna Citation II","business-jet",15.8,14.4],E55P:["Embraer Phenom 300","business-jet",15.9,15.6],E50P:["Embraer Phenom 100","business-jet",12.3,12.8],GLF5:["Gulfstream G550","business-jet",28.5,29.4],FA7X:["Dassault Falcon 7X","business-jet",26.2,23.4],CL60:["Bombardier Challenger 600","business-jet",19.6,20.9],LJ45:["Learjet 45","business-jet",14.6,17.7],H25B:["Hawker 800","business-jet",15.7,15.6],C172:["Cessna 172","light-piston",11,8.3],C152:["Cessna 152","light-piston",10.2,7.3],C182:["Cessna 182","light-piston",10.9,8.8],P28A:["Piper Cherokee","light-piston",10.7,7.2],PA34:["Piper Seneca","light-piston",11.8,8.7],SR20:["Cirrus SR20","light-piston",10.9,7.9],SR22:["Cirrus SR22","light-piston",11.7,7.9],S22T:["Cirrus SR22T","light-piston",11.7,7.9],DA40:["Diamond DA40","light-piston",11.6,8.1],DA42:["Diamond DA42","light-piston",13.4,8.6],BE20:["Beechcraft King Air 200","turboprop-light",16.6,13.3],BE58:["Beechcraft Baron","light-piston",11.5,9.1],C208:["Cessna Caravan","turboprop-light",15.9,11.5],PC12:["Pilatus PC-12","turboprop-light",16.3,14.4],TBM9:["Daher TBM 900","turboprop-light",12.8,10.7],EC35:["Airbus H135","helicopter-light",10.2,12.1],EC45:["Airbus H145","helicopter-medium",11,13.6],AS50:["Airbus H125","helicopter-light",10.7,12.9],EC30:["Airbus H130","helicopter-light",10.7,12.6],B407:["Bell 407","helicopter-light",10.7,12.7],B06:["Bell 206","helicopter-light",10.2,12],B429:["Bell 429","helicopter-medium",10.9,13],B505:["Bell 505","helicopter-light",10.4,11.9],R44:["Robinson R44","helicopter-light",10.1,11.7],R22:["Robinson R22","helicopter-light",7.7,8.8],A109:["Agusta A109","helicopter-medium",11,13],A139:["Leonardo AW139","helicopter-medium",13.8,16.7],S92:["Sikorsky S-92","helicopter-heavy",17.2,20.9],H60:["Sikorsky UH-60 Black Hawk","helicopter-heavy",16.4,19.8],T38:["Northrop T-38 Talon","military-jet",7.7,14.1],HAWK:["BAE Hawk","military-jet",9.4,11.9],GLID:["Glider","glider",17,7],BALL:["Balloon","balloon",15,20],ULAC:["Ultralight","ultralight",9.5,6],C42:["Ikarus C42","ultralight",9.4,6.3],DRON:["Drone","unmanned",1,.6]};static CATEGORIES={A1:["Light aircraft","light-piston",11,8.3],A2:["Small aircraft","business-jet",15,15],A3:["Large aircraft","airliner-narrow",34.1,37.6],A4:["High-vortex large aircraft","airliner-narrow",38,47.3],A5:["Heavy aircraft","airliner-wide",60.3,63.7],A6:["High-performance aircraft","military-jet",8,14],A7:["Rotorcraft","helicopter-medium",10.7,12.7],B1:["Glider","glider",17,7],B2:["Lighter-than-air","balloon",15,20],B4:["Ultralight","ultralight",9.5,6],B6:["Unmanned aircraft","unmanned",1.5,1]};static GENERIC={name:"Airliner",kind:"airliner-narrow",spanM:34.1,lengthM:37.6,basis:"nothing"};static of(t){const e=t?.type?.toUpperCase(),a=e?y.TYPES[e]:void 0;if(a)return{code:e,name:a[0],kind:a[1],spanM:a[2],lengthM:a[3],basis:"type"};const n=t?.category?y.CATEGORIES[t.category]:void 0;return n?{name:n[0],kind:n[1],spanM:n[2],lengthM:n[3],basis:"category"}:{...y.GENERIC}}static isHelicopter(t){return t.kind.startsWith("helicopter")}}class H{static DUSK_SUN_ELEVATION_DEG=-.83;static ALWAYS=new Set(["airliner-narrow","airliner-wide","regional-turboprop","regional-jet","business-jet"]);static NONE=new Set(["glider","balloon"]);static BRIGHTNESS={"light-piston":[.5,.2,.5],"turboprop-light":[.7,.4,.8],ultralight:[.4,.2,.4],unmanned:[0,.05,0],"helicopter-light":[1,1,1],"helicopter-medium":[1,1,1],"helicopter-heavy":[1,1,1],"military-jet":[1,1,1]};static lampsOn(t,e){if(H.NONE.has(t))return{navigation:!1,beacon:!1,strobes:!1};if(H.ALWAYS.has(t))return{navigation:!0,beacon:!0,strobes:!0};const a=e<H.DUSK_SUN_ELEVATION_DEG;return t==="unmanned"?{navigation:!1,beacon:!1,strobes:a}:{navigation:a,beacon:a,strobes:a}}static lights(t,e){const a=H.lampsOn(t.kind,e),n=t.kind.startsWith("helicopter"),i=lt.find(h=>h.id===(n?"helicopter":"airliner")).create(),[r,s]=n?[5,7]:[17,18],o=t.spanM/2/r,l=t.lengthM/2/s,[c,d,u]=H.BRIGHTNESS[t.kind]??[1,1,1];return i.filter(h=>h.id.startsWith("nav")?a.navigation:h.id.startsWith("strobe")?a.strobes:h.id.startsWith("beacon")?a.beacon:!0).filter(h=>!(h.id.startsWith("beacon")&&!a.beacon)).map(h=>{const p=h.id.startsWith("nav")?c:h.id.startsWith("strobe")?d:u;return{...h,offsetM:{x:h.offsetM.x*o,y:h.offsetM.y,z:h.offsetM.z*l},intensity:(h.intensity??1)*p}}).filter(h=>(h.intensity??1)>0)}static bodyColor(t){return t.kind==="military-jet"?"#8a8e94":t.kind.startsWith("helicopter")?"#c8ccd1":t.kind==="unmanned"?"#2c2e33":"#dde0e4"}}class F{static FAMILIES={"amvlab-a320":["A318","A319","A320","A321","A19N","A20N","A21N"],"amvlab-b737":["B732","B733","B734","B735","B736","B737","B738","B739","B37M","B38M","B39M","B3XM"],"amvlab-a350":["A359","A35K"],"amvlab-a380":["A388"],"amvlab-b787":["B788","B789","B78X"]};static BY_TYPE=new Map(Object.entries(F.FAMILIES).flatMap(([t,e])=>e.map(a=>[a,t])));static idOf(t){return t?F.BY_TYPE.get(t.toUpperCase()):void 0}}class M{static ID_PREFIX=U.ID_PREFIX;static MAX_OBJECTS=40;static FT_TO_M=.3048;static DEG=Math.PI/180;static from(t,e,a,n=M.MAX_OBJECTS,i={}){return new Ct(t,e,a,n,i).build()}static idOf(t,e){return U.idOf(t,e)}static keyOf(t){return U.keyOf(t)}static HEIGHT_OVER_LENGTH=.29;static sizeOf(t){return{widthM:t.spanM,lengthM:t.lengthM,heightM:t.lengthM*M.HEIGHT_OVER_LENGTH}}static offsetOf(t,e){const a=L.seenFrom(t,{lat:e.lat,lng:e.lng,heightM:e.altitudeFt*M.FT_TO_M}),n=a.distanceKm*1e3,i=n*Math.cos(a.altitudeDeg*M.DEG);return{eastM:i*Math.sin(a.azimuthDeg*M.DEG),northM:i*Math.cos(a.azimuthDeg*M.DEG),upM:n*Math.sin(a.altitudeDeg*M.DEG),altitudeDeg:a.altitudeDeg,distanceKm:a.distanceKm}}static segments(t){const e=[];let a=[];for(const n of t.points){const i=a[a.length-1];i&&n.t-i.t>P.MAX_GAP_S*1e3&&(e.push(a),a=[]),a.push(n)}return e.push(a),e.filter(n=>n.length>=2)}static bearingDeg(t,e){return(Math.atan2(e.eastM-t.eastM,e.northM-t.northM)/M.DEG+360)%360}}class Ct{constructor(t,e,a,n,i){this.tracks=t,this.observer=e,this.startMs=a,this.maxObjects=n,this.options=i}build(){const t=[];for(const a of this.tracks){const n=M.keyOf(a),i=this.options.models?.get(n)??y.of(void 0);M.segments(a).forEach((r,s)=>{const o=r.map(h=>({point:h,at:M.offsetOf(this.observer,h)}));if(!o.some(h=>h.at.altitudeDeg>=0))return;const l=o.map((h,p)=>({t:h.point.t-this.startMs,eastM:h.at.eastM,northM:h.at.northM,altitudeM:h.at.upM,headingDeg:h.point.trackDeg??(p+1<o.length?M.bearingDeg(h.at,o[p+1].at):M.bearingDeg(o[p-1].at,h.at))})),c=M.idOf(a,s),d=o[Math.floor(o.length/2)].point,u=this.options.sunElevationAt?.(d)??90;t.push({object:{id:c,kind:"aircraft",eastM:l[0].eastM,northM:l[0].northM,headingDeg:l[0].headingDeg,sizeM:M.sizeOf(i),model:F.idOf(i.code)?{id:F.idOf(i.code)}:void 0,color:H.bodyColor(i),lights:H.lights(i,u),track:l},presence:{fromMs:l[0].t,untilMs:l[l.length-1].t},flight:{icao:a.icao,nonIcao:a.nonIcao,points:r},closestKm:Math.min(...o.map(h=>h.at.distanceKm))})})}t.sort((a,n)=>a.closestKm-n.closestKm);const e=t.slice(0,this.maxObjects);return{objects:e.map(a=>a.object),presence:new Map(e.map(a=>[a.object.id,a.presence])),flights:new Map(e.map(a=>[a.object.id,a.flight])),total:t.length,shown:e.length}}}const ot=[{id:"turbofan-narrow-body",name:"Turbofan airliner, narrow-body",kinds:["airliner-narrow"],totalDbA:148,shapeDb:[-32,-17,-9,-6,-5,-7,-12,-22],character:{toneHz:1800,toneShare:.3,humHz:90,humShare:.7}},{id:"turbofan-wide-body",name:"Turbofan airliner, wide-body",kinds:["airliner-wide"],totalDbA:151,shapeDb:[-28,-14,-7,-4,-3,-6,-12,-22],character:{toneHz:1200,toneShare:.3,humHz:70,humShare:.7}},{id:"regional-jet",name:"Regional jet",kinds:["regional-jet"],totalDbA:144,shapeDb:[-32,-17,-9,-5,-4,-6,-11,-21],character:{toneHz:1900,toneShare:.3,humHz:95,humShare:.7}},{id:"business-jet",name:"Business jet",kinds:["business-jet"],totalDbA:141,shapeDb:[-30,-15,-8,-4,-3,-4,-9,-19],character:{toneHz:2500,toneShare:.25,humHz:110,humShare:.7}},{id:"turboprop",name:"Turboprop",kinds:["regional-turboprop","turboprop-light"],totalDbA:138,shapeDb:[-14,-9,-8,-6,-8,-13,-20,-28],character:{toneHz:80,toneShare:.5}},{id:"light-piston",name:"Light piston aircraft",kinds:["light-piston"],totalDbA:130,shapeDb:[-18,-9,-5,-4,-8,-14,-22,-30],character:{toneHz:80,toneShare:.4}},{id:"ultralight",name:"Ultralight",kinds:["ultralight"],totalDbA:124,shapeDb:[-16,-8,-5,-4,-9,-15,-23,-31],character:{toneHz:140,toneShare:.4}},{id:"helicopter-light",name:"Light helicopter",kinds:["helicopter-light"],totalDbA:134,shapeDb:[-15,-8,-4,-3,-6,-10,-16,-24],character:{modulationHz:20,modulationDepth:.5}},{id:"helicopter-medium",name:"Medium helicopter",kinds:["helicopter-medium"],totalDbA:138,shapeDb:[-14,-7,-4,-3,-6,-10,-16,-24],character:{modulationHz:22,modulationDepth:.5}},{id:"helicopter-heavy",name:"Heavy helicopter",kinds:["helicopter-heavy"],totalDbA:144,shapeDb:[-12,-6,-4,-4,-7,-11,-17,-25],character:{modulationHz:17,modulationDepth:.5}},{id:"military-jet",name:"Military jet",kinds:["military-jet"],totalDbA:152,shapeDb:[-26,-12,-6,-3,-2,-3,-7,-15]},{id:"glider",name:"Glider",kinds:["glider"],totalDbA:85,shapeDb:[-30,-22,-15,-10,-8,-8,-14,-22]},{id:"balloon",name:"Hot-air balloon",kinds:["balloon"],totalDbA:100,shapeDb:[-25,-15,-9,-5,-3,-6,-12,-20]},{id:"unmanned",name:"Unmanned aircraft",kinds:["unmanned"],totalDbA:88,shapeDb:[-40,-30,-20,-12,-6,-3,-3,-8],character:{toneHz:450,toneShare:1}}],it=ot.map(T=>({id:T.id,name:T.name,soundPowerA:T.shapeDb.map(t=>t+T.totalDbA-A.sumDb(T.shapeDb)),character:T.character}));class g{static DEFAULT_AMBIENT_DB_A=35;static DETECTION_MARGIN_DB=3;static AMBIENT_SHAPE_DB=[-12,-7,-5,-5,-7,-11,-17,-25];static HEARING_FLOOR_DB_A=0;static ITERATIONS=30;static CONVERGED_MS=.5;static VELOCITY_STEP_MS=500;static noiseOfKind(t){const e=ot.find(a=>a.kinds.includes(t));return it.find(a=>a.id===(e?.id??"turbofan-narrow-body"))}static bandsAt(t,e,a=A.STANDARD){const n=20*Math.log10(Math.max(e*1e3,1))+11;return A.OCTAVES.map((i,r)=>t.soundPowerA[r]-n-A.absorptionDbPerKm(i,a)*e)}static couldBeHeard(t,e,a=g.DEFAULT_AMBIENT_DB_A,n=A.STANDARD){const i=g.ambientBands(a);return g.bandsAt(t,e,n).some((r,s)=>r>=Math.max(i[s]+g.DETECTION_MARGIN_DB,g.HEARING_FLOOR_DB_A))}static ambientBands(t){const e=g.AMBIENT_SHAPE_DB,a=A.sumDb(e);return e.map(n=>t+n-a)}static heardAt(t,e,a,n={}){const i=n.air??A.STANDARD,r=A.speedOfSound(i.temperatureC),s=t.points[t.points.length-1]?.t;if(s===void 0)return;let o=Math.min(a,s),l=P.positionAt(t,o);if(!l)return;let c=L.seenFrom(e,l.geo);for(let R=0;R<g.ITERATIONS;R++){const O=a-c.distanceKm*1e3*1e3/r,G=Math.abs(O-o);if(o=O,l=P.positionAt(t,o),!l)return;if(c=L.seenFrom(e,l.geo),G<g.CONVERGED_MS)break}const d=P.positionAt(t,a),u=d?L.seenFrom(e,d.geo):c,h=n.noise??it[0],p=n.ambientDbA??g.DEFAULT_AMBIENT_DB_A,m=g.ambientBands(p),f=g.bandsAt(h,c.distanceKm,i),b=f.map((R,O)=>R>=Math.max(m[O]+g.DETECTION_MARGIN_DB,g.HEARING_FLOOR_DB_A)),N=f.indexOf(Math.max(...f)),_=b.lastIndexOf(!0);return{track:t,audible:b.some(Boolean),levelDbA:A.sumDb(f),bandsDbA:f,ambientDbA:p,delayS:(a-o)/1e3,emittedAtMs:o,sound:c,seen:u,lagDeg:g.angleBetween(c,u),dopplerRatio:g.doppler(t,e,o,r),dominantHz:A.OCTAVES[N],cutoffHz:_<0?void 0:A.OCTAVES[_]}}static profile(t,e,a,n,i=2e3,r={}){const s=[];let o,l,c=a;for(let d=a;d<=n;d+=i){const u=g.heardAt(t,e,d,r);u&&(!l||u.levelDbA>l.levelDbA)&&(l=u,c=d),u?.audible?o?o.untilMs=d:s.push(o={fromMs:d,untilMs:d}):o=void 0}return{track:t,audible:s,peakDbA:l?.levelDbA??-1/0,peakAtMs:c,peakDelayS:l?.delayS??0}}static angleBetween(t,e){const a=c=>{const d=c.altitudeDeg*Math.PI/180,u=c.azimuthDeg*Math.PI/180;return[Math.cos(d)*Math.sin(u),Math.cos(d)*Math.cos(u),Math.sin(d)]},[n,i,r]=a(t),[s,o,l]=a(e);return Math.acos(Math.min(1,Math.max(-1,n*s+i*o+r*l)))*180/Math.PI}static doppler(t,e,a,n){const i=g.VELOCITY_STEP_MS,r=P.positionAt(t,a-i),s=P.positionAt(t,a+i);if(!r||!s)return 1;const o=L.seenFrom(e,r.geo).distanceKm*1e3,l=L.seenFrom(e,s.geo).distanceKm*1e3;return 1/(1-(o-l)/(2*i/1e3)/n)}}class Lt{static at(t,e,a,n,i={}){const r=P.seenFrom(t,a,n);if(!r)return;const s=y.of(e),o=g.heardAt(t,a,n,{noise:g.noiseOfKind(s.kind),...i});return{hex:`${t.nonIcao?"~":""}${t.icao.toString(16).padStart(6,"0")}`,registration:e?.registration,typeCode:s.code??e?.type,name:s.basis==="nothing"?void 0:s.name,kind:s.kind,basis:s.basis,military:e?.military===!0,restricted:e?.restricted===!0,altitudeFt:r.altitudeFt,groundSpeedKt:r.groundSpeedKt,trackDeg:r.trackDeg,sky:r.sky,angularRateDegPerS:r.angularRateDegPerS,hearing:o&&{audible:o.audible,levelDbA:o.levelDbA,ambientDbA:o.ambientDbA,delayS:o.delayS,lagDeg:o.lagDeg,dopplerRatio:o.dopplerRatio,cutoffHz:o.cutoffHz,dominantHz:o.dominantHz}}}}class S{static REFERENCE_AMPLITUDE=.02;static MASKING_RANGE_DB=6;static KNEE_DB=20;static COMPRESSION_RATIO=1.5;static EXPANSION_RATIO=1.8;static DEFAULT_MAX_VOICES=4;static candidates(t,e,a,n,i={}){const r=new Set;for(const[s,o]of t){const l=g.noiseOfKind(y.of(e.get(a(o))).kind);let c=1/0;for(const d of o.points)c=Math.min(c,L.seenFrom(n,{lat:d.lat,lng:d.lng,heightM:d.altitudeFt*.3048}).distanceKm);g.couldBeHeard(l,c,i.ambientDbA,i.air)&&r.add(s)}return r}static voices(t,e,a,n,i,r,s={}){const o=[];for(const l of t){const c=e.get(l);if(!c||s.only?.(l)===!1)continue;const d=s.kindOf?.(l)??y.of(a.get(n(c))).kind,u=g.noiseOfKind(d),h=g.heardAt(c,i,r,{...s,noise:u});h?.audible&&o.push({id:l,kind:d,bandAmplitudes:S.bandAmplitudes(h.bandsDbA,h.ambientDbA,s.referenceAmplitude),levelDbA:h.levelDbA,distanceKm:h.sound.distanceKm,dopplerRatio:h.dopplerRatio,azimuthDeg:h.sound.azimuthDeg,elevationDeg:h.sound.altitudeDeg,character:u.character})}return o.sort((l,c)=>c.levelDbA-l.levelDbA).slice(0,s.maxVoices??S.DEFAULT_MAX_VOICES)}static bandAmplitudes(t,e,a=S.REFERENCE_AMPLITUDE){const n=g.ambientBands(e),i=g.DETECTION_MARGIN_DB,r=A.sumDb(t),s=r-e,o=s>=S.KNEE_DB?S.KNEE_DB+(s-S.KNEE_DB)/S.COMPRESSION_RATIO:S.KNEE_DB-(S.KNEE_DB-s)*S.EXPANSION_RATIO,l=a*10**(o/20);return t.map((c,d)=>{const u=Math.min(1,Math.max(0,(c-n[d]-i+S.MASKING_RANGE_DB)/(2*S.MASKING_RANGE_DB)));return u*u*(3-2*u)*l*10**((c-r)/20)})}static BANDS_HZ=A.OCTAVES}class K{static ENGLISH={unnamed:"Aircraft {hex}",altitude:"{value} ft",speed:"{value} kt",heading:"heading {value}°",position:"{distance} km away, {elevation}° above the horizon, {bearing}",heard:"Heard at {level} dB(A), left the aircraft {delay} s ago, {lag}° behind it: {character}{pitch}",rumble:"a low rumble, nothing above {cutoff} Hz",muffled:"a dull noise, nothing above {cutoff} Hz",broad:"a broad roar",pitchHigher:", pitch {percent} % higher",pitchLower:", pitch {percent} % lower",inaudible:"Not audible here: {level} dB(A) against {ambient} dB(A) of ambient noise",soundUnknown:"Its sound cannot be worked out: the aircraft was not recorded yet when it left",contrailPersistent:"Leaves a trail that lasts: the air is supersaturated over ice ({rhi} % over ice)",contrailShort:"Leaves a short-lived trail: the air is dry over ice ({rhi} % over ice)",military:"military",restricted:"identity withheld by its owner",candidate:"A compatible candidate, not an identification"};static RUMBLE_BELOW_HZ=500;static DULL_BELOW_HZ=2e3;static PITCH_NOTICED=.03;static text(t,e,a,n){const i=(u,h=0)=>u.toLocaleString(n,{maximumFractionDigits:h}),r=(u,h)=>u.replace(/\{(\w+)\}/g,(p,m)=>h[m]??`{${m}}`),s=[],o=[t.registration,t.name].filter(Boolean).join(" · ");s.push(o||r(e.unnamed,{hex:t.hex}));const l=[r(e.altitude,{value:i(Math.round(t.altitudeFt/100)*100)}),t.groundSpeedKt===void 0?void 0:r(e.speed,{value:i(Math.round(t.groundSpeedKt))}),t.trackDeg===void 0?void 0:r(e.heading,{value:i(Math.round(t.trackDeg))})].filter(Boolean);s.push(l.join(" · ")),s.push(r(e.position,{distance:i(t.sky.distanceKm,t.sky.distanceKm<10?1:0),elevation:i(Math.round(t.sky.altitudeDeg)),bearing:a(t.sky.azimuthDeg)}));const c=t.hearing;if(!c)s.push(e.soundUnknown);else if(!c.audible)s.push(r(e.inaudible,{level:i(Math.round(c.levelDbA)),ambient:i(Math.round(c.ambientDbA))}));else{const u=c.cutoffHz??0,h=u<=K.RUMBLE_BELOW_HZ?e.rumble:u<=K.DULL_BELOW_HZ?e.muffled:e.broad,p=c.dopplerRatio-1,m=Math.abs(p)<K.PITCH_NOTICED?"":r(p>0?e.pitchHigher:e.pitchLower,{percent:i(Math.round(Math.abs(p)*100))});s.push(r(e.heard,{level:i(Math.round(c.levelDbA)),delay:i(Math.round(c.delayS)),lag:i(Math.round(c.lagDeg)),character:r(h,{cutoff:i(u)}),pitch:m}))}t.contrail&&s.push(r(t.contrail.persistent?e.contrailPersistent:e.contrailShort,{rhi:i(Math.round(t.contrail.iceRelativeHumidity*100))}));const d=[t.military?e.military:void 0,t.restricted?e.restricted:void 0].filter(Boolean);return d.length>0&&s.push(d.join(" · ")),s.push(e.candidate),s.join(`
|
|
2
|
+
`)}}class X{static EFFICIENCY={"airliner-narrow":.34,"airliner-wide":.38,"regional-jet":.32,"business-jet":.3,"military-jet":.22,unknown:.34};static efficiencyOf(t){return X.EFFICIENCY[t]}}class E{static EMISSION_INDEX_WATER=1.25;static COMBUSTION_HEAT=432e5;static AIR_HEAT_CAPACITY=1004;static MOLAR_MASS_RATIO=.622;static FT_TO_M=.3048;static TROPOPAUSE_M=11e3;static TROPOPAUSE_HPA=226.32;static ISOTHERMAL_SCALE_HEIGHT_M=6341.62;static pressureAtAltitudeFt(t){const e=t*E.FT_TO_M;return e<=E.TROPOPAUSE_M?1013.25*(1-225577e-10*e)**5.25588:E.TROPOPAUSE_HPA*Math.exp(-(e-E.TROPOPAUSE_M)/E.ISOTHERMAL_SCALE_HEIGHT_M)}static saturationOverWaterPa(t){const e=t+273.15;return Math.exp(54.842763-6763.22/e-4.21*Math.log(e)+367e-6*e+Math.tanh(.0415*(e-218.8))*(53.878-1331.22/e-9.44523*Math.log(e)+.014025*e))}static saturationOverIcePa(t){const e=t+273.15;return Math.exp(9.550426-5723.265/e+3.53068*Math.log(e)-.00728332*e)}static iceRelativeHumidity(t,e){return e*E.saturationOverWaterPa(t)/E.saturationOverIcePa(t)}static mixingSlope(t,e){return E.EMISSION_INDEX_WATER*E.AIR_HEAT_CAPACITY*t*100/(E.MOLAR_MASS_RATIO*E.COMBUSTION_HEAT*(1-e))}static criticalTemperatureC(t,e){const a=Math.log(E.mixingSlope(t,e)-.053);return-46.46+9.43*a+.72*a*a}static requiredHumidity(t,e,a){const n=E.criticalTemperatureC(t,e);return(E.mixingSlope(t,e)*(a-n)+E.saturationOverWaterPa(n))/E.saturationOverWaterPa(a)}static evaluate(t,e){const a=E.criticalTemperatureC(t.pressureHpa,e),n=E.requiredHumidity(t.pressureHpa,e,t.temperatureC),i=E.iceRelativeHumidity(t.temperatureC,t.relativeHumidity),r=t.temperatureC<a&&t.relativeHumidity>=n;return{forms:r,persistent:r&&i>=1,criticalTemperatureC:a,requiredHumidity:n,iceRelativeHumidity:i}}}class k{static HOLD_MS=36e5;static DEG=Math.PI/180;static GAS_CONSTANT_OVER_GRAVITY=287.05/9.80665;static at(t,e,a){if(t.length===0)return;const n=t[0],i=t[t.length-1];if(e<n.t-k.HOLD_MS||e>i.t+k.HOLD_MS)return;const r=t.findIndex(h=>h.t>e),s=r===0?t[0]:t[(r===-1?t.length:r)-1],o=r===-1||r===0?s:t[r],l=k.atLevel(s,a),c=k.atLevel(o,a);if(!l||!c)return;const d=o.t>s.t?Math.min(1,Math.max(0,(e-s.t)/(o.t-s.t))):0,u=(h,p)=>h+(p-h)*d;return{pressureHpa:a,temperatureC:u(l.temperatureC,c.temperatureC),relativeHumidity:u(l.relativeHumidity,c.relativeHumidity),driftEastMs:u(l.driftEastMs,c.driftEastMs),driftNorthMs:u(l.driftNorthMs,c.driftNorthMs),shearPerS:u(l.shearPerS,c.shearPerS)}}static atLevel(t,e){const a=t.levels;for(let n=0;n+1<a.length;n++){const i=a[n],r=a[n+1];if(e>i.pressureHpa||e<r.pressureHpa)continue;const s=(Math.log(i.pressureHpa)-Math.log(e))/(Math.log(i.pressureHpa)-Math.log(r.pressureHpa)),o=(h,p)=>h+(p-h)*s,l=h=>{const p=h.windFromDeg*k.DEG;return{east:-h.windSpeedMs*Math.sin(p),north:-h.windSpeedMs*Math.cos(p)}},c=l(i),d=l(r),u=k.GAS_CONSTANT_OVER_GRAVITY*((i.temperatureC+r.temperatureC)/2+273.15)*Math.log(i.pressureHpa/r.pressureHpa);return{pressureHpa:e,temperatureC:o(i.temperatureC,r.temperatureC),relativeHumidity:o(i.relativeHumidity,r.relativeHumidity),driftEastMs:o(c.east,d.east),driftNorthMs:o(c.north,d.north),shearPerS:Math.hypot(d.east-c.east,d.north-c.north)/u}}}}class Pt{static plan(t,e,a,n){if(a.length===0)return[];const i=[];for(const r of t.objects){const s=t.flights.get(r.id),o=r.track;if(!s||!o||o.length!==s.points.length)continue;const l=e?.get(U.keyOf(s))??y.of(void 0),c=X.efficiencyOf(l.kind);if(c===void 0)continue;const d=[];o.forEach((u,h)=>{const p=s.points[h],m=E.pressureAtAltitudeFt(p.altitudeFt),f=k.at(a,n+u.t,m),b=f&&E.evaluate(f,c);d.push({tMs:u.t,eastM:u.eastM,northM:u.northM,upM:u.altitudeM??0,forms:b?.forms??!1,persistent:b?.persistent??!1,lifetimeS:b?Y.lifetimeS(b.iceRelativeHumidity):0,driftEastMs:f?.driftEastMs??0,driftNorthMs:f?.driftNorthMs??0,shearPerS:f?.shearPerS??Y.TYPICAL_SHEAR_PER_S,iceRelativeHumidity:b?.iceRelativeHumidity??0})}),d.some((u,h)=>u.forms&&d[h+1]?.forms)&&i.push({id:r.id,spanM:l.spanM,points:d})}return i}}const st=[500,400,300,250,200,150],Nt=["temperature","relative_humidity","wind_speed","wind_direction"],yt="2022-01-01",rt=.25;class wt{fetchImpl;baseUrl;cache=new Map;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.baseUrl=t.baseUrl??"https://historical-forecast-api.open-meteo.com/v1/forecast"}between(t,e,a){const n=new Date(e).toISOString().slice(0,10);if(n<yt)return Promise.resolve({status:"outside"});const i=new Date(a).toISOString().slice(0,10),s=`${`${Math.round(t.lat/rt)},${Math.round(t.lng/rt)}`}|${n}|${i}`;let o=this.cache.get(s);return o||(o=this.read(t,n,i),this.cache.set(s,o),o.then(l=>{l.status==="failed"&&this.cache.delete(s)})),o}async read(t,e,a){const n=st.flatMap(s=>Nt.map(o=>`${o}_${s}hPa`)),i=new URLSearchParams({latitude:String(t.lat),longitude:String(t.lng),start_date:e,end_date:a,hourly:n.join(","),wind_speed_unit:"ms",timezone:"UTC"}),r=`${this.baseUrl}?${i}`;try{const s=await this.fetchImpl(r);if(!s.ok)return{status:"failed"};const o=await s.json();return this.decode(o,{id:"open-meteo-forecast",name:"Open-Meteo (historical forecast)",url:r})}catch{return{status:"failed"}}}decode(t,e){const a=t.hourly;if(!a?.time)return{status:"outside"};const n=[];return a.time.forEach((i,r)=>{const s=[];for(const o of st){const l=p=>a[`${p}_${o}hPa`]?.[r],c=l("temperature"),d=l("relative_humidity"),u=l("wind_speed"),h=l("wind_direction");if([c,d,u,h].some(p=>p==null))return;s.push({pressureHpa:o,temperatureC:c,relativeHumidity:d/100,windSpeedMs:u,windFromDeg:h})}n.push({t:Date.parse(`${i}Z`),levels:s})}),n.length>0?{status:"found",samples:n,source:e}:{status:"outside"}}}const Ft=[{id:"open-meteo-forecast",name:"Open-Meteo (historical forecast)",credit:"Weather data by Open-Meteo.com, CC BY 4.0",creditUrl:"https://open-meteo.com/en/docs/historical-forecast-api",create:()=>new wt}];class B{static DEFAULT_KIND="airliner-narrow";static STEP_MS=1e3;static LEAD_MS=12e4;static FT_PER_M=1/.3048;static ID_PREFIX="decor:";tracks=new Map;static kindOf(t,e){if(t.kind!=="aircraft"||!B.flies(t))return;const a=t.aircraftSound??e??B.DEFAULT_KIND;return a==="silent"?void 0:a}static flies(t){return(t.track??[]).some(e=>(e.altitudeM??0)>0)}voices(t,e,a,n={},i=()=>{}){const r=t.event.place?.[0];if(!r)return[];const s=new Map,o=new Map,l=Math.max(t.observerTrack.duration,(t.event.durationSeconds??0)*1e3);for(const c of t.decor){const d=B.kindOf(c,i(c));if(!d)continue;const u=`${B.ID_PREFIX}${c.id}`;s.set(u,this.trackOf(c,u,r,l)),o.set(u,d)}for(const c of this.tracks.keys())s.has(c)||this.tracks.delete(c);return s.size===0?[]:S.voices(new Set(s.keys()),s,new Map,c=>String(c.icao),a,e,{...n,kindOf:c=>o.get(c)})}trackOf(t,e,a,n){const i=JSON.stringify([t.track,t.eastM,t.northM,t.headingDeg,a.lat,a.lng,n]),r=this.tracks.get(e);if(r?.key===i)return r.track;const s=[];for(let u=0;u<=n;u+=B.STEP_MS)s.push(B.pointAt(t,u,a));(s.length===0||s[s.length-1].t<n)&&s.push(B.pointAt(t,n,a));const o=s[0],l=s[1]??o,c=u=>(l[u]-o[u])/(l.t-o.t||1);for(let u=B.STEP_MS*10;u<=B.LEAD_MS;u+=B.STEP_MS*10)s.unshift({t:-u,lat:o.lat-c("lat")*u,lng:o.lng-c("lng")*u,altitudeFt:Math.max(0,o.altitudeFt-c("altitudeFt")*u)});const d={icao:B.hash(e),nonIcao:!0,points:s};return this.tracks.set(e,{key:i,track:d}),d}static pointAt(t,e,a){const n=ht(t,e),i=ut(n.eastM,-n.northM,a.lat,a.lng);return{t:e,lat:i.lat,lng:i.lng,altitudeFt:n.altitudeM*B.FT_PER_M}}static hash(t){let e=0;for(let a=0;a<t.length;a++)e=e*31+t.charCodeAt(a)>>>0;return e}}export{V as AircraftAudio,Pt as AircraftContrails,y as AircraftModels,I as AmbientNoise,B as DecorAircraftHearing,M as TrafficDecor,Lt as TrafficInfos,S as TrafficSound,K as TrafficTooltip,Ft as UPPER_AIR_SOURCES};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rr0/ufoathome",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.123.0",
|
|
5
5
|
"description": "UFO@home — record and replay a UFO sighting's shape, movement and appearance",
|
|
6
6
|
"author": "Jérôme Beau <rr0@rr0.org> (https://rr0.org)",
|
|
7
7
|
"license": "MIT",
|
|
@@ -18,12 +18,14 @@
|
|
|
18
18
|
"./sighting": "./dist-embed-sighting/rr0-sighting.mjs",
|
|
19
19
|
"./editor": "./dist-embed-sighting-editor/rr0-sighting-editor.mjs",
|
|
20
20
|
"./eyewitness": "./dist-embed-sighting/rr0-sighting.mjs",
|
|
21
|
-
"./recorder": "./dist-embed-sighting-editor/rr0-sighting-editor.mjs"
|
|
21
|
+
"./recorder": "./dist-embed-sighting-editor/rr0-sighting-editor.mjs",
|
|
22
|
+
"./interview": "./dist-embed-interview/rr0-interview.mjs"
|
|
22
23
|
},
|
|
23
24
|
"files": [
|
|
24
25
|
"dist-embed-scene",
|
|
25
26
|
"dist-embed-sighting",
|
|
26
|
-
"dist-embed-sighting-editor"
|
|
27
|
+
"dist-embed-sighting-editor",
|
|
28
|
+
"dist-embed-interview"
|
|
27
29
|
],
|
|
28
30
|
"scripts": {
|
|
29
31
|
"predev": "npm run build:schema",
|
|
@@ -32,12 +34,14 @@
|
|
|
32
34
|
"build": "tsc --noEmit && vite build",
|
|
33
35
|
"build:embed-scene": "tsc --noEmit && vite build --config vite.embed-scene.config.ts",
|
|
34
36
|
"build:embed-sighting": "tsc --noEmit && vite build --config vite.embed-sighting.config.ts",
|
|
35
|
-
"build:
|
|
36
|
-
"build:
|
|
37
|
+
"build:embed-interview": "vite build --config vite.embed-interview.config.ts",
|
|
38
|
+
"build:all": "npm run build:schema && npm run build && npm run build:embed-sighting-editor && npm run build:embed-scene && npm run build:embed-sighting && npm run build:embed-interview",
|
|
39
|
+
"build:site": "npm run build:schema && npm run build:embed-sighting-editor && npm run build:embed-scene && npm run build:embed-sighting && npm run build:embed-interview && vite build --config vite.site.config.ts && tsx site/build.ts",
|
|
37
40
|
"site": "tsx site/build.ts",
|
|
38
41
|
"site:watch": "node --watch-path=./site --watch-path=./public/demo-data --import tsx site/build.ts",
|
|
42
|
+
"deploy:site": "npm run build:site && npx netlify deploy --prod --dir dist-site --no-build --site 90e69d49-ac43-433a-9829-3cb861a623ef",
|
|
39
43
|
"site:serve": "vite preview --outDir dist-site --port 5181 --strictPort",
|
|
40
|
-
"prepublishOnly": "npm run build:schema && npm run build:embed-sighting-editor && npm run build:embed-scene && npm run build:embed-sighting && npm test",
|
|
44
|
+
"prepublishOnly": "npm run build:schema && npm run build:embed-sighting-editor && npm run build:embed-scene && npm run build:embed-sighting && npm run build:embed-interview && npm test",
|
|
41
45
|
"preview": "vite preview",
|
|
42
46
|
"test": "vitest run",
|
|
43
47
|
"test:watch": "vitest",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e={event:"Evento",accountOf:"Observación de",interviewOf:"Entrevista a",untitledInterview:"Entrevista {n}",deleteInterviewQuestion:"¿Eliminar esta entrevista del caso? Nada se escribe hasta guardar el caso.",untitledReading:"Lectura {n}",untitledObservation:"Observación {n}",deleteRecording:"Quitar esta grabación del caso",deleteReadingQuestion:"¿Eliminar esta lectura? Nada se escribe hasta guardar el caso.",deleteObservationQuestion:"¿Eliminar esta observación del caso? Nada se escribe hasta guardar el caso.",deleteRefused:"Esta observación es interpretada por {n} lectura(s): elimínelas primero.",titleField:"Título de la interpretación",authorField:"Autor",addTitle:"Añadir un evento",kindField:"Tipo",kindObservation:"Observación",kindInterview:"Entrevista",witnessField:"Testigo",mediumField:"Medio",interviewerField:"Entrevistador",plainTitleField:"Título",sourceField:"Origen",sourceBlank:"Una grabación en blanco",sourceFile:"Un archivo JSON",sourceUrl:"Una dirección",observerField:"Testigo",fileField:"Archivo",urlField:"Dirección",loadFailed:"No se pudo leer esa grabación.",isACase:"Eso es un caso, no una grabación.",ok:"Aceptar",cancel:"Cancelar",caseHeading:"Caso",caseId:"Identificador",recordingId:"Identificador",idTaken:"Otra grabación del caso tiene este identificador.",idInvalid:"Un identificador se compone de letras, dígitos, guiones y guiones bajos, y empieza por una letra o un dígito.",idNeeded:"Una interpretación designa esta grabación por su identificador: no puede quedar vacío.",idDuplicated:"Dos eventos del caso tienen el identificador «{id}»: una interpretación que lo designa es ambigua.",readingUnresolved:"Una interpretación designa «{id}», que ningún evento del caso tiene como identificador, ni ninguna grabación que enumera.",caseTitle:"Título",caseTime:"Fecha",eventsTab:"Eventos",fileTab:"Archivo",importFile:"Cargar un archivo JSON",importUrl:"O desde una dirección",importButton:"Cargar",fileNotACase:"Ese archivo no es un caso (no tiene eventos).",fileInvalid:"Este texto aún no es JSON válido, o no es un caso: el caso conserva lo último que entendió.",fileLoading:"Cargando el editor…",add:"Añadir",addHint:"Añadir un evento",interpretationOf:"Interpretación de",interpretationOfNone:"—",exportButton:"Guardar",exportTitle:"Guardar el caso",exportAlso:"Guardar también las observaciones",addToCase:"Añadir a un caso",unsavedChanges:"Cambios sin guardar",discardQuestion:"Hay cambios que aún no se han guardado. ¿Cargar de todos modos y perderlos?",discardTitle:"Cambios sin guardar",discardOk:"Cargar de todos modos",leaveQuestion:"Hay cambios que aún no se han guardado. ¿Salir de todos modos y perderlos?",leaveOk:"Salir de todos modos"};export{e as caseEditorMessages_es};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e={event:"Événement",accountOf:"Observation de",interviewOf:"Interview de",untitledInterview:"Interview {n}",deleteInterviewQuestion:"Supprimer cet entretien du dossier ? Rien n'est écrit avant la sauvegarde du dossier.",untitledReading:"Lecture {n}",untitledObservation:"Observation {n}",deleteRecording:"Retirer cet enregistrement du dossier",deleteReadingQuestion:"Supprimer cette lecture ? Rien n'est écrit avant la sauvegarde du dossier.",deleteObservationQuestion:"Supprimer cette observation du dossier ? Rien n'est écrit avant la sauvegarde du dossier.",deleteRefused:"Cette observation est interprétée par {n} lecture(s) : supprimez-les d'abord.",titleField:"Titre de l'interprétation",authorField:"Auteur",addTitle:"Ajouter un événement",kindField:"Type",kindObservation:"Observation",kindInterview:"Interview",witnessField:"Témoin",mediumField:"Moyen",interviewerField:"Enquêteur",plainTitleField:"Titre",sourceField:"Source",sourceBlank:"Un enregistrement vierge",sourceFile:"Un fichier JSON",sourceUrl:"Une adresse",observerField:"Témoin",fileField:"Fichier",urlField:"Adresse",loadFailed:"Cet enregistrement n'a pas pu être lu.",isACase:"C'est un dossier, pas un enregistrement.",ok:"OK",cancel:"Annuler",caseHeading:"Dossier",caseId:"Identifiant",recordingId:"Identifiant",idTaken:"Un autre enregistrement du dossier porte cet identifiant.",idInvalid:"Un identifiant est fait de lettres, de chiffres, de tirets et de soulignés, et commence par une lettre ou un chiffre.",idNeeded:"Une interprétation désigne cet enregistrement par son identifiant : il ne peut pas rester vide.",idDuplicated:"Deux événements du dossier portent l'identifiant « {id} » : une interprétation qui le désigne est ambiguë.",readingUnresolved:"Une interprétation désigne « {id} », qu'aucun événement du dossier ne porte comme identifiant, ni aucun enregistrement qu'il liste.",caseTitle:"Titre",caseTime:"Date",eventsTab:"Événements",fileTab:"Fichier",importFile:"Charger un fichier JSON",importUrl:"Ou depuis une adresse",importButton:"Charger",fileNotACase:"Ce fichier n'est pas un dossier (il n'a pas d'événements).",fileInvalid:"Ce texte n'est pas encore du JSON valide, ou pas un dossier : le dossier garde ce qu'il a compris en dernier.",fileLoading:"Chargement de l'éditeur…",add:"Ajouter",addHint:"Ajouter un événement",interpretationOf:"Interprétation de",interpretationOfNone:"—",exportButton:"Sauver",exportTitle:"Sauver le dossier",exportAlso:"Sauver aussi les observations",addToCase:"Ajouter à un dossier",unsavedChanges:"Modifications non sauvées",discardQuestion:"Des modifications ne sont pas encore sauvées. Charger quand même et les perdre ?",discardTitle:"Modifications non sauvées",discardOk:"Charger quand même",leaveQuestion:"Des modifications ne sont pas encore sauvées. Quitter quand même et les perdre ?",leaveOk:"Quitter quand même"};export{e as caseEditorMessages_fr};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e={event:"Evento",accountOf:"Osservazione di",interviewOf:"Intervista a",untitledInterview:"Intervista {n}",deleteInterviewQuestion:"Eliminare questa intervista dal caso? Nulla viene scritto prima del salvataggio del caso.",untitledReading:"Lettura {n}",untitledObservation:"Osservazione {n}",deleteRecording:"Togliere questa registrazione dal caso",deleteReadingQuestion:"Eliminare questa lettura? Nulla viene scritto prima del salvataggio del caso.",deleteObservationQuestion:"Eliminare questa osservazione dal caso? Nulla viene scritto prima del salvataggio del caso.",deleteRefused:"Questa osservazione è interpretata da {n} lettura/e: eliminale prima.",titleField:"Titolo dell'interpretazione",authorField:"Autore",addTitle:"Aggiungi un evento",kindField:"Tipo",kindObservation:"Osservazione",kindInterview:"Intervista",witnessField:"Testimone",mediumField:"Mezzo",interviewerField:"Intervistatore",plainTitleField:"Titolo",sourceField:"Origine",sourceBlank:"Una registrazione vuota",sourceFile:"Un file JSON",sourceUrl:"Un indirizzo",observerField:"Testimone",fileField:"File",urlField:"Indirizzo",loadFailed:"Impossibile leggere quella registrazione.",isACase:"Questo è un caso, non una registrazione.",ok:"OK",cancel:"Annulla",caseHeading:"Caso",caseId:"Identificativo",recordingId:"Identificativo",idTaken:"Un'altra registrazione del caso ha questo identificativo.",idInvalid:"Un identificativo è fatto di lettere, cifre, trattini e trattini bassi, e inizia con una lettera o una cifra.",idNeeded:"Un'interpretazione designa questa registrazione con il suo identificativo: non può restare vuoto.",idDuplicated:"Due eventi del caso hanno l'identificativo «{id}»: un'interpretazione che lo designa è ambigua.",readingUnresolved:"Un'interpretazione designa «{id}», che nessun evento del caso ha come identificativo, né alcuna registrazione che elenca.",caseTitle:"Titolo",caseTime:"Data",eventsTab:"Eventi",fileTab:"File",importFile:"Carica un file JSON",importUrl:"O da un indirizzo",importButton:"Carica",fileNotACase:"Quel file non è un caso (non ha eventi).",fileInvalid:"Questo testo non è ancora JSON valido, o non è un caso: il caso conserva l'ultimo che ha capito.",fileLoading:"Caricamento dell'editor…",add:"Aggiungi",addHint:"Aggiungi un evento",interpretationOf:"Interpretazione di",interpretationOfNone:"—",exportButton:"Salva",exportTitle:"Salva il caso",exportAlso:"Salva anche le osservazioni",addToCase:"Aggiungi a un caso",unsavedChanges:"Modifiche non salvate",discardQuestion:"Alcune modifiche non sono ancora state salvate. Caricare comunque e perderle?",discardTitle:"Modifiche non salvate",discardOk:"Carica comunque",leaveQuestion:"Alcune modifiche non sono ancora state salvate. Uscire comunque e perderle?",leaveOk:"Esci comunque"};export{e as caseEditorMessages_it};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{ai as Le,aj as Q,ak as he,al as Me,am as v,an as de,ao as w,Y as pe,a3 as F,ap as N,aq as U,af as Se,ar as ye,s as we,a1 as K,as as Ne,u as C,at as me,au as be,av as ge,aw as Ie,ax as Oe,ac as V,ay as Ce,az as Te,aA as Fe,aB as Pe,aC as He,aD as J,aE as Re,aF as Z,aG as ke,aH as De,a6 as Ge,aI as X,aJ as ve,n as Ee,ae as Ue,ad as G,aK as Ke,a5 as Be,aL as je,M as Ve,aM as Xe,aN as ze,aO as qe,a7 as We,G as z,t as Ye,a2 as Qe,aP as Je,aQ as Ze,aR as $e,aS as en,aT as nn,aU as tn,aV as xe,J as sn,aW as ne,aX as te,aY as se,aZ as ie,a_ as re,a$ as rn,b0 as on,o as an,p as cn}from"./rr0-sighting-editor.mjs";function oe(f,n){if(n===Le)return console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles."),f;if(n===Q||n===he){let e=f.getIndex();if(e===null){const r=[],a=f.getAttribute("position");if(a!==void 0){for(let o=0;o<a.count;o++)r.push(o);f.setIndex(r),e=f.getIndex()}else return console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible."),f}const s=e.count-2,t=[];if(n===Q)for(let r=1;r<=s;r++)t.push(e.getX(0)),t.push(e.getX(r)),t.push(e.getX(r+1));else for(let r=0;r<s;r++)r%2===0?(t.push(e.getX(r)),t.push(e.getX(r+1)),t.push(e.getX(r+2))):(t.push(e.getX(r+2)),t.push(e.getX(r+1)),t.push(e.getX(r)));t.length/3!==s&&console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles.");const i=f.clone();return i.setIndex(t),i.clearGroups(),i}else return console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:",n),f}class jn extends Me{constructor(n){super(n),this.dracoLoader=null,this.ktx2Loader=null,this.meshoptDecoder=null,this.pluginCallbacks=[],this.register(function(e){return new dn(e)}),this.register(function(e){return new pn(e)}),this.register(function(e){return new Ln(e)}),this.register(function(e){return new Mn(e)}),this.register(function(e){return new Sn(e)}),this.register(function(e){return new gn(e)}),this.register(function(e){return new Tn(e)}),this.register(function(e){return new Rn(e)}),this.register(function(e){return new En(e)}),this.register(function(e){return new hn(e)}),this.register(function(e){return new xn(e)}),this.register(function(e){return new mn(e)}),this.register(function(e){return new _n(e)}),this.register(function(e){return new An(e)}),this.register(function(e){return new ln(e)}),this.register(function(e){return new ae(e,g.EXT_MESHOPT_COMPRESSION)}),this.register(function(e){return new ae(e,g.KHR_MESHOPT_COMPRESSION)}),this.register(function(e){return new yn(e)})}load(n,e,s,t){const i=this;let r;if(this.resourcePath!=="")r=this.resourcePath;else if(this.path!==""){const c=v.extractUrlBase(n);r=v.resolveURL(c,this.path)}else r=v.extractUrlBase(n);this.manager.itemStart(n);const a=function(c){t?t(c):console.error(c),i.manager.itemError(n),i.manager.itemEnd(n)},o=new de(this.manager);o.setPath(this.path),o.setResponseType("arraybuffer"),o.setRequestHeader(this.requestHeader),o.setWithCredentials(this.withCredentials),o.load(n,function(c){try{i.parse(c,r,function(u){e(u),i.manager.itemEnd(n)},a)}catch(u){a(u)}},s,a)}setDRACOLoader(n){return this.dracoLoader=n,this}setKTX2Loader(n){return this.ktx2Loader=n,this}setMeshoptDecoder(n){return this.meshoptDecoder=n,this}register(n){return this.pluginCallbacks.indexOf(n)===-1&&this.pluginCallbacks.push(n),this}unregister(n){return this.pluginCallbacks.indexOf(n)!==-1&&this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(n),1),this}parse(n,e,s,t){let i;const r={},a={},o=new TextDecoder;if(typeof n=="string")i=JSON.parse(n);else if(n instanceof ArrayBuffer)if(o.decode(new Uint8Array(n,0,4))===Ae){try{r[g.KHR_BINARY_GLTF]=new wn(n)}catch(l){t&&t(l);return}i=JSON.parse(r[g.KHR_BINARY_GLTF].content)}else i=JSON.parse(o.decode(n));else i=n;if(i.asset===void 0||i.asset.version[0]<2){t&&t(new Error("THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported."));return}const c=new Un(i,{path:e||this.resourcePath||"",crossOrigin:this.crossOrigin,requestHeader:this.requestHeader,manager:this.manager,ktx2Loader:this.ktx2Loader,meshoptDecoder:this.meshoptDecoder});c.fileLoader.setRequestHeader(this.requestHeader);for(let u=0;u<this.pluginCallbacks.length;u++){const l=this.pluginCallbacks[u](c);l.name||console.error("THREE.GLTFLoader: Invalid plugin found: missing name"),a[l.name]=l,r[l.name]=!0}if(i.extensionsUsed)for(let u=0;u<i.extensionsUsed.length;++u){const l=i.extensionsUsed[u],h=i.extensionsRequired||[];switch(l){case g.KHR_MATERIALS_UNLIT:r[l]=new fn;break;case g.KHR_DRACO_MESH_COMPRESSION:r[l]=new Nn(i,this.dracoLoader);break;case g.KHR_TEXTURE_TRANSFORM:r[l]=new bn;break;case g.KHR_MESH_QUANTIZATION:r[l]=new In;break;default:h.indexOf(l)>=0&&a[l]===void 0&&console.warn('THREE.GLTFLoader: Unknown extension "'+l+'".')}}c.setExtensions(r),c.setPlugins(a),c.parse(s,t)}parseAsync(n,e){const s=this;return new Promise(function(t,i){s.parse(n,e,t,i)})}}function un(){let f={};return{get:function(n){return f[n]},add:function(n,e){f[n]=e},remove:function(n){delete f[n]},removeAll:function(){f={}}}}function _(f,n,e){const s=f.json.materials[n];return s.extensions&&s.extensions[e]?s.extensions[e]:null}const g={KHR_BINARY_GLTF:"KHR_binary_glTF",KHR_DRACO_MESH_COMPRESSION:"KHR_draco_mesh_compression",KHR_LIGHTS_PUNCTUAL:"KHR_lights_punctual",KHR_MATERIALS_CLEARCOAT:"KHR_materials_clearcoat",KHR_MATERIALS_DISPERSION:"KHR_materials_dispersion",KHR_MATERIALS_IOR:"KHR_materials_ior",KHR_MATERIALS_SHEEN:"KHR_materials_sheen",KHR_MATERIALS_SPECULAR:"KHR_materials_specular",KHR_MATERIALS_TRANSMISSION:"KHR_materials_transmission",KHR_MATERIALS_IRIDESCENCE:"KHR_materials_iridescence",KHR_MATERIALS_ANISOTROPY:"KHR_materials_anisotropy",KHR_MATERIALS_UNLIT:"KHR_materials_unlit",KHR_MATERIALS_VOLUME:"KHR_materials_volume",KHR_TEXTURE_BASISU:"KHR_texture_basisu",KHR_TEXTURE_TRANSFORM:"KHR_texture_transform",KHR_MESH_QUANTIZATION:"KHR_mesh_quantization",KHR_MATERIALS_EMISSIVE_STRENGTH:"KHR_materials_emissive_strength",EXT_MATERIALS_BUMP:"EXT_materials_bump",EXT_TEXTURE_WEBP:"EXT_texture_webp",EXT_TEXTURE_AVIF:"EXT_texture_avif",EXT_MESHOPT_COMPRESSION:"EXT_meshopt_compression",KHR_MESHOPT_COMPRESSION:"KHR_meshopt_compression",EXT_MESH_GPU_INSTANCING:"EXT_mesh_gpu_instancing"};class ln{constructor(n){this.parser=n,this.name=g.KHR_LIGHTS_PUNCTUAL,this.cache={refs:{},uses:{}}}_markDefs(){const n=this.parser,e=this.parser.json.nodes||[];for(let s=0,t=e.length;s<t;s++){const i=e[s];i.extensions&&i.extensions[this.name]&&i.extensions[this.name].light!==void 0&&n._addNodeRef(this.cache,i.extensions[this.name].light)}}_loadLight(n){const e=this.parser,s="light:"+n;let t=e.cache.get(s);if(t)return t;const i=e.json,o=((i.extensions&&i.extensions[this.name]||{}).lights||[])[n];let c;const u=new F(16777215);o.color!==void 0&&u.setRGB(o.color[0],o.color[1],o.color[2],N);const l=o.range!==void 0?o.range:0;switch(o.type){case"directional":c=new we(u),c.target.position.set(0,0,-1),c.add(c.target);break;case"point":c=new ye(u),c.distance=l;break;case"spot":c=new Se(u),c.distance=l,o.spot=o.spot||{},o.spot.innerConeAngle=o.spot.innerConeAngle!==void 0?o.spot.innerConeAngle:0,o.spot.outerConeAngle=o.spot.outerConeAngle!==void 0?o.spot.outerConeAngle:Math.PI/4,c.angle=o.spot.outerConeAngle,c.penumbra=1-o.spot.innerConeAngle/o.spot.outerConeAngle,c.target.position.set(0,0,-1),c.add(c.target);break;default:throw new Error("THREE.GLTFLoader: Unexpected light type: "+o.type)}return c.position.set(0,0,0),y(c,o),o.intensity!==void 0&&(c.intensity=o.intensity),c.name=e.createUniqueName(o.name||"light_"+n),t=Promise.resolve(c),e.cache.add(s,t),t}getDependency(n,e){if(n==="light")return this._loadLight(e)}createNodeAttachment(n){const e=this,s=this.parser,i=s.json.nodes[n],a=(i.extensions&&i.extensions[this.name]||{}).light;return a===void 0?null:this._loadLight(a).then(function(o){return s._getNodeRef(e.cache,a,o)})}}class fn{constructor(){this.name=g.KHR_MATERIALS_UNLIT}getMaterialType(){return G}extendParams(n,e,s){const t=[];n.color=new F(1,1,1),n.opacity=1;const i=e.pbrMetallicRoughness;if(i){if(Array.isArray(i.baseColorFactor)){const r=i.baseColorFactor;n.color.setRGB(r[0],r[1],r[2],N),n.opacity=r[3]}i.baseColorTexture!==void 0&&t.push(s.assignTexture(n,"map",i.baseColorTexture,U))}return Promise.all(t)}}class hn{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_EMISSIVE_STRENGTH}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);return s===null||s.emissiveStrength!==void 0&&(e.emissiveIntensity=s.emissiveStrength),Promise.resolve()}}class dn{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_CLEARCOAT}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);if(s===null)return Promise.resolve();const t=[];if(s.clearcoatFactor!==void 0&&(e.clearcoat=s.clearcoatFactor),s.clearcoatTexture!==void 0&&t.push(this.parser.assignTexture(e,"clearcoatMap",s.clearcoatTexture)),s.clearcoatRoughnessFactor!==void 0&&(e.clearcoatRoughness=s.clearcoatRoughnessFactor),s.clearcoatRoughnessTexture!==void 0&&t.push(this.parser.assignTexture(e,"clearcoatRoughnessMap",s.clearcoatRoughnessTexture)),s.clearcoatNormalTexture!==void 0&&(t.push(this.parser.assignTexture(e,"clearcoatNormalMap",s.clearcoatNormalTexture)),s.clearcoatNormalTexture.scale!==void 0)){const i=s.clearcoatNormalTexture.scale;e.clearcoatNormalScale=new pe(i,i)}return Promise.all(t)}}class pn{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_DISPERSION}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);return s===null||(e.dispersion=s.dispersion!==void 0?s.dispersion:0),Promise.resolve()}}class mn{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_IRIDESCENCE}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);if(s===null)return Promise.resolve();const t=[];return s.iridescenceFactor!==void 0&&(e.iridescence=s.iridescenceFactor),s.iridescenceTexture!==void 0&&t.push(this.parser.assignTexture(e,"iridescenceMap",s.iridescenceTexture)),s.iridescenceIor!==void 0&&(e.iridescenceIOR=s.iridescenceIor),e.iridescenceThicknessRange===void 0&&(e.iridescenceThicknessRange=[100,400]),s.iridescenceThicknessMinimum!==void 0&&(e.iridescenceThicknessRange[0]=s.iridescenceThicknessMinimum),s.iridescenceThicknessMaximum!==void 0&&(e.iridescenceThicknessRange[1]=s.iridescenceThicknessMaximum),s.iridescenceThicknessTexture!==void 0&&t.push(this.parser.assignTexture(e,"iridescenceThicknessMap",s.iridescenceThicknessTexture)),Promise.all(t)}}class gn{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_SHEEN}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);if(s===null)return Promise.resolve();const t=[];if(e.sheenColor=new F(0,0,0),e.sheenRoughness=0,e.sheen=1,s.sheenColorFactor!==void 0){const i=s.sheenColorFactor;e.sheenColor.setRGB(i[0],i[1],i[2],N)}return s.sheenRoughnessFactor!==void 0&&(e.sheenRoughness=s.sheenRoughnessFactor),s.sheenColorTexture!==void 0&&t.push(this.parser.assignTexture(e,"sheenColorMap",s.sheenColorTexture,U)),s.sheenRoughnessTexture!==void 0&&t.push(this.parser.assignTexture(e,"sheenRoughnessMap",s.sheenRoughnessTexture)),Promise.all(t)}}class Tn{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_TRANSMISSION}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);if(s===null)return Promise.resolve();const t=[];return s.transmissionFactor!==void 0&&(e.transmission=s.transmissionFactor),s.transmissionTexture!==void 0&&t.push(this.parser.assignTexture(e,"transmissionMap",s.transmissionTexture)),Promise.all(t)}}class Rn{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_VOLUME}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);if(s===null)return Promise.resolve();const t=[];e.thickness=s.thicknessFactor!==void 0?s.thicknessFactor:0,s.thicknessTexture!==void 0&&t.push(this.parser.assignTexture(e,"thicknessMap",s.thicknessTexture)),e.attenuationDistance=s.attenuationDistance||1/0;const i=s.attenuationColor||[1,1,1];return e.attenuationColor=new F().setRGB(i[0],i[1],i[2],N),Promise.all(t)}}class En{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_IOR}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);return s===null||(e.ior=s.ior!==void 0?s.ior:1.5,e.ior===0&&(e.ior=1e3)),Promise.resolve()}}class xn{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_SPECULAR}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);if(s===null)return Promise.resolve();const t=[];e.specularIntensity=s.specularFactor!==void 0?s.specularFactor:1,s.specularTexture!==void 0&&t.push(this.parser.assignTexture(e,"specularIntensityMap",s.specularTexture));const i=s.specularColorFactor||[1,1,1];return e.specularColor=new F().setRGB(i[0],i[1],i[2],N),s.specularColorTexture!==void 0&&t.push(this.parser.assignTexture(e,"specularColorMap",s.specularColorTexture,U)),Promise.all(t)}}class An{constructor(n){this.parser=n,this.name=g.EXT_MATERIALS_BUMP}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);if(s===null)return Promise.resolve();const t=[];return e.bumpScale=s.bumpFactor!==void 0?s.bumpFactor:1,s.bumpTexture!==void 0&&t.push(this.parser.assignTexture(e,"bumpMap",s.bumpTexture)),Promise.all(t)}}class _n{constructor(n){this.parser=n,this.name=g.KHR_MATERIALS_ANISOTROPY}getMaterialType(n){return _(this.parser,n,this.name)!==null?w:null}extendMaterialParams(n,e){const s=_(this.parser,n,this.name);if(s===null)return Promise.resolve();const t=[];return s.anisotropyStrength!==void 0&&(e.anisotropy=s.anisotropyStrength),s.anisotropyRotation!==void 0&&(e.anisotropyRotation=s.anisotropyRotation),s.anisotropyTexture!==void 0&&t.push(this.parser.assignTexture(e,"anisotropyMap",s.anisotropyTexture)),Promise.all(t)}}class Ln{constructor(n){this.parser=n,this.name=g.KHR_TEXTURE_BASISU}loadTexture(n){const e=this.parser,s=e.json,t=s.textures[n];if(!t.extensions||!t.extensions[this.name])return null;const i=t.extensions[this.name],r=e.options.ktx2Loader;if(!r){if(s.extensionsRequired&&s.extensionsRequired.indexOf(this.name)>=0)throw new Error("THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures");return null}return e.loadTextureImage(n,i.source,r)}}class Mn{constructor(n){this.parser=n,this.name=g.EXT_TEXTURE_WEBP}loadTexture(n){const e=this.name,s=this.parser,t=s.json,i=t.textures[n];if(!i.extensions||!i.extensions[e])return null;const r=i.extensions[e],a=t.images[r.source];let o=s.textureLoader;if(a.uri){const c=s.options.manager.getHandler(a.uri);c!==null&&(o=c)}return s.loadTextureImage(n,r.source,o)}}class Sn{constructor(n){this.parser=n,this.name=g.EXT_TEXTURE_AVIF}loadTexture(n){const e=this.name,s=this.parser,t=s.json,i=t.textures[n];if(!i.extensions||!i.extensions[e])return null;const r=i.extensions[e],a=t.images[r.source];let o=s.textureLoader;if(a.uri){const c=s.options.manager.getHandler(a.uri);c!==null&&(o=c)}return s.loadTextureImage(n,r.source,o)}}class ae{constructor(n,e){this.name=e,this.parser=n}loadBufferView(n){const e=this.parser.json,s=e.bufferViews[n];if(s.extensions&&s.extensions[this.name]){const t=s.extensions[this.name],i=this.parser.getDependency("buffer",t.buffer),r=this.parser.options.meshoptDecoder;if(!r||!r.supported){if(e.extensionsRequired&&e.extensionsRequired.indexOf(this.name)>=0)throw new Error("THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files");return null}return i.then(function(a){const o=t.byteOffset||0,c=t.byteLength||0,u=t.count,l=t.byteStride,h=new Uint8Array(a,o,c);return r.decodeGltfBufferAsync?r.decodeGltfBufferAsync(u,l,h,t.mode,t.filter).then(function(d){return d.buffer}):r.ready.then(function(){const d=new ArrayBuffer(u*l);return r.decodeGltfBuffer(new Uint8Array(d),u,l,h,t.mode,t.filter),d})})}else return null}}class yn{constructor(n){this.name=g.EXT_MESH_GPU_INSTANCING,this.parser=n}createNodeMesh(n){const e=this.parser.json,s=e.nodes[n];if(!s.extensions||!s.extensions[this.name]||s.mesh===void 0)return null;const t=e.meshes[s.mesh];for(const c of t.primitives)if(c.mode!==M.TRIANGLES&&c.mode!==M.TRIANGLE_STRIP&&c.mode!==M.TRIANGLE_FAN&&c.mode!==void 0)return null;const r=s.extensions[this.name].attributes,a=[],o={};for(const c in r)a.push(this.parser.getDependency("accessor",r[c]).then(u=>(o[c]=u,o[c])));return a.length<1?null:(a.push(this.parser.createNodeMesh(n)),Promise.all(a).then(c=>{const u=c.pop(),l=u.isGroup?u.children:[u],h=c[0].count,d=[];for(const p of l){const R=new K,m=new C,T=new me,A=new C(1,1,1),x=new Ne(p.geometry,p.material,h);for(let E=0;E<h;E++)o.TRANSLATION&&m.fromBufferAttribute(o.TRANSLATION,E),o.ROTATION&&T.fromBufferAttribute(o.ROTATION,E),o.SCALE&&A.fromBufferAttribute(o.SCALE,E),x.setMatrixAt(E,R.compose(m,T,A));for(const E in o)if(E==="_COLOR_0"){const L=o[E];x.instanceColor=new be(L.array,L.itemSize,L.normalized)}else E!=="TRANSLATION"&&E!=="ROTATION"&&E!=="SCALE"&&p.geometry.setAttribute(E,o[E]);ge.prototype.copy.call(x,p),this.parser.assignFinalMaterial(x),d.push(x)}return u.isGroup?(u.clear(),u.add(...d),u):d[0]}))}}const Ae="glTF",D=12,ce={JSON:1313821514,BIN:5130562};class wn{constructor(n){this.name=g.KHR_BINARY_GLTF,this.content=null,this.body=null;const e=new DataView(n,0,D),s=new TextDecoder;if(this.header={magic:s.decode(new Uint8Array(n.slice(0,4))),version:e.getUint32(4,!0),length:e.getUint32(8,!0)},this.header.magic!==Ae)throw new Error("THREE.GLTFLoader: Unsupported glTF-Binary header.");if(this.header.version<2)throw new Error("THREE.GLTFLoader: Legacy binary file detected.");const t=this.header.length-D,i=new DataView(n,D);let r=0;for(;r<t;){const a=i.getUint32(r,!0);r+=4;const o=i.getUint32(r,!0);if(r+=4,o===ce.JSON){const c=new Uint8Array(n,D+r,a);this.content=s.decode(c)}else if(o===ce.BIN){const c=D+r;this.body=n.slice(c,c+a)}r+=a}if(this.content===null)throw new Error("THREE.GLTFLoader: JSON content not found.")}}class Nn{constructor(n,e){if(!e)throw new Error("THREE.GLTFLoader: No DRACOLoader instance provided.");this.name=g.KHR_DRACO_MESH_COMPRESSION,this.json=n,this.dracoLoader=e,this.dracoLoader.preload()}decodePrimitive(n,e){const s=this.json,t=this.dracoLoader,i=n.extensions[this.name].bufferView,r=n.extensions[this.name].attributes,a={},o={},c={};for(const u in r){const l=$[u]||u.toLowerCase();a[l]=r[u]}for(const u in n.attributes){const l=$[u]||u.toLowerCase();if(r[u]!==void 0){const h=s.accessors[n.attributes[u]],d=H[h.componentType];c[l]=d.name,o[l]=h.normalized===!0}}return e.getDependency("bufferView",i).then(function(u){return new Promise(function(l,h){t.decodeDracoFile(u,function(d){for(const p in d.attributes){const R=d.attributes[p],m=o[p];m!==void 0&&(R.normalized=m)}l(d)},a,c,N,h)})})}}class bn{constructor(){this.name=g.KHR_TEXTURE_TRANSFORM}extendTexture(n,e){return(e.texCoord===void 0||e.texCoord===n.channel)&&e.offset===void 0&&e.rotation===void 0&&e.scale===void 0||(n=n.clone(),e.texCoord!==void 0&&(n.channel=e.texCoord),e.offset!==void 0&&n.offset.fromArray(e.offset),e.rotation!==void 0&&(n.rotation=e.rotation),e.scale!==void 0&&n.repeat.fromArray(e.scale),n.needsUpdate=!0),n}}class In{constructor(){this.name=g.KHR_MESH_QUANTIZATION}}class _e extends on{constructor(n,e,s,t){super(n,e,s,t)}copySampleValue_(n){const e=this.resultBuffer,s=this.sampleValues,t=this.valueSize,i=n*t*3+t;for(let r=0;r!==t;r++)e[r]=s[i+r];return e}interpolate_(n,e,s,t){const i=this.resultBuffer,r=this.sampleValues,a=this.valueSize,o=a*2,c=a*3,u=t-e,l=(s-e)/u,h=l*l,d=h*l,p=n*c,R=p-c,m=-2*d+3*h,T=d-h,A=1-m,x=T-h+l;for(let E=0;E!==a;E++){const L=r[R+E+a],b=r[R+E+o]*u,S=r[p+E+a],k=r[p+E]*u;i[E]=A*L+x*b+m*S+T*k}return i}}const On=new me;class Cn extends _e{interpolate_(n,e,s,t){const i=super.interpolate_(n,e,s,t);return On.fromArray(i).normalize().toArray(i),i}}const M={POINTS:0,LINES:1,LINE_LOOP:2,LINE_STRIP:3,TRIANGLES:4,TRIANGLE_STRIP:5,TRIANGLE_FAN:6},H={5120:Int8Array,5121:Uint8Array,5122:Int16Array,5123:Uint16Array,5125:Uint32Array,5126:Float32Array},ue={9728:Re,9729:J,9984:He,9985:Pe,9986:Fe,9987:Te},le={33071:De,33648:ke,10497:Z},q={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},$={POSITION:"position",NORMAL:"normal",TANGENT:"tangent",TEXCOORD_0:"uv",TEXCOORD_1:"uv1",TEXCOORD_2:"uv2",TEXCOORD_3:"uv3",COLOR_0:"color",WEIGHTS_0:"skinWeight",JOINTS_0:"skinIndex"},I={scale:"scale",translation:"position",rotation:"quaternion",weights:"morphTargetInfluences"},Fn={CUBICSPLINE:void 0,LINEAR:xe,STEP:tn},W={OPAQUE:"OPAQUE",MASK:"MASK",BLEND:"BLEND"};function Pn(f){return f.DefaultMaterial===void 0&&(f.DefaultMaterial=new Ee({color:16777215,emissive:0,metalness:1,roughness:1,transparent:!1,depthTest:!0,side:rn})),f.DefaultMaterial}function O(f,n,e){for(const s in e.extensions)f[s]===void 0&&(n.userData.gltfExtensions=n.userData.gltfExtensions||{},n.userData.gltfExtensions[s]=e.extensions[s])}function y(f,n){n.extras!==void 0&&(typeof n.extras=="object"?Object.assign(f.userData,n.extras):console.warn("THREE.GLTFLoader: Ignoring primitive type .extras, "+n.extras))}function Hn(f,n,e){let s=!1,t=!1,i=!1;for(let c=0,u=n.length;c<u;c++){const l=n[c];if(l.POSITION!==void 0&&(s=!0),l.NORMAL!==void 0&&(t=!0),l.COLOR_0!==void 0&&(i=!0),s&&t&&i)break}if(!s&&!t&&!i)return Promise.resolve(f);const r=[],a=[],o=[];for(let c=0,u=n.length;c<u;c++){const l=n[c];if(s){const h=l.POSITION!==void 0?e.getDependency("accessor",l.POSITION):f.attributes.position;r.push(h)}if(t){const h=l.NORMAL!==void 0?e.getDependency("accessor",l.NORMAL):f.attributes.normal;a.push(h)}if(i){const h=l.COLOR_0!==void 0?e.getDependency("accessor",l.COLOR_0):f.attributes.color;o.push(h)}}return Promise.all([Promise.all(r),Promise.all(a),Promise.all(o)]).then(function(c){const u=c[0],l=c[1],h=c[2];return s&&(f.morphAttributes.position=u),t&&(f.morphAttributes.normal=l),i&&(f.morphAttributes.color=h),f.morphTargetsRelative=!0,f})}function kn(f,n){if(f.updateMorphTargets(),n.weights!==void 0)for(let e=0,s=n.weights.length;e<s;e++)f.morphTargetInfluences[e]=n.weights[e];if(n.extras&&Array.isArray(n.extras.targetNames)){const e=n.extras.targetNames;if(f.morphTargetInfluences.length===e.length){f.morphTargetDictionary={};for(let s=0,t=e.length;s<t;s++)f.morphTargetDictionary[e[s]]=s}else console.warn("THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.")}}function Dn(f){let n;const e=f.extensions&&f.extensions[g.KHR_DRACO_MESH_COMPRESSION];if(e?n="draco:"+e.bufferView+":"+e.indices+":"+Y(e.attributes):n=f.indices+":"+Y(f.attributes)+":"+f.mode,f.targets!==void 0)for(let s=0,t=f.targets.length;s<t;s++)n+=":"+Y(f.targets[s]);return n}function Y(f){let n="";const e=Object.keys(f).sort();for(let s=0,t=e.length;s<t;s++)n+=e[s]+":"+f[e[s]]+";";return n}function ee(f){switch(f){case Int8Array:return 1/127;case Uint8Array:return 1/255;case Int16Array:return 1/32767;case Uint16Array:return 1/65535;default:throw new Error("THREE.GLTFLoader: Unsupported normalized accessor component type.")}}function Gn(f){return f.search(/\.jpe?g($|\?)/i)>0||f.search(/^data\:image\/jpeg/)===0?"image/jpeg":f.search(/\.webp($|\?)/i)>0||f.search(/^data\:image\/webp/)===0?"image/webp":f.search(/\.ktx2($|\?)/i)>0||f.search(/^data\:image\/ktx2/)===0?"image/ktx2":"image/png"}const vn=new K;class Un{constructor(n={},e={}){this.json=n,this.extensions={},this.plugins={},this.options=e,this.cache=new un,this.associations=new Map,this.primitiveCache={},this.nodeCache={},this.meshCache={refs:{},uses:{}},this.cameraCache={refs:{},uses:{}},this.lightCache={refs:{},uses:{}},this.sourceCache={},this.textureCache={},this.nodeNamesUsed={};let s=!1,t=-1,i=!1,r=-1;if(typeof navigator<"u"&&typeof navigator.userAgent<"u"){const a=navigator.userAgent;s=/^((?!chrome|android).)*safari/i.test(a)===!0;const o=a.match(/Version\/(\d+)/);t=s&&o?parseInt(o[1],10):-1,i=a.indexOf("Firefox")>-1,r=i?a.match(/Firefox\/([0-9]+)\./)[1]:-1}typeof createImageBitmap>"u"||s&&t<17||i&&r<98?this.textureLoader=new Ie(this.options.manager):this.textureLoader=new Oe(this.options.manager),this.textureLoader.setCrossOrigin(this.options.crossOrigin),this.textureLoader.setRequestHeader(this.options.requestHeader),this.fileLoader=new de(this.options.manager),this.fileLoader.setResponseType("arraybuffer"),this.options.crossOrigin==="use-credentials"&&this.fileLoader.setWithCredentials(!0)}setExtensions(n){this.extensions=n}setPlugins(n){this.plugins=n}parse(n,e){const s=this,t=this.json,i=this.extensions;this.cache.removeAll(),this.nodeCache={},this._invokeAll(function(r){return r._markDefs&&r._markDefs()}),Promise.all(this._invokeAll(function(r){return r.beforeRoot&&r.beforeRoot()})).then(function(){return Promise.all([s.getDependencies("scene"),s.getDependencies("animation"),s.getDependencies("camera")])}).then(function(r){const a={scene:r[0][t.scene||0],scenes:r[0],animations:r[1],cameras:r[2],asset:t.asset,parser:s,userData:{}};return O(i,a,t),y(a,t),Promise.all(s._invokeAll(function(o){return o.afterRoot&&o.afterRoot(a)})).then(function(){for(const o of a.scenes)o.updateMatrixWorld();n(a)})}).catch(e)}_markDefs(){const n=this.json.nodes||[],e=this.json.skins||[],s=this.json.meshes||[];for(let t=0,i=e.length;t<i;t++){const r=e[t].joints;for(let a=0,o=r.length;a<o;a++)n[r[a]].isBone=!0}for(let t=0,i=n.length;t<i;t++){const r=n[t];r.mesh!==void 0&&(this._addNodeRef(this.meshCache,r.mesh),r.skin!==void 0&&(s[r.mesh].isSkinnedMesh=!0)),r.camera!==void 0&&this._addNodeRef(this.cameraCache,r.camera)}}_addNodeRef(n,e){e!==void 0&&(n.refs[e]===void 0&&(n.refs[e]=n.uses[e]=0),n.refs[e]++)}_getNodeRef(n,e,s){if(n.refs[e]<=1)return s;const t=s.clone(),i=(r,a)=>{const o=this.associations.get(r);o!=null&&this.associations.set(a,o);for(const[c,u]of r.children.entries())i(u,a.children[c])};return i(s,t),t.name+="_instance_"+n.uses[e]++,t}_invokeOne(n){const e=Object.values(this.plugins);e.push(this);for(let s=0;s<e.length;s++){const t=n(e[s]);if(t)return t}return null}_invokeAll(n){const e=Object.values(this.plugins);e.unshift(this);const s=[];for(let t=0;t<e.length;t++){const i=n(e[t]);i&&s.push(i)}return s}getDependency(n,e){const s=n+":"+e;let t=this.cache.get(s);if(!t){switch(n){case"scene":t=this.loadScene(e);break;case"node":t=this._invokeOne(function(i){return i.loadNode&&i.loadNode(e)});break;case"mesh":t=this._invokeOne(function(i){return i.loadMesh&&i.loadMesh(e)});break;case"accessor":t=this.loadAccessor(e);break;case"bufferView":t=this._invokeOne(function(i){return i.loadBufferView&&i.loadBufferView(e)});break;case"buffer":t=this.loadBuffer(e);break;case"material":t=this._invokeOne(function(i){return i.loadMaterial&&i.loadMaterial(e)});break;case"texture":t=this._invokeOne(function(i){return i.loadTexture&&i.loadTexture(e)});break;case"skin":t=this.loadSkin(e);break;case"animation":t=this._invokeOne(function(i){return i.loadAnimation&&i.loadAnimation(e)});break;case"camera":t=this.loadCamera(e);break;default:if(t=this._invokeOne(function(i){return i!=this&&i.getDependency&&i.getDependency(n,e)}),!t)throw new Error("Unknown type: "+n);break}this.cache.add(s,t)}return t}getDependencies(n){let e=this.cache.get(n);if(!e){const s=this,t=this.json[n+(n==="mesh"?"es":"s")]||[];e=Promise.all(t.map(function(i,r){return s.getDependency(n,r)})),this.cache.add(n,e)}return e}loadBuffer(n){const e=this.json.buffers[n],s=this.fileLoader;if(e.type&&e.type!=="arraybuffer")throw new Error("THREE.GLTFLoader: "+e.type+" buffer type is not supported.");if(e.uri===void 0&&n===0)return Promise.resolve(this.extensions[g.KHR_BINARY_GLTF].body);const t=this.options;return new Promise(function(i,r){s.load(v.resolveURL(e.uri,t.path),i,void 0,function(){r(new Error('THREE.GLTFLoader: Failed to load buffer "'+e.uri+'".'))})})}loadBufferView(n){const e=this.json.bufferViews[n];return this.getDependency("buffer",e.buffer).then(function(s){const t=e.byteLength||0,i=e.byteOffset||0;return s.slice(i,i+t)})}loadAccessor(n){const e=this,s=this.json,t=this.json.accessors[n];if(t.bufferView===void 0&&t.sparse===void 0){const r=q[t.type],a=H[t.componentType],o=t.normalized===!0,c=new a(t.count*r);return Promise.resolve(new V(c,r,o))}const i=[];return t.bufferView!==void 0?i.push(this.getDependency("bufferView",t.bufferView)):i.push(null),t.sparse!==void 0&&(i.push(this.getDependency("bufferView",t.sparse.indices.bufferView)),i.push(this.getDependency("bufferView",t.sparse.values.bufferView))),Promise.all(i).then(function(r){const a=r[0],o=q[t.type],c=H[t.componentType],u=c.BYTES_PER_ELEMENT,l=u*o,h=t.byteOffset||0,d=t.bufferView!==void 0?s.bufferViews[t.bufferView].byteStride:void 0,p=t.normalized===!0;let R,m;if(d&&d!==l){const T=Math.floor(h/d),A="InterleavedBuffer:"+t.bufferView+":"+t.componentType+":"+T+":"+t.count;let x=e.cache.get(A);x||(R=new c(a,T*d,t.count*d/u),x=new Ce(R,d/u),e.cache.add(A,x)),m=new sn(x,o,h%d/u,p)}else a===null?R=new c(t.count*o):R=new c(a,h,t.count*o),m=new V(R,o,p);if(t.sparse!==void 0){const T=q.SCALAR,A=H[t.sparse.indices.componentType],x=t.sparse.indices.byteOffset||0,E=t.sparse.values.byteOffset||0,L=new A(r[1],x,t.sparse.count*T),b=new c(r[2],E,t.sparse.count*o);a!==null&&(m=new V(m.array.slice(),m.itemSize,m.normalized)),m.normalized=!1;for(let S=0,k=L.length;S<k;S++){const P=L[S];if(m.setX(P,b[S*o]),o>=2&&m.setY(P,b[S*o+1]),o>=3&&m.setZ(P,b[S*o+2]),o>=4&&m.setW(P,b[S*o+3]),o>=5)throw new Error("THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.")}m.normalized=p}return m})}loadTexture(n){const e=this.json,s=this.options,i=e.textures[n].source,r=e.images[i];let a=this.textureLoader;if(r.uri){const o=s.manager.getHandler(r.uri);o!==null&&(a=o)}return this.loadTextureImage(n,i,a)}loadTextureImage(n,e,s){const t=this,i=this.json,r=i.textures[n],a=i.images[e],o=(a.uri||a.bufferView)+":"+r.sampler;if(this.textureCache[o])return this.textureCache[o];const c=this.loadImageSource(e,s).then(function(u){u.flipY=!1,u.name=r.name||a.name||"",u.name===""&&typeof a.uri=="string"&&a.uri.startsWith("data:image/")===!1&&(u.name=a.uri);const h=(i.samplers||{})[r.sampler]||{};return u.magFilter=ue[h.magFilter]||J,u.minFilter=ue[h.minFilter]||Te,u.wrapS=le[h.wrapS]||Z,u.wrapT=le[h.wrapT]||Z,u.generateMipmaps=!u.isCompressedTexture&&u.minFilter!==Re&&u.minFilter!==J,t.associations.set(u,{textures:n}),u}).catch(function(){return null});return this.textureCache[o]=c,c}loadImageSource(n,e){const s=this,t=this.json,i=this.options;if(this.sourceCache[n]!==void 0)return this.sourceCache[n].then(l=>l.clone());const r=t.images[n],a=self.URL||self.webkitURL;let o=r.uri||"",c=!1;if(r.bufferView!==void 0)o=s.getDependency("bufferView",r.bufferView).then(function(l){c=!0;const h=new Blob([l],{type:r.mimeType});return o=a.createObjectURL(h),o});else if(r.uri===void 0)throw new Error("THREE.GLTFLoader: Image "+n+" is missing URI and bufferView");const u=Promise.resolve(o).then(function(l){return new Promise(function(h,d){let p=h;e.isImageBitmapLoader===!0&&(p=function(R){const m=new ne(R);m.needsUpdate=!0,h(m)}),e.load(v.resolveURL(l,i.path),p,void 0,d)})}).then(function(l){return c===!0&&a.revokeObjectURL(o),y(l,r),l.userData.mimeType=r.mimeType||Gn(r.uri),l}).catch(function(l){throw console.error("THREE.GLTFLoader: Couldn't load texture",o),l});return this.sourceCache[n]=u,u}assignTexture(n,e,s,t){const i=this;return this.getDependency("texture",s.index).then(function(r){if(!r)return null;if(s.texCoord!==void 0&&s.texCoord>0&&(r=r.clone(),r.channel=s.texCoord),i.extensions[g.KHR_TEXTURE_TRANSFORM]){const a=s.extensions!==void 0?s.extensions[g.KHR_TEXTURE_TRANSFORM]:void 0;if(a){const o=i.associations.get(r);r=i.extensions[g.KHR_TEXTURE_TRANSFORM].extendTexture(r,a),i.associations.set(r,o)}}return t!==void 0&&(r.colorSpace=t),n[e]=r,r})}assignFinalMaterial(n){const e=n.geometry;let s=n.material;const t=e.attributes.tangent===void 0,i=e.attributes.color!==void 0,r=e.attributes.normal===void 0;if(n.isPoints){const a="PointsMaterial:"+s.uuid;let o=this.cache.get(a);o||(o=new Ge,X.prototype.copy.call(o,s),o.color.copy(s.color),o.map=s.map,o.sizeAttenuation=!1,this.cache.add(a,o)),s=o}else if(n.isLine){const a="LineBasicMaterial:"+s.uuid;let o=this.cache.get(a);o||(o=new ve,X.prototype.copy.call(o,s),o.color.copy(s.color),o.map=s.map,this.cache.add(a,o)),s=o}if(t||i||r){let a="ClonedMaterial:"+s.uuid+":";t&&(a+="derivative-tangents:"),i&&(a+="vertex-colors:"),r&&(a+="flat-shading:");let o=this.cache.get(a);o||(o=s.clone(),i&&(o.vertexColors=!0),r&&(o.flatShading=!0),t&&(o.normalScale&&(o.normalScale.y*=-1),o.clearcoatNormalScale&&(o.clearcoatNormalScale.y*=-1)),this.cache.add(a,o),this.associations.set(o,this.associations.get(s))),s=o}n.material=s}getMaterialType(){return Ee}loadMaterial(n){const e=this,s=this.json,t=this.extensions,i=s.materials[n];let r;const a={},o=i.extensions||{},c=[];if(o[g.KHR_MATERIALS_UNLIT]){const l=t[g.KHR_MATERIALS_UNLIT];r=l.getMaterialType(),c.push(l.extendParams(a,i,e))}else{const l=i.pbrMetallicRoughness||{};if(a.color=new F(1,1,1),a.opacity=1,Array.isArray(l.baseColorFactor)){const h=l.baseColorFactor;a.color.setRGB(h[0],h[1],h[2],N),a.opacity=h[3]}l.baseColorTexture!==void 0&&c.push(e.assignTexture(a,"map",l.baseColorTexture,U)),a.metalness=l.metallicFactor!==void 0?l.metallicFactor:1,a.roughness=l.roughnessFactor!==void 0?l.roughnessFactor:1,l.metallicRoughnessTexture!==void 0&&(c.push(e.assignTexture(a,"metalnessMap",l.metallicRoughnessTexture)),c.push(e.assignTexture(a,"roughnessMap",l.metallicRoughnessTexture))),r=this._invokeOne(function(h){return h.getMaterialType&&h.getMaterialType(n)}),c.push(Promise.all(this._invokeAll(function(h){return h.extendMaterialParams&&h.extendMaterialParams(n,a)})))}i.doubleSided===!0&&(a.side=Ue);const u=i.alphaMode||W.OPAQUE;if(u===W.BLEND?(a.transparent=!0,a.depthWrite=!1):(a.transparent=!1,u===W.MASK&&(a.alphaTest=i.alphaCutoff!==void 0?i.alphaCutoff:.5)),i.normalTexture!==void 0&&r!==G&&(c.push(e.assignTexture(a,"normalMap",i.normalTexture)),a.normalScale=new pe(1,1),i.normalTexture.scale!==void 0)){const l=i.normalTexture.scale;a.normalScale.set(l,l)}if(i.occlusionTexture!==void 0&&r!==G&&(c.push(e.assignTexture(a,"aoMap",i.occlusionTexture)),i.occlusionTexture.strength!==void 0&&(a.aoMapIntensity=i.occlusionTexture.strength)),i.emissiveFactor!==void 0&&r!==G){const l=i.emissiveFactor;a.emissive=new F().setRGB(l[0],l[1],l[2],N)}return i.emissiveTexture!==void 0&&r!==G&&c.push(e.assignTexture(a,"emissiveMap",i.emissiveTexture,U)),Promise.all(c).then(function(){const l=new r(a);return i.name&&(l.name=i.name),y(l,i),e.associations.set(l,{materials:n}),i.extensions&&O(t,l,i),l})}createUniqueName(n){const e=Ke.sanitizeNodeName(n||"");return e in this.nodeNamesUsed?e+"_"+ ++this.nodeNamesUsed[e]:(this.nodeNamesUsed[e]=0,e)}loadGeometries(n){const e=this,s=this.extensions,t=this.primitiveCache;function i(a){return s[g.KHR_DRACO_MESH_COMPRESSION].decodePrimitive(a,e).then(function(o){return fe(o,a,e)})}const r=[];for(let a=0,o=n.length;a<o;a++){const c=n[a],u=Dn(c),l=t[u];if(l)r.push(l.promise);else{let h;c.extensions&&c.extensions[g.KHR_DRACO_MESH_COMPRESSION]?h=i(c):h=fe(new Be,c,e),t[u]={primitive:c,promise:h},r.push(h)}}return Promise.all(r)}loadMesh(n){const e=this,s=this.json,t=this.extensions,i=s.meshes[n],r=i.primitives,a=[];for(let o=0,c=r.length;o<c;o++){const u=r[o].material===void 0?Pn(this.cache):this.getDependency("material",r[o].material);a.push(u)}return a.push(e.loadGeometries(r)),Promise.all(a).then(function(o){const c=o.slice(0,o.length-1),u=o[o.length-1],l=[];for(let d=0,p=u.length;d<p;d++){const R=u[d],m=r[d];let T;const A=c[d];if(m.mode===M.TRIANGLES||m.mode===M.TRIANGLE_STRIP||m.mode===M.TRIANGLE_FAN||m.mode===void 0)T=i.isSkinnedMesh===!0?new je(R,A):new Ve(R,A),T.isSkinnedMesh===!0&&T.normalizeSkinWeights(),m.mode===M.TRIANGLE_STRIP?T.geometry=oe(T.geometry,he):m.mode===M.TRIANGLE_FAN&&(T.geometry=oe(T.geometry,Q));else if(m.mode===M.LINES)T=new Xe(R,A);else if(m.mode===M.LINE_STRIP)T=new ze(R,A);else if(m.mode===M.LINE_LOOP)T=new qe(R,A);else if(m.mode===M.POINTS)T=new We(R,A);else throw new Error("THREE.GLTFLoader: Primitive mode unsupported: "+m.mode);Object.keys(T.geometry.morphAttributes).length>0&&kn(T,i),T.name=e.createUniqueName(i.name||"mesh_"+n),y(T,i),m.extensions&&O(t,T,m),e.assignFinalMaterial(T),l.push(T)}for(let d=0,p=l.length;d<p;d++)e.associations.set(l[d],{meshes:n,primitives:d});if(l.length===1)return i.extensions&&O(t,l[0],i),l[0];const h=new z;i.extensions&&O(t,h,i),e.associations.set(h,{meshes:n});for(let d=0,p=l.length;d<p;d++)h.add(l[d]);return h})}loadCamera(n){let e;const s=this.json.cameras[n],t=s[s.type];if(!t){console.warn("THREE.GLTFLoader: Missing camera parameters.");return}return s.type==="perspective"?e=new Ye(Qe.radToDeg(t.yfov),t.aspectRatio||1,t.znear||1,t.zfar||2e6):s.type==="orthographic"&&(e=new Je(-t.xmag,t.xmag,t.ymag,-t.ymag,t.znear,t.zfar)),s.name&&(e.name=this.createUniqueName(s.name)),y(e,s),Promise.resolve(e)}loadSkin(n){const e=this.json.skins[n],s=[];for(let t=0,i=e.joints.length;t<i;t++)s.push(this._loadNodeShallow(e.joints[t]));return e.inverseBindMatrices!==void 0?s.push(this.getDependency("accessor",e.inverseBindMatrices)):s.push(null),Promise.all(s).then(function(t){const i=t.pop(),r=t,a=[],o=[];for(let c=0,u=r.length;c<u;c++){const l=r[c];if(l){a.push(l);const h=new K;i!==null&&h.fromArray(i.array,c*16),o.push(h)}else console.warn('THREE.GLTFLoader: Joint "%s" could not be found.',e.joints[c])}return new Ze(a,o)})}loadAnimation(n){const e=this.json,s=this,t=e.animations[n],i=t.name?t.name:"animation_"+n,r=[],a=[],o=[],c=[],u=[];for(let l=0,h=t.channels.length;l<h;l++){const d=t.channels[l],p=t.samplers[d.sampler],R=d.target,m=R.node,T=t.parameters!==void 0?t.parameters[p.input]:p.input,A=t.parameters!==void 0?t.parameters[p.output]:p.output;R.node!==void 0&&(r.push(this.getDependency("node",m)),a.push(this.getDependency("accessor",T)),o.push(this.getDependency("accessor",A)),c.push(p),u.push(R))}return Promise.all([Promise.all(r),Promise.all(a),Promise.all(o),Promise.all(c),Promise.all(u)]).then(function(l){const h=l[0],d=l[1],p=l[2],R=l[3],m=l[4],T=[];for(let x=0,E=h.length;x<E;x++){const L=h[x],b=d[x],S=p[x],k=R[x],P=m[x];if(L===void 0)continue;L.updateMatrix&&L.updateMatrix();const B=s._createAnimationTracks(L,b,S,k,P);if(B)for(let j=0;j<B.length;j++)T.push(B[j])}const A=new $e(i,void 0,T);return y(A,t),A})}createNodeMesh(n){const e=this.json,s=this,t=e.nodes[n];return t.mesh===void 0?null:s.getDependency("mesh",t.mesh).then(function(i){const r=s._getNodeRef(s.meshCache,t.mesh,i);return t.weights!==void 0&&r.traverse(function(a){if(a.isMesh)for(let o=0,c=t.weights.length;o<c;o++)a.morphTargetInfluences[o]=t.weights[o]}),r})}loadNode(n){const e=this.json,s=this,t=e.nodes[n],i=s._loadNodeShallow(n),r=[],a=t.children||[];for(let c=0,u=a.length;c<u;c++)r.push(s.getDependency("node",a[c]));const o=t.skin===void 0?Promise.resolve(null):s.getDependency("skin",t.skin);return Promise.all([i,Promise.all(r),o]).then(function(c){const u=c[0],l=c[1],h=c[2];h!==null&&u.traverse(function(d){d.isSkinnedMesh&&d.bind(h,vn)});for(let d=0,p=l.length;d<p;d++)u.add(l[d]);if(u.userData.pivot!==void 0&&l.length>0){const d=u.userData.pivot,p=l[0];u.pivot=new C().fromArray(d),u.position.x-=d[0],u.position.y-=d[1],u.position.z-=d[2],p.position.set(0,0,0),delete u.userData.pivot}return u})}_loadNodeShallow(n){const e=this.json,s=this.extensions,t=this;if(this.nodeCache[n]!==void 0)return this.nodeCache[n];const i=e.nodes[n],r=i.name?t.createUniqueName(i.name):"",a=[],o=t._invokeOne(function(c){return c.createNodeMesh&&c.createNodeMesh(n)});return o&&a.push(o),i.camera!==void 0&&a.push(t.getDependency("camera",i.camera).then(function(c){return t._getNodeRef(t.cameraCache,i.camera,c)})),t._invokeAll(function(c){return c.createNodeAttachment&&c.createNodeAttachment(n)}).forEach(function(c){a.push(c)}),this.nodeCache[n]=Promise.all(a).then(function(c){let u;if(i.isBone===!0?u=new en:c.length>1?u=new z:c.length===1?u=c[0]:u=new ge,u!==c[0])for(let l=0,h=c.length;l<h;l++)u.add(c[l]);if(i.name&&(u.userData.name=i.name,u.name=r),y(u,i),i.extensions&&O(s,u,i),i.matrix!==void 0){const l=new K;l.fromArray(i.matrix),u.applyMatrix4(l)}else i.translation!==void 0&&u.position.fromArray(i.translation),i.rotation!==void 0&&u.quaternion.fromArray(i.rotation),i.scale!==void 0&&u.scale.fromArray(i.scale);if(!t.associations.has(u))t.associations.set(u,{});else if(i.mesh!==void 0&&t.meshCache.refs[i.mesh]>1){const l=t.associations.get(u);t.associations.set(u,{...l})}return t.associations.get(u).nodes=n,u}),this.nodeCache[n]}loadScene(n){const e=this.extensions,s=this.json.scenes[n],t=this,i=new z;s.name&&(i.name=t.createUniqueName(s.name)),y(i,s),s.extensions&&O(e,i,s);const r=s.nodes||[],a=[];for(let o=0,c=r.length;o<c;o++)a.push(t.getDependency("node",r[o]));return Promise.all(a).then(function(o){for(let u=0,l=o.length;u<l;u++){const h=o[u];h.parent!==null?i.add(nn(h)):i.add(h)}const c=u=>{const l=new Map;for(const[h,d]of t.associations)(h instanceof X||h instanceof ne)&&l.set(h,d);return u.traverse(h=>{const d=t.associations.get(h);d!=null&&l.set(h,d)}),l};return t.associations=c(i),i})}_createAnimationTracks(n,e,s,t,i){const r=[],a=n.name?n.name:n.uuid,o=[];function c(d){d.morphTargetInfluences&&o.push(d.name?d.name:d.uuid)}I[i.path]===I.weights?(c(n),n.isGroup&&n.children.forEach(c)):o.push(a);let u;switch(I[i.path]){case I.weights:u=se;break;case I.rotation:u=ie;break;case I.translation:case I.scale:u=te;break;default:switch(s.itemSize){case 1:u=se;break;case 2:case 3:default:u=te;break}break}const l=t.interpolation!==void 0?Fn[t.interpolation]:xe,h=this._getArrayFromAccessor(s);for(let d=0,p=o.length;d<p;d++){const R=new u(o[d]+"."+I[i.path],e.array,h,l);t.interpolation==="CUBICSPLINE"&&this._createCubicSplineTrackInterpolant(R),r.push(R)}return r}_getArrayFromAccessor(n){let e=n.array;if(n.normalized){const s=ee(e.constructor),t=new Float32Array(e.length);for(let i=0,r=e.length;i<r;i++)t[i]=e[i]*s;e=t}return e}_createCubicSplineTrackInterpolant(n){n.createInterpolant=function(s){const t=this instanceof ie?Cn:_e;return new t(this.times,this.values,this.getValueSize()/3,s)},n.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline=!0}}function Kn(f,n,e){const s=n.attributes,t=new an;if(s.POSITION!==void 0){const a=e.json.accessors[s.POSITION],o=a.min,c=a.max;if(o!==void 0&&c!==void 0){if(t.set(new C(o[0],o[1],o[2]),new C(c[0],c[1],c[2])),a.normalized){const u=ee(H[a.componentType]);t.min.multiplyScalar(u),t.max.multiplyScalar(u)}}else{console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION.");return}}else return;const i=n.targets;if(i!==void 0){const a=new C,o=new C;for(let c=0,u=i.length;c<u;c++){const l=i[c];if(l.POSITION!==void 0){const h=e.json.accessors[l.POSITION],d=h.min,p=h.max;if(d!==void 0&&p!==void 0){if(o.setX(Math.max(Math.abs(d[0]),Math.abs(p[0]))),o.setY(Math.max(Math.abs(d[1]),Math.abs(p[1]))),o.setZ(Math.max(Math.abs(d[2]),Math.abs(p[2]))),h.normalized){const R=ee(H[h.componentType]);o.multiplyScalar(R)}a.max(o)}else console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION.")}}t.expandByVector(a)}f.boundingBox=t;const r=new cn;t.getCenter(r.center),r.radius=t.min.distanceTo(t.max)/2,f.boundingSphere=r}function fe(f,n,e){const s=n.attributes,t=[];function i(r,a){return e.getDependency("accessor",r).then(function(o){f.setAttribute(a,o)})}for(const r in s){const a=$[r]||r.toLowerCase();a in f.attributes||t.push(i(s[r],a))}if(n.indices!==void 0&&!f.index){const r=e.getDependency("accessor",n.indices).then(function(a){f.setIndex(a)});t.push(r)}return re.workingColorSpace!==N&&"COLOR_0"in s&&console.warn(`THREE.GLTFLoader: Converting vertex colors from "srgb-linear" to "${re.workingColorSpace}" not supported.`),y(f,n),Kn(f,n,e),Promise.all(t).then(function(){return n.targets!==void 0?Hn(f,n.targets,e):f})}export{jn as GLTFLoader};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import{af as b,M as g,u as P,ag as m,a5 as C,ac as E,N as L,a3 as x,ae as R,ah as I}from"./rr0-sighting-editor.mjs";class i{constructor(e){this.scene=e}static REAL_BEAMS=4;static LAMPS=2;static DISTANCE_M=500;static AIR_LENGTH_M=90;static CLEAR_AIR_SCATTER_PER_M=2e-4;static SHADOW_MAP_PX=1024;beams=new Map;static airGeometry;has(e){return this.beams.has(e)}get size(){return this.beams.size}lamps(e){return this.beams.get(e)?.lamps??[]}airMeshes(e){return this.beams.get(e)?.air??[]}add(e){if(this.beams.has(e))return!0;if(this.beams.size>=i.REAL_BEAMS)return!1;const t=[],r=[];for(let n=0;n<i.LAMPS;n++){const a=new b(16777215,0,i.DISTANCE_M,Math.PI/8,.5,2);a.castShadow=e==="observer",a.shadow.mapSize.set(i.SHADOW_MAP_PX,i.SHADOW_MAP_PX),a.shadow.camera.near=.4,a.shadow.camera.far=110,a.shadow.bias=-4e-4,a.shadow.normalBias=.04,a.shadow.radius=2,this.scene.add(a),this.scene.add(a.target),t.push(a);const o=new g(i.airCone(),i.airMaterial());o.visible=!1,o.frustumCulled=!1,o.renderOrder=8,o.castShadow=!1,o.receiveShadow=!1,o.name="headlight air",this.scene.add(o),r.push(o)}return this.beams.set(e,{lamps:t,air:r}),!0}remove(e){const t=this.beams.get(e);if(t){for(const r of t.lamps)r.removeFromParent(),r.target.removeFromParent(),r.dispose();for(const r of t.air)r.removeFromParent(),r.material.dispose();this.beams.delete(e)}}clear(e){for(const t of[...this.beams.keys()])e&&t==="observer"||this.remove(t)}dispose(){this.clear(!1),i.airGeometry?.dispose(),i.airGeometry=void 0}aim(e,t,r,n,a,o,l){const c=this.beams.get(e),w=Math.max(l,i.CLEAR_AIR_SCATTER_PER_M);if(!c)return;const u=m.BEAMS[t],f=new P(-n.z,0,n.x),A=e==="observer"&&u!==void 0;c.lamps.forEach((s,d)=>{if(!u){s.intensity=0,c.air[d].visible=!1,s.shadow.autoUpdate=!1;return}const v=d===0?-1:1,h=u.pitchDeg*Math.PI/180,p=u.candela*m.DISPLAY_GAIN*o/c.lamps.length;s.color.set(u.color),s.intensity=p,s.angle=u.halfAngleDeg*Math.PI/180,s.penumbra=u.penumbra,A?(s.shadow.autoUpdate||(s.shadow.needsUpdate=!0),s.shadow.autoUpdate=!0):s.shadow.autoUpdate=!1,s.position.copy(r).addScaledVector(f,v*a);const M=n.clone().addScaledVector(f,-v*Math.tan(m.TOE_IN_DEG*Math.PI/180)).normalize();s.target.position.set(s.position.x+M.x*Math.cos(h)*50,s.position.y-Math.sin(h)*50,s.position.z+M.z*Math.cos(h)*50),s.target.updateMatrixWorld(),this.aimAir(c.air[d],s,u.color,p,w)})}aimAir(e,t,r,n,a){if(e.visible=a*n>1e-4,!e.visible)return;const o=i.AIR_LENGTH_M,l=o*Math.tan(t.angle);e.position.copy(t.position),e.scale.set(l,l,o),e.lookAt(t.target.position),e.updateMatrixWorld();const c=e.material.uniforms;c.uColor.value.set(r),c.uCandela.value=n,c.uScatter.value=a,c.uLength.value=o,c.uRadius.value=l}static airCone(){if(i.airGeometry)return i.airGeometry;const e=24,t=new Float32Array((e+1)*3);for(let a=0;a<e;a++){const o=a/e*Math.PI*2;t.set([Math.cos(o),Math.sin(o),1],(a+1)*3)}const r=[];for(let a=0;a<e;a++)r.push(0,1+a,1+(a+1)%e);const n=new C;return n.setAttribute("position",new E(t,3)),n.setIndex(r),i.airGeometry=n,n}static airMaterial(){return new L({transparent:!0,depthWrite:!1,depthTest:!0,blending:I,side:R,uniforms:{uColor:{value:new x(1,1,1)},uCandela:{value:0},uScatter:{value:0},uLength:{value:90},uRadius:{value:20}},vertexShader:`
|
|
2
|
-
varying vec3 vLocal;
|
|
3
|
-
varying vec3 vNormalView;
|
|
4
|
-
varying vec3 vViewDir;
|
|
5
|
-
void main() {
|
|
6
|
-
vLocal = position;
|
|
7
|
-
vec4 viewPosition = modelViewMatrix * vec4(position, 1.0);
|
|
8
|
-
// The side's normal, out of the axis: the apex has none (its length is nought), and a normal of nought there would spread NaN over the whole cone.
|
|
9
|
-
float ring = length(position.xy);
|
|
10
|
-
vec3 outward = ring > 1e-5 ? vec3(position.xy / ring, 0.0) : vec3(0.0, 0.0, 1.0);
|
|
11
|
-
vNormalView = normalize(normalMatrix * outward);
|
|
12
|
-
vViewDir = -viewPosition.xyz;
|
|
13
|
-
gl_Position = projectionMatrix * viewPosition;
|
|
14
|
-
}`,fragmentShader:`
|
|
15
|
-
uniform vec3 uColor;
|
|
16
|
-
uniform float uCandela;
|
|
17
|
-
uniform float uScatter;
|
|
18
|
-
uniform float uLength;
|
|
19
|
-
uniform float uRadius;
|
|
20
|
-
varying vec3 vLocal;
|
|
21
|
-
varying vec3 vNormalView;
|
|
22
|
-
varying vec3 vViewDir;
|
|
23
|
-
void main() {
|
|
24
|
-
float t = clamp(vLocal.z, 0.0, 1.0);
|
|
25
|
-
float distanceM = max(t * uLength, 1.5);
|
|
26
|
-
// The chord a ray makes through a cone of this thickness: long going along the beam, short going across its edge.
|
|
27
|
-
float facing = abs(dot(normalize(vNormalView), normalize(vViewDir + vec3(0.0, 0.0, 1e-4))));
|
|
28
|
-
float chord = 2.0 * uRadius * t * (0.25 + 0.75 * facing);
|
|
29
|
-
// The beam's own profile averaged over the chord: strongest on the axis, none at the edge of the cone.
|
|
30
|
-
float profile = 0.55;
|
|
31
|
-
float radiance = uScatter * uCandela * chord * profile / (distanceM * distanceM + 9.0);
|
|
32
|
-
float ends = (1.0 - smoothstep(0.75, 1.0, t)) * smoothstep(0.0, 0.04, t);
|
|
33
|
-
gl_FragColor = vec4(uColor * radiance * ends, 1.0);
|
|
34
|
-
}`})}}export{i as HeadlightSystem};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e={title:"Título",time:"Fecha",by:"Entrevistador",medium:"Medio",witness:"Testigo",witnessNone:"—",summary:"Descripción",transcript:"Transcripción",transcriptHint:"Dirección del archivo de transcripción anonimizada (opcional)",summaryTab:"Resumen",fileTab:"Archivo",importFile:"Cargar un archivo JSON",importUrl:"O desde una dirección",importButton:"Cargar",saveButton:"Guardar",loading:"Cargando la transcripción…",invalid:"Este texto aún no es JSON válido: la entrevista conserva la última transcripción que entendió.",notATranscript:"Ese archivo no es una transcripción de entrevista (no tiene turnos de palabra).",loadFailed:"No se pudo leer esa transcripción.",editorLabel:"Transcripción de la entrevista en JSON",byHint:"Identificadores de personas de RR0, separados por comas"};export{e as interviewMessages_es};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e={title:"Titre",time:"Date",by:"Enquêteur",medium:"Moyen",witness:"Témoin",witnessNone:"—",summary:"Description",transcript:"Transcription",transcriptHint:"Adresse du fichier de transcription anonymisée (facultative)",summaryTab:"Résumé",fileTab:"Fichier",importFile:"Charger un fichier JSON",importUrl:"Ou depuis une adresse",importButton:"Charger",saveButton:"Sauver",loading:"Chargement de la transcription…",invalid:"Ce texte n'est pas encore du JSON valide : l'interview garde la dernière transcription qu'elle a comprise.",notATranscript:"Ce fichier n'est pas une transcription d'interview (il n'a pas de tours de parole).",loadFailed:"Cette transcription n'a pas pu être lue.",editorLabel:"Transcription de l'interview en JSON",byHint:"Identifiants de personnes RR0, séparés par des virgules"};export{e as interviewMessages_fr};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const i={title:"Titolo",time:"Data",by:"Intervistatore",medium:"Mezzo",witness:"Testimone",witnessNone:"—",summary:"Descrizione",transcript:"Trascrizione",transcriptHint:"Indirizzo del file di trascrizione anonimizzata (facoltativo)",summaryTab:"Riepilogo",fileTab:"File",importFile:"Carica un file JSON",importUrl:"O da un indirizzo",importButton:"Carica",saveButton:"Salva",loading:"Caricamento della trascrizione…",invalid:"Questo testo non è ancora JSON valido: l'intervista conserva l'ultima trascrizione che ha capito.",notATranscript:"Quel file non è una trascrizione di intervista (non ha turni di parola).",loadFailed:"Impossibile leggere quella trascrizione.",editorLabel:"Trascrizione dell'intervista in JSON",byHint:"Identificatori di persone RR0, separati da virgole"};export{i as interviewMessages_it};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const e={type:"number"},t={type:"string"},n={type:"string"},s={type:"string",doc:"What the interview is called, in the languages it has.",loose:!0},a={type:"string",doc:"When it was held, as RR0 writes a time."},i={type:"enum",doc:"What it was held through: face to face (`in-person`), by `phone`, in a `video` call, by `chat`, by `email`, by `letter`, or `other`.",values:["letter","in-person","phone","video","chat","email","other"]},o={type:"array",doc:"Who held it."},r={type:"string",doc:"The `id`, or the ids, of the sighting events of the case it was held with.",loose:!0},c={type:"string",doc:"What it established, in the languages it has.",loose:!0},p={type:"object"},y={type:"object",fields:{method:{type:"enum",values:["automatic","manual"]},engine:{type:"string"},proofread:{type:"boolean"},note:{type:"string"}}},h={type:"object",doc:"What was taken out to anonymise it, and what stands in its place.",fields:{replaced:{type:"array"},marker:{type:"string"}}},l={type:"array",fields:{speaker:{type:"string"},start:{type:"number"},end:{type:"number"},text:{type:"string"}}},d={version:e,id:t,language:n,title:s,time:a,medium:i,by:o,interviewOf:r,summary:c,speakers:p,transcription:y,anonymization:h,segments:l};export{h as anonymization,o as by,d as default,t as id,r as interviewOf,n as language,i as medium,l as segments,p as speakers,c as summary,a as time,s as title,y as transcription,e as version};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{S,O as k,I as R,a as F}from"./rr0-sighting-editor.mjs";class K{constructor(t){if(this.candidates=t,t.length===0)throw new Error("A survey needs at least one candidate");this.current=t[0]}current;get id(){return this.current.id}get name(){return this.current.name}get attribution(){return this.current.attribution}get creditUrl(){return this.current.creditUrl}get contemporary(){return this.current.contemporary}covers(t,e){return this.candidates.some(o=>o.covers(t,e))}async getSurroundings(t,e){let o;for(const n of this.candidates)if(n.covers(t.lat,t.lng))try{const s=await n.getSurroundings(t,e);return this.current=n,s}catch(s){if(o??=s,!(s instanceof S))throw s}throw o??new S("no-coverage","No survey reaches this place")}}class w{constructor(t,e,o,n){this.heights=t,this.building=e,this.width=o,this.height=n}static ROOF_PERCENTILE=.9;static STEP_M=.9;static RECTANGLE_FILL=.72;static MIN_DEPTH_M=2.5;static MAX_PARTS=24;static MAX_CELLS=640;buildings(t){const e=t.metresPerPixel,o=t.minAreaM2??12,n=new Uint8Array(this.width*this.height),s=[];for(let r=0;r<this.building.length;r++){if(!this.building[r]||n[r])continue;const a=this.patchFrom(r,n);if(!(a.length*e*e<o))for(const i of this.buildingsOf(a,e,o))Math.hypot(i.eastM,i.northM)<=t.radiusM&&s.push(i)}return s.sort((r,a)=>Math.hypot(r.eastM,r.northM)-Math.hypot(a.eastM,a.northM)),s.slice(0,t.maxBuildings??60)}patchFrom(t,e){const o=[],n=[t];for(e[t]=1;n.length>0;){const s=n.pop();o.push(s);const r=s%this.width,a=Math.floor(s/this.width);for(const[i,c]of[[1,0],[-1,0],[0,1],[0,-1]]){const l=r+i,h=a+c;if(l<0||h<0||l>=this.width||h>=this.height)continue;const u=h*this.width+l;this.building[u]&&!e[u]&&Math.abs(this.heights[u]-this.heights[s])<=w.STEP_M&&(e[u]=1,n.push(u))}}return o}buildingsOf(t,e,o){const n=this.width/2,s=this.height/2,r=[],a=[],i=[];for(const c of t){const l=c%this.width,h=Math.floor(c/this.width);r.push((l+.5-n)*e),a.push((s-h-.5)*e),i.push(this.heights[c])}return w.ofPoints(r,a,i,e,o)}static ofPoints(t,e,o,n,s,r=w.RECTANGLE_FILL,a=[]){const i=[];for(let m=0;m<t.length;m++)for(const[E,P]of[[-.5,-.5],[.5,-.5],[-.5,.5],[.5,.5]])i.push([t[m]+E*n,e[m]+P*n]);const c=w.hull(i),{angle:l,rectangle:h}=w.smallestRectangle(c),u=t.length*n*n,M=(h.maxU-h.minU)*(h.maxV-h.minV);if(u/M>=r||u<4*s)return[w.building(h,l,w.roof(o))];const f=c.map((m,E)=>({from:{east:m[0],north:m[1]},to:{east:c[(E+1)%c.length][0],north:c[(E+1)%c.length][1]}})),d=w.dominantAngles([...a,...f]);return w.parts(t,e,o,d.length>0?d:[l],n,s)}static dominantAngles(t,e=3){const o=new Map;for(const n of t){const s=Math.hypot(n.to.east-n.from.east,n.to.north-n.from.north);if(s<1e-6)continue;const r=(Math.atan2(n.to.north-n.from.north,n.to.east-n.from.east)%(Math.PI/2)+Math.PI/2)%(Math.PI/2),a=Math.round(r/(Math.PI/60));o.set(a,(o.get(a)??0)+s)}return[...o.entries()].sort((n,s)=>s[1]-n[1]).slice(0,e).map(([n])=>n*Math.PI/60)}static parts(t,e,o,n,s,r){let a=t.map((c,l)=>l);const i=[];for(let c=0;c<w.MAX_PARTS&&a.length>0;c++){let l;for(const M of n){const f=w.largestIn(t,e,a,M,s);f&&(l===void 0||f.area>l.area)&&(l=f)}if(l===void 0||l.area<r)break;const h=l.covered;Math.min(l.rectangle.maxU-l.rectangle.minU,l.rectangle.maxV-l.rectangle.minV)>=w.MIN_DEPTH_M&&i.push(w.building(l.rectangle,l.angle,w.roof([...h].map(M=>o[M])))),a=a.filter(M=>!h.has(M))}return i}static largestIn(t,e,o,n,s){const r=Math.cos(n),a=Math.sin(n);let i=1/0,c=-1/0,l=1/0,h=-1/0;const u=[],M=[];for(const D of o){const y=t[D]*r+e[D]*a,b=-t[D]*a+e[D]*r;u.push(y),M.push(b),i=Math.min(i,y),c=Math.max(c,y),l=Math.min(l,b),h=Math.max(h,b)}const f=Math.max(s*Math.SQRT2,Math.max(c-i,h-l)/w.MAX_CELLS),d=Math.max(1,Math.ceil((c-i)/f+1e-9)),m=Math.max(1,Math.ceil((h-l)/f+1e-9)),E=new Uint8Array(d*m),P=o.map((D,y)=>{const b=Math.min(d-1,Math.max(0,Math.floor((u[y]-i)/f))),T=Math.min(m-1,Math.max(0,Math.floor((M[y]-l)/f)));return E[T*d+b]=1,T*d+b}),p=w.largestRectangle(E,d,m);if(p===void 0)return;const O=new Set;return o.forEach((D,y)=>{const b=P[y]%d,T=Math.floor(P[y]/d);b>=p.column&&b<p.column+p.columns&&T>=p.row&&T<p.row+p.rows&&O.add(D)}),{area:p.area*f*f,angle:n,covered:O,rectangle:{minU:i+p.column*f,maxU:i+(p.column+p.columns)*f,minV:l+p.row*f,maxV:l+(p.row+p.rows)*f}}}static largestRectangle(t,e,o){const n=new Array(e).fill(0);let s;for(let r=0;r<o;r++){for(let i=0;i<e;i++)n[i]=t[r*e+i]?n[i]+1:0;const a=[];for(let i=0;i<=e;i++){const c=i===e?0:n[i];for(;a.length>0&&n[a[a.length-1]]>=c;){const l=a.pop(),h=a.length===0?i:i-a[a.length-1]-1,u=n[l]*h;(s===void 0||u>s.area)&&(s={column:i-h,row:r-n[l]+1,columns:h,rows:n[l],area:u})}a.push(i)}}return s}static roof(t){const e=[...t].sort((o,n)=>o-n);return Math.max(2,e[Math.min(e.length-1,Math.floor(e.length*w.ROOF_PERCENTILE))])}static building(t,e,o){const n=Math.cos(e),s=Math.sin(e),r=t.maxU-t.minU,a=t.maxV-t.minV,i=(t.minU+t.maxU)/2,c=(t.minV+t.maxV)/2,h=((90-(r<a?e:e+Math.PI/2)*180/Math.PI)%180+180)%180;return{eastM:w.tenth(i*n-c*s),northM:w.tenth(i*s+c*n),widthM:w.tenth(Math.max(r,a)),lengthM:w.tenth(Math.min(r,a)),heightM:w.tenth(o),headingDeg:Math.round(h*10)/10}}static smallestRectangle(t){let e={area:1/0,angle:0,rectangle:{minU:0,maxU:0,minV:0,maxV:0}};for(let o=0;o<Math.max(1,t.length);o++){const[n,s]=t[o]??[0,0],[r,a]=t[(o+1)%t.length]??[1,0],i=Math.atan2(a-s,r-n),c=Math.cos(i),l=Math.sin(i);let h=1/0,u=-1/0,M=1/0,f=-1/0;for(const[m,E]of t){const P=m*c+E*l,p=-m*l+E*c;h=Math.min(h,P),u=Math.max(u,P),M=Math.min(M,p),f=Math.max(f,p)}const d=(u-h)*(f-M);d<e.area&&(e={area:d,angle:i,rectangle:{minU:h,maxU:u,minV:M,maxV:f}})}return e}static hull(t){const e=[...t].sort((a,i)=>a[0]-i[0]||a[1]-i[1]),o=e.filter((a,i)=>i===0||a[0]!==e[i-1][0]||a[1]!==e[i-1][1]);if(o.length<3)return o;const n=(a,i,c)=>(i[0]-a[0])*(c[1]-a[1])-(i[1]-a[1])*(c[0]-a[0]),s=[];for(const a of o){for(;s.length>=2&&n(s[s.length-2],s[s.length-1],a)<=0;)s.pop();s.push(a)}const r=[];for(const a of[...o].reverse()){for(;r.length>=2&&n(r[r.length-2],r[r.length-1],a)<=0;)r.pop();r.push(a)}return[...s.slice(0,-1),...r.slice(0,-1)]}static tenth(t){return Math.round(t*10)/10}}class x{constructor(t,e,o,n){this.heights=t,this.vegetation=e,this.width=o,this.height=n}static SUMMIT_RADIUS_M=2.5;static CROWN_REACH_M=8;static MAX_WIDTH_M=16;static MIN_WIDTH_M=2;static tenth(t){return Math.round(t*10)/10}trees(t){const e=t.metresPerPixel,o=t.minHeightM??4,n=t.eyeM??1.6,s=t.minElevationDeg??2,r=Math.max(1,Math.round(x.SUMMIT_RADIUS_M/e)),a=Math.round(x.CROWN_REACH_M/e),i=this.width/2,c=this.height/2,l=[];for(let h=0;h<this.height;h++)for(let u=0;u<this.width;u++){const M=this.canopy(u,h);if(M<o)continue;const f=(u+.5-i)*e,d=(c-h-.5)*e,m=Math.hypot(f,d);if(m>t.radiusM||!this.isSummit(u,h,M,r))continue;const E=Math.atan2(M-n,Math.max(m,1))*180/Math.PI;E<s||l.push({tree:{eastM:x.tenth(f),northM:x.tenth(d),heightM:x.tenth(M),widthM:x.tenth(this.crownWidth(u,h,M,e,a))},elevation:E})}return l.sort((h,u)=>u.elevation-h.elevation),l.slice(0,t.maxTrees??150).map(h=>h.tree)}canopy(t,e){if(t<0||e<0||t>=this.width||e>=this.height)return 0;const o=e*this.width+t;return this.vegetation[o]?this.heights[o]:0}isSummit(t,e,o,n){for(let s=-n;s<=n;s++)for(let r=-n;r<=n;r++){if(r===0&&s===0)continue;const a=this.canopy(t+r,e+s);if(a>o||a===o&&(s<0||s===0&&r<0))return!1}return!0}crownWidth(t,e,o,n,s){let r=0;for(let i=-s;i<=s;i++)for(let c=-s;c<=s;c++)Math.hypot(c,i)*n<=x.CROWN_REACH_M&&this.canopy(t+c,e+i)>=o*.5&&r++;const a=2*Math.sqrt(r*n*n/Math.PI);return Math.max(x.MIN_WIDTH_M,Math.min(a,x.MAX_WIDTH_M))}}class A{static WALLS={1:"stone",2:"meuliere",3:"concrete",4:"brick",5:"block",6:"wood",9:"other"};static ROOFS={1:"tile",2:"slate",3:"zinc",4:"concrete",9:"other"};static WALL_COLOURS={stone:"#b9ae9b",meuliere:"#b8a78a",concrete:"#b4b2ac",brick:"#a65f48",block:"#d0c6b2",wood:"#7d5c3e",other:"#c9c0ae"};static PLASTER="#d3cab8";static ROOF_COLOURS={tile:"#a0583f",slate:"#4a5059",zinc:"#8d969c",concrete:"#8f8e8a",other:"#7a7872"};static VARIATION=.12;static of(t,e){const o=String(t??"").trim();if(!/^\d{1,2}$/.test(o))return;const n=Number(o),s=n%10!==0?n%10:Math.floor(n/10);return(e==="wall"?A.WALLS:A.ROOFS)[String(s)]}static roofColor(t){return t?A.ROOF_COLOURS[t]:void 0}static fit(t){return t.map(e=>{if(e.facade)return e;const o={color:A.wallColor(e)};return{...e,facade:o}})}static wallColor(t){const e=t.wallMaterial?A.WALL_COLOURS[t.wallMaterial]:A.PLASTER,o=Math.sin(t.eastM*12.9898+t.northM*78.233)*43758.5453,n=1+(o-Math.floor(o)-.5)*2*A.VARIATION,s=r=>Math.max(0,Math.min(255,Math.round(parseInt(e.slice(r,r+2),16)*n))).toString(16).padStart(2,"0");return`#${s(1)}${s(3)}${s(5)}`}}class g{static MIN_RISE_M=1.2;static MIN_EAVES_M=2.5;static MIN_SEEN=.35;static NO_DATA=-9999;static BANDS=7;static INSET_M=.9;static LIFT=1.18;static PEAK=.3;static LEVEL=.45;static fit(t,e,o){return!e&&!o&&!t.some(n=>n.roofMaterial)?t:t.map(n=>{const s=e?g.shapeOf(n,e):void 0,r=(o?g.colorOf(n,o):void 0)??A.roofColor(n.roofMaterial);if(!s&&!r)return n;const a={shape:s?.shape??"flat",...s?.ridge==="depth"?{ridge:"depth"}:{},riseM:s?.riseM??0,...r?{color:r}:{}},i=s&&s.shape!=="flat"?s.topM:n.heightM;return{...n,heightM:i,roof:a}})}static world(t,e,o){const n=t.headingDeg*Math.PI/180;return{east:t.eastM+e*Math.cos(n)+o*Math.sin(n),north:t.northM-e*Math.sin(n)+o*Math.cos(n)}}static shapeOf(t,e){const o=g.BANDS,n=Math.max(e.metresPerPixel,.5),s=t.widthM/2-g.INSET_M,r=t.lengthM/2-g.INSET_M;if(s<=0||r<=0)return;const a=[],i=Array.from({length:o},()=>({sum:0,n:0})),c=Array.from({length:o},()=>({sum:0,n:0}));let l=0;for(let y=-s;y<=s;y+=n)for(let b=-r;b<=r;b+=n){l++;const{east:T,north:X}=g.world(t,y,b),C=Math.floor(T/e.metresPerPixel+e.size/2),z=Math.floor(e.size/2-X/e.metresPerPixel);if(C<0||z<0||C>=e.size||z>=e.size)continue;const V=z*e.size+C,U=e.heights[V];if(e.vegetation[V]||U===g.NO_DATA||!(U>0))continue;a.push(U);const W=i[Math.min(o-1,Math.floor((y+s)/(2*s)*o))],$=c[Math.min(o-1,Math.floor((b+r)/(2*r)*o))];W.sum+=U,W.n++,$.sum+=U,$.n++}if(l===0||a.length/l<g.MIN_SEEN)return;a.sort((y,b)=>y-b);const h=g.percentile(a,.08),u=g.percentile(a,.92),M=u-h;if(h<g.MIN_EAVES_M||M>Math.min(t.widthM,t.lengthM))return;if(M<g.MIN_RISE_M)return{shape:"flat",riseM:0,topM:u};const f=g.profile(i),d=g.profile(c);if(!f||!d)return;const m=g.peak(d)/M,E=g.peak(f)/M,P=g.spread(f)/M,p=g.spread(d)/M,O=m>=g.PEAK&&P<=g.LEVEL,D=E>=g.PEAK&&p<=g.LEVEL;if(O&&(!D||m>=E))return{shape:"gable",ridge:"width",riseM:M,topM:u};if(D)return{shape:"gable",ridge:"depth",riseM:M,topM:u};if(m>=g.PEAK&&E>=g.PEAK/2)return{shape:"hip",ridge:"width",riseM:M,topM:u}}static profile(t){const e=t.map(o=>o.n>0?o.sum/o.n:NaN);return e.filter(Number.isFinite).length>=t.length-1?e.map((o,n)=>Number.isFinite(o)?o:g.neighbour(e,n)):void 0}static neighbour(t,e){return Number.isFinite(t[e-1])?t[e-1]:t[e+1]}static peak(t){const e=Math.max(1,Math.floor(t.length/3)),o=s=>s.reduce((r,a)=>r+a,0)/s.length,n=[...t.slice(0,e),...t.slice(t.length-e)];return o(t.slice(e,t.length-e))-o(n)}static spread(t){return Math.max(...t)-Math.min(...t)}static percentile(t,e){return t[Math.min(t.length-1,Math.floor(t.length*e))]}static colorOf(t,e){const o=Math.max(e.metresPerPixel,.5),n=Math.max(t.widthM/2-g.INSET_M,o),s=Math.max(t.lengthM/2-g.INSET_M,o),r=[],a=[],i=[];for(let h=-n;h<=n;h+=o)for(let u=-s;u<=s;u+=o){const{east:M,north:f}=g.world(t,h,u),d=Math.floor(M/e.metresPerPixel+e.size/2),m=Math.floor(e.size/2-f/e.metresPerPixel);if(d<0||m<0||d>=e.size||m>=e.size)continue;const E=(m*e.size+d)*e.samples,P=e.values[E],p=e.values[E+1],O=e.values[E+2];p>P&&p>O||(r.push(P),a.push(p),i.push(O))}if(r.length===0)return;const c=h=>h.sort((u,M)=>u-M)[Math.floor(h.length/2)],l=h=>Math.min(255,Math.round(h*g.LIFT)).toString(16).padStart(2,"0");return`#${l(c(r))}${l(c(a))}${l(c(i))}`}}class v{static DEFAULT_HEIGHT_M=6;static METRES_PER_DEGREE=111320;static STREET_SPACING_M=35;static KERB_OFFSET_M=1;static DEFAULT_WIDTH_M=5.5;static PATIENCE_MS=15e3;static MAX=150;client;constructor(t={}){this.client=new k(t)}static today(){return new Date().toISOString().slice(0,10)}async near(t,e){const o=e/v.METRES_PER_DEGREE,n=e/(v.METRES_PER_DEGREE*Math.cos(t.lat*Math.PI/180)),s=[t.lat-o,t.lng-n,t.lat+o,t.lng+n].map(i=>i.toFixed(6)).join(",");let r;const a=new Promise(i=>{r=setTimeout(()=>i(void 0),v.PATIENCE_MS)});try{const i=await Promise.race([this.client.query(`[out:json][timeout:25];(node["highway"="street_lamp"](${s});way["highway"]["lit"="yes"](${s}););out geom;`),a]);return i?v.lampsFrom(i,t,e):[]}catch{return[]}finally{clearTimeout(r)}}static lampsFrom(t,e,o){const n=[];for(const r of t.elements??[]){if(r.type==="way"){v.alongStreet(r,e,n);continue}if(typeof r.lat!="number"||typeof r.lon!="number")continue;const a=(r.lon-e.lng)*v.METRES_PER_DEGREE*Math.cos(e.lat*Math.PI/180),i=(r.lat-e.lat)*v.METRES_PER_DEGREE;if(Math.hypot(a,i)>o)continue;const c=Number.parseFloat(r.tags?.height??"");n.push({eastM:Math.round(a*10)/10,northM:Math.round(i*10)/10,...Number.isFinite(c)&&c>=2&&c<=20?{heightM:c}:{}})}const s=n.filter(r=>Math.hypot(r.eastM,r.northM)<=o);return n.length=0,n.push(...s),n.sort((r,a)=>Math.hypot(r.eastM,r.northM)-Math.hypot(a.eastM,a.northM)),n.slice(0,v.MAX)}static alongStreet(t,e,o){const n=t.geometry;if(!n||n.length<2)return;const s=f=>[(f.lon-e.lng)*v.METRES_PER_DEGREE*Math.cos(e.lat*Math.PI/180),(f.lat-e.lat)*v.METRES_PER_DEGREE],r=n.map(s),a=Number.parseFloat(t.tags?.width??""),i=Number.parseInt(t.tags?.lanes??"",10),l=(Number.isFinite(a)&&a>0?a:Number.isFinite(i)&&i>0?i*3.5:v.DEFAULT_WIDTH_M)/2+v.KERB_OFFSET_M;let h=1,u=v.STREET_SPACING_M/2,M=0;for(let f=1;f<r.length;f++){const[d,m]=r[f-1],[E,P]=r[f],p=Math.hypot(E-d,P-m);if(p===0)continue;const O=(E-d)/p,D=(P-m)/p;for(;u<=M+p;u+=v.STREET_SPACING_M){const y=u-M;o.push({eastM:Math.round((d+O*y+D*l*h)*10)/10,northM:Math.round((m+D*y-O*l*h)*10)/10}),h=-h}M+=p}}}class j{id="ign-lidar-hd";name="IGN LiDAR HD";attribution="Canopy and roofs © IGN, LiDAR HD (Licence Ouverte 2.0), as surveyed on a day the service does not give";creditUrl="https://geoservices.ign.fr/lidarhd";contemporary=!0;platform;lamps;constructor(t={},e){this.platform=new R(t),this.lamps=e}covers(t,e){return R.covers(t,e)}async getSurroundings(t,e){if(!this.covers(t.lat,t.lng))throw new S("no-coverage","The LiDAR HD survey covers France only");const o=R.lidarRadius(e),[n,s,r,a,i]=await Promise.all([this.platform.lidar(t,o),this.platform.photo(t,o).catch(()=>{}),this.lamps?.near(t,e),this.platform.laserDate(t),this.platform.photoDate(t)]);return{trees:new x(n.heights,n.vegetation,n.size,n.size).trees({metresPerPixel:n.metresPerPixel,radiusM:o}),buildings:A.fit(g.fit(new w(n.heights,n.building,n.size,n.size).buildings({metresPerPixel:n.metresPerPixel,radiusM:o,maxBuildings:300}),n,s)),bridges:[],lines:[],...r?{lamps:r}:{},dates:{...a?{laser:a}:{},...s&&i?{photo:i}:{},...r?.length?{lamps:v.today()}:{}}}}}class I{static METRES_PER_DEGREE=111320;static NAMED_NATURES={Silo:"Silo"};static DEFAULT_HEIGHT_M=6;static FLOOR_HEIGHT_M=3;static FINE_M=.5;static COARSE_M=1;static MAX_CELLS=4e4;static RECTANGLE_FILL=.9;static buildings(t,e,o,n=12,s=300){const r=[];for(const i of t){const c=I.rings(i,e);if(c.length===0)continue;const l=Number(i.properties.nombre_d_etages),h=Number(i.properties.hauteur),u=Number.isFinite(h)&&h>0?h:Number.isFinite(l)&&l>0?l*I.FLOOR_HEIGHT_M:I.DEFAULT_HEIGHT_M;for(const M of I.rectanglesOf(c,u,n)){if(Math.hypot(M.eastM,M.northM)>o)continue;const f=A.of(i.properties.materiaux_des_murs,"wall"),d=A.of(i.properties.materiaux_de_la_toiture,"roof"),m=I.NAMED_NATURES[String(i.properties.nature??"")];r.push({...M,...m?{name:m}:{},...Number.isFinite(l)&&l>0?{floors:l}:{},...f?{wallMaterial:f}:{},...d?{roofMaterial:d}:{}})}}const a=i=>Math.hypot(i.eastM,i.northM);if(r.length>s){const i=c=>(c.heightM+6)*Math.sqrt(c.widthM*c.lengthM)/Math.max(a(c),50);r.sort((c,l)=>i(l)-i(c)),r.length=s}return r.sort((i,c)=>a(i)-a(c)),r}static named(t,e,o){const n=e.map(s=>({name:typeof s.properties.toponyme=="string"?s.properties.toponyme:"",rings:I.rings(s,o)})).filter(s=>s.name.length>0&&s.rings.length>0);return n.length===0?t:t.map(s=>{const r=n.find(a=>I.inside(s.eastM,s.northM,a.rings));return r?{...s,name:r.name}:s})}static inside(t,e,o){let n=0;for(const s of o)for(let r=0;r+1<s.length;r++){const a=s[r],i=s[r+1];a.north<=e!=i.north<=e&&a.east+(e-a.north)/(i.north-a.north)*(i.east-a.east)>t&&n++}return n%2===1}static rings(t,e){const o=t.geometry,n=o.type==="Polygon"?[o.coordinates]:o.type==="MultiPolygon"?o.coordinates:[],s=Math.cos(e.lat*Math.PI/180),r=[];for(const a of n)for(const i of a)r.push(i.map(([c,l])=>({east:(c-e.lng)*I.METRES_PER_DEGREE*s,north:(l-e.lat)*I.METRES_PER_DEGREE})));return r}static rectanglesOf(t,e,o){let n=1/0,s=-1/0,r=1/0,a=-1/0;for(const u of t)for(const M of u)n=Math.min(n,M.east),s=Math.max(s,M.east),r=Math.min(r,M.north),a=Math.max(a,M.north);let i=I.FINE_M;(s-n)*(a-r)/(i*i)>I.MAX_CELLS&&(i=I.COARSE_M);const c=[],l=[];for(let u=r+i/2;u<a;u+=i){const M=[];for(const f of t)for(let d=0;d+1<f.length;d++){const m=f[d],E=f[d+1];m.north<=u!=E.north<=u&&M.push(m.east+(u-m.north)/(E.north-m.north)*(E.east-m.east))}M.sort((f,d)=>f-d);for(let f=0;f+1<M.length;f+=2)for(let d=Math.ceil((M[f]-i/2)/i)*i+i/2;d<M[f+1];d+=i)c.push(d),l.push(u)}if(c.length*i*i<o)return[];const h=t.flatMap(u=>u.slice(0,-1).map((M,f)=>({from:M,to:u[f+1]})));return w.ofPoints(c,l,new Array(c.length).fill(e),i,o,I.RECTANGLE_FILL,h)}}class q{id="ign-lidar-topo";name="IGN LiDAR HD + BD TOPO";attribution="Canopy © IGN, LiDAR HD; buildings, bridges and lines © IGN, BD TOPO (Licence Ouverte 2.0), as surveyed on days the services do not give";creditUrl="https://geoservices.ign.fr/lidarhd";contemporary=!0;platform;lamps;constructor(t={},e){this.platform=new R(t),this.lamps=e}covers(t,e){return R.covers(t,e)}async getSurroundings(t,e){if(!this.covers(t.lat,t.lng))throw new S("no-coverage","The IGN's surveys cover France only");const o=R.radius(e),[n,s,r,a,i,c]=await Promise.allSettled([this.platform.lidar(t,o),this.platform.vectors(t,o,!0),this.platform.photo(t,o),this.lamps?.near(t,e)??Promise.resolve(void 0),this.platform.laserDate(t),this.platform.photoDate(t)]),l=R.lidarRadius(o);if(n.status==="rejected"&&s.status==="rejected")throw n.reason;const h=n.status==="fulfilled"?n.value:void 0,u=s.status==="fulfilled"?s.value:void 0,M=u!==void 0&&u.buildings.length===0&&u.bridges.length===0&&u.lines.length===0;if(n.status==="rejected"&&n.reason instanceof S&&n.reason.reason==="no-coverage"&&M)throw n.reason;return{trees:h?new x(h.heights,h.vegetation,h.size,h.size).trees({metresPerPixel:h.metresPerPixel,radiusM:l}):[],buildings:this.roofed(this.buildings(h,u,t,o),h,r.status==="fulfilled"?r.value:void 0),bridges:u?F.bridges(u,t,o,h?.structures):[],lines:u?F.lines(u,t,o,h?.structures):[],...a.status==="fulfilled"&&a.value?{lamps:a.value}:{},dates:{...n.status==="fulfilled"&&i.status==="fulfilled"&&i.value?{laser:i.value}:{},...r.status==="fulfilled"&&c.status==="fulfilled"&&c.value?{photo:c.value}:{},...u?.mapDate?{map:u.mapDate}:{},...a.status==="fulfilled"&&a.value?.length?{lamps:v.today()}:{}}}}roofed(t,e,o){return A.fit(g.fit(t,e,o))}buildings(t,e,o,n){const s=e?I.buildings(e.buildings,o,n):[],r=s.length>0||t===void 0?s:new w(t.heights,t.building,t.size,t.size).buildings({metresPerPixel:t.metresPerPixel,radiusM:R.lidarRadius(n),maxBuildings:300});return e?I.named(r,e.zones,o):r}}class Y{id="ign-bd-topo";name="IGN BD TOPO";attribution="Buildings, bridges and lines © IGN, BD TOPO (Licence Ouverte 2.0), as drawn on a day the service does not give";creditUrl="https://geoservices.ign.fr/bdtopo";contemporary=!0;platform;lamps;constructor(t={},e){this.platform=new R(t),this.lamps=e}covers(t,e){return R.covers(t,e)}async getSurroundings(t,e){if(!this.covers(t.lat,t.lng))throw new S("no-coverage","BD TOPO covers France only");const o=R.radius(e),[n,s,r,a]=await Promise.all([this.platform.vectors(t,o,!0),this.platform.photo(t,o).catch(()=>{}),this.lamps?.near(t,e),this.platform.photoDate(t)]);return{trees:[],buildings:A.fit(g.fit(I.named(I.buildings(n.buildings,t,o),n.zones,t),void 0,s)),bridges:F.bridges(n,t,o,void 0),lines:F.lines(n,t,o,void 0),...r?{lamps:r}:{},dates:{...n.mapDate?{map:n.mapDate}:{},...s&&a?{photo:a}:{},...r?.length?{lamps:v.today()}:{}}}}}class N{static ROOF_SHAPES={flat:"flat",gabled:"gable",gambrel:"gable",saltbox:"gable","half-hipped":"hip",hipped:"hip",pyramidal:"hip",mansard:"hip",round:"gable"};static WALL_MATERIALS={brick:"brick",stone:"stone",granite:"stone",sandstone:"stone",limestone:"stone",concrete:"concrete",cement_block:"block",block:"block",wood:"wood",timber_framing:"wood"};static ROOF_MATERIALS={roof_tiles:"tile",tiles:"tile",tile:"tile",slate:"slate",metal:"zinc",zinc:"zinc",tin:"zinc",copper:"zinc",concrete:"concrete",eternit:"other"};static COLOURS={white:"#e8e6e0",grey:"#8c8c8a",gray:"#8c8c8a",black:"#3a3a3a",red:"#a8483a",brown:"#6e4f38",beige:"#d6c9a8",yellow:"#d8c070",orange:"#c9773a",green:"#5f7a52",blue:"#506a8a",tan:"#c0a37a",cream:"#e6dcc0",pink:"#c99a96",silver:"#b4b6b6"};static height(t){const e=Number.parseFloat((t??"").replace(",","."));return Number.isFinite(e)&&e>=2&&e<=500?e:void 0}static levels(t){const e=Number.parseInt(t??"",10);return Number.isFinite(e)&&e>=1&&e<=150?e:void 0}static roofShape(t){return N.ROOF_SHAPES[(t??"").trim().toLowerCase()]}static wallMaterial(t){return N.WALL_MATERIALS[(t??"").trim().toLowerCase()]}static roofMaterial(t){return N.ROOF_MATERIALS[(t??"").trim().toLowerCase()]}static colour(t){const e=(t??"").trim().toLowerCase();return/^#[0-9a-f]{6}$/.test(e)?e:/^#[0-9a-f]{3}$/.test(e)?`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`:N.COLOURS[e]}}class L{id="osm-buildings";name="OpenStreetMap buildings";attribution="Buildings © OpenStreetMap contributors (ODbL), as drawn on the day of the data, which a recording is not";creditUrl="https://www.openstreetmap.org/copyright";contemporary=!0;static MAX_RADIUS_M=1500;static MIN_AREA_M2=12;static MAX_BUILDINGS=300;client;lamps;constructor(t={},e){this.client=new k(t),this.lamps=e}covers(){return!0}async getSurroundings(t,e){const o=Math.min(e,L.MAX_RADIUS_M);let n;try{n=await this.client.query(`[out:json][timeout:30];(way["building"](around:${o},${t.lat},${t.lng});relation["building"]["type"="multipolygon"](around:${o},${t.lat},${t.lng}););out geom;`)}catch(a){throw new S("unreachable",a instanceof Error?a.message:String(a))}const s=await this.lamps?.near(t,e),r=(n.osm3s?.timestamp_osm_base??"").slice(0,10);return{trees:[],buildings:A.fit(L.buildings(n,t,o)),bridges:[],lines:[],...s?{lamps:s}:{},dates:{.../^\d{4}-\d{2}-\d{2}$/.test(r)?{map:r}:{},...s?.length?{lamps:v.today()}:{}}}}static buildings(t,e,o){const n=[];for(const s of t.elements??[]){const r=L.ringsOf(s);if(r.length===0)continue;const a=s.tags??{},i=N.levels(a["building:levels"]),c=N.height(a.height),l={geometry:{type:"Polygon",coordinates:r},properties:{...c?{hauteur:c}:{},...i?{nombre_d_etages:i}:{}}};for(const h of I.buildings([l],e,o,L.MIN_AREA_M2,50))n.push(L.described(h,a,c!==void 0))}return n.sort((s,r)=>Math.hypot(s.eastM,s.northM)-Math.hypot(r.eastM,r.northM)),n.slice(0,L.MAX_BUILDINGS)}static ringsOf(t){const e=n=>{if(!n||n.length<4)return;const s=n.map(i=>[i.lon,i.lat]),r=s[0],a=s[s.length-1];return r[0]===a[0]&&r[1]===a[1]?s:void 0};if(t.type==="way"){const n=e(t.geometry);return n?[n]:[]}return(t.members??[]).filter(n=>n.role==="outer").map(n=>e(n.geometry)).filter(n=>n!==void 0).slice(0,1)}static described(t,e,o){const n=N.wallMaterial(e["building:material"]),s=N.roofMaterial(e["roof:material"]),r=N.colour(e["building:colour"]),a=N.colour(e["roof:colour"])??A.roofColor(s),i=N.roofShape(e["roof:shape"]),c=r?{color:r}:void 0;let l,h=t.heightM;if(i==="gable"||i==="hip"){const u=N.height(e["roof:height"]),M=Math.round((u??Math.min(5,Math.max(1.5,.29*Math.min(t.widthM,t.lengthM))))*10)/10;o||(h=Math.round((t.heightM+M)*10)/10),l={shape:i,riseM:M,...e["roof:orientation"]==="across"?{ridge:"depth"}:{},...a?{color:a}:{}}}else(i==="flat"||a)&&(l={shape:"flat",riseM:0,...a?{color:a}:{}});return{...t,heightM:h,...e.name?{name:e.name}:{},...n?{wallMaterial:n}:{},...s?{roofMaterial:s}:{},...c?{facade:c}:{},...l?{roof:l}:{}}}}const _=[{id:"ign-lidar-topo",name:"IGN LiDAR HD + BD TOPO",credit:"© IGN, LiDAR HD and BD TOPO, Licence Ouverte 2.0; street lamps © OpenStreetMap contributors",creditUrl:"https://geoservices.ign.fr/lidarhd",create:()=>new q({},new v)},{id:"ign-lidar-hd",name:"IGN LiDAR HD",credit:"© IGN, LiDAR HD, Licence Ouverte 2.0; street lamps © OpenStreetMap contributors",creditUrl:"https://geoservices.ign.fr/lidarhd",create:()=>new j({},new v)},{id:"ign-bd-topo",name:"IGN BD TOPO",credit:"© IGN, BD TOPO, Licence Ouverte 2.0; street lamps © OpenStreetMap contributors",creditUrl:"https://geoservices.ign.fr/bdtopo",create:()=>new Y({},new v)},{id:"osm-buildings",name:"OpenStreetMap buildings",credit:"Buildings and street lamps © OpenStreetMap contributors (ODbL)",creditUrl:"https://www.openstreetmap.org/copyright",create:()=>new L({},new v)}];class G{static DEFAULT_ID=_[0].id;static WORLD_ID="osm-buildings";static NONE="none";static byId(t){return t===G.NONE?void 0:_.find(e=>e.id===t)??_[0]}static providerFor(t,e,o){const n=G.byId(t)?.create();if(t!==void 0&&t!==G.DEFAULT_ID)return n?.covers(e,o)?n:void 0;const s=_.find(a=>a.id===G.WORLD_ID).create(),r=[n,s].filter(a=>a!==void 0&&a.covers(e,o));return r.length>1?new K(r):r[0]}}export{_ as SURROUNDINGS_SOURCES,G as SurroundingsSources};
|