83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
export interface DirectAgentAngleEditOptions {
|
||
horizontalAngle: number;
|
||
verticalAngle: number;
|
||
zoom: number;
|
||
loraScale?: number;
|
||
}
|
||
|
||
export function clampAngleEditNumber(
|
||
value: number | undefined,
|
||
min: number,
|
||
max: number,
|
||
fallback: number,
|
||
) {
|
||
if (!Number.isFinite(value)) return fallback;
|
||
return Math.min(max, Math.max(min, Number(value)));
|
||
}
|
||
|
||
function parseFirstNumberMatch(text: string, patterns: RegExp[]) {
|
||
for (const pattern of patterns) {
|
||
const match = text.match(pattern);
|
||
const value = Number(match?.[1]);
|
||
if (Number.isFinite(value)) return value;
|
||
}
|
||
return undefined;
|
||
}
|
||
|
||
export function inferAngleEditOptionsFromText(text: string): DirectAgentAngleEditOptions {
|
||
const normalizedText = String(text || "").toLowerCase().replace(/\s+/g, "");
|
||
const explicitHorizontal = parseFirstNumberMatch(normalizedText, [
|
||
/(?:水平角|水平|环绕|左右|horizontal|h)[::]?(-?\d{1,3})(?:度|°)?/,
|
||
/(?:旋转|转|转到|换成|改成)(-?\d{1,3})(?:度|°)/,
|
||
]);
|
||
const explicitVertical = parseFirstNumberMatch(normalizedText, [
|
||
/(?:垂直角|垂直|俯仰|上下|vertical|v)[::]?(-?\d{1,3})(?:度|°)?/,
|
||
]);
|
||
const explicitZoom = parseFirstNumberMatch(normalizedText, [
|
||
/(?:zoom|缩放|景别)[::]?(\d{1,2})(?:倍|x)?/,
|
||
]);
|
||
|
||
let horizontalAngle = explicitHorizontal ?? 45;
|
||
if (explicitHorizontal === undefined) {
|
||
if (/背面|背后|背视|后视|back/.test(normalizedText)) {
|
||
horizontalAngle = 180;
|
||
} else if (/左侧|左边|左视|left/.test(normalizedText)) {
|
||
horizontalAngle = 270;
|
||
} else if (/右侧|右边|右视|侧面|侧视|profile|side/.test(normalizedText)) {
|
||
horizontalAngle = 90;
|
||
} else if (/正面|正视|front/.test(normalizedText)) {
|
||
horizontalAngle = 0;
|
||
} else if (/三分之四|四分之三|斜侧|45度|45°/.test(normalizedText)) {
|
||
horizontalAngle = 45;
|
||
}
|
||
}
|
||
|
||
let verticalAngle = explicitVertical ?? 0;
|
||
if (explicitVertical === undefined) {
|
||
if (/俯视|俯拍|鸟瞰|高机位|top|overhead/.test(normalizedText)) {
|
||
verticalAngle = 45;
|
||
} else if (/仰视|仰拍|低机位|lowangle/.test(normalizedText)) {
|
||
verticalAngle = -20;
|
||
} else if (/平视|eyelevel/.test(normalizedText)) {
|
||
verticalAngle = 0;
|
||
}
|
||
}
|
||
|
||
let zoom = explicitZoom ?? 5;
|
||
if (explicitZoom === undefined) {
|
||
if (/特写|近景|拉近|推近|zoomin/.test(normalizedText)) {
|
||
zoom = 7;
|
||
} else if (/远景|全身|拉远|zoomout/.test(normalizedText)) {
|
||
zoom = 3;
|
||
} else if (/中景/.test(normalizedText)) {
|
||
zoom = 5;
|
||
}
|
||
}
|
||
|
||
return {
|
||
horizontalAngle: clampAngleEditNumber(horizontalAngle, 0, 360, 45),
|
||
verticalAngle: clampAngleEditNumber(verticalAngle, -30, 90, 0),
|
||
zoom: clampAngleEditNumber(zoom, 0, 10, 5),
|
||
};
|
||
}
|