// Helper functions for Robot Monitor window.robotMonitor = { // Get element size getElementSize: function (element) { const rect = element.getBoundingClientRect(); return { Width: rect.width, Height: rect.height }; }, // Get element bounding rect getElementBoundingRect: function (element) { const rect = element.getBoundingClientRect(); return { X: rect.x, Y: rect.y, Width: rect.width, Height: rect.height }; }, // Convert trajectory to SVG path trajectoryToPath: function (trajectory, startX, startY, endX, endY) { if (!trajectory || !trajectory.ControlPoints || trajectory.ControlPoints.length === 0) { // Linear path return `M ${startX} ${startY} L ${endX} ${endY}`; } const degree = trajectory.Degree || 1; const controlPoints = trajectory.ControlPoints; if (degree === 1) { // Linear return `M ${startX} ${startY} L ${endX} ${endY}`; } else if (degree === 2) { // Quadratic bezier if (controlPoints.length > 0) { const cp1 = controlPoints[0]; return `M ${startX} ${startY} Q ${cp1.X} ${cp1.Y} ${endX} ${endY}`; } return `M ${startX} ${startY} L ${endX} ${endY}`; } else if (degree === 3) { // Cubic bezier if (controlPoints.length >= 2) { const cp1 = controlPoints[0]; const cp2 = controlPoints[1]; return `M ${startX} ${startY} C ${cp1.X} ${cp1.Y}, ${cp2.X} ${cp2.Y}, ${endX} ${endY}`; } else if (controlPoints.length === 1) { const cp1 = controlPoints[0]; return `M ${startX} ${startY} Q ${cp1.X} ${cp1.Y} ${endX} ${endY}`; } return `M ${startX} ${startY} L ${endX} ${endY}`; } return `M ${startX} ${startY} L ${endX} ${endY}`; }, // Load image and get dimensions loadImageAndGetDimensions: function (imageUrl) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { resolve({ Width: img.naturalWidth || img.width, Height: img.naturalHeight || img.height }); }; img.onerror = () => { reject(new Error(`Failed to load image: ${imageUrl}`)); }; img.src = imageUrl; }); } };