diff --git a/src/features/autoScale/.gitkeep b/src/features/autoScale/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/features/autoScale/__tests__/calculateScale.test.ts b/src/features/autoScale/__tests__/calculateScale.test.ts new file mode 100644 index 0000000..fdea04e --- /dev/null +++ b/src/features/autoScale/__tests__/calculateScale.test.ts @@ -0,0 +1,48 @@ +import { calculateScale } from '../calculateScale'; + +describe('calculateScale', () => { + it('사진 어깨 / 카메라 옷 너비 비율을 그대로 반환한다', () => { + const result = calculateScale({ + photoShoulderPx: 200, + cameraClothWidthPx: 400, + }); + expect(result.scale).toBe(0.5); + expect(result.confidence).toBeGreaterThan(0); + }); + + it('카메라 옷 너비가 0이면 scale=1, confidence=0으로 폴백한다', () => { + const result = calculateScale({ + photoShoulderPx: 200, + cameraClothWidthPx: 0, + }); + expect(result.scale).toBe(1); + expect(result.confidence).toBe(0); + }); + + it('카메라 옷 너비가 음수여도 0과 동일하게 폴백한다', () => { + const result = calculateScale({ + photoShoulderPx: 200, + cameraClothWidthPx: -5, + }); + expect(result.scale).toBe(1); + expect(result.confidence).toBe(0); + }); + + it('비율이 3.0을 초과하면 3.0으로 클램핑 + confidence 낮춤', () => { + const result = calculateScale({ photoShoulderPx: 200, cameraClothWidthPx: 10 }); + expect(result.scale).toBe(3.0); + expect(result.confidence).toBeLessThan(1); + }); + + it('비율이 0.3 미만이면 0.3으로 클램핑 + confidence 낮춤', () => { + const result = calculateScale({ photoShoulderPx: 10, cameraClothWidthPx: 200 }); + expect(result.scale).toBe(0.3); + expect(result.confidence).toBeLessThan(1); + }); + + it('클램핑 안 되는 정상 비율이면 confidence=1', () => { + const result = calculateScale({ photoShoulderPx: 200, cameraClothWidthPx: 200 }); + expect(result.scale).toBe(1.0); + expect(result.confidence).toBe(1); + }); +}); diff --git a/src/features/autoScale/calculateScale.ts b/src/features/autoScale/calculateScale.ts new file mode 100644 index 0000000..86b961a --- /dev/null +++ b/src/features/autoScale/calculateScale.ts @@ -0,0 +1,22 @@ +export interface ScaleInput { + photoShoulderPx: number; + cameraClothWidthPx: number; +} + +export interface ScaleResult { + scale: number; + confidence: number; +} + +export const MIN_SCALE = 0.3; +export const MAX_SCALE = 3.0; + +export function calculateScale({ photoShoulderPx, cameraClothWidthPx }: ScaleInput): ScaleResult { + if (cameraClothWidthPx <= 0) { + return { scale: 1, confidence: 0 }; + } + const raw = photoShoulderPx / cameraClothWidthPx; + const scale = Math.max(MIN_SCALE, Math.min(MAX_SCALE, raw)); + const confidence = scale === raw ? 1 : 0.5; + return { scale, confidence }; +}