Spaces:
Running
Running
File size: 4,654 Bytes
16ab111 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
import { LoadingManager, Object3D } from "three";
import { toast } from "sonner";
import { loadMeshFile } from "./meshLoaders";
import { URDFViewerElement } from "./urdfAnimationHelpers";
// Extended URDF Viewer Element with mesh loading capability
export interface ExtendedURDFViewerElement extends URDFViewerElement {
loadMeshFunc: (
path: string,
manager: LoadingManager,
done: (result: Object3D | null, err?: Error) => void
) => void;
}
/**
* Creates and configures a URDF viewer element
*/
export function createUrdfViewer(
container: HTMLDivElement,
isDarkMode: boolean
): ExtendedURDFViewerElement {
// Clear any existing content
container.innerHTML = "";
// Create the urdf-viewer element
const viewer = document.createElement(
"urdf-viewer"
) as ExtendedURDFViewerElement;
viewer.classList.add("w-full", "h-full");
// Add the element to the container
container.appendChild(viewer);
// Set initial viewer properties
viewer.setAttribute("up", "Z");
viewer.setAttribute("highlight-color", isDarkMode ? "#5b9aff" : "#3373ff");
viewer.setAttribute("ambient-color", isDarkMode ? "#202a30" : "#cfd8dc");
viewer.setAttribute("auto-redraw", "true");
viewer.setAttribute("display-shadow", ""); // Enable shadows
return viewer;
}
/**
* Setup mesh loading function for URDF viewer
*/
export function setupMeshLoader(
viewer: ExtendedURDFViewerElement,
urlModifierFunc: ((url: string) => string) | null
): void {
if ("loadMeshFunc" in viewer) {
viewer.loadMeshFunc = (
path: string,
manager: LoadingManager,
done: (result: Object3D | null, err?: Error) => void
) => {
// Apply URL modifier if available (for custom uploads)
const modifiedPath = urlModifierFunc ? urlModifierFunc(path) : path;
// If loading fails, log the error but continue
try {
loadMeshFile(modifiedPath, manager, (result, err) => {
if (err) {
console.warn(`Error loading mesh ${modifiedPath}:`, err);
// Try to continue with other meshes
done(null);
} else {
done(result);
}
});
} catch (err) {
console.error(`Exception loading mesh ${modifiedPath}:`, err);
done(null, err as Error);
}
};
}
}
/**
* Setup event handlers for joint highlighting
*/
export function setupJointHighlighting(
viewer: URDFViewerElement,
setHighlightedJoint: (joint: string | null) => void
): () => void {
const onJointMouseover = (e: Event) => {
const customEvent = e as CustomEvent;
setHighlightedJoint(customEvent.detail);
};
const onJointMouseout = () => {
setHighlightedJoint(null);
};
// Add event listeners
viewer.addEventListener("joint-mouseover", onJointMouseover);
viewer.addEventListener("joint-mouseout", onJointMouseout);
// Return cleanup function
return () => {
viewer.removeEventListener("joint-mouseover", onJointMouseover);
viewer.removeEventListener("joint-mouseout", onJointMouseout);
};
}
/**
* Setup model loading and error handling
*/
export function setupModelLoading(
viewer: URDFViewerElement,
urdfPath: string,
packagePath: string,
setCustomUrdfPath: (path: string) => void,
alternativeUrdfModels: string[] = [] // Add parameter for alternative models
): () => void {
// Add XML content type hint for blob URLs
const loadPath =
urdfPath.startsWith("blob:") && !urdfPath.includes("#.")
? urdfPath + "#.urdf" // Add extension hint if it's a blob URL
: urdfPath;
// Set the URDF path
viewer.setAttribute("urdf", loadPath);
viewer.setAttribute("package", packagePath);
// Handle error loading
const onLoadError = () => {
toast.error("Failed to load model", {
description: "There was an error loading the URDF model.",
duration: 3000,
});
// Use the provided alternativeUrdfModels instead of the global window object
if (alternativeUrdfModels.length > 0) {
const nextModel = alternativeUrdfModels[0];
if (nextModel) {
setCustomUrdfPath(nextModel);
toast.info("Trying alternative model...", {
description: `First model failed to load. Trying ${
nextModel.split("/").pop() || "alternative model"
}`,
duration: 2000,
});
}
}
};
viewer.addEventListener("error", onLoadError);
// Return cleanup function
return () => {
viewer.removeEventListener("error", onLoadError);
};
}
// For backward compatibility - to be removed in the future
declare global {
interface Window {
alternativeUrdfModels?: string[];
}
}
|