3 lines
15 KiB
JavaScript
3 lines
15 KiB
JavaScript
import{m as $,i as V,p as X}from"./index-BkFzql5p.js";import"./vendor-react-7jnMmQ9s.js";import"./vendor-ui-CtsphK4U.js";import"./vendor-icons-FFp724MI.js";import"./vendor-three-SYzIooV9.js";const S=Object.freeze([1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]),w="__model__",y="world",T="__sdf_model__";function E(e){return String(e?.localName||e?.tagName||"").split(":").pop()}function I(e){return Array.from(e?.childNodes||[]).filter(t=>t?.nodeType===1)}function g(e,t){return I(e).filter(r=>E(r)===t)}function b(e,t,r=[]){for(const n of I(e))E(n)===t&&r.push(n),b(n,t,r);return r}function F(e,t){return String(g(e,t)[0]?.textContent||"").trim()}function Y(e){return String(e?.getAttribute("name")||"").trim()}function H(e){return String(e?.getAttribute("filename")||"").trim()}function j(e,t,r,n){const o=String(e||"").trim();if(!o)return[...r];const i=o.split(/\s+/).map(l=>Number(l));if(i.length!==t||i.some(l=>!Number.isFinite(l)))throw new Error(`${n} must contain ${t} numeric values`);return i}function Z(e,t,r){return[e,0,0,0,0,t,0,0,0,0,r,0,0,0,0,1]}function J(e){return X(e)}function Q(e,t=!1){const r=String(e??"").trim().toLowerCase();return r?["1","true","yes","on"].includes(r)?!0:["0","false","no","off"].includes(r)?!1:t:t}function _(e,t){const r=g(e,"pose")[0]||null;if(!r)return{hasPose:!1,rotationFormat:"euler_rpy",relativeTo:"",values:[0,0,0,0,0,0],transform:[...S]};const n=String(r.getAttribute("rotation_format")||"euler_rpy").trim().toLowerCase();if(n!=="euler_rpy")throw new Error(`${t} pose uses unsupported rotation_format ${JSON.stringify(n)}`);const o=j(r.textContent,6,[0,0,0,0,0,0],`${t} pose`);return Q(r.getAttribute("degrees"),!1)&&(o[3]*=Math.PI/180,o[4]*=Math.PI/180,o[5]*=Math.PI/180),{hasPose:!0,rotationFormat:n,relativeTo:String(r.getAttribute("relative_to")||"").trim(),values:o,transform:J(o)}}function ee(e){return e instanceof URL?e.toString():new URL(String(e),globalThis.window?.location?.href||"http://localhost/").toString()}function te(e){try{const t=new URL(String(e||""));return!!(t.origin&&t.origin!=="null")}catch{return!1}}function re(e,{sourceUrl:t}){return te(t)?e.toString():`${e.pathname}${e.search}`}function ne(e,t){const r=String(e||"").trim();if(!r)throw new Error("SDF mesh URI is required");const n=ee(t);let o;if(r.startsWith("package://"))o=new URL(r.slice(10).replace(/^\/+/,""),new URL("/",n));else{if(/^[a-z][a-z0-9+.-]*:\/\//i.test(r))throw new Error(`Unsupported SDF mesh URI scheme: ${r}`);o=new URL(r,n)}return re(o,{sourceUrl:t})}function oe(e){const t=String(e||"").split("/");return t[t.length-1]||"mesh"}function P(e,t){const r=Array.isArray(e)&&e.length===16?e:S,[n,o,i]=Array.isArray(t)?t:[0,0,1];return[r[0]*n+r[1]*o+r[2]*i,r[4]*n+r[5]*o+r[6]*i,r[8]*n+r[9]*o+r[10]*i]}function B(e,t=[0,0,1]){const r=Array.isArray(e)&&e.length>=3?e:t,n=Number(r[0]),o=Number(r[1]),i=Number(r[2]),l=Math.hypot(n,o,i);return!Number.isFinite(l)||l<=1e-9?[...t]:[n/l,o/l,i/l]}function ie(e,t,r){const n=P(t,e);return P(V(r),n)}function z(e,t){const r=String(e||"").trim().split(/\s+/).filter(Boolean);if(r.length!==3&&r.length!==4)throw new Error(`${t} must contain 3 or 4 numeric color values`);const n=r.map(o=>Number(o));if(n.some(o=>!Number.isFinite(o)||o<0||o>1))throw new Error(`${t} must use color values between 0 and 1`);return`#${n.slice(0,3).map(o=>Math.round(o*255).toString(16).padStart(2,"0")).join("")}`}function se(e,t){if(!e)return"";const r=F(e,"diffuse");if(r)return z(r,`${t} diffuse material`);const n=F(e,"ambient");return n?z(n,`${t} ambient material`):""}function L(e){const t=String(e||"").trim(),r=/(?:^|_)o(\d+(?:_\d+)+)(?:_|$)/i.exec(t);return r?`o${r[1].replace(/_/g,".")}`:""}function U(e,{linkName:t,kind:r,index:n,sourceUrl:o}){const i=r==="collision"?"collision":"visual",l=String(e?.getAttribute("name")||"").trim(),c=_(e,`SDF link ${t} ${i} ${n}`),m=g(e,"geometry")[0]||null,u=m?g(m,"mesh")[0]:null;if(!u){const v=m?E(I(m)[0])||"unknown":"missing";return{id:`${t}:${r[0]}${n}`,label:`${v} ${i}`,instanceId:l,occurrenceId:L(l)||L(t),meshUrl:"",color:"",localTransform:c.transform,pose:c,unsupportedGeometry:v}}const s=F(u,"uri");if(!s)return{id:`${t}:${r[0]}${n}`,label:`mesh ${i}`,instanceId:l,occurrenceId:L(l)||L(t),meshUrl:"",color:"",localTransform:c.transform,pose:c,unsupportedGeometry:"mesh"};const[a,d,h]=j(F(u,"scale"),3,[1,1,1],`SDF link ${t} ${i} ${n} mesh scale`),p=Z(a,d,h);return{id:`${t}:${r[0]}${n}`,label:oe(s),instanceId:l,occurrenceId:L(l)||L(t),meshUrl:ne(s,o||"/"),color:se(g(e,"material")[0]||null,`SDF link ${t} ${i} ${n}`),localTransform:$(c.transform,p),pose:c,scaleTransform:p}}function ae(e,t){const r=String(e.getAttribute("name")||"").trim();if(!r)throw new Error("SDF link name is required");const n=g(e,"visual").map((i,l)=>U(i,{linkName:r,kind:"visual",index:l+1,sourceUrl:t})),o=g(e,"collision").map((i,l)=>U(i,{linkName:r,kind:"collision",index:l+1,sourceUrl:t}));return{name:r,visuals:n,collisions:o,pose:_(e,`SDF link ${r}`)}}function le(e){const t=String(e.getAttribute("name")||"").trim();if(!t)throw new Error("SDF frame name is required");return{name:t,attachedTo:String(e.getAttribute("attached_to")||"").trim(),pose:_(e,`SDF frame ${t}`)}}function me(e,t,r){if(r==="continuous")return{minValueDeg:-180,maxValueDeg:180};if(r!=="revolute"&&r!=="prismatic")return{minValueDeg:0,maxValueDeg:0};const n=g(e,"limit")[0]||null,o=Number(F(n,"lower")),i=Number(F(n,"upper"));if(!Number.isFinite(o)||!Number.isFinite(i))throw new Error(`SDF ${r} joint ${t} has invalid limits`);return r==="revolute"?{minValueDeg:o*180/Math.PI,maxValueDeg:i*180/Math.PI}:{minValueDeg:o,maxValueDeg:i}}function D(e,{modelName:t,defaultFrame:r=w}={}){const n=String(e||"").trim();return n?n===t||n===w?w:n===y?y:n:r}function ce(e,{modelName:t}){const r=String(e.getAttribute("name")||"").trim();if(!r)throw new Error("SDF joint name is required");const n=String(e.getAttribute("type")||"").trim().toLowerCase();if(!["fixed","continuous","revolute","prismatic"].includes(n))throw new Error(`Unsupported SDF joint type: ${n||"(missing)"}`);const o=D(F(e,"parent"),{modelName:t,defaultFrame:""}),i=D(F(e,"child"),{modelName:t,defaultFrame:""});if(!o||!i)throw new Error(`SDF joint ${r} must declare parent and child frames`);if(i===y)throw new Error(`SDF joint ${r} cannot use world as the child frame`);const l=g(e,"axis")[0]||null,c=g(l,"xyz")[0]||null,m=n==="fixed"?[1,0,0]:B(j(c?.textContent,3,[0,0,1],`SDF joint ${r} axis`)),u=me(l,r,n);return{name:r,type:n,parentFrame:o,childFrame:i,pose:_(e,`SDF joint ${r}`),axis:m,axisExpressedIn:String(c?.getAttribute("expressed_in")||"").trim(),defaultValueDeg:0,minValueDeg:u.minValueDeg,maxValueDeg:u.maxValueDeg,mimic:null}}function ue({modelName:e,modelWorldTransform:t,links:r,frames:n,joints:o}){const i=new Map([[y,{name:y,kind:"world",worldTransform:[...S]}],[w,{name:w,kind:"model",worldTransform:t}]]),l=new Set,c=(s,a)=>{if(i.has(s))throw new Error(`Duplicate SDF frame/link/joint name: ${s}`);i.set(s,a)};for(const s of r)l.add(s.name),c(s.name,{name:s.name,kind:"link",pose:s.pose,defaultRelativeTo:w});for(const s of n){const a=D(s.attachedTo,{modelName:e,defaultFrame:w});c(s.name,{name:s.name,kind:"frame",pose:s.pose,attachedTo:a,defaultRelativeTo:a})}for(const s of o)c(s.name,{name:s.name,kind:"joint",pose:s.pose,childFrame:s.childFrame,defaultRelativeTo:s.childFrame});const m=(s,a=w,d=new Set)=>{const h=D(s,{modelName:e,defaultFrame:a}),p=i.get(h);if(!p)throw new Error(`SDF references unknown frame ${JSON.stringify(h)}`);if(p.worldTransform)return p.worldTransform;if(d.has(h))throw new Error(`SDF frame graph contains a cycle at ${h}`);d.add(h);const v=p.pose||{relativeTo:"",transform:[...S]},R=D(v.relativeTo,{modelName:e,defaultFrame:p.defaultRelativeTo||w}),k=m(R,w,d),x=$(k,v.transform||S);return p.worldTransform=x,d.delete(h),x},u=(s,a=new Set)=>{const d=D(s,{modelName:e,defaultFrame:w});if(l.has(d))return d;if(d===w||d===y)return"";const h=i.get(d);if(!h)throw new Error(`SDF references unknown frame ${JSON.stringify(d)}`);if(a.has(d))throw new Error(`SDF attached_to graph contains a cycle at ${d}`);return a.add(d),h.kind==="frame"?u(h.attachedTo||w,a):h.kind==="joint"?u(h.childFrame,a):""};return{descriptors:i,linkNames:l,resolveFrameWorld:m,resolveAttachedLink:u}}function q(e,{linkName:t,resolver:r,modelName:n}){const o=r.resolveFrameWorld(t),i=e.pose||{relativeTo:"",transform:[...S]},l=D(i.relativeTo,{modelName:n,defaultFrame:t}),c=$(r.resolveFrameWorld(l),i.transform),m=$(V(o),c),{pose:u,scaleTransform:s,...a}=e;return{...a,localTransform:$(m,s||S)}}function de(e,t,r){return e.map(n=>({name:n.name,visuals:n.visuals.map(o=>q(o,{linkName:n.name,resolver:t,modelName:r})),collisions:n.collisions.map(o=>q(o,{linkName:n.name,resolver:t,modelName:r}))}))}function fe(e,t,r){const n=t.resolveAttachedLink(e.parentFrame)||T,o=t.resolveAttachedLink(e.childFrame);if(!o)throw new Error(`SDF joint ${e.name} child frame ${JSON.stringify(e.childFrame)} is not attached to a link`);if(n===o)throw new Error(`SDF joint ${e.name} resolves parent and child to the same link ${o}`);const i=n===T?[...S]:t.resolveFrameWorld(n),l=t.resolveFrameWorld(e.name),c=t.resolveFrameWorld(o),m=$(V(i),l),u=$(V(l),c),s=D(e.axisExpressedIn,{modelName:r,defaultFrame:e.name}),a=e.type==="fixed"?[1,0,0]:B(ie(e.axis,t.resolveFrameWorld(s),l));return{name:e.name,type:e.type,parentLink:n,childLink:o,originTransform:$(m,u),preMotionTransform:m,postMotionTransform:u,axis:a,axisInJointFrame:a,defaultValueDeg:e.defaultValueDeg,minValueDeg:e.minValueDeg,maxValueDeg:e.maxValueDeg,mimic:null,sdf:{parentFrame:e.parentFrame,childFrame:e.childFrame,jointFrame:e.name,axisExpressedIn:s}}}function pe(e,t,r){const n=t.resolveFrameWorld(e);return{name:`${T}_to_${e}_${r}`,type:"fixed",parentLink:T,childLink:e,originTransform:n,preMotionTransform:n,postMotionTransform:[...S],axis:[1,0,0],axisInJointFrame:[1,0,0],defaultValueDeg:0,minValueDeg:0,maxValueDeg:0,mimic:null,sdf:{parentFrame:w,childFrame:e,jointFrame:`${T}_to_${e}_${r}`,synthetic:!0}}}function he(e,t,r){const n=new Set(e.map(m=>m.name)),o=new Set(t.map(m=>m.childLink)),i=[...n].filter(m=>!o.has(m));if(!(i.length!==1||t.some(m=>m.parentLink===T))){const m=i[0];return{links:e,joints:t,rootLink:m,rootWorldTransform:r.resolveFrameWorld(m),syntheticRoot:!1}}const c=i.map((m,u)=>pe(m,r,u+1));return{links:[{name:T,visuals:[],collisions:[],synthetic:!0},...e],joints:[...c,...t],rootLink:T,rootWorldTransform:[...S],syntheticRoot:!0}}function ge(e,t){const r=new Set(e.map(a=>a.name)),n=new Set,o=new Map,i=new Set;for(const a of t){if(i.has(a.name))throw new Error(`Duplicate SDF joint name: ${a.name}`);if(i.add(a.name),n.has(a.childLink))throw new Error(`SDF link ${a.childLink} has multiple parents`);n.add(a.childLink);const d=o.get(a.parentLink)||[];d.push(a.childLink),o.set(a.parentLink,d)}const l=[...r].filter(a=>!n.has(a));if(l.length!==1)throw new Error(`SDF must form a single rooted joint tree; found roots ${JSON.stringify(l)}`);const c=l[0],m=new Set,u=new Set,s=a=>{if(!m.has(a)){if(u.has(a))throw new Error("SDF joint graph contains a cycle");u.add(a);for(const d of o.get(a)||[])s(d);u.delete(a),m.add(a)}};if(s(c),m.size!==e.length){const a=e.map(d=>d.name).filter(d=>!m.has(d));throw new Error(`SDF leaves links disconnected from the root: ${JSON.stringify(a)}`)}return c}function C(e,t){return Object.fromEntries(t.map(r=>[r,String(e?.getAttribute(r)||"").trim()]).filter(([,r])=>r))}function we(e,t){return{id:`include:${t+1}`,uri:F(e,"uri"),name:F(e,"name")}}function Se(e,t){const r=Y(e),n=H(e);return{id:`plugin:${t+1}`,name:r,filename:n,customAnimation:n==="cad-viewer-input-motion"||r==="cad_viewer_input_motion"}}function Fe(e,t){return{id:`sensor:${t+1}`,...C(e,["name","type"])}}function De(e,t){return{id:`light:${t+1}`,...C(e,["name","type"])}}function $e(e,t){return{id:`physics:${t+1}`,...C(e,["name","type","default"])}}function ye(e){const t=b(e,"include").map(we),r=b(e,"plugin").map(Se),n=b(e,"sensor").map(Fe),o=b(e,"light").map(De),i=b(e,"physics").map($e),l=b(e,"model").filter(m=>m.parentNode&&E(m.parentNode)==="model").length,c=[];return t.length&&c.push("SDF includes are listed as static metadata; CAD Viewer does not resolve external models."),r.length&&c.push("SDF plugins are listed as static metadata; CAD Viewer does not execute simulator plugins."),r.some(m=>m.customAnimation)&&c.push("CAD Viewer input-motion plugins are ignored; SDF rendering is static unless joints are posed manually."),n.length&&c.push("SDF sensors are listed as static metadata; CAD Viewer does not simulate sensor output."),o.length&&c.push("SDF lights are listed as static metadata; CAD Viewer does not execute simulator lighting behavior."),i.length&&c.push("SDF physics settings are listed as static metadata; CAD Viewer does not run simulation physics."),l&&c.push("Nested SDF models are listed as static metadata; CAD Viewer renders the selected model's direct links."),{includes:t,plugins:r,sensors:n,lights:o,physics:i,nestedModelCount:l,warnings:c}}function Te(e){const t=g(e,"model");if(t.length===1)return{documentKind:"model",worldName:"",model:t[0]};if(t.length>1)throw new Error("SDF rendering currently requires one direct <model>; multiple top-level models are listed only as metadata");const r=g(e,"world");if(r.length!==1)throw new Error("SDF rendering requires one direct <model> or one <world> containing one direct <model>");const n=r[0],o=g(n,"model");if(o.length!==1)throw new Error("SDF world rendering currently requires exactly one direct <model>");return{documentKind:"world",worldName:String(n.getAttribute("name")||"").trim(),model:o[0]}}function Ee(e,{sourceUrl:t}={}){if(typeof DOMParser>"u")throw new Error("DOMParser is unavailable in this environment");const r=new DOMParser().parseFromString(String(e||""),"application/xml");if(r.querySelector("parsererror"))throw new Error("Failed to parse SDF XML");const o=r.documentElement;if(!o||E(o)!=="sdf")throw new Error("SDF root element must be <sdf>");const i=String(o.getAttribute("version")||"").trim();if(!i)throw new Error("SDF root element must declare a version");const l=ye(o),{documentKind:c,worldName:m,model:u}=Te(o),s=String(u.getAttribute("name")||"").trim();if(!s)throw new Error("SDF model name is required");const a=_(u,`SDF model ${s}`);if(D(a.relativeTo,{modelName:s,defaultFrame:y})!==y)throw new Error(`SDF model ${s} uses unsupported pose frame ${JSON.stringify(a.relativeTo)}`);const h=a.transform,p=g(u,"link").map(f=>ae(f,t));if(!p.length)throw new Error("SDF model must define at least one link");const v=p.flatMap(f=>f.visuals).filter(f=>f.unsupportedGeometry).length,R=p.flatMap(f=>f.collisions).filter(f=>f.unsupportedGeometry).length,k=new Set;for(const f of p){if(k.has(f.name))throw new Error(`Duplicate SDF link name: ${f.name}`);k.add(f.name)}const x=g(u,"frame").map(le),M=g(u,"joint").map(f=>ce(f,{modelName:s})),W=new Set;for(const f of M){if(W.has(f.name))throw new Error(`Duplicate SDF joint name: ${f.name}`);W.add(f.name)}const N=ue({modelName:s,modelWorldTransform:h,links:p,frames:x,joints:M}),K=de(p,N,s),G=M.map(f=>fe(f,N,s)),A=he(K,G,N),O=ge(A.links,A.joints);return{robotName:s,rootLink:O,rootWorldTransform:A.rootWorldTransform,links:A.links,joints:A.joints,motion:null,sourceFormat:"sdf",sdf:{version:i,documentKind:c,worldName:m,modelName:s,nativeFrameSemantics:!0,syntheticRoot:A.syntheticRoot,frameCount:x.length,linkCount:p.length,jointCount:M.length,rootLink:O,unsupportedVisualCount:v,unsupportedCollisionCount:R,staticMetadata:l},srdf:null}}export{Ee as parseSdf};
|
|
//# sourceMappingURL=parseSdf-D2U6Dgo_.js.map
|