33 lines
1.4 KiB
TypeScript
33 lines
1.4 KiB
TypeScript
|
|
import type { AppConfig, Calibration, Mat3, Vec2 } from './types';
|
||
|
|
|
||
|
|
export const DEFAULT_RENDER = { cutColor: '#00e5ff', rapidColor: '#ff9800', lineWidth: 1.5 };
|
||
|
|
|
||
|
|
function isVec2Array(v: unknown): v is Vec2[] {
|
||
|
|
return Array.isArray(v) && v.every((p) => Array.isArray(p) && p.length === 2 && p.every((n) => typeof n === 'number'));
|
||
|
|
}
|
||
|
|
|
||
|
|
function parseCalibration(c: unknown): Calibration | null {
|
||
|
|
if (!c || typeof c !== 'object') return null;
|
||
|
|
const obj = c as Record<string, unknown>;
|
||
|
|
if (!isVec2Array(obj.imagePoints) || !isVec2Array(obj.machinePoints)) return null;
|
||
|
|
if (!Array.isArray(obj.homography) || obj.homography.length !== 9) return null;
|
||
|
|
if (!obj.homography.every((n) => typeof n === 'number')) return null;
|
||
|
|
if (obj.imagePoints.length !== obj.machinePoints.length || obj.imagePoints.length < 4) return null;
|
||
|
|
return {
|
||
|
|
imagePoints: obj.imagePoints,
|
||
|
|
machinePoints: obj.machinePoints,
|
||
|
|
homography: obj.homography as Mat3,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function loadConfig(url: string): Promise<AppConfig> {
|
||
|
|
const res = await fetch(url);
|
||
|
|
if (!res.ok) throw new Error(`Failed to load ${url}: ${res.status}`);
|
||
|
|
const raw = (await res.json()) as Record<string, unknown>;
|
||
|
|
return {
|
||
|
|
streamUrl: typeof raw.streamUrl === 'string' ? raw.streamUrl : '',
|
||
|
|
calibration: parseCalibration(raw.calibration),
|
||
|
|
renderDefaults: { ...DEFAULT_RENDER, ...(raw.renderDefaults as object | undefined) },
|
||
|
|
};
|
||
|
|
}
|