Use SVG to get component positions and handle inverted schematics

This commit is contained in:
Shrikanth Upadhayaya 2025-04-03 11:54:26 -04:00
parent ff2d6595fb
commit 280736732c
No known key found for this signature in database

View File

@ -129,6 +129,39 @@ def find_page_viewbox(
return view_box
def find_component_by_id(
page: ET.Element,
component_id: str,
) -> Optional[ET.Element]:
"""
Find a component element by the given ID.
"""
for child in page:
if (
child.tag == "{http://www.w3.org/2000/svg}g"
and child.get("data-path") == "components"
and child.get("data-id") == component_id
):
return child
return None
def x_y_from_transform(
transform: Optional[str],
) -> Optional[Position]:
"""
Get the x and y coordinates from the transform string.
"""
if not transform:
return None
x, y = transform.lstrip("translate(").rstrip(")").split(",")
x = float(x)
y = float(y)
return {"x": x, "y": y}
def find_component_position(
page: ET.Element,
component_id: str,
@ -144,18 +177,14 @@ def find_component_position(
and child.get("data-id") == component_id
):
transform = child.get("transform")
if not transform:
return None
x, y = transform.lstrip("translate(").rstrip(")").split(",")
x = float(x)
y = float(y)
return {"x": x, "y": y}
return x_y_from_transform(transform)
return None
def position_of_element(
element_designator: str,
ir_page: dict,
svg_page: ET.Element,
) -> Optional[Position]:
split_designator = element_designator.split(".")
component_designator = split_designator[0]
@ -174,9 +203,14 @@ def position_of_element(
if not component:
return None
component_position = component.get("position")
component_id = component["id"]
svg_component = find_component_by_id(svg_page, component_id)
if svg_component is None:
return component.get("position")
component_position = x_y_from_transform(svg_component.get("transform"))
if not component_position:
return None
return component.get("position")
if pin_designator:
pin = None
@ -198,6 +232,37 @@ def position_of_element(
return component_position
def percentage_view_box(
view_box: list[float], view_bounds: list[float], shifted: bool
) -> list[float]:
margin = 2.5
sig_figs = 6
width = view_bounds[2]
height = view_bounds[3]
percentage_view_box = [
(view_box[0] - view_bounds[0]) / width * 100,
(view_box[1] - view_bounds[1]) / height * 100,
(view_box[2] - view_bounds[0]) / width * 100,
(view_box[3] - view_bounds[1]) / height * 100,
]
if shifted:
view_coords = [
max(0, round(percentage_view_box[0] - margin, sig_figs)),
max(0, round((100 - percentage_view_box[3]) - margin, sig_figs)),
min(100, round(percentage_view_box[2] + margin, sig_figs)),
min(100, round((100 - percentage_view_box[1]) + margin, sig_figs)),
]
else:
view_coords = [
max(0, round(percentage_view_box[0] - margin, sig_figs)),
max(0, round(percentage_view_box[1] - margin, sig_figs)),
min(100, round(percentage_view_box[2] + margin, sig_figs)),
min(100, round(percentage_view_box[3] + margin, sig_figs)),
]
return view_coords
def format_snippet(
view_box: list[float],
id: str,
@ -208,31 +273,13 @@ def format_snippet(
dr_number: str,
view_bounds: list[float],
) -> str:
margin = 2.5
sig_figs = 6
width = view_bounds[2] - view_bounds[0]
height = view_bounds[3] - view_bounds[1]
percentage_view_box = [
(view_box[0] - view_bounds[0]) / width * 100,
(view_box[1] - view_bounds[1]) / height * 100,
(view_box[2] - view_bounds[0]) / width * 100,
(view_box[3] - view_bounds[1]) / height * 100,
]
view_coords = [
max(0, round(percentage_view_box[0] - margin, sig_figs)),
max(0, round((100 - percentage_view_box[3]) - margin, sig_figs)),
min(100, round(percentage_view_box[2] + margin, sig_figs)),
min(100, round((100 - percentage_view_box[1]) + margin, sig_figs)),
]
aspect_ratio = round(
(view_bounds[2] - view_bounds[0]) / (view_bounds[3] - view_bounds[1]), sig_figs
)
aspect_ratio = view_bounds[2] / view_bounds[3]
snippet = (
f'!thumbnail[]({file_path}){"{"} diff="{repo}:{base_commit}...{head_commit}" '
f'pr="{dr_number}" is-added=true doc-id="{id}" diff-visibility="full" variant="default" '
f'view-coords="{view_coords[0]:.2f},{view_coords[1]:.2f},{view_coords[2]:.2f},{view_coords[3]:.2f}" '
f'aspect-ratio="{aspect_ratio}" '
f'view-coords="{view_box[0]:.2f},{view_box[1]:.2f},{view_box[2]:.2f},{view_box[3]:.2f}" '
f'aspect-ratio="{aspect_ratio:.2f}" '
'}'
)
@ -276,12 +323,15 @@ def into_review_comment(
if elements:
elements = elements.split(", ")
if ir_page and svg_page:
if ir_page and (svg_page is not None):
page_view_bounds = find_page_viewbox(svg_page, y_shift)
positions: list[Position] = []
for element in elements:
if pos := position_of_element(element, ir_page):
if pos := position_of_element(element, ir_page, svg_page):
# 🤷‍♂️
if y_shift != 0:
pos["y"] = -pos["y"]
positions.append(pos)
if positions:
@ -290,6 +340,11 @@ def into_review_comment(
min_y = min([pos["y"] for pos in positions])
max_y = max([pos["y"] for pos in positions])
view_box = [min_x, min_y, max_x, max_y]
view_box = percentage_view_box(
view_box,
page_view_bounds,
y_shift != 0,
)
snippet = format_snippet(
view_box,
ir_page["id"],