{"id":36955,"date":"2026-09-08T16:00:03","date_gmt":"2026-09-08T16:00:03","guid":{"rendered":"https:\/\/volatusaerospace.com\/?page_id=36955"},"modified":"2026-09-08T17:22:30","modified_gmt":"2026-09-08T17:22:30","slug":"photogrammetry","status":"publish","type":"page","link":"https:\/\/volatusaerospace.com\/fr-ca\/services\/technical-capabilities\/photogrammetry\/","title":{"rendered":"Services de photogramm\u00e9trie par drone | Mod\u00e9lisation 3D et cartographie a\u00e9rienne"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"36955\" class=\"elementor elementor-36955\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b2e87a7 e-con-full dark-section e-flex e-con e-parent\" data-id=\"b2e87a7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b31b43e elementor-widget__width-inherit elementor-absolute elementor-widget elementor-widget-html\" data-id=\"b31b43e\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;_position&quot;:&quot;absolute&quot;}\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div id=\"volatus-3d-hero\">\r\n  <!-- 3D WebGL Canvas -->\r\n  <canvas id=\"scene\" aria-label=\"Interactive 3D photogrammetric digital twin of Volatus Aerospace survey site\"><\/canvas>\r\n  \r\n  <!-- Left-to-Right Dark Smooth Gradient Scrim (Underneath Elementor Text) -->\r\n  <div class=\"hero-gradient-scrim\"><\/div>\r\n\r\n  <!-- Circular Compass Only -->\r\n  <div class=\"compass-cluster\">\r\n    <div class=\"compass\"><div id=\"compass-needle\">N<\/div><\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<style>\r\n#volatus-3d-hero {\r\n  --volatus-black: #000000 !important; \/* Changed to pure black *\/\r\n  --volatus-gold: #FFB601 !important;\r\n  --volatus-gold-glow: rgba(255, 182, 1, 0.35) !important;\r\n  --volatus-gold-hover: #e5a300 !important;\r\n  --volatus-card: rgba(20, 22, 25, 0.88) !important;\r\n  --light-gray: #E2E2E2 !important;\r\n  --medium-gray: #B3B3B3 !important;\r\n  --border-subtle: rgba(255, 255, 255, 0.08) !important;\r\n  --font-sans: 'Inter', -apple-system, sans-serif !important;\r\n  --font-mono: 'JetBrains Mono', monospace !important;\r\n\r\n  position: absolute !important;\r\n  top: 0 !important;\r\n  left: 0 !important;\r\n  width: 100vw !important;\r\n  height: 100% !important;\r\n  min-height: 100vh !important;\r\n  overflow: hidden !important;\r\n  background: var(--volatus-black) !important;\r\n  z-index: 1 !important;\r\n}\r\n\r\n#volatus-3d-hero * {\r\n  box-sizing: border-box !important;\r\n}\r\n\r\n#volatus-3d-hero #scene {\r\n  position: absolute !important;\r\n  inset: 0 !important;\r\n  width: 100% !important;\r\n  height: 100% !important;\r\n  display: block !important;\r\n  cursor: grab !important;\r\n  touch-action: none !important;\r\n  z-index: 1 !important;\r\n}\r\n\r\n#volatus-3d-hero #scene.dragging { \r\n  cursor: grabbing !important; \r\n}\r\n\r\n#volatus-3d-hero .hero-gradient-scrim {\r\n  position: absolute !important;\r\n  inset: 0 !important;\r\n  pointer-events: none !important;\r\n  z-index: 2 !important;\r\n  \/* Updated gradient to use pure black *\/\r\n  background: linear-gradient(90deg, \r\n      #000000 0%, \r\n      #000000 34%, \r\n      rgba(0, 0, 0, 0.94) 44%, \r\n      rgba(0, 0, 0, 0.65) 54%, \r\n      rgba(0, 0, 0, 0.2) 68%, \r\n      transparent 82%\r\n    ),\r\n    linear-gradient(180deg, \r\n      rgba(0, 0, 0, 0.8) 0%, \r\n      transparent 12%, \r\n      transparent 86%, \r\n      #000000 100%\r\n    ) !important;\r\n}\r\n\r\n#volatus-3d-hero .compass-cluster {\r\n  position: absolute !important;\r\n  right: 32px !important;\r\n  bottom: 28px !important;\r\n  z-index: 12 !important;\r\n  pointer-events: none !important;\r\n}\r\n\r\n#volatus-3d-hero .compass {\r\n  width: 48px !important;\r\n  height: 48px !important;\r\n  border-radius: 50% !important;\r\n  border: 1px solid var(--border-subtle) !important;\r\n  background: var(--volatus-card) !important;\r\n  backdrop-filter: blur(12px) !important;\r\n  -webkit-backdrop-filter: blur(12px) !important;\r\n  position: relative !important;\r\n  box-shadow: 0 8px 24px rgba(0,0,0,.6) !important;\r\n}\r\n\r\n#volatus-3d-hero .compass::after {\r\n  content: \"\" !important;\r\n  position: absolute !important;\r\n  left: 50% !important;\r\n  top: 50% !important;\r\n  width: 2px !important;\r\n  height: 2px !important;\r\n  background: var(--medium-gray) !important;\r\n  border-radius: 50% !important;\r\n  transform: translate(-50%, -50%) !important;\r\n}\r\n\r\n#volatus-3d-hero #compass-needle {\r\n  position: absolute !important;\r\n  inset: 0 !important;\r\n  display: flex !important;\r\n  justify-content: center !important;\r\n  padding-top: 4px !important;\r\n  font-family: var(--font-mono) !important;\r\n  font-size: 0.6rem !important;\r\n  color: var(--volatus-gold) !important;\r\n  transition: transform 0.1s linear !important;\r\n}\r\n\r\n#volatus-3d-hero #compass-needle::after {\r\n  content: \"\" !important;\r\n  position: absolute !important;\r\n  top: 50% !important;\r\n  left: 50% !important;\r\n  width: 1px !important;\r\n  height: 13px !important;\r\n  background: linear-gradient(to bottom, var(--volatus-gold), transparent) !important;\r\n  transform: translate(-50%, -100%) !important;\r\n}\r\n\r\n@media (max-width: 1024px) {\r\n  #volatus-3d-hero .hero-gradient-scrim {\r\n    \/* Top 35% solid black for text, transitioning into bottom 65% animation area *\/\r\n    background: linear-gradient(180deg, \r\n      #000000 0%, \r\n      #000000 35%, \r\n      rgba(0, 0, 0, 0.88) 42%, \r\n      rgba(0, 0, 0, 0.52) 50%, \r\n      rgba(0, 0, 0, 0.15) 58%, \r\n      transparent 65%\r\n    ) !important;\r\n  }\r\n  #volatus-3d-hero .compass-cluster { \r\n    right: 20px !important; \r\n    bottom: 20px !important; \r\n  }\r\n  #volatus-3d-hero .compass {\r\n    width: 42px !important;\r\n    height: 42px !important;\r\n  }\r\n}\r\n<\/style>\r\n\r\n<script src=\"https:\/\/unpkg.com\/three@0.152.2\/build\/three.min.js\"><\/script>\r\n<script>\r\ndocument.addEventListener(\"DOMContentLoaded\", function() {\r\n  'use strict';\r\n  if(!window.THREE) return;\r\n  const REDUCED = matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n  const GOLD = 0xFFB601;\r\n  const isMobile = window.innerWidth <= 768;\r\n  const clamp=(v,a,b)=>Math.min(b,Math.max(a,v));\r\n  const sstep=(a,b,x)=>{const t=clamp((x-a)\/(b-a),0,1);return t*t*(3-2*t);};\r\n  const lerp=(a,b,t)=>a+(b-a)*t;\r\n\r\n  \/* ================= SURROUNDING MOUNTAINS NOISE FIELD ================= *\/\r\n  function hash2(x,z){const n=Math.sin(x*127.1+z*311.7)*43758.5453;return n-Math.floor(n);}\r\n  function vnoise(x,z){const xi=Math.floor(x),zi=Math.floor(z),xf=x-xi,zf=z-zi,u=xf*xf*(3-2*xf),v=zf*zf*(3-2*zf);\r\n    const a=hash2(xi,zi),b=hash2(xi+1,zi),c=hash2(xi,zi+1),d=hash2(xi+1,zi+1);\r\n    return a+(b-a)*u+(c-a)*v+(a-b-c+d)*u*v;}\r\n  function fbm(x,z,o=4){let t=0,a=.5,f=1;for(let i=0;i<o;i++){t+=a*vnoise(x*f,z*f);f*=2.03;a*=.5;}return t;}\r\n  function ridged(x,z,o=5){let t=0,a=.55,f=1;for(let i=0;i<o;i++){const n=1-Math.abs(2*vnoise(x*f+i*17.7,z*f-i*9.3)-1);t+=a*n*n;f*=2.11;a*=.55;}return t;}\r\n\r\n  const SITE_LEVEL_Y = 1.2;\r\n  function heightAt(x,z){\r\n    const dx=Math.max(0,Math.abs(x)-46), dz=Math.max(0,Math.abs(z)-38);\r\n    const dSite=Math.hypot(dx,dz);\r\n    if(dSite===0) return SITE_LEVEL_Y;\r\n    const blend=sstep(0,1,Math.min(1,dSite\/24));\r\n    let h=SITE_LEVEL_Y+(fbm(x*.02,z*.02)-.5)*5;\r\n    const r=Math.hypot(x,z);\r\n    const southGate=sstep(25,75,z)*(1-sstep(42,75,Math.abs(x)));\r\n    const mask=Math.max(sstep(58,115,r)*(1-southGate*.9),0);\r\n    const warp=(fbm(x*.013+3.7,z*.013+8.2)-.5)*1.9;\r\n    const m=ridged(x*.021+warp,z*.021-warp,5);\r\n    h+=mask*(m*52+Math.pow(m,3)*26);\r\n    return SITE_LEVEL_Y*(1-blend)+h*blend;\r\n  }\r\n\r\n  \/* ================= PROCEDURAL TEXTURES (INDUSTRIAL SITE) ================= *\/\r\n  function srgb(t){\r\n    if('colorSpace' in t && THREE.SRGBColorSpace) t.colorSpace=THREE.SRGBColorSpace;\r\n    t.anisotropy=4;\r\n    return t;\r\n  }\r\n\r\n  function barBetween(a,b,r,mat){\r\n    const d=new THREE.Vector3().subVectors(b,a), len=d.length();\r\n    const m=new THREE.Mesh(new THREE.CylinderGeometry(r,r,len,6),mat);\r\n    m.position.copy(a).addScaledVector(d,0.5);\r\n    m.quaternion.setFromUnitVectors(new THREE.Vector3(0,1,0),d.clone().normalize());\r\n    return m;\r\n  }\r\n\r\n  function createSitePadTexture(){\r\n    const s=14, W=Math.round(92*s), H=Math.round(76*s);\r\n    const c=document.createElement('canvas'); c.width=W; c.height=H;\r\n    const x=c.getContext('2d');\r\n    const MX=v=>(v+46)*s, MZ=v=>(v+38)*s, M=v=>v*s;\r\n\r\n    x.fillStyle='#3a3832'; x.fillRect(0,0,W,H);\r\n    for(let i=0;i<30000;i++){\r\n      const g=48+Math.random()*28|0;\r\n      x.fillStyle=`rgb(${g+6},${g+4},${g-2})`;\r\n      x.fillRect(Math.random()*W,Math.random()*H,2,2);\r\n    }\r\n    for(let i=0;i<26;i++){\r\n      const r=M(3+Math.random()*9), gx=Math.random()*W, gy=Math.random()*H;\r\n      const g=x.createRadialGradient(gx,gy,0,gx,gy,r);\r\n      g.addColorStop(0,'rgba(12,11,9,0.18)'); g.addColorStop(1,'rgba(12,11,9,0)');\r\n      x.fillStyle=g; x.beginPath(); x.arc(gx,gy,r,0,7); x.fill();\r\n    }\r\n\r\n    const apron=(wx,wz,w,d)=>{\r\n      x.fillStyle='#54595e';\r\n      x.fillRect(MX(wx-w\/2),MZ(wz-d\/2),M(w),M(d));\r\n      x.strokeStyle='rgba(40,43,46,0.85)'; x.lineWidth=1.5;\r\n      for(let i=0;i<=w;i+=4){\r\n        x.beginPath(); x.moveTo(MX(wx-w\/2+i),MZ(wz-d\/2)); x.lineTo(MX(wx-w\/2+i),MZ(wz+d\/2)); x.stroke();\r\n      }\r\n      for(let j=0;j<=d;j+=4){\r\n        x.beginPath(); x.moveTo(MX(wx-w\/2),MZ(wz-d\/2+j)); x.lineTo(MX(wx+w\/2),MZ(wz-d\/2+j)); x.stroke();\r\n      }\r\n    };\r\n    apron(-8,-4,25,18);\r\n    apron(18,-14,29,17);\r\n    apron(22,16,21,15);\r\n    apron(-32,2,11,12);\r\n    apron(7,25,25,13);\r\n\r\n    x.strokeStyle='#262628'; x.lineCap='round'; x.lineWidth=M(9);\r\n    x.beginPath();\r\n    x.moveTo(MX(8),MZ(40)); x.lineTo(MX(8),MZ(12));\r\n    x.bezierCurveTo(MX(8),MZ(2),MX(0),MZ(2),MX(-14),MZ(2));\r\n    x.lineTo(MX(-24),MZ(2)); x.bezierCurveTo(MX(-30),MZ(2),MX(-30),MZ(-6),MX(-24),MZ(-6));\r\n    x.lineTo(MX(14),MZ(-6)); x.bezierCurveTo(MX(22),MZ(-6),MX(22),MZ(-14),MX(22),MZ(-20));\r\n    x.stroke();\r\n\r\n    x.strokeStyle='rgba(255,182,1,0.75)'; x.lineWidth=M(0.35); x.setLineDash([M(2.2),M(2.2)]);\r\n    x.beginPath();\r\n    x.moveTo(MX(8),MZ(40)); x.lineTo(MX(8),MZ(12));\r\n    x.bezierCurveTo(MX(8),MZ(2),MX(0),MZ(2),MX(-14),MZ(2));\r\n    x.lineTo(MX(-24),MZ(2)); x.bezierCurveTo(MX(-30),MZ(2),MX(-30),MZ(-6),MX(-24),MZ(-6));\r\n    x.lineTo(MX(14),MZ(-6)); x.bezierCurveTo(MX(22),MZ(-6),MX(22),MZ(-14),MX(22),MZ(-20));\r\n    x.stroke();\r\n    x.setLineDash([]);\r\n\r\n    x.strokeStyle='rgba(240,240,235,0.7)'; x.lineWidth=M(0.22);\r\n    for(let i=0;i<7;i++){\r\n      const px=MX(-15+i*2.6);\r\n      x.beginPath(); x.moveTo(px,MZ(5)); x.lineTo(px,MZ(9.6)); x.stroke();\r\n    }\r\n    x.beginPath(); x.moveTo(MX(-15),MZ(5)); x.lineTo(MX(-15+6*2.6),MZ(5)); x.stroke();\r\n\r\n    x.strokeStyle='rgba(250,250,245,0.92)'; x.lineWidth=M(0.4);\r\n    x.beginPath(); x.arc(MX(32),MZ(2),M(6),0,7); x.stroke();\r\n    x.beginPath(); x.arc(MX(32),MZ(2),M(4.4),0,7); x.stroke();\r\n    x.font=`bold ${M(4.4)}px Arial`; x.fillStyle='rgba(250,250,245,0.95)';\r\n    x.textAlign='center'; x.textBaseline='middle'; x.fillText('H',MX(32),MZ(2.2));\r\n\r\n    x.save();\r\n    x.beginPath(); x.rect(MX(13),MZ(24.2),M(18),M(1.6)); x.clip();\r\n    x.fillStyle='#FFB601'; x.fillRect(MX(13),MZ(24.2),M(18),M(1.6));\r\n    x.fillStyle='#151515';\r\n    for(let hx=MX(13)-M(2);hx<MX(32);hx+=M(2)){\r\n      x.beginPath();\r\n      x.moveTo(hx,MZ(25.8)); x.lineTo(hx+M(1),MZ(24.2)); x.lineTo(hx+M(2),MZ(24.2)); x.lineTo(hx+M(1),MZ(25.8));\r\n      x.closePath(); x.fill();\r\n    }\r\n    x.restore();\r\n\r\n    x.strokeStyle='rgba(255,182,1,0.55)'; x.lineWidth=M(0.35);\r\n    x.strokeRect(M(2),M(2),W-M(4),H-M(4));\r\n\r\n    return srgb(new THREE.CanvasTexture(c));\r\n  }\r\n\r\n  function createCorrugatedTexture(){\r\n    const c=document.createElement('canvas'); c.width=128; c.height=128; const x=c.getContext('2d');\r\n    x.fillStyle='#c4c4c4'; x.fillRect(0,0,128,128);\r\n    for(let px=0;px<128;px+=10){\r\n      x.fillStyle='#e2e2e2'; x.fillRect(px,0,4,128);\r\n      x.fillStyle='#9e9e9e'; x.fillRect(px+4,0,3,128);\r\n      x.fillStyle='#b5b5b5'; x.fillRect(px+7,0,3,128);\r\n    }\r\n    return srgb(new THREE.CanvasTexture(c));\r\n  }\r\n\r\n  function createConcreteTexture(){\r\n    const c=document.createElement('canvas'); c.width=256; c.height=256; const x=c.getContext('2d');\r\n    x.fillStyle='#9ca0a4'; x.fillRect(0,0,256,256);\r\n    for(let i=0;i<3200;i++){\r\n      const g=140+Math.random()*32|0; x.fillStyle=`rgb(${g},${g+1},${g+2})`;\r\n      x.fillRect(Math.random()*256,Math.random()*256,1.6,1.6);\r\n    }\r\n    x.strokeStyle='rgba(70,72,76,0.45)'; x.lineWidth=1.5;\r\n    for(let i=0;i<=256;i+=64){\r\n      x.beginPath(); x.moveTo(i,0); x.lineTo(i,256); x.moveTo(0,i); x.lineTo(256,i); x.stroke();\r\n    }\r\n    const t=srgb(new THREE.CanvasTexture(c)); t.wrapS=t.wrapT=THREE.RepeatWrapping; return t;\r\n  }\r\n\r\n  function createAggregateTexture(){\r\n    const c=document.createElement('canvas'); c.width=256; c.height=256; const x=c.getContext('2d');\r\n    x.fillStyle='#9c8f78'; x.fillRect(0,0,256,256);\r\n    for(let i=0;i<7000;i++){\r\n      const v=125+Math.random()*70|0; x.fillStyle=`rgb(${v+12},${v},${v-14})`;\r\n      x.fillRect(Math.random()*256,Math.random()*256,2,2);\r\n    }\r\n    const t=srgb(new THREE.CanvasTexture(c)); t.wrapS=t.wrapT=THREE.RepeatWrapping; t.repeat.set(3,2); return t;\r\n  }\r\n\r\n  function createFacadeTexture(wM,hM,floors){\r\n    const S=26, W=Math.round(wM*S), H=Math.round(hM*S);\r\n    const c=document.createElement('canvas'); c.width=W; c.height=H; const x=c.getContext('2d');\r\n    x.fillStyle='#6c7278'; x.fillRect(0,0,W,H);\r\n    for(let i=0;i<W*H\/110;i++){\r\n      const g=95+Math.random()*28|0; x.fillStyle=`rgb(${g},${g+2},${g+4})`;\r\n      x.fillRect(Math.random()*W,Math.random()*H,1.4,1.4);\r\n    }\r\n    const floorH=H\/floors;\r\n    for(let f=0;f<floors;f++){\r\n      const y0=H-(f+1)*floorH;\r\n      x.fillStyle='#555b62'; x.fillRect(0,y0,W,floorH*0.34);\r\n      if(f===0){\r\n        x.fillStyle='#131b23'; x.fillRect(W*0.04,y0+floorH*0.34,W*0.92,floorH*0.6);\r\n        x.fillStyle='rgba(210,230,245,0.22)'; x.fillRect(W*0.04,y0+floorH*0.34,W*0.92,floorH*0.14);\r\n        x.strokeStyle='#2b3036'; x.lineWidth=3;\r\n        for(let m=1;m<6;m++){\r\n          const mx=W*0.04+m*W*0.92\/6;\r\n          x.beginPath(); x.moveTo(mx,y0+floorH*0.34); x.lineTo(mx,y0+floorH*0.94); x.stroke();\r\n        }\r\n      }else{\r\n        const cols=Math.max(3,Math.round(wM\/1.9)), cw=W\/cols;\r\n        for(let ci=0;ci<cols;ci++){\r\n          const wx=ci*cw+cw*0.18, wy=y0+floorH*0.34, ww=cw*0.64, wh=floorH*0.58;\r\n          const lit=Math.random()<0.25;\r\n          x.fillStyle=lit?'#ffc966':'#151f28'; x.fillRect(wx,wy,ww,wh);\r\n          x.fillStyle=lit?'rgba(255,255,255,0.4)':'rgba(195,210,225,0.18)'; x.fillRect(wx,wy,ww,wh*0.3);\r\n          x.strokeStyle='#282c32'; x.lineWidth=2; x.strokeRect(wx,wy,ww,wh);\r\n        }\r\n      }\r\n    }\r\n    return srgb(new THREE.CanvasTexture(c));\r\n  }\r\n\r\n  function createTrailerTexture(){\r\n    const c=document.createElement('canvas'); c.width=512; c.height=128; const x=c.getContext('2d');\r\n    x.fillStyle='#e2e0d8'; x.fillRect(0,0,512,128);\r\n    x.fillStyle='#182028'; x.fillRect(20,30,472,52);\r\n    x.fillStyle='rgba(210,225,240,0.2)'; x.fillRect(20,30,472,14);\r\n    x.strokeStyle='#98968f'; x.lineWidth=4;\r\n    for(let m=0;m<=8;m++){const mx=20+m*59; x.beginPath(); x.moveTo(mx,30); x.lineTo(mx,82); x.stroke();}\r\n    x.fillStyle='#FFB601'; x.fillRect(0,112,512,8);\r\n    const t=srgb(new THREE.CanvasTexture(c)); t.wrapS=t.wrapT=THREE.RepeatWrapping; return t;\r\n  }\r\n\r\n  function createGCPTexture(){\r\n    const c=document.createElement('canvas'); c.width=c.height=128; const x=c.getContext('2d');\r\n    x.fillStyle='#111111'; x.fillRect(0,0,128,128);\r\n    x.fillStyle='#FFB601'; x.fillRect(0,0,64,64); x.fillRect(64,64,64,64);\r\n    x.strokeStyle='#ffffff'; x.lineWidth=3;\r\n    x.beginPath(); x.moveTo(64,6); x.lineTo(64,122); x.moveTo(6,64); x.lineTo(122,64); x.stroke();\r\n    return srgb(new THREE.CanvasTexture(c));\r\n  }\r\n\r\n  \/* ================= RENDERER \/ SCENE \/ LIGHTING ================= *\/\r\n  const canvas=document.getElementById('scene');\r\n  const container=document.getElementById('volatus-3d-hero');\r\n  const renderer=new THREE.WebGLRenderer({canvas,antialias:true,powerPreference:'high-performance', alpha: true});\r\n  renderer.setClearColor(0x000000,1); \/\/ Set to pure black\r\n  renderer.setPixelRatio(Math.min(devicePixelRatio||1,isMobile?1.5:2));\r\n  renderer.setSize(container.clientWidth,container.clientHeight,false);\r\n  renderer.toneMapping=THREE.ACESFilmicToneMapping;\r\n  renderer.toneMappingExposure=1.35;\r\n  renderer.shadowMap.enabled=true;\r\n  renderer.shadowMap.type=THREE.PCFSoftShadowMap;\r\n  renderer.outputColorSpace=THREE.SRGBColorSpace;\r\n\r\n  const scene=new THREE.Scene();\r\n  scene.fog=new THREE.FogExp2(0x000000,0.0020); \/\/ Pure black fog\r\n  const camera=new THREE.PerspectiveCamera(40, container.clientWidth \/ container.clientHeight, 1.0, 1000);\r\n\r\n  \/\/ Sky dome\r\n  scene.add(new THREE.Mesh(new THREE.SphereGeometry(560,24,12),new THREE.ShaderMaterial({side:THREE.BackSide,depthWrite:false,fog:false,\r\n    vertexShader:'varying vec3 vP;void main(){vP=position;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.);}',\r\n    fragmentShader:`varying vec3 vP;void main(){float h=normalize(vP).y*.5+.5;\r\n      vec3 c=mix(vec3(.06,.08,.10),vec3(.12,.16,.21),pow(h,.6));\r\n      c+=vec3(.45,.32,.12)*pow(max(0.,1.-abs(normalize(vP).y+.02)*2.8),3.)*.45;\r\n      gl_FragColor=vec4(c,1.);}`})));\r\n\r\n  const hemiLight = new THREE.HemisphereLight(0x758ca3,0x363028,1.2);\r\n  scene.add(hemiLight);\r\n\r\n  const sun = new THREE.DirectionalLight(0xfff1db,2.3);\r\n  sun.position.set(-95,85,-38);\r\n  sun.castShadow=true;\r\n  sun.shadow.mapSize.set(isMobile?1024:2048,isMobile?1024:2048);\r\n  Object.assign(sun.shadow.camera,{near:10,far:420,left:-130,right:130,top:130,bottom:-130});\r\n  sun.shadow.bias=-.0004;\r\n  scene.add(sun);\r\n\r\n  const rim = new THREE.DirectionalLight(0x5a7894,0.65);\r\n  rim.position.set(70,55,85);\r\n  scene.add(rim);\r\n\r\n  const fill = new THREE.DirectionalLight(0xdfc090,0.45);\r\n  fill.position.set(60,25,-50);\r\n  scene.add(fill);\r\n\r\n  \/* ================= SURROUNDING MOUNTAINS TERRAIN ================= *\/\r\n  const TER_SIZE=320, TER_SEG=isMobile?120:200;\r\n  const terrainGeo=new THREE.PlaneGeometry(TER_SIZE,TER_SIZE,TER_SEG,TER_SEG);\r\n  terrainGeo.rotateX(-Math.PI\/2);\r\n  {\r\n    const p=terrainGeo.attributes.position;\r\n    for(let i=0;i<p.count;i++)p.setY(i,heightAt(p.getX(i),p.getZ(i)));\r\n    terrainGeo.computeVertexNormals();\r\n    const col=new Float32Array(p.count*3), n=terrainGeo.attributes.normal;\r\n    for(let i=0;i<p.count;i++){\r\n      const x=p.getX(i),z=p.getZ(i),h=p.getY(i);\r\n      let c=.18+fbm(x*.06,z*.06)*.11;\r\n      c+=sstep(6,58,h)*.24;\r\n      const slope=1-n.getY(i); if(slope>.32)c*=.78;\r\n      if(h>46)c+=Math.min(.32,(h-46)*.014);\r\n      col[i*3]=c;col[i*3+1]=c*.97;col[i*3+2]=c*.92;\r\n    }\r\n    terrainGeo.setAttribute('color',new THREE.BufferAttribute(col,3));\r\n  }\r\n  const terrainMeshMat=new THREE.MeshStandardMaterial({vertexColors:true,color:0x3f3d38,roughness:.92,flatShading:true});\r\n  const terrainMesh=new THREE.Mesh(terrainGeo,terrainMeshMat);\r\n  terrainMesh.receiveShadow=true;scene.add(terrainMesh);\r\n\r\n  \/* ================= INDUSTRIAL SITE 3D MODEL ================= *\/\r\n  function buildIndustrialSiteModel(){\r\n    const siteGroup = new THREE.Group();\r\n    siteGroup.name = \"IndustrialSiteAsset\";\r\n\r\n    const corrTex = createCorrugatedTexture();\r\n    const slabTex = createConcreteTexture();\r\n    const slabMat = new THREE.MeshStandardMaterial({map:slabTex, roughness:0.85});\r\n    const roofMat = new THREE.MeshStandardMaterial({color:0x2c2f33, roughness:0.95});\r\n    const goldMat = new THREE.MeshStandardMaterial({color:0xFFB601, roughness:0.32, metalness:0.75});\r\n    const glassMat = new THREE.MeshStandardMaterial({color:0x1f2937, roughness:0.12, metalness:0.85, transparent:true, opacity:0.9});\r\n    const darkMetalMat = new THREE.MeshStandardMaterial({color:0x1c1f23, roughness:0.5, metalness:0.6});\r\n    const emissiveMat = new THREE.MeshStandardMaterial({color:0x0c0f13, emissive:0xffb35c, emissiveIntensity:0.75});\r\n    const beaconMat = new THREE.MeshBasicMaterial({color:0xFFB601, transparent:true, opacity:0.95});\r\n\r\n    function getCorrMat(tint, rx, ry){\r\n      const t = corrTex.clone();\r\n      t.needsUpdate = true;\r\n      t.repeat.set(rx, ry);\r\n      return new THREE.MeshStandardMaterial({map:t, color:tint, roughness:0.55, metalness:0.45});\r\n    }\r\n\r\n    function reg(mesh, mat){\r\n      mesh.userData.mat = mat;\r\n      mesh.castShadow = mesh.receiveShadow = true;\r\n      siteGroup.add(mesh);\r\n      return mesh;\r\n    }\r\n\r\n    function makeFoundation(x, z, w, d, h){\r\n      const b = reg(new THREE.Mesh(new THREE.BoxGeometry(w, h, d), slabMat), slabMat);\r\n      b.position.set(x, h*0.5, z);\r\n      return h;\r\n    }\r\n\r\n    const padTex = createSitePadTexture();\r\n    const padMesh = reg(new THREE.Mesh(\r\n      new THREE.PlaneGeometry(92, 76),\r\n      new THREE.MeshStandardMaterial({map:padTex, roughness:0.92, polygonOffset:true, polygonOffsetFactor:-1})\r\n    ), padTex);\r\n    padMesh.rotation.x = -Math.PI\/2;\r\n    padMesh.position.y = 0.02;\r\n\r\n    const baseSlab = reg(new THREE.Mesh(\r\n      new THREE.BoxGeometry(92.5, 0.4, 76.5),\r\n      new THREE.MeshStandardMaterial({color:0x202224, roughness:0.95})\r\n    ), slabMat);\r\n    baseSlab.position.y = -0.2;\r\n\r\n    {\r\n      const O = {x:-8, z:-4, w:22, d:15, h:15};\r\n      const baseY = makeFoundation(O.x, O.z, O.w+2.4, O.d+2.4, 0.8);\r\n      const facZ = new THREE.MeshStandardMaterial({map:createFacadeTexture(O.w, O.h, 4), roughness:0.8});\r\n      const facX = new THREE.MeshStandardMaterial({map:createFacadeTexture(O.d, O.h, 4), roughness:0.8});\r\n      const off = reg(new THREE.Mesh(new THREE.BoxGeometry(O.w, O.h, O.d), [facX, facX, roofMat, slabMat, facZ, facZ]), facZ);\r\n      off.position.set(O.x, baseY + O.h\/2, O.z);\r\n\r\n      const pr = [[[0, O.d\/2],[O.w+0.3, 0.3]], [[0, -O.d\/2],[O.w+0.3, 0.3]], [[O.w\/2, 0],[0.3, O.d+0.3]], [[-O.w\/2, 0],[0.3, O.d+0.3]]];\r\n      pr.forEach(([pz, sz])=>{\r\n        const m = reg(new THREE.Mesh(new THREE.BoxGeometry(sz[0], 0.7, sz[1]), roofMat), roofMat);\r\n        m.position.set(O.x+pz[0], baseY+O.h+0.35, O.z+pz[1]);\r\n      });\r\n\r\n      const ph = reg(new THREE.Mesh(new THREE.BoxGeometry(6, 2.6, 5), roofMat), roofMat);\r\n      ph.position.set(O.x-4, baseY+O.h+1.3, O.z-2);\r\n\r\n      for(let i=0; i<3; i++){\r\n        const m = getCorrMat(0x8e959b, 1, 1);\r\n        const h = reg(new THREE.Mesh(new THREE.BoxGeometry(2.4, 1.1, 1.6), m), m);\r\n        h.position.set(O.x+3+i*3.4, baseY+O.h+0.55, O.z+2.5-(i%2)*4);\r\n      }\r\n\r\n      const ant = reg(new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 4.5, 6), darkMetalMat), darkMetalMat);\r\n      ant.position.set(O.x-4, baseY+O.h+2.6+2.25, O.z-2);\r\n      const beacon = reg(new THREE.Mesh(new THREE.SphereGeometry(0.16, 8, 8), beaconMat), beaconMat);\r\n      beacon.position.set(O.x-4, baseY+O.h+2.6+4.6, O.z-2);\r\n\r\n      const can = reg(new THREE.Mesh(new THREE.BoxGeometry(8, 0.25, 2.8), darkMetalMat), darkMetalMat);\r\n      can.position.set(O.x, baseY+3.3, O.z+O.d\/2+1.2);\r\n      const fascia = reg(new THREE.Mesh(new THREE.BoxGeometry(8, 0.3, 0.12), goldMat), goldMat);\r\n      fascia.position.set(O.x, baseY+3.3, O.z+O.d\/2+2.55);\r\n      [-3.4, 3.4].forEach(dx=>{\r\n        const s = reg(new THREE.Mesh(new THREE.CylinderGeometry(0.09, 0.09, 3.2, 8), darkMetalMat), darkMetalMat);\r\n        s.position.set(O.x+dx, 1.6, O.z+O.d\/2+2.2);\r\n      });\r\n      const door = reg(new THREE.Mesh(new THREE.BoxGeometry(3, 2.6, 0.16), glassMat), glassMat);\r\n      door.position.set(O.x, baseY+1.3, O.z+O.d\/2+0.08);\r\n    }\r\n\r\n    {\r\n      const W = {x:18, z:-14, len:26, w:14, eh:6.4, apex:9.6};\r\n      const baseY = makeFoundation(W.x, W.z, W.w+2, W.len+2, 0.6);\r\n      const shape = new THREE.Shape();\r\n      shape.moveTo(-W.w\/2, 0); shape.lineTo(W.w\/2, 0); shape.lineTo(W.w\/2, W.eh);\r\n      shape.lineTo(0, W.apex); shape.lineTo(-W.w\/2, W.eh); shape.lineTo(-W.w\/2, 0);\r\n      const g = new THREE.ExtrudeGeometry(shape, {depth:W.len, bevelEnabled:false});\r\n      g.translate(0, 0, -W.len\/2);\r\n\r\n      const grp = new THREE.Group();\r\n      const walls = getCorrMat(0xb9c0c6, 13, 13);\r\n      const wh = new THREE.Mesh(g, [slabMat, walls]);\r\n      wh.userData.mat = walls; wh.castShadow = wh.receiveShadow = true;\r\n      grp.add(wh);\r\n\r\n      [-8, 0, 8].forEach(dz=>{\r\n        const frame = new THREE.Mesh(new THREE.BoxGeometry(0.2, 4.8, 4.7), goldMat);\r\n        frame.userData.mat = goldMat; frame.position.set(W.w\/2+0.06, 2.4, dz); grp.add(frame);\r\n        const door = new THREE.Mesh(new THREE.BoxGeometry(0.14, 4.3, 4.2), darkMetalMat);\r\n        door.userData.mat = darkMetalMat; door.position.set(W.w\/2+0.18, 2.15, dz); grp.add(door);\r\n      });\r\n\r\n      [-1, 1].forEach(s=>{\r\n        const cl = new THREE.Mesh(new THREE.BoxGeometry(0.16, 0.8, W.len-3), emissiveMat);\r\n        cl.userData.mat = emissiveMat; cl.position.set(s*(W.w\/2+0.05), 5.6, 0); grp.add(cl);\r\n        const band = new THREE.Mesh(new THREE.BoxGeometry(0.1, 0.5, W.len), goldMat);\r\n        band.userData.mat = goldMat; band.position.set(s*(W.w\/2+0.02), 0.25, 0); grp.add(band);\r\n      });\r\n      const ridge = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.3, W.len+0.6), goldMat);\r\n      ridge.userData.mat = goldMat; ridge.position.set(0, W.apex+0.12, 0); grp.add(ridge);\r\n\r\n      grp.rotation.y = -Math.PI\/2;\r\n      grp.position.set(W.x, baseY, W.z);\r\n      siteGroup.add(grp);\r\n    }\r\n\r\n    {\r\n      const T = {x:-26, z:-18, w:14, d:7};\r\n      const baseY = makeFoundation(T.x, T.z, T.w+1.5, T.d+1.5, 0.4);\r\n      const trailTex = createTrailerTexture();\r\n      const tw = new THREE.MeshStandardMaterial({map:trailTex, roughness:0.6});\r\n      const tr = new THREE.MeshStandardMaterial({color:0x8f8d86, roughness:0.9});\r\n      for(let lvl=0; lvl<2; lvl++){\r\n        const m = reg(new THREE.Mesh(new THREE.BoxGeometry(T.w, 2.8, T.d), [tw,tw,tr,tr,tw,tw]), tw);\r\n        m.position.set(T.x, baseY+lvl*3+1.4, T.z);\r\n        const tThick = 0.10, tH = 0.16;\r\n        \/\/ Perimeter gold trim on outer walls (does not cover or coplanar-fight with roof)\r\n        [-1, 1].forEach(dz => {\r\n          const tb = reg(new THREE.Mesh(new THREE.BoxGeometry(T.w+0.22, tH, tThick), goldMat), goldMat);\r\n          tb.position.set(T.x, baseY+lvl*3+2.68, T.z+dz*(T.d\/2+tThick\/2));\r\n        });\r\n        [-1, 1].forEach(dx => {\r\n          const tb = reg(new THREE.Mesh(new THREE.BoxGeometry(tThick, tH, T.d), goldMat), goldMat);\r\n          tb.position.set(T.x+dx*(T.w\/2+tThick\/2), baseY+lvl*3+2.68, T.z);\r\n        });\r\n      }\r\n      for(let s=0; s<5; s++){\r\n        const st = reg(new THREE.Mesh(new THREE.BoxGeometry(1.1, 0.12, 0.5), darkMetalMat), darkMetalMat);\r\n        st.position.set(T.x+T.w\/2+0.55, 0.3+s*0.56, T.z+T.d\/2-1+s*0.55);\r\n      }\r\n      const mast = reg(new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.1, 9, 8), darkMetalMat), darkMetalMat);\r\n      mast.position.set(T.x+5.4, baseY+5.6+4.5, T.z-2.4);\r\n      const b2 = reg(new THREE.Mesh(new THREE.SphereGeometry(0.14, 8, 8), beaconMat), beaconMat);\r\n      b2.position.set(T.x+5.4, baseY+10.3, T.z-2.4);\r\n    }\r\n\r\n    {\r\n      const M = {x:22, z:16, w:18, d:12, h:6};\r\n      const baseY = makeFoundation(M.x, M.z, M.w+1.5, M.d+1.5, 0.5);\r\n      const mShop = getCorrMat(0xaab4bc, 10, 4);\r\n      const shop = reg(new THREE.Mesh(new THREE.BoxGeometry(M.w, M.h, M.d), mShop), mShop);\r\n      shop.position.set(M.x, baseY+M.h\/2, M.z);\r\n\r\n      [[0, M.d\/2],[0, -M.d\/2]].forEach(([ox, oz])=>{\r\n        const p = reg(new THREE.Mesh(new THREE.BoxGeometry(M.w+0.3, 0.6, 0.25), roofMat), roofMat);\r\n        p.position.set(M.x+ox, baseY+M.h+0.3, M.z+oz);\r\n      });\r\n      [[M.w\/2, 0],[-M.w\/2, 0]].forEach(([ox, oz])=>{\r\n        const p = reg(new THREE.Mesh(new THREE.BoxGeometry(0.25, 0.6, M.d+0.3), roofMat), roofMat);\r\n        p.position.set(M.x+ox, baseY+M.h+0.3, M.z+oz);\r\n      });\r\n      [-4, 4].forEach(dx=>{\r\n        const bay = reg(new THREE.Mesh(new THREE.BoxGeometry(5, 0.15, 4.4), goldMat), goldMat);\r\n        bay.position.set(M.x+dx, baseY+2.4, M.z+M.d\/2+0.06);\r\n        const din = reg(new THREE.Mesh(new THREE.BoxGeometry(4.4, 0.1, 3.9), darkMetalMat), darkMetalMat);\r\n        din.position.set(M.x+dx, baseY+2.4, M.z+M.d\/2+0.14);\r\n      });\r\n      [-3, 3].forEach(dx=>{\r\n        const st = reg(new THREE.Mesh(new THREE.CylinderGeometry(0.28, 0.28, 2.2, 10), darkMetalMat), darkMetalMat);\r\n        st.position.set(M.x+dx, baseY+M.h+1.1, M.z-3);\r\n      });\r\n    }\r\n\r\n    {\r\n      const S = {x:-32, z:2};\r\n      makeFoundation(S.x, S.z, 12, 11, 0.4);\r\n      const bodyMat = getCorrMat(0xc4cad0, 7, 2);\r\n      [[-3, -2.5],[3, -2.5],[0, 3]].forEach(([ox, oz], i)=>{\r\n        const cy = S.x+ox, cz = S.z+oz;\r\n        const body = reg(new THREE.Mesh(new THREE.CylinderGeometry(1.9, 1.9, 10, 24), bodyMat), bodyMat);\r\n        body.position.set(cy, 2.2+5, cz);\r\n        const skirt = reg(new THREE.Mesh(new THREE.CylinderGeometry(1.9, 1.6, 2.2, 20, 1, true), darkMetalMat), darkMetalMat);\r\n        skirt.position.set(cy, 1.1, cz);\r\n        const mCap = getCorrMat(0x8b9298, 4, 1);\r\n        const cap = reg(new THREE.Mesh(new THREE.ConeGeometry(1.95, 1.8, 24), mCap), mCap);\r\n        cap.position.set(cy, 2.2+10+0.9, cz);\r\n        [4, 7.5].forEach(hy=>{\r\n          const ring = reg(new THREE.Mesh(new THREE.TorusGeometry(1.92, 0.06, 8, 24), goldMat), goldMat);\r\n          ring.rotation.x = Math.PI\/2; ring.position.set(cy, 2.2+hy, cz);\r\n        });\r\n        if(i===0){\r\n          for(let r=0; r<9; r++){\r\n            const rung = reg(new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.06, 0.06), darkMetalMat), darkMetalMat);\r\n            rung.position.set(cy-1.95, 2.6+r*1.05, cz);\r\n          }\r\n        }\r\n      });\r\n      siteGroup.add(barBetween(new THREE.Vector3(S.x-3, 8, S.z-2.5), new THREE.Vector3(S.x+3, 8, S.z-2.5), 0.13, darkMetalMat));\r\n      siteGroup.add(barBetween(new THREE.Vector3(S.x, 8, S.z+3), new THREE.Vector3(S.x, 8, S.z-2.5), 0.13, darkMetalMat));\r\n    }\r\n\r\n    {\r\n      const C = {x:7, z:25};\r\n      makeFoundation(C.x, C.z, 25, 12, 0.3);\r\n      const cGeo = new THREE.BoxGeometry(4.3, 2.6, 2.4);\r\n      const tints = [0x39434a, 0x4a4238, 0x2c3134, 0xFFB601, 0x37424b, 0x3f3931];\r\n      let ci = 0;\r\n      for(let gx=-2; gx<=2; gx++) for(let gz=-1; gz<=1; gz++){\r\n        const m = getCorrMat(tints[ci%tints.length], 2, 1);\r\n        const c1 = reg(new THREE.Mesh(cGeo, m), m);\r\n        c1.position.set(C.x+gx*4.6, 0.3+1.3, C.z+gz*3.4);\r\n        if(ci%3===0){\r\n          const c2 = reg(new THREE.Mesh(cGeo, m), m);\r\n          c2.position.set(C.x+gx*4.6, 0.3+3.9, C.z+gz*3.4);\r\n        }\r\n        ci++;\r\n      }\r\n    }\r\n\r\n    const crane = { slew: null, trolley: null, cable: null, hook: null };\r\n    {\r\n      const CR = {x:4, z:-5};\r\n      const mast = reg(new THREE.Mesh(new THREE.BoxGeometry(1.3, 30, 1.3), goldMat), goldMat);\r\n      mast.position.set(CR.x, 15, CR.z);\r\n\r\n      crane.slew = new THREE.Group();\r\n      crane.slew.position.set(CR.x, 30, CR.z);\r\n      const jib = new THREE.Mesh(new THREE.BoxGeometry(26, 0.55, 0.55), goldMat);\r\n      jib.userData.mat = goldMat; jib.position.x = 8; jib.castShadow = true; crane.slew.add(jib);\r\n      const cjib = new THREE.Mesh(new THREE.BoxGeometry(8, 0.5, 0.5), goldMat);\r\n      cjib.userData.mat = goldMat; cjib.position.x = -6; crane.slew.add(cjib);\r\n      const weight = new THREE.Mesh(new THREE.BoxGeometry(1.6, 2, 1.6), slabMat);\r\n      weight.userData.mat = slabMat; weight.position.set(-9.5, -0.8, 0); weight.castShadow = true; crane.slew.add(weight);\r\n      const cab = new THREE.Mesh(new THREE.BoxGeometry(1.8, 2.1, 1.6), darkMetalMat);\r\n      cab.userData.mat = darkMetalMat; cab.position.set(0.6, -1.2, 0); crane.slew.add(cab);\r\n      const pylon = new THREE.Mesh(new THREE.BoxGeometry(0.45, 3.4, 0.45), goldMat);\r\n      pylon.userData.mat = goldMat; pylon.position.y = 1.9; crane.slew.add(pylon);\r\n\r\n      crane.slew.add(barBetween(new THREE.Vector3(0, 3.4, 0), new THREE.Vector3(20, 0.3, 0), 0.045, darkMetalMat));\r\n      crane.slew.add(barBetween(new THREE.Vector3(0, 3.4, 0), new THREE.Vector3(-9.5, 0.3, 0), 0.045, darkMetalMat));\r\n\r\n      crane.trolley = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.4, 0.8), darkMetalMat);\r\n      crane.trolley.userData.mat = darkMetalMat; crane.trolley.position.set(10, 0.1, 0); crane.slew.add(crane.trolley);\r\n\r\n      crane.cable = new THREE.Mesh(new THREE.CylinderGeometry(0.04, 0.04, 1, 6), darkMetalMat);\r\n      crane.cable.userData.mat = darkMetalMat; crane.trolley.add(crane.cable);\r\n\r\n      crane.hook = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.5, 2.6), slabMat);\r\n      crane.hook.userData.mat = slabMat; crane.trolley.add(crane.hook);\r\n\r\n      siteGroup.add(crane.slew);\r\n    }\r\n\r\n    const truckAt = (tx, tz, ry)=>{\r\n      const g = new THREE.Group();\r\n      const chassis = new THREE.Mesh(new THREE.BoxGeometry(5.8, 0.5, 2.5), darkMetalMat);\r\n      chassis.userData.mat = darkMetalMat; chassis.position.y = 0.95; chassis.castShadow = true; g.add(chassis);\r\n      const mBed = getCorrMat(0x6f7780, 2, 1);\r\n      const bed = new THREE.Mesh(new THREE.BoxGeometry(4.2, 1.5, 2.5), mBed);\r\n      bed.userData.mat = mBed; bed.position.set(-0.6, 1.95, 0); bed.castShadow = true; g.add(bed);\r\n      const cab = new THREE.Mesh(new THREE.BoxGeometry(1.5, 1.7, 2.4), goldMat);\r\n      cab.userData.mat = goldMat; cab.position.set(2.15, 2, 0); cab.castShadow = true; g.add(cab);\r\n      const win = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.8, 2.1), glassMat);\r\n      win.userData.mat = glassMat; win.position.set(2.7, 2.3, 0); g.add(win);\r\n      const wGeo = new THREE.CylinderGeometry(0.55, 0.55, 0.42, 12);\r\n      [[2.3, 1.1],[2.3, -1.1],[-1.3, 1.1],[-1.3, -1.1],[-2.4, 1.1],[-2.4, -1.1]].forEach(([wx, wz])=>{\r\n        const w = new THREE.Mesh(wGeo, darkMetalMat);\r\n        w.userData.mat = darkMetalMat; w.rotation.x = Math.PI\/2; w.position.set(wx, 0.55, wz); g.add(w);\r\n      });\r\n      g.position.set(tx, 0, tz); g.rotation.y = ry;\r\n      siteGroup.add(g);\r\n    };\r\n    truckAt(35, 24, Math.PI);\r\n    truckAt(40, 25.5, Math.PI);\r\n\r\n    {\r\n      const g = new THREE.Group();\r\n      const body = new THREE.Mesh(new THREE.BoxGeometry(2.6, 1.5, 1.9), getCorrMat(0x565d63, 1, 1));\r\n      body.position.y = 1.55; body.castShadow = true; g.add(body);\r\n      const cab = new THREE.Mesh(new THREE.BoxGeometry(1.3, 1.2, 1.6), glassMat);\r\n      cab.position.set(-0.2, 2.8, 0); g.add(cab);\r\n      [[1.1, 1],[-1.1, 1],[1.1, -1],[-1.1, -1]].forEach(([wx, wz])=>{\r\n        const w = new THREE.Mesh(new THREE.CylinderGeometry(0.6, 0.6, 0.5, 12), darkMetalMat);\r\n        w.rotation.x = Math.PI\/2; w.position.set(wx, 0.6, wz); g.add(w);\r\n      });\r\n      [-0.55, 0.55].forEach(lz=>{\r\n        const arm = new THREE.Mesh(new THREE.BoxGeometry(1.8, 0.18, 0.18), goldMat);\r\n        arm.position.set(2.1, 2.1, lz); arm.rotation.z = 0.5; g.add(arm);\r\n      });\r\n      const bucket = new THREE.Mesh(new THREE.BoxGeometry(0.8, 1, 2), goldMat);\r\n      bucket.position.set(3.05, 1.35, 0); bucket.rotation.z = 0.3; bucket.castShadow = true; g.add(bucket);\r\n      g.position.set(-12, 0, 14.5);\r\n      siteGroup.add(g);\r\n    }\r\n\r\n    const excavator = { boom: null, stick: null };\r\n    {\r\n      const g = new THREE.Group();\r\n      [[-0.75],[0.75]].forEach(([tz])=>{\r\n        const tr = new THREE.Mesh(new THREE.BoxGeometry(3.6, 1, 0.85), darkMetalMat);\r\n        tr.position.set(0, 0.5, tz); tr.castShadow = true; g.add(tr);\r\n      });\r\n      const house = new THREE.Mesh(new THREE.BoxGeometry(2.8, 1.5, 2.2), getCorrMat(0x565d63, 1, 1));\r\n      house.position.y = 1.85; house.castShadow = true; g.add(house);\r\n      const cab = new THREE.Mesh(new THREE.BoxGeometry(1, 1.2, 1), goldMat);\r\n      cab.position.set(0.9, 2.1, 0.55); g.add(cab);\r\n      excavator.boom = new THREE.Group(); excavator.boom.position.set(1.3, 2.5, 0);\r\n      const boomMesh = new THREE.Mesh(new THREE.BoxGeometry(3.4, 0.45, 0.4), goldMat);\r\n      boomMesh.position.x = 1.7; boomMesh.castShadow = true; excavator.boom.add(boomMesh);\r\n      excavator.stick = new THREE.Group(); excavator.stick.position.set(3.4, 0, 0);\r\n      const stickMesh = new THREE.Mesh(new THREE.BoxGeometry(2.4, 0.35, 0.3), goldMat);\r\n      stickMesh.position.x = 1.2; excavator.stick.add(stickMesh);\r\n      const bucket = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.7, 0.75), darkMetalMat);\r\n      bucket.position.set(2.55, -0.35, 0); bucket.rotation.z = 0.8; excavator.stick.add(bucket);\r\n      excavator.boom.add(excavator.stick); g.add(excavator.boom);\r\n      excavator.boom.rotation.z = -0.55; excavator.stick.rotation.z = -1.05;\r\n      g.position.set(-26, 0.2, 16); g.rotation.y = -0.7;\r\n      siteGroup.add(g);\r\n    }\r\n\r\n    const aggTex = createAggregateTexture();\r\n    function makeStockpile(x, z, r, h){\r\n      const geo = new THREE.ConeGeometry(r, h, 32, 6);\r\n      const p = geo.attributes.position;\r\n      for(let i=0; i<p.count; i++){\r\n        const vx = p.getX(i), vy = p.getY(i), vz = p.getZ(i);\r\n        const k = (vy + h\/2)\/h;\r\n        const n = 1 + Math.sin(vx*1.9 + z*0.7) * Math.cos(vz*2.1 - x*0.5) * 0.13 * k;\r\n        p.setX(i, vx*n); p.setZ(i, vz*n);\r\n      }\r\n      geo.computeVertexNormals();\r\n      const m = new THREE.MeshStandardMaterial({map:aggTex.clone(), roughness:0.95});\r\n      m.map.needsUpdate = true;\r\n      const mesh = reg(new THREE.Mesh(geo, m), m);\r\n      mesh.position.set(x, h\/2, z);\r\n      return mesh;\r\n    }\r\n    makeStockpile(-12, 24, 7.5, 6.8);\r\n    makeStockpile(-24, 28, 5.2, 4.8);\r\n    makeStockpile(34, 10, 5.5, 4.2);\r\n\r\n    {\r\n      const rg = new THREE.RingGeometry(7.7, 8.0, 48);\r\n      rg.rotateX(-Math.PI\/2);\r\n      const ring = new THREE.Mesh(rg, new THREE.MeshBasicMaterial({color:0xFFB601, side:THREE.DoubleSide, transparent:true, opacity:0.85}));\r\n      ring.position.set(-12, 0.08, 24);\r\n      siteGroup.add(ring);\r\n    }\r\n\r\n    [[-20, 10],[10, 6],[-2, 33],[34, 26],[-38, 14],[36, -2]].forEach(([px, pz])=>{\r\n      const pole = reg(new THREE.Mesh(new THREE.CylinderGeometry(0.09, 0.12, 7.5, 8), darkMetalMat), darkMetalMat);\r\n      pole.position.set(px, 3.75, pz);\r\n      const head = reg(new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.16, 0.35), emissiveMat), emissiveMat);\r\n      head.position.set(px, 7.5, pz);\r\n    });\r\n\r\n    const gcpTex = createGCPTexture();\r\n    [[-16, -28],[32, -26],[-30, 33],[28, 30]].forEach(([gx, gz])=>{\r\n      const plate = new THREE.Mesh(new THREE.PlaneGeometry(2.4, 2.4), new THREE.MeshBasicMaterial({map:gcpTex, side:THREE.DoubleSide}));\r\n      plate.rotation.x = -Math.PI\/2; plate.position.set(gx, 0.06, gz);\r\n      const pin = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 0.7, 8), new THREE.MeshBasicMaterial({color:0xFFB601}));\r\n      pin.position.set(gx, 0.35, gz);\r\n      siteGroup.add(plate, pin);\r\n    });\r\n\r\n    return {\r\n      group: siteGroup,\r\n      crane: crane,\r\n      excavator: excavator\r\n    };\r\n  }\r\n\r\n  const siteData = buildIndustrialSiteModel();\r\n  siteData.group.position.set(0, SITE_LEVEL_Y, 0);\r\n  scene.add(siteData.group);\r\n\r\n  \/* ================= AUTHENTIC ENTERPRISE DRONE ================= *\/\r\n  function buildEnterpriseDrone(){\r\n    const g = new THREE.Group();\r\n    \r\n    const carbonMat = new THREE.MeshStandardMaterial({color:0x1b1e22, roughness:0.35, metalness:0.65});\r\n    const goldMat = new THREE.MeshStandardMaterial({color:GOLD, roughness:0.28, metalness:0.8});\r\n    const darkMetal = new THREE.MeshStandardMaterial({color:0x121416, roughness:0.45, metalness:0.75});\r\n    const motorMat = new THREE.MeshStandardMaterial({color:0x2a2e33, roughness:0.3, metalness:0.85});\r\n    const glassMat = new THREE.MeshStandardMaterial({color:0x0d283d, roughness:0.1, metalness:0.95, transparent:true, opacity:0.85});\r\n    const ledRed = new THREE.MeshBasicMaterial({color:0xff1f1f});\r\n    const ledGreen = new THREE.MeshBasicMaterial({color:0x1fff44});\r\n    const ledWhite = new THREE.MeshBasicMaterial({color:0xffffff});\r\n    const ledGold = new THREE.MeshBasicMaterial({color:GOLD});\r\n\r\n    const bodyGeo = new THREE.BoxGeometry(3.6, 0.9, 1.8);\r\n    const body = new THREE.Mesh(bodyGeo, carbonMat);\r\n    body.castShadow = true;\r\n    g.add(body);\r\n\r\n    const canopy = new THREE.Mesh(new THREE.BoxGeometry(2.8, 0.35, 1.2), carbonMat);\r\n    canopy.position.y = 0.55;\r\n    g.add(canopy);\r\n\r\n    const goldSpine = new THREE.Mesh(new THREE.BoxGeometry(3.2, 0.08, 0.3), goldMat);\r\n    goldSpine.position.y = 0.74;\r\n    g.add(goldSpine);\r\n\r\n    const bat1 = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.7, 0.6), darkMetal);\r\n    bat1.position.set(-1.1, 0.1, -0.42);\r\n    const bat2 = new THREE.Mesh(new THREE.BoxGeometry(0.8, 0.7, 0.6), darkMetal);\r\n    bat2.position.set(-1.1, 0.1, 0.42);\r\n    g.add(bat1, bat2);\r\n\r\n    [[-1.2, -0.55], [-1.2, 0.55]].forEach(([rx, rz])=>{\r\n      const stalk = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 0.6, 8), darkMetal);\r\n      stalk.position.set(rx, 0.75, rz);\r\n      const puck = new THREE.Mesh(new THREE.CylinderGeometry(0.24, 0.24, 0.2, 16), goldMat);\r\n      puck.position.set(rx, 1.05, rz);\r\n      const rtkLed = new THREE.Mesh(new THREE.SphereGeometry(0.06, 8, 8), ledGold);\r\n      rtkLed.position.set(rx, 1.16, rz);\r\n      g.add(stalk, puck, rtkLed);\r\n    });\r\n\r\n    const fpvPod = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.5, 0.8), darkMetal);\r\n    fpvPod.position.set(1.9, 0.1, 0);\r\n    const fpvLens1 = new THREE.Mesh(new THREE.CylinderGeometry(0.09, 0.09, 0.15, 10), glassMat);\r\n    fpvLens1.rotation.z = Math.PI\/2; fpvLens1.position.set(2.28, 0.15, -0.22);\r\n    const fpvLens2 = new THREE.Mesh(new THREE.CylinderGeometry(0.09, 0.09, 0.15, 10), glassMat);\r\n    fpvLens2.rotation.z = Math.PI\/2; fpvLens2.position.set(2.28, 0.15, 0.22);\r\n    g.add(fpvPod, fpvLens1, fpvLens2);\r\n\r\n    const armCoords = [\r\n      {x: 1.9, z: 1.6, led: ledGreen},\r\n      {x: 1.9, z: -1.6, led: ledRed},\r\n      {x: -1.9, z: 1.6, led: ledWhite},\r\n      {x: -1.9, z: -1.6, led: ledWhite}\r\n    ];\r\n\r\n    const propMeshes = [];\r\n\r\n    armCoords.forEach(a => {\r\n      const armLen = Math.hypot(a.x * 0.75, a.z * 0.75);\r\n      const arm = new THREE.Mesh(new THREE.CylinderGeometry(0.12, 0.14, armLen, 8), carbonMat);\r\n      arm.position.set(a.x * 0.45, 0.12, a.z * 0.45);\r\n      arm.quaternion.setFromUnitVectors(new THREE.Vector3(0,1,0), new THREE.Vector3(a.x, 0, a.z).normalize());\r\n      g.add(arm);\r\n\r\n      const pod = new THREE.Mesh(new THREE.CylinderGeometry(0.28, 0.28, 0.5, 16), motorMat);\r\n      pod.position.set(a.x, 0.22, a.z);\r\n      const podAccent = new THREE.Mesh(new THREE.TorusGeometry(0.29, 0.04, 8, 20), goldMat);\r\n      podAccent.rotation.x = Math.PI\/2; podAccent.position.set(a.x, 0.35, a.z);\r\n      g.add(pod, podAccent);\r\n\r\n      const navLed = new THREE.Mesh(new THREE.SphereGeometry(0.08, 8, 8), a.led);\r\n      navLed.position.set(a.x, -0.05, a.z);\r\n      g.add(navLed);\r\n\r\n      const pGroup = new THREE.Group();\r\n      pGroup.position.set(a.x, 0.52, a.z);\r\n      const hub = new THREE.Mesh(new THREE.CylinderGeometry(0.14, 0.14, 0.18, 12), darkMetal);\r\n      pGroup.add(hub);\r\n\r\n      const b1 = new THREE.Mesh(new THREE.BoxGeometry(2.4, 0.03, 0.2), carbonMat);\r\n      b1.castShadow = true;\r\n      const tip1 = new THREE.Mesh(new THREE.BoxGeometry(0.4, 0.035, 0.21), goldMat);\r\n      tip1.position.x = 1.0;\r\n      const tip2 = new THREE.Mesh(new THREE.BoxGeometry(0.4, 0.035, 0.21), goldMat);\r\n      tip2.position.x = -1.0;\r\n      b1.add(tip1, tip2);\r\n      pGroup.add(b1);\r\n\r\n      g.add(pGroup);\r\n      propMeshes.push(pGroup);\r\n    });\r\n\r\n    const skidZ = 1.35;\r\n    [-skidZ, skidZ].forEach(sz => {\r\n      const runner = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, 4.4, 8), carbonMat);\r\n      runner.rotation.x = Math.PI\/2; runner.position.set(0, -1.05, sz);\r\n      g.add(runner);\r\n\r\n      [-1.2, 1.2].forEach(sx => {\r\n        const strut = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 1.3, 8), darkMetal);\r\n        strut.position.set(sx, -0.52, sz * 0.7);\r\n        strut.quaternion.setFromUnitVectors(new THREE.Vector3(0,1,0), new THREE.Vector3(0, -0.55, sz * 0.35).normalize());\r\n        g.add(strut);\r\n      });\r\n    });\r\n\r\n    const gimbalGroup = new THREE.Group();\r\n    gimbalGroup.position.set(0.3, -0.48, 0);\r\n\r\n    const mountPlate = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.12, 0.9), darkMetal);\r\n    gimbalGroup.add(mountPlate);\r\n\r\n    const yawMotor = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.18, 0.25, 14), goldMat);\r\n    yawMotor.position.y = -0.15;\r\n    const yawArm = new THREE.Mesh(new THREE.BoxGeometry(0.12, 0.38, 0.65), darkMetal);\r\n    yawArm.position.set(0, -0.35, 0.28);\r\n    gimbalGroup.add(yawMotor, yawArm);\r\n\r\n    const camBody = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.65, 0.8), darkMetal);\r\n    camBody.position.set(0, -0.58, 0);\r\n    \r\n    const lensBarrel = new THREE.Mesh(new THREE.CylinderGeometry(0.34, 0.34, 0.55, 20), darkMetal);\r\n    lensBarrel.position.set(0, -0.92, 0);\r\n    const lensApertureRing = new THREE.Mesh(new THREE.TorusGeometry(0.35, 0.035, 8, 24), goldMat);\r\n    lensApertureRing.rotation.x = Math.PI\/2; lensApertureRing.position.set(0, -1.05, 0);\r\n    const frontElement = new THREE.Mesh(new THREE.CylinderGeometry(0.28, 0.28, 0.05, 20), glassMat);\r\n    frontElement.position.set(0, -1.2, 0);\r\n    \r\n    const lrfPort = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, 0.1, 12), goldMat);\r\n    lrfPort.position.set(0.24, -0.95, -0.22);\r\n\r\n    camBody.add(lensBarrel, lensApertureRing, frontElement, lrfPort);\r\n    gimbalGroup.add(camBody);\r\n    g.add(gimbalGroup);\r\n\r\n    return {\r\n      group: g,\r\n      props: propMeshes\r\n    };\r\n  }\r\n\r\n  const droneData = buildEnterpriseDrone();\r\n  const drone = droneData.group;\r\n  scene.add(drone);\r\n\r\n  \/\/ Optical Frustum\r\n  const frustumGeo=new THREE.BufferGeometry();\r\n  frustumGeo.setAttribute('position',new THREE.BufferAttribute(new Float32Array(54),3).setUsage(THREE.DynamicDrawUsage));\r\n  const frustumMesh=new THREE.Mesh(frustumGeo,new THREE.MeshBasicMaterial({color:GOLD,transparent:true,opacity:.14,side:THREE.DoubleSide,depthWrite:false}));\r\n  const frustumWire=new THREE.LineSegments(frustumGeo,new THREE.LineBasicMaterial({color:GOLD,transparent:true,opacity:.55}));\r\n  scene.add(frustumMesh,frustumWire);\r\n\r\n  \/\/ Survey Flight Grid (50m AGL)\r\n  const FLIGHT_ALT=50, flightLines=[]; let fdir=1;\r\n  for(let z=-46;z<=46;z+=16){\r\n    flightLines.push(fdir===1?new THREE.Vector3(-55,FLIGHT_ALT,z):new THREE.Vector3(55,FLIGHT_ALT,z));\r\n    flightLines.push(fdir===1?new THREE.Vector3(55,FLIGHT_ALT,z):new THREE.Vector3(-55,FLIGHT_ALT,z));\r\n    fdir*=-1;\r\n  }\r\n  const flightCurve=new THREE.CatmullRomCurve3(flightLines,false,'catmullrom',.25);\r\n  const fpGeo=new THREE.BufferGeometry().setFromPoints(flightCurve.getPoints(200));\r\n  const flightPath=new THREE.Line(fpGeo,new THREE.LineDashedMaterial({color:GOLD,dashSize:2.4,gapSize:1.4,transparent:true,opacity:.38}));\r\n  flightPath.computeLineDistances();scene.add(flightPath);\r\n\r\n  const shutterFlash=new THREE.PointLight(0xfff3d6,0,65);scene.add(shutterFlash);\r\n\r\n  const footprints=[];for(let i=0;i<32;i++){\r\n    const m=new THREE.MeshBasicMaterial({color:GOLD,transparent:true,opacity:0,side:THREE.DoubleSide,depthWrite:false});\r\n    const fp=new THREE.Mesh(new THREE.PlaneGeometry(16,11),m);fp.rotation.x=-Math.PI\/2;fp.visible=false;scene.add(fp);\r\n    footprints.push({mesh:fp,mat:m,life:0});\r\n  }\r\n  let fpIdx=0;\r\n\r\n  \/* ================= CAMERA PROJECTION OFFSET ================= *\/\r\n  const initW = container.clientWidth || innerWidth;\r\n  const initH = container.clientHeight || innerHeight;\r\n  const isMobileInit = initW <= 1024;\r\n  const initRadius = isMobileInit ? Math.max(230, Math.round(118 \/ ((initW \/ (initH || 1)) || 0.5))) : 175;\r\n\r\n  let yaw = -0.78, pitch = 0.52, radius = initRadius;\r\n  let targetYaw = yaw, targetPitch = pitch, targetRadius = initRadius;\r\n  const targetLookAt = new THREE.Vector3(0, SITE_LEVEL_Y + 7, 0);\r\n  const currentLookAt = new THREE.Vector3(0, SITE_LEVEL_Y + 7, 0);\r\n\r\n  let isDragging = false, lx = 0, ly = 0;\r\n  let autoOrbit = !REDUCED;\r\n  let idleTimer = 0;\r\n\r\n  const pointers = new Map();\r\n\r\n  function updateCameraViewOffset(){\r\n    const w = container.clientWidth || innerWidth;\r\n    const h = container.clientHeight || innerHeight;\r\n    renderer.setSize(w, h, false);\r\n    camera.aspect = w \/ h;\r\n    \r\n    if (w > 1024) {\r\n      \/\/ Desktop: Shifts the focal point of the 3D scene to the right side of the screen\r\n      targetRadius = 175;\r\n      camera.setViewOffset(w, h, -w * 0.18, 0, w, h);\r\n    } else {\r\n      \/\/ Mobile View:\r\n      \/\/ 1. Text is placed in the top 35% (100vh container), 3D animation occupies bottom 65%.\r\n      \/\/ 2. Scale the animation nicely to fill the bottom 65% while keeping the entire facility & drone visible.\r\n      const mobileRadius = Math.max(230, Math.round(118 \/ (camera.aspect || 0.5)));\r\n      targetRadius = mobileRadius;\r\n      \/\/ 3. Shift the focal point vertically to center in the bottom 65% window (centers around 67.5% height)\r\n      camera.setViewOffset(w, h, 0, -h * 0.175, w, h);\r\n    }\r\n    camera.updateProjectionMatrix();\r\n  }\r\n  updateCameraViewOffset();\r\n  window.addEventListener('resize', updateCameraViewOffset);\r\n\r\n  canvas.addEventListener('pointerdown', e => {\r\n    pointers.set(e.pointerId, { x: e.clientX, y: e.clientY });\r\n    if (pointers.size === 1) {\r\n      isDragging = true;\r\n      lx = e.clientX;\r\n      ly = e.clientY;\r\n      canvas.classList.add('dragging');\r\n    }\r\n    idleTimer = 0;\r\n  });\r\n\r\n  window.addEventListener('pointermove', e => {\r\n    if (!pointers.has(e.pointerId)) return;\r\n    pointers.set(e.pointerId, { x: e.clientX, y: e.clientY });\r\n\r\n    \/\/ Multi-touch logic disabled to remove zoom\r\n    if (pointers.size === 2) {\r\n      idleTimer = 0;\r\n      return; \r\n    }\r\n\r\n    if (!isDragging) return;\r\n    const dx = e.clientX - lx;\r\n    const dy = e.clientY - ly;\r\n    targetYaw += dx * 0.0055;\r\n    targetPitch = clamp(targetPitch + dy * 0.0035, 0.44, 1.50);\r\n    lx = e.clientX;\r\n    ly = e.clientY;\r\n    idleTimer = 0;\r\n  });\r\n\r\n  window.addEventListener('pointerup', e => {\r\n    pointers.delete(e.pointerId);\r\n    if (pointers.size === 0) {\r\n      isDragging = false;\r\n      canvas.classList.remove('dragging');\r\n    }\r\n  });\r\n\r\n  \/* Wheel zoom removed *\/\r\n\r\n  \/* ================= MAIN ANIMATION & SURVEY LOOP ================= *\/\r\n  let flightT = 0.05, photoTimer = 0, photoCount = 148;\r\n  let last = performance.now();\r\n  const needle = document.getElementById('compass-needle');\r\n  const fv = frustumGeo.attributes.position.array;\r\n\r\n  function animate(now){\r\n    requestAnimationFrame(animate);\r\n    const dt = Math.min((now - last) \/ 1000, 0.05);\r\n    last = now;\r\n    const time = now \/ 1000;\r\n\r\n    idleTimer += dt;\r\n    if (autoOrbit && !isDragging) {\r\n      targetYaw += dt * 0.045;\r\n    }\r\n    yaw = lerp(yaw, targetYaw, 0.06);\r\n    pitch = lerp(pitch, targetPitch, 0.06);\r\n    radius = lerp(radius, targetRadius, 0.06);\r\n    currentLookAt.lerp(targetLookAt, 0.06);\r\n\r\n    const cp = Math.cos(pitch);\r\n    camera.position.set(\r\n      currentLookAt.x + radius * cp * Math.sin(yaw),\r\n      currentLookAt.y + radius * Math.sin(pitch),\r\n      currentLookAt.z + radius * cp * Math.cos(yaw)\r\n    );\r\n    camera.lookAt(currentLookAt);\r\n\r\n    if(siteData.crane && siteData.crane.slew){\r\n      siteData.crane.slew.rotation.y = Math.sin(time * 0.12) * 0.85;\r\n      siteData.crane.trolley.position.x = 5 + (Math.sin(time * 0.08) * 0.5 + 0.5) * 13;\r\n      const clen = 13 + Math.sin(time * 0.05) * 4;\r\n      siteData.crane.cable.scale.y = clen;\r\n      siteData.crane.cable.position.y = -clen\/2;\r\n      siteData.crane.hook.position.y = -clen + 0.3;\r\n    }\r\n    if(siteData.excavator && siteData.excavator.boom){\r\n      siteData.excavator.boom.rotation.z = -0.55 + Math.sin(time * 0.6) * 0.06;\r\n      siteData.excavator.stick.rotation.z = -1.05 + Math.sin(time * 0.6 + 1.1) * 0.09;\r\n    }\r\n\r\n    flightT = (flightT + dt * 0.034) % 1;\r\n    const dp = flightCurve.getPointAt(flightT);\r\n    const dl = flightCurve.getPointAt((flightT + 0.015) % 1);\r\n    drone.position.set(dp.x, dp.y + (REDUCED ? 0 : Math.sin(time * 2.2) * 0.16), dp.z);\r\n    drone.lookAt(dl.x, dp.y, dl.z);\r\n\r\n    if (!REDUCED && droneData.props) {\r\n      droneData.props.forEach((p, idx) => {\r\n        p.rotation.y += dt * (32 + idx * 3);\r\n      });\r\n    }\r\n\r\n    const gy = heightAt(dp.x, dp.z), fH = dp.y - gy, fW = fH * 0.44, fD = fH * 0.32;\r\n    const ay = dp.y - 1.2;\r\n    let i0 = 0;\r\n    const C = [[dp.x - fW, gy, dp.z - fD], [dp.x + fW, gy, dp.z - fD], [dp.x + fW, gy, dp.z + fD], [dp.x - fW, gy, dp.z + fD]];\r\n    for(let k=0; k<4; k++){\r\n      const a = C[k], b = C[(k+1)%4];\r\n      fv[i0++]=dp.x; fv[i0++]=ay; fv[i0++]=dp.z; fv[i0++]=a[0]; fv[i0++]=a[1]; fv[i0++]=a[2]; fv[i0++]=b[0]; fv[i0++]=b[1]; fv[i0++]=b[2];\r\n    }\r\n    fv[i0++]=C[0][0]; fv[i0++]=C[0][1]; fv[i0++]=C[0][2]; fv[i0++]=C[1][0]; fv[i0++]=C[1][1]; fv[i0++]=C[1][2]; fv[i0++]=C[2][0]; fv[i0++]=C[2][1]; fv[i0++]=C[2][2];\r\n    fv[i0++]=C[0][0]; fv[i0++]=C[0][1]; fv[i0++]=C[0][2]; fv[i0++]=C[2][0]; fv[i0++]=C[2][1]; fv[i0++]=C[2][2]; fv[i0++]=C[3][0]; fv[i0++]=C[3][1]; fv[i0++]=C[3][2];\r\n    frustumGeo.attributes.position.needsUpdate = true;\r\n\r\n    photoTimer += dt;\r\n    if(photoTimer > 1.15){\r\n      photoTimer = 0;\r\n      photoCount++;\r\n      shutterFlash.position.set(dp.x, ay, dp.z);\r\n      shutterFlash.intensity = 5.2;\r\n\r\n      const fp = footprints[fpIdx];\r\n      fp.mesh.position.set(dp.x, gy + 0.08, dp.z);\r\n      fp.mesh.rotation.z = drone.rotation.y;\r\n      fp.life = 1;\r\n      fp.mesh.visible = true;\r\n      fpIdx = (fpIdx + 1) % 32;\r\n    }\r\n    shutterFlash.intensity = Math.max(0, shutterFlash.intensity - dt * 14);\r\n    footprints.forEach(f => {\r\n      if(f.life > 0){\r\n        f.life -= dt * 0.14;\r\n        f.mat.opacity = f.life * 0.32;\r\n        if(f.life <= 0) f.mesh.visible = false;\r\n      }\r\n    });\r\n\r\n    needle.style.transform = `rotate(${-yaw * 57.2958}deg)`;\r\n    renderer.render(scene, camera);\r\n  }\r\n  requestAnimationFrame(animate);\r\n});\r\n<\/script>\r\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-16566cc e-con-full e-flex e-con e-child\" data-id=\"16566cc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ad43cba elementor-icon-list--layout-inline elementor-mobile-align-center elementor-list-item-link-full_width elementor-widget elementor-widget-icon-list\" data-id=\"ad43cba\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-list.default\">\n\t\t\t\t\t\t\t<ul class=\"elementor-icon-list-items elementor-inline-items\">\n\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/volatusaerospace.com\/\">\n\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Home<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">\/<\/span>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/volatusaerospace.com\/fr-ca\/services\/\">\n\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Services<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">\/<\/span>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t\t<a href=\"https:\/\/volatusaerospace.com\/fr-ca\/services\/technical-capabilities\/\">\n\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">Technical Capabilities<\/span>\n\t\t\t\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\">\/<\/span>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-inline-item\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text\"> <span style=\"color: #FFB601\">Photogrammetry<span><\/span>\n\t\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-324a979 elementor-widget-mobile__width-inherit elementor-widget__width-inherit elementor-widget-laptop__width-initial elementor-widget-tablet__width-initial elementor-widget elementor-widget-heading\" data-id=\"324a979\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Photogrammetry\n<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4ddfffc elementor-widget__width-initial elementor-widget-tablet__width-initial elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"4ddfffc\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tOverlapping images. Measurable ground truth.\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-da29c6f elementor-widget__width-initial elementor-widget-mobile__width-inherit elementor-widget-laptop__width-initial elementor-widget-tablet__width-initial elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-text-editor\" data-id=\"da29c6f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tIt creates a measurable digital record of a site, structure, or corridor without putting survey crews across the entire area. A drone captures overlapping high-resolution images from a planned flight path. Processing converts those images into orthomosaics, point clouds, digital surface models, 2D maps, and 3D models. The resulting georeferenced data supports planning, surveying, construction and asset management.\n\t\t\t\t\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-69ddd11 e-con-full e-flex e-con e-child\" data-id=\"69ddd11\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1014729 elementor-widget elementor-widget-button\" data-id=\"1014729\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"button.default\">\n\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"#elementor-action%3Aaction%3Dpopup%3Aopen%26settings%3DeyJpZCI6IjQ5NjIiLCJ0b2dnbGUiOmZhbHNlfQ%3D%3D\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Talk To An Expert<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-38f87ba e-con-full e-flex e-con e-child\" data-id=\"38f87ba\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;position&quot;:&quot;absolute&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2c509cf elementor-widget elementor-widget-html\" data-id=\"2c509cf\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div class=\"scroll-indicator-container\">\r\n  <svg class=\"scroll-arrow arrow-1\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg>\r\n  <svg class=\"scroll-arrow arrow-2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg>\r\n  <svg class=\"scroll-arrow arrow-3\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" stroke=\"currentColor\" stroke-width=\"2\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"><\/polyline><\/svg>\r\n<\/div>\r\n\r\n<style>\r\n.scroll-indicator-container {\r\n  display: flex;\r\n  flex-direction: column;\r\n  align-items: center;\r\n  justify-content: center;\r\n}\r\n\r\n.scroll-arrow {\r\n  color: #555555; \/* Base gray color *\/\r\n  animation: lightSequence 2s infinite;\r\n  margin-top: -12px; \/* Adjusted overlap for smaller arrows *\/\r\n}\r\n\r\n\/* Delaying each arrow to create the cascading light effect *\/\r\n.arrow-1 { animation-delay: 0s; }\r\n.arrow-2 { animation-delay: 0.3s; }\r\n.arrow-3 { animation-delay: 0.6s; }\r\n\r\n@keyframes lightSequence {\r\n  0% { color: #555555; }\r\n  20% { \r\n    color: #ffffff; \/* White light *\/\r\n  }\r\n  40% { color: #555555; }\r\n  100% { color: #555555; }\r\n}\r\n<\/style>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-39cf43b e-flex e-con-boxed e-con e-parent\" data-id=\"39cf43b\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-1c69abb e-con-full e-flex e-con e-child\" data-id=\"1c69abb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-8fcaf7a e-con-full e-flex e-con e-child\" data-id=\"8fcaf7a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-3a989f8 e-con-full e-flex e-con e-child\" data-id=\"3a989f8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-55e52be elementor-widget elementor-widget-heading\" data-id=\"55e52be\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">What is<span style=\"color: #FFB601\">\n Photogrammetry?<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e17d817 elementor-widget elementor-widget-text-editor\" data-id=\"e17d817\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>Photogrammetry uses overlapping aerial photographs to create accurate maps, measurements, and three-dimensional models of an area or object. It turns a series of images into spatial data that can be measured, analyzed, and used for surveying, planning, and asset management. Each image captures the subject from a different position.<\/p><p>Photogrammetry software identifies common points across the images and uses them to reconstruct the geometry of the subject. The result is an orthomosaic for mapping, a point cloud for measurement, a digital surface model for elevation analysis, or a 3D model for visualization and inspection.<\/p><p>RTK and PPK positioning provide accurate georeferencing for captured imagery, while ground control points can be added where additional survey control is required. The appropriate combination depends on the required accuracy and site conditions.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9a35e17 e-con-full e-flex e-con e-child\" data-id=\"9a35e17\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ebca8a7 elementor-widget elementor-widget-image\" data-id=\"ebca8a7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"800\" height=\"423\" src=\"https:\/\/volatusaerospace.com\/wp-content\/uploads\/2026\/09\/Photogrammetry1-1024x542.webp\" class=\"attachment-large size-large wp-image-37120\" alt=\"\" srcset=\"https:\/\/volatusaerospace.com\/wp-content\/uploads\/2026\/09\/Photogrammetry1-1024x542.webp 1024w, https:\/\/volatusaerospace.com\/wp-content\/uploads\/2026\/09\/Photogrammetry1-300x159.webp 300w, https:\/\/volatusaerospace.com\/wp-content\/uploads\/2026\/09\/Photogrammetry1-768x406.webp 768w, https:\/\/volatusaerospace.com\/wp-content\/uploads\/2026\/09\/Photogrammetry1-1536x813.webp 1536w, https:\/\/volatusaerospace.com\/wp-content\/uploads\/2026\/09\/Photogrammetry1.webp 1920w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-8246aea e-flex e-con-boxed e-con e-parent\" data-id=\"8246aea\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0277ed2 elementor-widget elementor-widget-heading\" data-id=\"0277ed2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Industry \n\n<span style=\"color: #FFB601\">Use Cases\n<\/h2>\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-28ed614 e-grid e-con-full e-con e-child\" data-id=\"28ed614\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-b36c88f e-con-full e-flex e-con e-child\" data-id=\"b36c88f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-6e6adc8 e-con-full e-flex e-con e-child\" data-id=\"6e6adc8\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-23cb1db e-con-full e-flex e-con e-child\" data-id=\"23cb1db\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-732d11e elementor-widget elementor-widget-heading\" data-id=\"732d11e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Surveying and mapping<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-779c241 elementor-widget elementor-widget-text-editor\" data-id=\"779c241\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tTopographic surveys, site mapping, corridor mapping, and aerial imagery for infrastructure and development projects.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-fd54d5e e-con-full e-flex e-con e-child\" data-id=\"fd54d5e\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7d69f6c e-con-full e-flex e-con e-child\" data-id=\"7d69f6c\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-837b07c e-con-full e-flex e-con e-child\" data-id=\"837b07c\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8b50fcb elementor-widget elementor-widget-heading\" data-id=\"8b50fcb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Construction<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fc988a6 elementor-widget elementor-widget-text-editor\" data-id=\"fc988a6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tSite surveys, progress tracking, earthwork measurement, as-built documentation, and 3D site models.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-17a22b2 e-con-full e-flex e-con e-child\" data-id=\"17a22b2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-460dd09 e-con-full e-flex e-con e-child\" data-id=\"460dd09\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a07eb66 e-con-full e-flex e-con e-child\" data-id=\"a07eb66\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0a8581d elementor-widget elementor-widget-heading\" data-id=\"0a8581d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Mining and aggregates<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-95a72e3 elementor-widget elementor-widget-text-editor\" data-id=\"95a72e3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tStockpile volumes, terrain models, site mapping and repeat surveys for tracking material movement.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-dbd7546 e-con-full e-flex e-con e-child\" data-id=\"dbd7546\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-68687fe e-con-full e-flex e-con e-child\" data-id=\"68687fe\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d844d55 e-con-full e-flex e-con e-child\" data-id=\"d844d55\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5c24558 elementor-widget elementor-widget-heading\" data-id=\"5c24558\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Infrastructure<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e1a7d5c elementor-widget elementor-widget-text-editor\" data-id=\"e1a7d5c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tRoads, rail, utilities, pipelines, and other linear assets where large areas need to be mapped consistently.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c02cfce e-con-full e-flex e-con e-child\" data-id=\"c02cfce\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-7a31985 e-con-full e-flex e-con e-child\" data-id=\"7a31985\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-4bdbc8d e-con-full e-flex e-con e-child\" data-id=\"4bdbc8d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-fb5ba4f elementor-widget elementor-widget-heading\" data-id=\"fb5ba4f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Industrial sites<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3a82f49 elementor-widget elementor-widget-text-editor\" data-id=\"3a82f49\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tHigh-resolution mapping and 3D modeling of facilities, structures, and operational areas.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c1200c8 e-con-full e-flex e-con e-child\" data-id=\"c1200c8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-b35e09d e-con-full e-flex e-con e-child\" data-id=\"b35e09d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2ab2ec9 e-con-full e-flex e-con e-child\" data-id=\"2ab2ec9\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2352f2f elementor-widget elementor-widget-heading\" data-id=\"2352f2f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Environmental and forestry<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2880f34 elementor-widget elementor-widget-text-editor\" data-id=\"2880f34\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tForest mapping, surface deposits, wetlands, logging roads and areas affected by development or disturbance.\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-977c26e e-flex e-con-boxed e-con e-parent\" data-id=\"977c26e\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-047c363 elementor-widget__width-initial elementor-widget elementor-widget-heading\" data-id=\"047c363\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">How photogrammetry \n <span style=\"color: #FFB601\">supports an asset monitoring program <\/h2>\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6feb451 e-con-full filter-section item-drones e-flex e-con e-child\" data-id=\"6feb451\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-62ad6a8 e-con-full e-flex e-con e-child\" data-id=\"62ad6a8\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-6c2b10f e-con-full e-flex e-con e-child\" data-id=\"6c2b10f\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;sticky&quot;:&quot;top&quot;,&quot;sticky_offset&quot;:90,&quot;sticky_parent&quot;:&quot;yes&quot;,&quot;sticky_on&quot;:[&quot;desktop&quot;,&quot;laptop&quot;],&quot;sticky_effects_offset&quot;:0,&quot;sticky_anchor_link_offset&quot;:0}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-cfaccf3 elementor-widget elementor-widget-heading\" data-id=\"cfaccf3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">A single survey tells you what a site looks like today.\n <span style=\"color: #FFB601\">Repeat photogrammetry tells you what changed.\n\n<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e172996 elementor-widget elementor-widget-html\" data-id=\"e172996\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"UTF-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n<title>Asset Monitoring \u2014 Repeat Survey Analysis (Elementor Dynamic Height Widget)<\/title>\r\n<!-- Google Fonts for Elementor & Standalone Preview -->\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\r\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Archivo:wdth,wght@62..125,100..900&family=IBM+Plex+Mono:wght@400;500;600&display=swap\" rel=\"stylesheet\">\r\n\r\n<style>\r\n\/* =========================================================================\r\n   >>> MANUAL HEIGHT & DIMENSION CONTROLS (EDIT HERE) <<<\r\n   Adjust these values directly to increase or decrease the animation height.\r\n   ========================================================================= *\/\r\n:root, .volatus-cutfill-widget {\r\n  \/* \r\n     1. MAIN GRAPH HEIGHT (Desktop & Laptop):\r\n     Default: 380px.\r\n     Increase to 420px, 450px, or 500px for a taller, more spacious curve.\r\n     Decrease to 320px or 350px for a more compact card.\r\n  *\/\r\n  --canvas-height: 340px;\r\n\r\n  \/* \r\n     2. MOBILE GRAPH HEIGHT (Screens under 680px wide):\r\n     Default: 280px.\r\n  *\/\r\n  --canvas-mobile-height: 280px;\r\n\r\n  \/* \r\n     3. WIDGET MAX-HEIGHT RESTRICTION:\r\n     Set to 'none' for natural unrestricted height (recommended).\r\n     Or set to 'calc(100vh - 80px)' if you want a strict viewport cap.\r\n  *\/\r\n  --widget-max-height: none;\r\n}\r\n\r\n\/* =========================================================================\r\n   ELEMENTOR COMPATIBLE WIDGET STYLES (FULL BLACK #000000 & OFF-BLACK #111111)\r\n   All styling strictly scoped to .volatus-cutfill-widget with !important.\r\n   No global html\/body resets so outer website layout is 100% untouched.\r\n   ========================================================================= *\/\r\n\r\n\/* Scoped Widget Container *\/\r\n.volatus-cutfill-widget {\r\n  box-sizing: border-box !important;\r\n  font-family: \"Archivo\", sans-serif !important;\r\n  display: flex !important;\r\n  flex-direction: column !important;\r\n  width: 100% !important;\r\n  max-width: 980px !important;\r\n  margin: 0 auto !important;\r\n  background-color: #000000 !important;\r\n  color: #ECEEEA !important;\r\n  -webkit-font-smoothing: antialiased !important;\r\n  line-height: 1.4 !important;\r\n  max-height: var(--widget-max-height, none) !important;\r\n}\r\n\r\n.volatus-cutfill-widget *,\r\n.volatus-cutfill-widget *::before,\r\n.volatus-cutfill-widget *::after {\r\n  box-sizing: border-box !important;\r\n  font-family: inherit !important;\r\n}\r\n\r\n\/* Outer Panel Card (Off-Black #111111) *\/\r\n.volatus-cutfill-widget .sv-panel {\r\n  border: 1px solid rgba(255, 255, 255, 0.12) !important;\r\n  background-color: #111111 !important;\r\n  position: relative !important;\r\n  overflow: hidden !important;\r\n  border-radius: 4px !important;\r\n  width: 100% !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n  display: flex !important;\r\n  flex-direction: column !important;\r\n  flex: 1 1 auto !important;\r\n}\r\n\r\n\/* 1. Header Bar with Title & Status *\/\r\n.volatus-cutfill-widget .sv-top {\r\n  display: flex !important;\r\n  justify-content: space-between !important;\r\n  align-items: center !important;\r\n  gap: 12px !important;\r\n  flex-wrap: wrap !important;\r\n  padding: 13px 20px !important;\r\n  border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important;\r\n  background-color: #111111 !important;\r\n  margin: 0 !important;\r\n  flex-shrink: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-title-group {\r\n  display: flex !important;\r\n  align-items: center !important;\r\n  gap: 10px !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-status-dot {\r\n  width: 7px !important;\r\n  height: 7px !important;\r\n  border-radius: 50% !important;\r\n  background-color: #FFAE1A !important;\r\n  animation: pulseDot 2s infinite ease-in-out !important;\r\n  flex-shrink: 0 !important;\r\n  display: inline-block !important;\r\n}\r\n\r\n@keyframes pulseDot {\r\n  0%, 100% { opacity: 1; transform: scale(1); }\r\n  50% { opacity: 0.35; transform: scale(1.3); }\r\n}\r\n\r\n.volatus-cutfill-widget .sv-top h3 {\r\n  font-family: \"IBM Plex Mono\", ui-monospace, monospace !important;\r\n  font-size: 11px !important;\r\n  font-weight: 600 !important;\r\n  letter-spacing: .2em !important;\r\n  text-transform: uppercase !important;\r\n  color: #ECEEEA !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n  line-height: 1.2 !important;\r\n  border: none !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-legend {\r\n  display: flex !important;\r\n  align-items: center !important;\r\n  gap: 16px !important;\r\n  font-family: \"IBM Plex Mono\", ui-monospace, monospace !important;\r\n  font-size: 10px !important;\r\n  letter-spacing: .14em !important;\r\n  color: #A6AEB4 !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-legend span {\r\n  display: inline-flex !important;\r\n  align-items: center !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-legend i {\r\n  display: inline-block !important;\r\n  width: 8px !important;\r\n  height: 8px !important;\r\n  margin-right: 6px !important;\r\n  vertical-align: middle !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-legend .lf { background-color: #FFAE1A !important; }\r\n.volatus-cutfill-widget .sv-legend .lc { background-color: #7FB2C8 !important; }\r\n.volatus-cutfill-widget .sv-legend .lb {\r\n  display: inline-block !important;\r\n  width: 12px !important;\r\n  height: 0 !important;\r\n  border-top: 2px dashed rgba(255, 255, 255, 0.45) !important;\r\n  margin-right: 6px !important;\r\n  vertical-align: middle !important;\r\n}\r\n\r\n\/* 2. Telemetry Readout Strip *\/\r\n.volatus-cutfill-widget .sv-readout {\r\n  display: grid !important;\r\n  grid-template-columns: repeat(4, 1fr) !important;\r\n  border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important;\r\n  background-color: #000000 !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n  gap: 1px !important;\r\n  flex-shrink: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .ro-card {\r\n  padding: 11px 18px !important;\r\n  background-color: #111111 !important;\r\n  display: flex !important;\r\n  flex-direction: column !important;\r\n  gap: 3px !important;\r\n  margin: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .ro-card .k {\r\n  font-family: \"IBM Plex Mono\", ui-monospace, monospace !important;\r\n  font-size: 8.5px !important;\r\n  letter-spacing: .2em !important;\r\n  color: #6E7880 !important;\r\n  text-transform: uppercase !important;\r\n  line-height: 1.2 !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .ro-card .v {\r\n  font-family: \"IBM Plex Mono\", ui-monospace, monospace !important;\r\n  font-size: 15.5px !important;\r\n  font-weight: 600 !important;\r\n  letter-spacing: .02em !important;\r\n  color: #ECEEEA !important;\r\n  line-height: 1.2 !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .ro-card .v-sub {\r\n  font-family: \"IBM Plex Mono\", ui-monospace, monospace !important;\r\n  font-size: 9px !important;\r\n  color: #A6AEB4 !important;\r\n  letter-spacing: 0.05em !important;\r\n  font-weight: 400 !important;\r\n}\r\n\r\n.volatus-cutfill-widget #svFill { color: #FFAE1A !important; }\r\n.volatus-cutfill-widget #svCut  { color: #7FB2C8 !important; }\r\n.volatus-cutfill-widget #svNet  { color: #ECEEEA !important; }\r\n\r\n\/* 3. Concise Stage Status Strip *\/\r\n.volatus-cutfill-widget .sv-phase-strip {\r\n  display: flex !important;\r\n  justify-content: space-between !important;\r\n  align-items: center !important;\r\n  gap: 10px !important;\r\n  padding: 8px 20px !important;\r\n  background-color: #000000 !important;\r\n  border-bottom: 1px solid rgba(255, 255, 255, 0.08) !important;\r\n  font-family: \"IBM Plex Mono\", ui-monospace, monospace !important;\r\n  font-size: 10px !important;\r\n  margin: 0 !important;\r\n  flex-shrink: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-phase-tag {\r\n  font-weight: 600 !important;\r\n  letter-spacing: .16em !important;\r\n  color: #FFAE1A !important;\r\n  text-transform: uppercase !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-phase-desc {\r\n  color: #A6AEB4 !important;\r\n  letter-spacing: .04em !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n\/* 4. Canvas Section \u2014 CONTROLLED BY --canvas-height *\/\r\n.volatus-cutfill-widget .canvas-holder {\r\n  position: relative !important;\r\n  width: 100% !important;\r\n  background-color: #000000 !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n  flex: 1 1 auto !important;\r\n}\r\n\r\n.volatus-cutfill-widget #svCanvas {\r\n  display: block !important;\r\n  width: 100% !important;\r\n  \/* Controlled by the --canvas-height variable at the top *\/\r\n  height: var(--canvas-height, 380px) !important;\r\n  min-height: 220px !important;\r\n  cursor: ew-resize !important;\r\n  touch-action: pan-y !important;\r\n  background-color: #000000 !important;\r\n  border: none !important;\r\n  outline: none !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n\/* 5. Bottom Controls Bar *\/\r\n.volatus-cutfill-widget .sv-controls {\r\n  display: flex !important;\r\n  align-items: center !important;\r\n  justify-content: space-between !important;\r\n  gap: 8px !important;\r\n  padding: 10px 20px !important;\r\n  border-top: 1px solid rgba(255, 255, 255, 0.08) !important;\r\n  background-color: #111111 !important;\r\n  margin: 0 !important;\r\n  flex-shrink: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-btn-group {\r\n  display: flex !important;\r\n  gap: 6px !important;\r\n  flex: 1 !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget button.sv-btn {\r\n  all: unset !important;\r\n  box-sizing: border-box !important;\r\n  font-family: \"IBM Plex Mono\", ui-monospace, monospace !important;\r\n  font-size: 10px !important;\r\n  letter-spacing: .1em !important;\r\n  color: #A6AEB4 !important;\r\n  border: 1px solid rgba(255, 255, 255, 0.16) !important;\r\n  background-color: #000000 !important;\r\n  padding: 8px 12px !important;\r\n  transition: all .2s ease !important;\r\n  display: flex !important;\r\n  align-items: center !important;\r\n  justify-content: center !important;\r\n  gap: 5px !important;\r\n  border-radius: 2px !important;\r\n  flex: 1 !important;\r\n  text-align: center !important;\r\n  cursor: pointer !important;\r\n  margin: 0 !important;\r\n  line-height: 1 !important;\r\n}\r\n\r\n.volatus-cutfill-widget button.sv-btn .badge-day {\r\n  font-size: 8px !important;\r\n  color: #FFAE1A !important;\r\n  opacity: 0.9 !important;\r\n}\r\n\r\n.volatus-cutfill-widget button.sv-btn:hover {\r\n  color: #ECEEEA !important;\r\n  border-color: rgba(255, 255, 255, 0.35) !important;\r\n  background-color: #181818 !important;\r\n}\r\n\r\n.volatus-cutfill-widget button.sv-btn.active {\r\n  border-color: #FFAE1A !important;\r\n  color: #FFAE1A !important;\r\n  background-color: rgba(255, 174, 26, 0.1) !important;\r\n  font-weight: 600 !important;\r\n}\r\n\r\n.volatus-cutfill-widget button.sv-play {\r\n  all: unset !important;\r\n  box-sizing: border-box !important;\r\n  width: 36px !important;\r\n  height: 36px !important;\r\n  border: 1px solid rgba(255, 255, 255, 0.16) !important;\r\n  background-color: #000000 !important;\r\n  display: flex !important;\r\n  align-items: center !important;\r\n  justify-content: center !important;\r\n  transition: all .2s ease !important;\r\n  border-radius: 2px !important;\r\n  flex-shrink: 0 !important;\r\n  cursor: pointer !important;\r\n  color: #ECEEEA !important;\r\n  margin: 0 !important;\r\n  padding: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget button.sv-play:hover {\r\n  border-color: #FFAE1A !important;\r\n  color: #FFAE1A !important;\r\n  background-color: #181818 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-play svg {\r\n  width: 13px !important;\r\n  height: 13px !important;\r\n  fill: currentColor !important;\r\n  margin: 0 !important;\r\n}\r\n\r\n\/* While playing: show pause icon, hide play icon *\/\r\n.volatus-cutfill-widget .sv-play #icoPlay {\r\n  display: none !important;\r\n}\r\n.volatus-cutfill-widget .sv-play #icoPause {\r\n  display: block !important;\r\n}\r\n\r\n\/* While paused: show play icon, hide pause icon *\/\r\n.volatus-cutfill-widget .sv-play.is-paused #icoPlay {\r\n  display: block !important;\r\n}\r\n.volatus-cutfill-widget .sv-play.is-paused #icoPause {\r\n  display: none !important;\r\n}\r\n\r\n\/* 6. Footer Hint *\/\r\n.volatus-cutfill-widget .sv-hint {\r\n  font-family: \"IBM Plex Mono\", ui-monospace, monospace !important;\r\n  font-size: 9px !important;\r\n  letter-spacing: .14em !important;\r\n  color: #6E7880 !important;\r\n  text-transform: uppercase !important;\r\n  margin-top: 8px !important;\r\n  display: flex !important;\r\n  align-items: center !important;\r\n  justify-content: space-between !important;\r\n  gap: 10px !important;\r\n  padding: 0 4px !important;\r\n  flex-shrink: 0 !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-hint-left {\r\n  display: flex !important;\r\n  align-items: center !important;\r\n  gap: 8px !important;\r\n}\r\n\r\n.volatus-cutfill-widget .sv-hint-left::before {\r\n  content: \"\" !important;\r\n  width: 14px !important;\r\n  height: 1px !important;\r\n  background-color: #FFAE1A !important;\r\n  display: inline-block !important;\r\n}\r\n\r\n\/* ============ MOBILE RESPONSIVENESS (WIDTH <= 680px) ============ *\/\r\n@media (max-width: 680px) {\r\n  .volatus-cutfill-widget #svCanvas {\r\n    height: var(--canvas-mobile-height, 280px) !important;\r\n  }\r\n  .volatus-cutfill-widget .sv-readout {\r\n    grid-template-columns: 1fr 1fr !important;\r\n  }\r\n  .volatus-cutfill-widget .ro-card {\r\n    padding: 9px 12px !important;\r\n  }\r\n  .volatus-cutfill-widget .sv-phase-desc {\r\n    display: none !important;\r\n  }\r\n  .volatus-cutfill-widget .sv-top {\r\n    padding: 9px 12px !important;\r\n  }\r\n  .volatus-cutfill-widget .sv-controls {\r\n    padding: 7px 10px !important;\r\n  }\r\n  .volatus-cutfill-widget button.sv-btn {\r\n    padding: 6px 4px !important;\r\n    font-size: 9px !important;\r\n  }\r\n  .volatus-cutfill-widget .sv-btn .badge-day {\r\n    display: none !important;\r\n  }\r\n}\r\n\r\n@media (max-width: 420px) {\r\n  .volatus-cutfill-widget #svCanvas {\r\n    height: 240px !important;\r\n  }\r\n  .volatus-cutfill-widget .ro-card .v {\r\n    font-size: 13.5px !important;\r\n  }\r\n  .volatus-cutfill-widget .sv-legend {\r\n    font-size: 9px !important;\r\n    gap: 8px !important;\r\n  }\r\n}\r\n<\/style>\r\n<\/head>\r\n<body>\r\n\r\n<!-- =========================================================================\r\n     ELEMENTOR HTML WIDGET START\r\n     ========================================================================= -->\r\n<div class=\"volatus-cutfill-widget\" id=\"volatusCutFillWidget\">\r\n  <div class=\"sv-panel\">\r\n    <!-- Header with Live Legend -->\r\n    <div class=\"sv-top\">\r\n      <div class=\"sv-title-group\">\r\n        <span class=\"sv-status-dot\"><\/span>\r\n        <h3>Repeat Survey Analysis<\/h3>\r\n      <\/div>\r\n      <div class=\"sv-legend\">\r\n        <span><i class=\"lb\"><\/i>BASELINE<\/span>\r\n        <span><i class=\"lf\"><\/i>FILL<\/span>\r\n        <span><i class=\"lc\"><\/i>CUT<\/span>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- 4 Clean Telemetry Metric Cards -->\r\n    <div class=\"sv-readout\">\r\n      <div class=\"ro-card\">\r\n        <span class=\"k\">Active Survey<\/span>\r\n        <div class=\"v\"><span id=\"svEpoch\">E01<\/span> <span class=\"v-sub\" id=\"svDays\">(Ref)<\/span><\/div>\r\n      <\/div>\r\n      <div class=\"ro-card\">\r\n        <span class=\"k\">\u0394 Fill<\/span>\r\n        <div class=\"v\" id=\"svFill\">+0 m\u00b3<\/div>\r\n      <\/div>\r\n      <div class=\"ro-card\">\r\n        <span class=\"k\">\u0394 Cut<\/span>\r\n        <div class=\"v\" id=\"svCut\">\u22120 m\u00b3<\/div>\r\n      <\/div>\r\n      <div class=\"ro-card\">\r\n        <span class=\"k\">Net Volume<\/span>\r\n        <div class=\"v\" id=\"svNet\">0 m\u00b3<\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Concise Status Sub-Bar -->\r\n    <div class=\"sv-phase-strip\">\r\n      <span class=\"sv-phase-tag\" id=\"bannerPhase\">E01 \u00b7 BASELINE ESTABLISHED<\/span>\r\n      <span class=\"sv-phase-desc\" id=\"bannerDesc\">2026-03-08 \u00b7 Initial reference datum<\/span>\r\n    <\/div>\r\n\r\n    <!-- Canvas Container (Full Black #000000) -->\r\n    <div class=\"canvas-holder\">\r\n      <canvas id=\"svCanvas\"><\/canvas>\r\n    <\/div>\r\n\r\n    <!-- Epoch Selector Buttons & Playback -->\r\n    <div class=\"sv-controls\" id=\"svControls\">\r\n      <div class=\"sv-btn-group\">\r\n        <button type=\"button\" class=\"sv-btn active\" data-k=\"0\">\r\n          <span>E01<\/span><span class=\"badge-day\">REF<\/span>\r\n        <\/button>\r\n        <button type=\"button\" class=\"sv-btn\" data-k=\"1\">\r\n          <span>E02<\/span><span class=\"badge-day\">+55d<\/span>\r\n        <\/button>\r\n        <button type=\"button\" class=\"sv-btn\" data-k=\"2\">\r\n          <span>E03<\/span><span class=\"badge-day\">+125d<\/span>\r\n        <\/button>\r\n        <button type=\"button\" class=\"sv-btn\" data-k=\"3\">\r\n          <span>E04<\/span><span class=\"badge-day\">+202d<\/span>\r\n        <\/button>\r\n      <\/div>\r\n\r\n      <button type=\"button\" class=\"sv-play\" id=\"svPlay\" aria-label=\"Toggle auto survey sequence\">\r\n        <svg id=\"icoPlay\" viewBox=\"0 0 24 24\"><path d=\"M8 5v14l11-7z\"\/><\/svg>\r\n        <svg id=\"icoPause\" viewBox=\"0 0 24 24\"><path d=\"M6 5h4v14H6zM14 5h4v14h-4z\"\/><\/svg>\r\n      <\/button>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <!--<div class=\"sv-hint\">-->\r\n  <!--  <div class=\"sv-hint-left\">-->\r\n  <!--    <span>Drag section or select E01\u2013E04 to scrub<\/span>-->\r\n  <!--  <\/div>-->\r\n  <!--  <span>WGS84 DATUM<\/span>-->\r\n  <!--<\/div>-->\r\n<\/div>\r\n<!-- =========================================================================\r\n     ELEMENTOR HTML WIDGET END\r\n     ========================================================================= -->\r\n\r\n<script>\r\n\/**\r\n * Scoped IIFE for WordPress \/ Elementor Compatibility\r\n * All selectors query strictly within #volatusCutFillWidget\r\n *\/\r\n(function() {\r\n  'use strict';\r\n\r\n  var root = document.getElementById('volatusCutFillWidget');\r\n  if (!root) return;\r\n\r\n  var cv = root.querySelector('#svCanvas');\r\n  if (!cv) return;\r\n  var ctx = cv.getContext('2d');\r\n\r\n  var DOM = {\r\n    ep:          root.querySelector('#svEpoch'),\r\n    days:        root.querySelector('#svDays'),\r\n    fill:        root.querySelector('#svFill'),\r\n    cut:         root.querySelector('#svCut'),\r\n    net:         root.querySelector('#svNet'),\r\n    bannerPhase: root.querySelector('#bannerPhase'),\r\n    bannerDesc:  root.querySelector('#bannerDesc'),\r\n    icoPlay:     root.querySelector('#icoPlay'),\r\n    icoPause:    root.querySelector('#icoPause'),\r\n    playBtn:     root.querySelector('#svPlay')\r\n  };\r\n\r\n  var lerp = function(a, b, t) { return a + (b - a) * t; };\r\n  var clamp = function(v, a, b) { return Math.min(b, Math.max(a, v)); };\r\n\r\n  \/\/ 4 Epoch Definitions\r\n  var EPOCHS = [\r\n    { k: 0, tag: 'E01', d: '2026-03-08', days: 'Baseline', s: 7.5,  p: 1.5, phase: 'E01 \u00b7 BASELINE ESTABLISHED', desc: '2026-03-08 \u00b7 Initial reference datum' },\r\n    { k: 1, tag: 'E02', d: '2026-05-02', days: '+55d',      s: 13.0, p: 4.0, phase: 'E02 \u00b7 MATERIAL MOVEMENT',    desc: '2026-05-02 \u00b7 Initial aggregate stockpiling' },\r\n    { k: 2, tag: 'E03', d: '2026-07-11', days: '+125d',     s: 18.5, p: 6.5, phase: 'E03 \u00b7 PEAK EXCAVATION',     desc: '2026-07-11 \u00b7 Quarry excavation and fill expansion' },\r\n    { k: 3, tag: 'E04', d: '2026-09-26', days: '+202d',     s: 24.0, p: 9.0, phase: 'E04 \u00b7 RECONCILIATION',       desc: '2026-09-26 \u00b7 Final mass-haul reconciliation' }\r\n  ];\r\n\r\n  var SX = 30, SS = 8;         \/\/ Stockpile mound center & spread\r\n  var PX = 82, PS = 6.5;       \/\/ Excavation pit center & spread\r\n  var DOMAIN = 120, WIDTH = 45;\/\/ 120m cross-section, 45m corridor width\r\n  var EMIN = 10, EMAX = 56;\r\n\r\n  \/\/ Harmonic Baseline Terrain Generator\r\n  var baseG = function(x) { return 24 + 3.5 * Math.sin(x \/ 14 + .8) + 1.6 * Math.sin(x \/ 5.2 + 2); };\r\n  var gs    = function(x) { return Math.exp(-((x - SX) * (x - SX)) \/ (2 * SS * SS)); };\r\n  var gp    = function(x) { return Math.exp(-((x - PX) * (x - PX)) \/ (2 * PS * PS)); };\r\n  var profK = function(x, k) { return baseG(x) + EPOCHS[k].s * gs(x) - EPOCHS[k].p * gp(x); };\r\n\r\n  \/\/ Smooth Interpolated Surface at parameter 't' (0.0 to 3.0)\r\n  var profT = function(x, t) {\r\n    var k = clamp(Math.floor(t), 0, 2);\r\n    var f = clamp(t - k, 0, 1);\r\n    var ease = f * f * (3 - 2 * f);\r\n    var s = lerp(EPOCHS[k].s, EPOCHS[k + 1].s, ease);\r\n    var p = lerp(EPOCHS[k].p, EPOCHS[k + 1].p, ease);\r\n    return baseG(x) + s * gs(x) - p * gp(x);\r\n  };\r\n\r\n  \/\/ Soil body pattern (Pure Black with delicate white hatch)\r\n  var pc = document.createElement('canvas');\r\n  pc.width = pc.height = 8;\r\n  var pctx = pc.getContext('2d');\r\n  pctx.strokeStyle = 'rgba(255, 255, 255, 0.04)';\r\n  pctx.lineWidth = 1;\r\n  pctx.beginPath();\r\n  pctx.moveTo(0, 8);  pctx.lineTo(8, 0);\r\n  pctx.moveTo(-4, 4); pctx.lineTo(4, -4);\r\n  pctx.moveTo(4, 12); pctx.lineTo(12, 4);\r\n  pctx.stroke();\r\n  var hatch = ctx.createPattern(pc, 'repeat');\r\n\r\n  \/\/ Minimal Pill Badge Drawing Helper (Off-Black #111111)\r\n  function drawPill(context, text, cx, cy, fgColor, bgColor, borderColor, font) {\r\n    context.save();\r\n    context.font = font || '9px \"IBM Plex Mono\", monospace';\r\n    var w = context.measureText(text).width + 12;\r\n    var h = 18;\r\n    var x = cx - w \/ 2;\r\n    var y = cy - h \/ 2;\r\n\r\n    context.fillStyle = bgColor || '#111111';\r\n    context.beginPath();\r\n    if (context.roundRect) context.roundRect(x, y, w, h, 2);\r\n    else context.rect(x, y, w, h);\r\n    context.fill();\r\n\r\n    if (borderColor) {\r\n      context.strokeStyle = borderColor;\r\n      context.lineWidth = 1;\r\n      context.stroke();\r\n    }\r\n\r\n    context.fillStyle = fgColor;\r\n    context.textAlign = 'center';\r\n    context.textBaseline = 'middle';\r\n    context.fillText(text, cx, cy);\r\n    context.restore();\r\n  }\r\n\r\n  \/\/ Animation State\r\n  var W = 0, H = 0;\r\n  var t = 0;\r\n  var displayFill = 0, displayCut = 0, displayNet = 0;\r\n  var isAutoPlaying = true;\r\n  var isDragging = false;\r\n  var animId = null;\r\n\r\n  \/\/ Auto-tour timeline timings\r\n  var tourTimeline = 0;\r\n  var DWELL_E01 = 1.8;\r\n  var SHIFT_12  = 1.4;\r\n  var DWELL_E02 = 1.5;\r\n  var SHIFT_23  = 1.4;\r\n  var DWELL_E03 = 1.5;\r\n  var SHIFT_34  = 1.4;\r\n  var DWELL_E04 = 2.0;\r\n  var RESET_01  = 1.6;\r\n  var TOUR_TOTAL = DWELL_E01 + SHIFT_12 + DWELL_E02 + SHIFT_23 + DWELL_E03 + SHIFT_34 + DWELL_E04 + RESET_01;\r\n\r\n  function draw() {\r\n    \/\/ Clear canvas to Full Black #000000\r\n    ctx.fillStyle = '#000000';\r\n    ctx.fillRect(0, 0, W, H);\r\n\r\n    \/\/ Responsive Canvas Margins that Adapt to Custom Height\r\n    var isMobile = W < 540;\r\n    var isShort = H < 280;\r\n    var M = {\r\n      l: isMobile ? 36 : (isShort ? 44 : 50),\r\n      r: isMobile ? 14 : (isShort ? 16 : 20),\r\n      t: isShort ? 30 : 44,\r\n      b: isShort ? 22 : 32\r\n    };\r\n\r\n    var X = function(x) { return M.l + (x \/ DOMAIN) * (W - M.l - M.r); };\r\n    var Y = function(e) { return M.t + (1 - (e - EMIN) \/ (EMAX - EMIN)) * (H - M.t - M.b); };\r\n\r\n    var activeEpochIdx = clamp(Math.round(t), 0, 3);\r\n    var isBaselineOnly = (t < 0.04);\r\n\r\n    \/* 1. Grid Lines & Elevation Rulers *\/\r\n    ctx.font = (isShort || isMobile ? '8px' : '9px') + ' \"IBM Plex Mono\", monospace';\r\n    ctx.strokeStyle = 'rgba(255, 255, 255, 0.06)';\r\n    ctx.fillStyle = 'rgba(166, 174, 180, 0.65)';\r\n    ctx.textAlign = 'right';\r\n    ctx.lineWidth = 1;\r\n\r\n    for (var e = EMIN; e <= 50; e += 10) {\r\n      var y = Y(e);\r\n      ctx.beginPath();\r\n      ctx.moveTo(M.l, y);\r\n      ctx.lineTo(W - M.r, y);\r\n      ctx.stroke();\r\n      ctx.fillText(e, M.l - 6, y + 3);\r\n    }\r\n\r\n    \/\/ Distance Ticks\r\n    ctx.textAlign = 'center';\r\n    var xStep = isMobile ? 40 : 20;\r\n    for (var x = 0; x <= DOMAIN; x += xStep) {\r\n      ctx.fillText(x + 'm', X(x), H - (isShort ? 7 : 10));\r\n    }\r\n\r\n    \/* 2. Volume Integration Across Spatial Slices *\/\r\n    var N = isMobile ? 140 : 220, dx = DOMAIN \/ N;\r\n    var pts = [];\r\n    var currentFillVol = 0, currentCutVol = 0;\r\n\r\n    for (var i = 0; i <= N; i++) {\r\n      var curX = i * dx;\r\n      var yNow = profT(curX, t);\r\n      var yBase = profK(curX, 0);\r\n      var diff = yNow - yBase;\r\n\r\n      if (diff > 0) currentFillVol += diff * dx;\r\n      else currentCutVol -= diff * dx;\r\n\r\n      pts.push([X(curX), Y(yNow), diff, curX]);\r\n    }\r\n    currentFillVol *= WIDTH;\r\n    currentCutVol  *= WIDTH;\r\n    var currentNetVol = currentFillVol - currentCutVol;\r\n\r\n    \/* 3. Smooth Number Updates *\/\r\n    displayFill = lerp(displayFill, currentFillVol, 0.14);\r\n    displayCut  = lerp(displayCut, currentCutVol, 0.14);\r\n    displayNet  = lerp(displayNet, currentNetVol, 0.14);\r\n\r\n    DOM.ep.textContent = EPOCHS[activeEpochIdx].tag;\r\n    DOM.days.textContent = '(' + EPOCHS[activeEpochIdx].days + ')';\r\n\r\n    if (isBaselineOnly) {\r\n      DOM.fill.textContent = '+0 m\u00b3';\r\n      DOM.cut.textContent  = '\u22120 m\u00b3';\r\n      DOM.net.textContent  = '0 m\u00b3';\r\n      DOM.fill.style.color = '#A6AEB4';\r\n      DOM.cut.style.color  = '#A6AEB4';\r\n    } else {\r\n      DOM.fill.textContent = '+' + Math.round(displayFill).toLocaleString('en-US') + ' m\u00b3';\r\n      DOM.cut.textContent  = '\u2212' + Math.round(displayCut).toLocaleString('en-US') + ' m\u00b3';\r\n      var netSign = displayNet >= 0 ? '+' : '\u2212';\r\n      DOM.net.textContent  = netSign + Math.abs(Math.round(displayNet)).toLocaleString('en-US') + ' m\u00b3';\r\n      DOM.fill.style.color = '#FFAE1A';\r\n      DOM.cut.style.color  = '#7FB2C8';\r\n    }\r\n\r\n    DOM.bannerPhase.textContent = EPOCHS[activeEpochIdx].phase;\r\n    DOM.bannerDesc.textContent  = EPOCHS[activeEpochIdx].desc;\r\n\r\n    var btns = root.querySelectorAll('.sv-btn');\r\n    for (var b = 0; b < btns.length; b++) {\r\n      btns[b].classList.toggle('active', parseInt(btns[b].getAttribute('data-k'), 10) === activeEpochIdx);\r\n    }\r\n\r\n    \/* 4. Sub-Terrain Cross-Section Body *\/\r\n    ctx.beginPath();\r\n    for (var p = 0; p < pts.length; p++) {\r\n      if (p === 0) ctx.moveTo(pts[p][0], pts[p][1]);\r\n      else ctx.lineTo(pts[p][0], pts[p][1]);\r\n    }\r\n    ctx.lineTo(X(DOMAIN), Y(EMIN));\r\n    ctx.lineTo(X(0), Y(EMIN));\r\n    ctx.closePath();\r\n    ctx.fillStyle = hatch;\r\n    ctx.fill();\r\n\r\n    \/* 5. Fill & Cut Shading *\/\r\n    if (!isBaselineOnly) {\r\n      var poly = function(run) {\r\n        ctx.beginPath();\r\n        for (var j = 0; j < run.length; j++) {\r\n          if (j === 0) ctx.moveTo(run[j][0], run[j][1]);\r\n          else ctx.lineTo(run[j][0], run[j][1]);\r\n        }\r\n        for (var k = run.length - 1; k >= 0; k--) {\r\n          ctx.lineTo(run[k][0], Y(profK(run[k][3], 0)));\r\n        }\r\n        ctx.closePath();\r\n      };\r\n\r\n      var idx = 0;\r\n      while (idx < pts.length) {\r\n        var d = pts[idx][2];\r\n        if (Math.abs(d) <= 0.3) { idx++; continue; }\r\n        var isFill = d > 0, run = [];\r\n        while (idx < pts.length && ((pts[idx][2] > 0) === isFill) && Math.abs(pts[idx][2]) > 0.3) {\r\n          run.push(pts[idx]);\r\n          idx++;\r\n        }\r\n        if (run.length > 1) {\r\n          poly(run);\r\n          var changeRatio = Math.min(1, t \/ 0.85);\r\n          ctx.fillStyle = isFill\r\n            ? 'rgba(255, 174, 26, ' + (0.22 * changeRatio) + ')'\r\n            : 'rgba(127, 178, 200, ' + (0.20 * changeRatio) + ')';\r\n          ctx.fill();\r\n\r\n          ctx.strokeStyle = isFill\r\n            ? 'rgba(255, 174, 26, ' + (0.6 * changeRatio) + ')'\r\n            : 'rgba(127, 178, 200, ' + (0.6 * changeRatio) + ')';\r\n          ctx.lineWidth = 1.2;\r\n          ctx.stroke();\r\n        }\r\n      }\r\n\r\n      \/\/ Minimal Zone Labels (Off-Black #111111 Pill)\r\n      if (t > 0.25) {\r\n        var fillPeakY = Y(profT(SX, t));\r\n        var badgeFillY = Math.max(M.t + 14, fillPeakY - 14);\r\n        drawPill(ctx, '\u25b2 FILL', X(SX), badgeFillY, '#FFAE1A', '#111111', 'rgba(255, 174, 26, 0.5)', (isShort || isMobile) ? '8px \"IBM Plex Mono\", monospace' : '9px \"IBM Plex Mono\", monospace');\r\n\r\n        var cutPitY = Y(profT(PX, t));\r\n        var badgeCutY = Math.min(H - M.b - 14, cutPitY + 16);\r\n        drawPill(ctx, '\u25bc CUT', X(PX), badgeCutY, '#7FB2C8', '#111111', 'rgba(127, 178, 200, 0.5)', (isShort || isMobile) ? '8px \"IBM Plex Mono\", monospace' : '9px \"IBM Plex Mono\", monospace');\r\n      }\r\n    }\r\n\r\n    \/* 6. Baseline Reference Curve *\/\r\n    if (isBaselineOnly) {\r\n      ctx.strokeStyle = '#FFAE1A';\r\n      ctx.lineWidth = 2.2;\r\n      ctx.beginPath();\r\n      for (var bIdx = 0; bIdx <= N; bIdx++) {\r\n        var bX = bIdx * dx, bY = Y(profK(bX, 0));\r\n        if (bIdx === 0) ctx.moveTo(X(bX), bY);\r\n        else ctx.lineTo(X(bX), bY);\r\n      }\r\n      ctx.stroke();\r\n    } else {\r\n      ctx.setLineDash([4, 4]);\r\n      ctx.strokeStyle = 'rgba(255, 255, 255, 0.35)';\r\n      ctx.lineWidth = 1.2;\r\n      ctx.beginPath();\r\n      for (var gIdx = 0; gIdx <= N; gIdx++) {\r\n        var gX = gIdx * dx, gY = Y(profK(gX, 0));\r\n        if (gIdx === 0) ctx.moveTo(X(gX), gY);\r\n        else ctx.lineTo(X(gX), gY);\r\n      }\r\n      ctx.stroke();\r\n      ctx.setLineDash([]);\r\n\r\n      \/* 7. Active Survey Surface Line *\/\r\n      ctx.strokeStyle = '#FFAE1A';\r\n      ctx.lineWidth = 2.2;\r\n      ctx.beginPath();\r\n      for (var sIdx = 0; sIdx < pts.length; sIdx++) {\r\n        if (sIdx === 0) ctx.moveTo(pts[sIdx][0], pts[sIdx][1]);\r\n        else ctx.lineTo(pts[sIdx][0], pts[sIdx][1]);\r\n      }\r\n      ctx.stroke();\r\n    }\r\n\r\n    \/* 8. GCP Control Markers *\/\r\n    var gcps = [\r\n      [14, 'GCP 1'],\r\n      [58, 'GCP 2'],\r\n      [104, 'GCP 3']\r\n    ];\r\n\r\n    for (var g = 0; g < gcps.length; g++) {\r\n      var gx = gcps[g][0], label = gcps[g][1];\r\n      var gy = Y(profK(gx, 0));\r\n\r\n      ctx.fillStyle = 'rgba(236, 238, 234, 0.8)';\r\n      ctx.beginPath();\r\n      ctx.moveTo(X(gx) - 3.5, gy);\r\n      ctx.lineTo(X(gx) + 3.5, gy);\r\n      ctx.lineTo(X(gx), gy - 6);\r\n      ctx.closePath();\r\n      ctx.fill();\r\n\r\n      ctx.fillStyle = 'rgba(166, 174, 180, 0.75)';\r\n      ctx.font = (isShort ? '7.5px' : '8px') + ' \"IBM Plex Mono\", monospace';\r\n      ctx.textAlign = 'center';\r\n      ctx.fillText(label, X(gx), gy + 12);\r\n    }\r\n\r\n    \/* 9. Interactive Vertical Scrub Indicator *\/\r\n    var sx = X((t \/ 3) * DOMAIN);\r\n    ctx.setLineDash([3, 4]);\r\n    ctx.strokeStyle = 'rgba(255, 174, 26, 0.4)';\r\n    ctx.lineWidth = 1;\r\n    ctx.beginPath();\r\n    ctx.moveTo(sx, M.t);\r\n    ctx.lineTo(sx, H - M.b);\r\n    ctx.stroke();\r\n    ctx.setLineDash([]);\r\n\r\n    \/\/ Diamond handle\r\n    ctx.fillStyle = '#FFAE1A';\r\n    ctx.save();\r\n    ctx.translate(sx, M.t + 4);\r\n    ctx.rotate(Math.PI \/ 4);\r\n    ctx.fillRect(-3, -3, 6, 6);\r\n    ctx.restore();\r\n\r\n    \/\/ Date tag badge in top margin (Off-Black #111111)\r\n    var tagText = isMobile ? EPOCHS[activeEpochIdx].d : (EPOCHS[activeEpochIdx].d + ' \u00b7 ' + EPOCHS[activeEpochIdx].days);\r\n    var clampedSx = clamp(sx, M.l + (isMobile ? 38 : 55), W - M.r - (isMobile ? 38 : 55));\r\n    drawPill(ctx, tagText, clampedSx, M.t - 14, '#FFAE1A', '#111111', 'rgba(255, 174, 26, 0.7)', (isShort || isMobile) ? '8px \"IBM Plex Mono\", monospace' : '9px \"IBM Plex Mono\", monospace');\r\n  }\r\n\r\n  \/\/ Responsive Canvas Sizing (Instantly updates when --canvas-height is edited)\r\n  function resize() {\r\n    var dpr = Math.min(window.devicePixelRatio || 1, 2);\r\n    W = cv.clientWidth || root.clientWidth || 320;\r\n    H = cv.clientHeight || 380;\r\n    cv.width = W * dpr;\r\n    cv.height = H * dpr;\r\n    ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\r\n    draw();\r\n  }\r\n\r\n  if (window.ResizeObserver) {\r\n    new ResizeObserver(resize).observe(cv);\r\n  }\r\n  window.addEventListener('resize', resize, { passive: true });\r\n  setTimeout(resize, 60);\r\n\r\n  \/* =====================================================\r\n     AUTOMATED CHOREOGRAPHED TOUR\r\n  ===================================================== *\/\r\n  var lastTime = performance.now();\r\n\r\n  function tourTick(now) {\r\n    var dt = Math.min((now - lastTime) \/ 1000, 0.08);\r\n    lastTime = now;\r\n\r\n    if (isAutoPlaying && !isDragging) {\r\n      tourTimeline = (tourTimeline + dt) % TOUR_TOTAL;\r\n      var elapsed = tourTimeline;\r\n\r\n      if (elapsed < DWELL_E01) {\r\n        t = 0.0;\r\n      } else if (elapsed < DWELL_E01 + SHIFT_12) {\r\n        var p1 = (elapsed - DWELL_E01) \/ SHIFT_12;\r\n        t = lerp(0.0, 1.0, p1 * p1 * (3 - 2 * p1));\r\n      } else if (elapsed < DWELL_E01 + SHIFT_12 + DWELL_E02) {\r\n        t = 1.0;\r\n      } else if (elapsed < DWELL_E01 + SHIFT_12 + DWELL_E02 + SHIFT_23) {\r\n        var p2 = (elapsed - (DWELL_E01 + SHIFT_12 + DWELL_E02)) \/ SHIFT_23;\r\n        t = lerp(1.0, 2.0, p2 * p2 * (3 - 2 * p2));\r\n      } else if (elapsed < DWELL_E01 + SHIFT_12 + DWELL_E02 + SHIFT_23 + DWELL_E03) {\r\n        t = 2.0;\r\n      } else if (elapsed < DWELL_E01 + SHIFT_12 + DWELL_E02 + SHIFT_23 + DWELL_E03 + SHIFT_34) {\r\n        var p3 = (elapsed - (DWELL_E01 + SHIFT_12 + DWELL_E02 + SHIFT_23 + DWELL_E03)) \/ SHIFT_34;\r\n        t = lerp(2.0, 3.0, p3 * p3 * (3 - 2 * p3));\r\n      } else if (elapsed < DWELL_E01 + SHIFT_12 + DWELL_E02 + SHIFT_23 + DWELL_E03 + SHIFT_34 + DWELL_E04) {\r\n        t = 3.0;\r\n      } else {\r\n        var p4 = (elapsed - (TOUR_TOTAL - RESET_01)) \/ RESET_01;\r\n        t = lerp(3.0, 0.0, p4 * p4 * (3 - 2 * p4));\r\n      }\r\n\r\n      draw();\r\n    }\r\n\r\n    animId = requestAnimationFrame(tourTick);\r\n  }\r\n  animId = requestAnimationFrame(tourTick);\r\n\r\n  \/* =====================================================\r\n     USER INTERACTION: SCRUBBING & BUTTONS\r\n  ===================================================== *\/\r\n  function pauseTour() {\r\n    isAutoPlaying = false;\r\n    DOM.playBtn.classList.add('is-paused');\r\n    DOM.icoPlay.style.setProperty('display', 'block', 'important');\r\n    DOM.icoPause.style.setProperty('display', 'none', 'important');\r\n  }\r\n\r\n  function resumeTour() {\r\n    isAutoPlaying = true;\r\n    DOM.playBtn.classList.remove('is-paused');\r\n    DOM.icoPlay.style.setProperty('display', 'none', 'important');\r\n    DOM.icoPause.style.setProperty('display', 'block', 'important');\r\n    lastTime = performance.now();\r\n  }\r\n\r\n  var scrub = function(e) {\r\n    var isMobile = W < 540;\r\n    var isShort = H < 280;\r\n    var leftMargin = isMobile ? 36 : (isShort ? 44 : 50);\r\n    var rightMargin = isMobile ? 14 : (isShort ? 16 : 20);\r\n    var r = cv.getBoundingClientRect();\r\n    t = clamp(((e.clientX - r.left) - leftMargin) \/ (r.width - leftMargin - rightMargin), 0, 1) * 3;\r\n    draw();\r\n  };\r\n\r\n  cv.addEventListener('pointerdown', function(e) {\r\n    isDragging = true;\r\n    pauseTour();\r\n    if (cv.setPointerCapture) cv.setPointerCapture(e.pointerId);\r\n    scrub(e);\r\n  });\r\n  cv.addEventListener('pointermove', function(e) { if (isDragging) scrub(e); });\r\n  cv.addEventListener('pointerup', function() { isDragging = false; });\r\n\r\n  function jumpToEpoch(k) {\r\n    pauseTour();\r\n    var from = t, start = performance.now(), dur = 550;\r\n    function step(now) {\r\n      var p = clamp((now - start) \/ dur, 0, 1);\r\n      t = lerp(from, k, 1 - Math.pow(1 - p, 3));\r\n      draw();\r\n      if (p < 1) requestAnimationFrame(step);\r\n    }\r\n    requestAnimationFrame(step);\r\n  }\r\n\r\n  var epochBtns = root.querySelectorAll('.sv-btn');\r\n  epochBtns.forEach(function(btn) {\r\n    btn.addEventListener('click', function() {\r\n      jumpToEpoch(parseInt(btn.getAttribute('data-k'), 10));\r\n    });\r\n  });\r\n\r\n  DOM.playBtn.addEventListener('click', function() {\r\n    if (isAutoPlaying) pauseTour();\r\n    else resumeTour();\r\n  });\r\n\r\n})();\r\n<\/script>\r\n\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b99c290 e-con-full e-flex e-con e-child\" data-id=\"b99c290\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-f37eeb2 e-grid e-con-full e-con e-child\" data-id=\"f37eeb2\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-b16b965 e-con-full e-flex e-con e-child\" data-id=\"b16b965\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-522f312 elementor-widget__width-auto elementor-widget elementor-widget-heading\" data-id=\"522f312\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">01<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9b87e44 elementor-widget elementor-widget-icon-box\" data-id=\"9b87e44\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tRepeat surveys\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tThe same site can be captured at fixed intervals, creating a consistent record of construction progress, terrain change, stockpile movement, or asset condition.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d7c08c2 e-con-full e-flex e-con e-child\" data-id=\"d7c08c2\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9adaf8d elementor-widget__width-auto elementor-widget elementor-widget-heading\" data-id=\"9adaf8d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">02<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7184b9f elementor-widget elementor-widget-icon-box\" data-id=\"7184b9f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tGeoreferenced mapping\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tEvery image and derived dataset is tied to its geographic position, allowing measurements and findings to be located precisely.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-7f2a070 e-con-full e-flex e-con e-child\" data-id=\"7f2a070\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-11b3064 elementor-widget__width-auto elementor-widget elementor-widget-heading\" data-id=\"11b3064\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">03<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-12e8f69 elementor-widget elementor-widget-icon-box\" data-id=\"12e8f69\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\t2D and 3D data\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tOne capture produces multiple outputs, from orthomosaics and elevation models to point clouds and 3D models.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-b82dbb1 e-con-full e-flex e-con e-child\" data-id=\"b82dbb1\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-29a98b5 elementor-widget__width-auto elementor-widget elementor-widget-heading\" data-id=\"29a98b5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">04<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4be7259 elementor-widget elementor-widget-icon-box\" data-id=\"4be7259\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tVolumetric measurements\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tSurface models allow stockpile and material volumes to be calculated, and changes between surveys are to be tracked.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-cde6c1d e-con-full e-flex e-con e-child\" data-id=\"cde6c1d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;gradient&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3ab1ec4 elementor-widget__width-auto elementor-widget elementor-widget-heading\" data-id=\"3ab1ec4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">05<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-91c2765 elementor-widget elementor-widget-icon-box\" data-id=\"91c2765\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tChange detection\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tRepeat datasets can be compared to identifying where terrain, structures, or site conditions have changed.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-a16b83d e-flex e-con-boxed e-con e-parent\" data-id=\"a16b83d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-5d6ae31 elementor-widget elementor-widget-heading\" data-id=\"5d6ae31\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Why <span style=\"color: #FFB601\"> Volatus\n<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ca54d42 elementor-hidden-desktop elementor-hidden-tablet elementor-hidden-mobile elementor-widget elementor-widget-html\" data-id=\"ca54d42\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<style>\r\n\/* Expanded to fill the ENTIRE container *\/\r\n.vts-gravity-module {\r\n  position: absolute;\r\n  top: 0; \r\n  left: 0; \r\n  width: 100%; \r\n  height: 100%; \/* Changed from 50% *\/\r\n  min-height: 250px; \r\n  z-index: 0; \r\n  pointer-events: none; \r\n  background: transparent; \r\n  overflow: hidden; \r\n  font-family: 'Courier New', monospace; \r\n  user-select: none;\r\n}\r\n\r\n.vts-gravity-module canvas {\r\n  width: 100% !important; height: 100% !important; display: block;\r\n}\r\n<\/style>\r\n\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/three.js\/r128\/three.min.js\"><\/script>\r\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/simplex-noise\/2.4.0\/simplex-noise.min.js\"><\/script>\r\n\r\n<div class=\"vts-gravity-module\"><\/div>\r\n\r\n<script>\r\n\/\/ ==========================================\r\n\/\/ EASY CUSTOMIZATION OPTIONS\r\n\/\/ ==========================================\r\nconst VTS_CONFIG = {\r\n  particleColor: 0xFFB601, \/\/ Lighter yellow (Hex format: 0xRRGGBB)\r\n  particleOpacity: 0.3,    \/\/ Lowered opacity (0.0 is invisible, 1.0 is solid)\r\n  particleSize: 3,         \/\/ Size of the individual dots\r\n  particleCount: 2000,     \/\/ Total number of dots in the scene\r\n  flowSpeed: 0.4,          \/\/ How fast the particles flow horizontally\r\n  waveSpeed: 0.002         \/\/ How fast the 3D waves ripple\r\n};\r\n\r\n(function(){\r\n  let bootAttempts = 0;\r\n  \r\n  function bootAllModules(){\r\n    if(bootAttempts > 50) return;\r\n    bootAttempts++;\r\n\r\n    \/\/ Wait for libraries\r\n    if(!window.THREE || !window.SimplexNoise) {\r\n        setTimeout(bootAllModules, 100);\r\n        return;\r\n    }\r\n\r\n    \/\/ Find ALL wrappers on the page that haven't been initialized yet\r\n    const wrappers = document.querySelectorAll('.vts-gravity-module:not(.vts-active)');\r\n    \r\n    wrappers.forEach(wrapper => {\r\n        wrapper.classList.add('vts-active');\r\n\r\n        \/\/ ==========================================\r\n        \/\/ ELEMENTOR DOM RELOCATION FIX \r\n        \/\/ ==========================================\r\n        const parentContainer = wrapper.closest('.e-con, .e-container, .elementor-section');\r\n        if(parentContainer && wrapper.parentElement !== parentContainer) {\r\n            parentContainer.style.position = 'relative';\r\n            parentContainer.style.overflow = 'hidden';\r\n            parentContainer.insertBefore(wrapper, parentContainer.firstChild); \r\n        }\r\n\r\n        let W = wrapper.clientWidth;\r\n        let H = wrapper.clientHeight;\r\n        if (H < 100) H = 250;\r\n\r\n        \/\/ ==========================================\r\n        \/\/ ISOLATED 3D SCENE SETUP\r\n        \/\/ ==========================================\r\n        const scene = new THREE.Scene(); \r\n        const camera = new THREE.PerspectiveCamera(45, W\/H, 1, 2000); \r\n        \r\n        \/\/ Leveled the camera\r\n        camera.position.set(0, 10, 200); \r\n        camera.lookAt(0, 0, 0); \/\/ Adjusted lookAt to center\r\n\r\n        const renderer = new THREE.WebGLRenderer({alpha: true, antialias: true}); \r\n        renderer.setSize(W, H); \r\n        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));\r\n        wrapper.appendChild(renderer.domElement);\r\n        \r\n        \/\/ ==========================================\r\n        \/\/ PARTICLE SYSTEM\r\n        \/\/ ==========================================\r\n        const particleCount = VTS_CONFIG.particleCount;\r\n        const geo = new THREE.BufferGeometry();\r\n        const posArray = new Float32Array(particleCount * 3);\r\n        const initialY = new Float32Array(particleCount);\r\n\r\n        for(let i = 0; i < particleCount; i++) {\r\n            posArray[i * 3] = (Math.random() - 0.5) * 1400; \/\/ X spread    \r\n            \/\/ Spreads particles fully across the vertical space\r\n            posArray[i * 3 + 1] = (Math.random() - 0.5) * 600;   \r\n            posArray[i * 3 + 2] = (Math.random() - 0.5) * 800; \/\/ Z spread \r\n            initialY[i] = posArray[i * 3 + 1];\r\n        }\r\n        \r\n        geo.setAttribute('position', new THREE.BufferAttribute(posArray, 3));\r\n\r\n        const canvas = document.createElement('canvas');\r\n        canvas.width = 16; canvas.height = 16;\r\n        const context = canvas.getContext('2d');\r\n        context.beginPath(); context.arc(8, 8, 8, 0, 2 * Math.PI);\r\n        context.fillStyle = '#ffffff'; context.fill();\r\n        const circleTexture = new THREE.CanvasTexture(canvas);\r\n\r\n        const mat = new THREE.PointsMaterial({ \r\n            color: VTS_CONFIG.particleColor, \r\n            size: VTS_CONFIG.particleSize, \r\n            map: circleTexture, \r\n            transparent: true, \r\n            opacity: VTS_CONFIG.particleOpacity, \r\n            alphaTest: 0.1, \r\n            sizeAttenuation: true \r\n        });\r\n        \r\n        const particles = new THREE.Points(geo, mat); \r\n        scene.add(particles);\r\n\r\n        const simplex = new SimplexNoise();\r\n        let localTime = Math.random() * 100; \r\n        \r\n        \/\/ ==========================================\r\n        \/\/ LOCAL ANIMATION LOOP\r\n        \/\/ ==========================================\r\n        function animateGrav() {\r\n            requestAnimationFrame(animateGrav);\r\n            localTime += VTS_CONFIG.waveSpeed; \r\n\r\n            const pos = geo.attributes.position.array;\r\n            \r\n            for(let i = 0; i < particleCount; i++) {\r\n                let index = i * 3;\r\n                pos[index] -= VTS_CONFIG.flowSpeed; \r\n                \r\n                if (pos[index] < -700) { pos[index] = 700; }\r\n\r\n                const x = pos[index], z = pos[index + 2];\r\n                const noiseVal = simplex.noise3D(x * 0.004, z * 0.004, localTime) * 25;\r\n                const dist = Math.sqrt(x*x + z*z);\r\n                const well = dist < 150 ? -30 * Math.cos(dist*Math.PI\/300) : 0;\r\n                \r\n                const slope = x * 0.06; \r\n                \r\n                pos[index + 1] = initialY[i] + noiseVal + well + slope;\r\n            }\r\n            \r\n            geo.attributes.position.needsUpdate = true;\r\n            renderer.render(scene, camera);\r\n        }\r\n        \r\n        animateGrav();\r\n\r\n        \/\/ ==========================================\r\n        \/\/ ISOLATED RESIZE OBSERVER\r\n        \/\/ ==========================================\r\n        let resizeTimer;\r\n        if(window.ResizeObserver) {\r\n            new ResizeObserver(()=>{\r\n              clearTimeout(resizeTimer);\r\n              resizeTimer = setTimeout(() => {\r\n                  if(!wrapper) return;\r\n                  const newW = wrapper.clientWidth;\r\n                  let newH = wrapper.clientHeight;\r\n                  if (newH < 100) newH = 250;\r\n                  \r\n                  if(newW > 0 && newH > 0 && (newW !== W || newH !== H)){\r\n                      W = newW; H = newH;\r\n                      renderer.setSize(W, H);\r\n                      camera.aspect = W \/ H;\r\n                      camera.updateProjectionMatrix();\r\n                  }\r\n              }, 200);\r\n            }).observe(parentContainer || wrapper);\r\n        }\r\n    });\r\n  }\r\n  \r\n  if(document.readyState==='complete'){ bootAllModules(); } \r\n  else { window.addEventListener('load', bootAllModules); }\r\n  document.addEventListener('DOMContentLoaded', bootAllModules);\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-39a7e7a e-con-full e-flex e-con e-child\" data-id=\"39a7e7a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-dd5db26 e-con-full e-flex e-con e-child\" data-id=\"dd5db26\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-8bc67b9 e-con-full glass-card  e-flex e-con e-child\" data-id=\"8bc67b9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-56e9844 elementor-widget elementor-widget-heading\" data-id=\"56e9844\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">01<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0ed999e elementor-widget elementor-widget-icon-box\" data-id=\"0ed999e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tIntegrated lidar capability\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tVolatus drones are equipped with lidar can be added to provide dense three-dimensional data where vegetation, terrain or structural complexity limits photogrammetry.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d2e0c7d e-con-full e-flex e-con e-child\" data-id=\"d2e0c7d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-b74524a e-con-full glass-card  e-flex e-con e-child\" data-id=\"b74524a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-899ff7e elementor-widget elementor-widget-heading\" data-id=\"899ff7e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">02<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7d12efe elementor-widget elementor-widget-icon-box\" data-id=\"7d12efe\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tProfessional processing\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tVolatus supports photogrammetry workflows using platforms including Pix4D and DJI Terra for processing imagery into maps, point clouds and 3D models.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-082f613 e-con-full glass-card  e-flex e-con e-child\" data-id=\"082f613\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-7c4f4df elementor-widget elementor-widget-heading\" data-id=\"7c4f4df\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">03<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cf6a1d9 elementor-widget elementor-widget-icon-box\" data-id=\"cf6a1d9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tAerial and terrestrial capability\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tVolatus combines aerial acquisition with terrestrial geomatics capabilities, allowing the survey method to match the site and required deliverable.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-56f221a e-con-full e-flex e-con e-child\" data-id=\"56f221a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-4ef8762 e-con-full glass-card  e-flex e-con e-child\" data-id=\"4ef8762\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1f464ba elementor-widget elementor-widget-heading\" data-id=\"1f464ba\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">04<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7810d29 elementor-widget elementor-widget-icon-box\" data-id=\"7810d29\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tExtended coverage capability\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tFor projects that call for operations beyond standard visual-line-of-sight limits, Volatus has the regulatory experience and operational planning to scope and execute accordingly.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-70f102a e-con-full glass-card  e-flex e-con e-child\" data-id=\"70f102a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-8bac450 elementor-widget elementor-widget-heading\" data-id=\"8bac450\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">05<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-70fad29 elementor-widget elementor-widget-icon-box\" data-id=\"70fad29\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tRTK and PPK positioning\t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\t High-accuracy positioning supports georeferenced aerial data and repeatable mapping workflows.\t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-6d1283b e-flex e-con-boxed e-con e-parent\" data-id=\"6d1283b\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-dbbc721 e-con-full e-flex e-con e-child\" data-id=\"dbbc721\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-46592e0 e-con-full e-flex e-con e-child\" data-id=\"46592e0\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;sticky&quot;:&quot;top&quot;,&quot;sticky_on&quot;:[&quot;desktop&quot;,&quot;laptop&quot;],&quot;sticky_offset&quot;:90,&quot;sticky_parent&quot;:&quot;yes&quot;,&quot;sticky_effects_offset&quot;:0,&quot;sticky_anchor_link_offset&quot;:0}\">\n\t\t<div class=\"elementor-element elementor-element-5a350b8 e-con-full e-flex e-con e-child\" data-id=\"5a350b8\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t<div class=\"elementor-element elementor-element-129bcb6 elementor-widget elementor-widget-icon-box\" data-id=\"129bcb6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon-box.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-box-wrapper\">\n\n\t\t\t\n\t\t\t\t\t\t<div class=\"elementor-icon-box-content\">\n\n\t\t\t\t\t\t\t\t\t<h3 class=\"elementor-icon-box-title\">\n\t\t\t\t\t\t<span  >\n\t\t\t\t\t\t\tDiscuss your <span style=\"color: #FFB601\">program  \t\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/h3>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<p class=\"elementor-icon-box-description\">\n\t\t\t\t\t\tTell us the site, the scale, and what mapping data already exists. We will recommend the right photogrammetry approach, including the aircraft, sensors, positioning and deliverables required, and say so if photogrammetry is not the right fit. \t\t\t\t\t<\/p>\n\t\t\t\t\n\t\t\t<\/div>\n\t\t\t\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-796daa8 elementor-widget elementor-widget-button\" data-id=\"796daa8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"button.default\">\n\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-button elementor-button-link elementor-size-sm\" href=\"https:\/\/volatusaerospace.com\/contact-us\/\">\n\t\t\t\t\t\t<span class=\"elementor-button-content-wrapper\">\n\t\t\t\t\t\t\t\t\t<span class=\"elementor-button-text\">Contact a specialist<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-9ec60b6 e-con-full e-flex e-con e-child\" data-id=\"9ec60b6\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e77695d elementor-widget elementor-widget-heading\" data-id=\"e77695d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Frequently Asked <span style=\"color: #FFB601\">Questions<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-de8624d va-faq elementor-widget elementor-widget-n-accordion\" data-id=\"de8624d\" data-element_type=\"widget\" data-e-type=\"widget\" data-settings=\"{&quot;default_state&quot;:&quot;expanded&quot;,&quot;max_items_expended&quot;:&quot;one&quot;,&quot;n_accordion_animation_duration&quot;:{&quot;unit&quot;:&quot;ms&quot;,&quot;size&quot;:400,&quot;sizes&quot;:[]}}\" data-widget_type=\"nested-accordion.default\">\n\t\t\t\t\t\t\t<div class=\"e-n-accordion\" aria-label=\"Accordion. Open links with Enter or Space, close with Escape, and navigate with Arrow Keys\">\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2330\" class=\"e-n-accordion-item\" open>\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"1\" tabindex=\"0\" aria-expanded=\"true\" aria-controls=\"e-n-accordion-item-2330\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">01<\/span>What is photogrammetry?   <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2330\" class=\"elementor-element elementor-element-e6d8be2 e-con-full e-flex e-con e-child\" data-id=\"e6d8be2\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2330\" class=\"elementor-element elementor-element-5d96dc4 e-flex e-con-boxed e-con e-child\" data-id=\"5d96dc4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6635bd8 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"6635bd8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tPhotogrammetry uses overlapping photographs to create maps, measurements, and 3D models. Drone photogrammetry captures those images from the air, allowing large sites and difficult-to-access areas to be mapped efficiently. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2331\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"2\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2331\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">02<\/span>How does drone photogrammetry work?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2331\" class=\"elementor-element elementor-element-e7ce6ef e-con-full e-flex e-con e-child\" data-id=\"e7ce6ef\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2331\" class=\"elementor-element elementor-element-c0964c9 e-flex e-con-boxed e-con e-child\" data-id=\"c0964c9\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-da6ac2e elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"da6ac2e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tThe drone captures overlapping images along a planned flight path. Photogrammetry software identifies common points between images and reconstructs the surveyed area in three dimensions. The resulting data can be processed into orthomosaics, point clouds, surface models, and 3D models. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2332\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"3\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2332\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">03<\/span>What does photogrammetry produce?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2332\" class=\"elementor-element elementor-element-d2a93ff e-con-full e-flex e-con e-child\" data-id=\"d2a93ff\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2332\" class=\"elementor-element elementor-element-8d6eb7c e-flex e-con-boxed e-con e-child\" data-id=\"8d6eb7c\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-b712c9b elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"b712c9b\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tDepending on the project, outputs include orthomosaics, photogrammetric point clouds, digital surface models, 2D maps, 3D models, and volumetric calculations. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2333\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"4\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2333\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">04<\/span>How accurate is drone photogrammetry?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2333\" class=\"elementor-element elementor-element-0e01593 e-con-full e-flex e-con e-child\" data-id=\"0e01593\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2333\" class=\"elementor-element elementor-element-73379aa e-flex e-con-boxed e-con e-child\" data-id=\"73379aa\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c372b49 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"c372b49\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tAccuracy depends on the aircraft, camera, positioning system, ground control, flight planning, and processing workflow. Volatus uses RTK and PPK positioning as part of its high-accuracy mapping workflows. Survey methodology is selected around project requirements rather than applying one accuracy figure to every survey. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2334\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"5\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2334\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">05<\/span>What are RTK and PPK?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2334\" class=\"elementor-element elementor-element-a3b0351 e-con-full e-flex e-con e-child\" data-id=\"a3b0351\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2334\" class=\"elementor-element elementor-element-70ae2ef e-flex e-con-boxed e-con e-child\" data-id=\"70ae2ef\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1d1e36d elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"1d1e36d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tRTK and PPK are positioning technologies used to improve the geographic accuracy of drone data. They allow aerial imagery to be accurately positioned during or after the flight, reducing reliance on extensive ground control depending on project requirements. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2335\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"6\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2335\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">06<\/span>Does photogrammetry require ground control points?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2335\" class=\"elementor-element elementor-element-250c690 e-con-full e-flex e-con e-child\" data-id=\"250c690\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2335\" class=\"elementor-element elementor-element-e0eb03f e-flex e-con-boxed e-con e-child\" data-id=\"e0eb03f\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-357c187 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"357c187\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tNot always. RTK\/PPK positioning can provide accurate georeferencing, while ground control points can be added when additional survey control is required. The appropriate approach depends on the required accuracy and site conditions. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2336\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"7\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2336\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">07<\/span>What is an orthomosaic?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2336\" class=\"elementor-element elementor-element-5a2ebcf e-con-full e-flex e-con e-child\" data-id=\"5a2ebcf\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2336\" class=\"elementor-element elementor-element-dc044b7 e-flex e-con-boxed e-con e-child\" data-id=\"dc044b7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f6f69a6 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"f6f69a6\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tAn orthomosaic is a single map created by combining multiple aerial photographs and correcting them for perspective and terrain. Unlike a conventional aerial photograph, it can be used as a measurable geographic reference. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2337\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"8\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2337\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">08<\/span>Can photogrammetry create 3D models?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2337\" class=\"elementor-element elementor-element-538c981 e-con-full e-flex e-con e-child\" data-id=\"538c981\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2337\" class=\"elementor-element elementor-element-8d12174 e-flex e-con-boxed e-con e-child\" data-id=\"8d12174\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-471b780 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"471b780\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tYes. Overlapping aerial images can be processed into three-dimensional point clouds and models. These models provide a digital representation of terrain, structures, and project sites. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2338\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"9\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2338\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">09<\/span>Can photogrammetry calculate stockpile volumes?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2338\" class=\"elementor-element elementor-element-5596069 e-con-full e-flex e-con e-child\" data-id=\"5596069\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2338\" class=\"elementor-element elementor-element-f5ed1fa e-flex e-con-boxed e-con e-child\" data-id=\"f5ed1fa\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-4d34655 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"4d34655\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tYes. Photogrammetric surface models can be used to calculate stockpile and material volumes. Repeat surveys can also show how those volumes change over time. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-2339\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"10\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-2339\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">10<\/span>Can photogrammetry be used for construction progress?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2339\" class=\"elementor-element elementor-element-9f12f9f e-con-full e-flex e-con e-child\" data-id=\"9f12f9f\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-2339\" class=\"elementor-element elementor-element-e28b4f3 e-flex e-con-boxed e-con e-child\" data-id=\"e28b4f3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-45ed114 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"45ed114\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tYes. Repeat drone surveys create comparable maps and models of a construction site. They can document progress, compare conditions, and maintain a visual record throughout the project. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-23310\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"11\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-23310\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">11<\/span>What is the difference between photogrammetry and LiDAR?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-23310\" class=\"elementor-element elementor-element-beeb9ad e-con-full e-flex e-con e-child\" data-id=\"beeb9ad\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-23310\" class=\"elementor-element elementor-element-d62b4ee e-flex e-con-boxed e-con e-child\" data-id=\"d62b4ee\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0123baa elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"0123baa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tPhotogrammetry builds 2D and 3D information from imagery. LiDAR uses laser measurements to create dense three-dimensional point clouds. Photogrammetry is effective for visual mapping and modelling; LiDAR provides additional terrain and structural information, particularly where vegetation or complex surfaces make image-based mapping less effective. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t\t<details id=\"e-n-accordion-item-23311\" class=\"e-n-accordion-item\" >\n\t\t\t\t<summary class=\"e-n-accordion-item-title\" data-accordion-index=\"12\" tabindex=\"-1\" aria-expanded=\"false\" aria-controls=\"e-n-accordion-item-23311\" >\n\t\t\t\t\t<span class='e-n-accordion-item-title-header'><div class=\"e-n-accordion-item-title-text\"> <span class=\"faq-no\">12<\/span>Can photogrammetry and LiDAR be captured together?  <\/div><\/span>\n\t\t\t\t\t\t\t<span class='e-n-accordion-item-title-icon'>\n\t\t\t<span class='e-opened' ><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-minus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h384c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t\t<span class='e-closed'><svg aria-hidden=\"true\" class=\"e-font-icon-svg e-fas-plus\" viewBox=\"0 0 448 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M416 208H272V64c0-17.67-14.33-32-32-32h-32c-17.67 0-32 14.33-32 32v144H32c-17.67 0-32 14.33-32 32v32c0 17.67 14.33 32 32 32h144v144c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32V304h144c17.67 0 32-14.33 32-32v-32c0-17.67-14.33-32-32-32z\"><\/path><\/svg><\/span>\n\t\t<\/span>\n\n\t\t\t\t\t\t<\/summary>\n\t\t\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-23311\" class=\"elementor-element elementor-element-8eb7f3d e-con-full e-flex e-con e-child\" data-id=\"8eb7f3d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t<div role=\"region\" aria-labelledby=\"e-n-accordion-item-23311\" class=\"elementor-element elementor-element-4cd38fa e-flex e-con-boxed e-con e-child\" data-id=\"4cd38fa\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-569d0e8 elementor-widget-mobile__width-inherit elementor-widget elementor-widget-text-editor\" data-id=\"569d0e8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\tYes. Volatus can combine RGB photogrammetry and LiDAR when a project requires both visual imagery and detailed three-dimensional data. This provides a more complete dataset from the same aerial operation. \t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/details>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Transformez l'imagerie a\u00e9rienne en donn\u00e9es spatiales pr\u00e9cises. Orthomosa\u00efques haute r\u00e9solution, nuages de points, mod\u00e8les num\u00e9riques de surface et cartographie de terrain 3D pour l'arpentage.<\/p>","protected":false},"author":3,"featured_media":0,"parent":36391,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"class_list":["post-36955","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/pages\/36955","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/comments?post=36955"}],"version-history":[{"count":182,"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/pages\/36955\/revisions"}],"predecessor-version":[{"id":37489,"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/pages\/36955\/revisions\/37489"}],"up":[{"embeddable":true,"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/pages\/36391"}],"wp:attachment":[{"href":"https:\/\/volatusaerospace.com\/fr-ca\/wp-json\/wp\/v2\/media?parent=36955"}],"curies":[{"name":"Bien jou\u00e9","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}