Johnntirs's picture
Room Visualizer backend (Docker)
0cdb4e8
Raw
History Blame Contribute Delete
1.78 kB
"""Perspective scaling: map real-world cm dimensions to a pixel footprint.
Uses the row-based ``Perspective`` model so an item is the correct apparent size
for where it sits in the room (spec section 5, stage 4).
"""
from __future__ import annotations
from .floor_plane import Perspective
def footprint_quad(
persp: Perspective, anchor_xy: tuple[float, float], width_cm: float, depth_cm: float
) -> list[list[float]]:
"""Floor corners (px) of a ``width_cm`` x ``depth_cm`` rectangle whose FRONT
edge is centered at ``anchor_xy``.
Returns 4 points ordered front-left, front-right, back-right, back-left. The
back edge is both higher up the image and narrower, giving a perspective-
correct trapezoid rather than a flat sprite.
"""
x_a, y_a = anchor_xy
ppc_front = persp.ppc(y_a)
w_front = width_cm * ppc_front
dy = depth_cm * ppc_front * persp.foreshorten
y_back = max(persp.horizon_y + 1.0, y_a - dy)
w_back = width_cm * persp.ppc(y_back)
return [
[x_a - w_front / 2, y_a],
[x_a + w_front / 2, y_a],
[x_a + w_back / 2, y_back],
[x_a - w_back / 2, y_back],
]
def object_height_px(persp: Perspective, anchor_y: float, height_cm: float) -> float:
"""Apparent vertical extent (px) of an item of ``height_cm`` at row ``anchor_y``."""
return height_cm * persp.ppc(anchor_y)
def describe_scale(
persp: Perspective,
anchor_xy: tuple[float, float],
width_cm: float,
depth_cm: float,
height_cm: float,
) -> str:
x_a, y_a = anchor_xy
ppc = persp.ppc(y_a)
return (
f"floor row y={int(y_a)} -> {ppc:.2f}px/cm; "
f"{width_cm}x{depth_cm}x{height_cm}cm item renders ~"
f"{int(width_cm * ppc)}x{int(height_cm * ppc)}px (W*H)"
)