style: apply Black formatting to all Python files
Add [tool.black] config to pyproject.toml and Black hook to .pre-commit-config.yaml (rev 26.3.1), then auto-format all Python source and test files with line-length=100, target-version=py310. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,8 @@ from .layers import BoardLayerCommands
|
||||
from .outline import BoardOutlineCommands
|
||||
from .view import BoardViewCommands
|
||||
|
||||
logger = logging.getLogger('kicad_interface')
|
||||
logger = logging.getLogger("kicad_interface")
|
||||
|
||||
|
||||
class BoardCommands:
|
||||
"""Handles board-related KiCAD operations"""
|
||||
@@ -75,8 +76,8 @@ class BoardCommands:
|
||||
"""Get a 2D image of the PCB"""
|
||||
self.view_commands.board = self.board
|
||||
return self.view_commands.get_board_2d_view(params)
|
||||
|
||||
def get_board_extents(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Get the bounding box extents of the board"""
|
||||
self.view_commands.board = self.board
|
||||
return self.view_commands.get_board_extents(params)
|
||||
|
||||
def get_board_extents(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Get the bounding box extents of the board"""
|
||||
self.view_commands.board = self.board
|
||||
return self.view_commands.get_board_extents(params)
|
||||
|
||||
@@ -6,7 +6,8 @@ import pcbnew
|
||||
import logging
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
logger = logging.getLogger('kicad_interface')
|
||||
logger = logging.getLogger("kicad_interface")
|
||||
|
||||
|
||||
class BoardLayerCommands:
|
||||
"""Handles board layer operations"""
|
||||
@@ -22,7 +23,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No board is loaded",
|
||||
"errorDetails": "Load or create a board first"
|
||||
"errorDetails": "Load or create a board first",
|
||||
}
|
||||
|
||||
name = params.get("name")
|
||||
@@ -34,7 +35,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Missing parameters",
|
||||
"errorDetails": "name, type, and position are required"
|
||||
"errorDetails": "name, type, and position are required",
|
||||
}
|
||||
|
||||
# Get layer stack
|
||||
@@ -47,7 +48,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Missing layer number",
|
||||
"errorDetails": "number is required for inner layers"
|
||||
"errorDetails": "number is required for inner layers",
|
||||
}
|
||||
layer_id = pcbnew.In1_Cu + (number - 1)
|
||||
elif position == "top":
|
||||
@@ -59,7 +60,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Invalid layer position",
|
||||
"errorDetails": "position must be 'top', 'bottom', or 'inner'"
|
||||
"errorDetails": "position must be 'top', 'bottom', or 'inner'",
|
||||
}
|
||||
|
||||
# Set layer properties
|
||||
@@ -72,21 +73,12 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Added layer: {name}",
|
||||
"layer": {
|
||||
"name": name,
|
||||
"type": layer_type,
|
||||
"position": position,
|
||||
"number": number
|
||||
}
|
||||
"layer": {"name": name, "type": layer_type, "position": position, "number": number},
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding layer: {str(e)}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Failed to add layer",
|
||||
"errorDetails": str(e)
|
||||
}
|
||||
return {"success": False, "message": "Failed to add layer", "errorDetails": str(e)}
|
||||
|
||||
def set_active_layer(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Set the active layer for PCB operations"""
|
||||
@@ -95,7 +87,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No board is loaded",
|
||||
"errorDetails": "Load or create a board first"
|
||||
"errorDetails": "Load or create a board first",
|
||||
}
|
||||
|
||||
layer = params.get("layer")
|
||||
@@ -103,7 +95,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No layer specified",
|
||||
"errorDetails": "layer parameter is required"
|
||||
"errorDetails": "layer parameter is required",
|
||||
}
|
||||
|
||||
# Find layer ID by name
|
||||
@@ -112,7 +104,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Layer not found",
|
||||
"errorDetails": f"Layer '{layer}' does not exist"
|
||||
"errorDetails": f"Layer '{layer}' does not exist",
|
||||
}
|
||||
|
||||
# Set active layer
|
||||
@@ -121,10 +113,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Set active layer to: {layer}",
|
||||
"layer": {
|
||||
"name": layer,
|
||||
"id": layer_id
|
||||
}
|
||||
"layer": {"name": layer, "id": layer_id},
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
@@ -132,7 +121,7 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Failed to set active layer",
|
||||
"errorDetails": str(e)
|
||||
"errorDetails": str(e),
|
||||
}
|
||||
|
||||
def get_layer_list(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
@@ -142,32 +131,27 @@ class BoardLayerCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No board is loaded",
|
||||
"errorDetails": "Load or create a board first"
|
||||
"errorDetails": "Load or create a board first",
|
||||
}
|
||||
|
||||
layers = []
|
||||
for layer_id in range(pcbnew.PCB_LAYER_ID_COUNT):
|
||||
if self.board.IsLayerEnabled(layer_id):
|
||||
layers.append({
|
||||
"name": self.board.GetLayerName(layer_id),
|
||||
"type": self._get_layer_type_name(self.board.GetLayerType(layer_id)),
|
||||
"id": layer_id
|
||||
# Note: isActive removed - GetActiveLayer() doesn't exist in KiCAD 9.0
|
||||
# Active layer is a UI concept not applicable to headless scripting
|
||||
})
|
||||
layers.append(
|
||||
{
|
||||
"name": self.board.GetLayerName(layer_id),
|
||||
"type": self._get_layer_type_name(self.board.GetLayerType(layer_id)),
|
||||
"id": layer_id,
|
||||
# Note: isActive removed - GetActiveLayer() doesn't exist in KiCAD 9.0
|
||||
# Active layer is a UI concept not applicable to headless scripting
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"layers": layers
|
||||
}
|
||||
return {"success": True, "layers": layers}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting layer list: {str(e)}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Failed to get layer list",
|
||||
"errorDetails": str(e)
|
||||
}
|
||||
return {"success": False, "message": "Failed to get layer list", "errorDetails": str(e)}
|
||||
|
||||
def _get_layer_type(self, type_name: str) -> int:
|
||||
"""Convert layer type name to KiCAD layer type constant"""
|
||||
@@ -175,7 +159,7 @@ class BoardLayerCommands:
|
||||
"copper": pcbnew.LT_SIGNAL,
|
||||
"technical": pcbnew.LT_SIGNAL,
|
||||
"user": pcbnew.LT_SIGNAL, # LT_USER removed in KiCAD 9.0, use LT_SIGNAL instead
|
||||
"signal": pcbnew.LT_SIGNAL
|
||||
"signal": pcbnew.LT_SIGNAL,
|
||||
}
|
||||
return type_map.get(type_name.lower(), pcbnew.LT_SIGNAL)
|
||||
|
||||
@@ -185,7 +169,7 @@ class BoardLayerCommands:
|
||||
pcbnew.LT_SIGNAL: "signal",
|
||||
pcbnew.LT_POWER: "power",
|
||||
pcbnew.LT_MIXED: "mixed",
|
||||
pcbnew.LT_JUMPER: "jumper"
|
||||
pcbnew.LT_JUMPER: "jumper",
|
||||
}
|
||||
# Note: LT_USER was removed in KiCAD 9.0
|
||||
return type_map.get(type_id, "unknown")
|
||||
|
||||
@@ -224,9 +224,7 @@ class BoardOutlineCommands:
|
||||
}
|
||||
|
||||
# Convert to internal units (nanometers)
|
||||
scale = (
|
||||
1000000 if position.get("unit", "mm") == "mm" else 25400000
|
||||
) # mm or inch to nm
|
||||
scale = 1000000 if position.get("unit", "mm") == "mm" else 25400000 # mm or inch to nm
|
||||
x_nm = int(position["x"] * scale)
|
||||
y_nm = int(position["y"] * scale)
|
||||
diameter_nm = int(diameter * scale)
|
||||
@@ -252,9 +250,7 @@ class BoardOutlineCommands:
|
||||
pad = pcbnew.PAD(module)
|
||||
pad.SetNumber(1)
|
||||
pad.SetShape(pcbnew.PAD_SHAPE_CIRCLE)
|
||||
pad.SetAttribute(
|
||||
pcbnew.PAD_ATTRIB_PTH if plated else pcbnew.PAD_ATTRIB_NPTH
|
||||
)
|
||||
pad.SetAttribute(pcbnew.PAD_ATTRIB_PTH if plated else pcbnew.PAD_ATTRIB_NPTH)
|
||||
pad.SetSize(pcbnew.VECTOR2I(pad_diameter_nm, pad_diameter_nm))
|
||||
pad.SetDrillSize(pcbnew.VECTOR2I(diameter_nm, diameter_nm))
|
||||
pad.SetPosition(pcbnew.VECTOR2I(0, 0)) # Position relative to module
|
||||
@@ -311,9 +307,7 @@ class BoardOutlineCommands:
|
||||
}
|
||||
|
||||
# Convert to internal units (nanometers)
|
||||
scale = (
|
||||
1000000 if position.get("unit", "mm") == "mm" else 25400000
|
||||
) # mm or inch to nm
|
||||
scale = 1000000 if position.get("unit", "mm") == "mm" else 25400000 # mm or inch to nm
|
||||
x_nm = int(position["x"] * scale)
|
||||
y_nm = int(position["y"] * scale)
|
||||
size_nm = int(size * scale)
|
||||
@@ -372,9 +366,7 @@ class BoardOutlineCommands:
|
||||
"errorDetails": str(e),
|
||||
}
|
||||
|
||||
def _add_edge_line(
|
||||
self, start: pcbnew.VECTOR2I, end: pcbnew.VECTOR2I, layer: int
|
||||
) -> None:
|
||||
def _add_edge_line(self, start: pcbnew.VECTOR2I, end: pcbnew.VECTOR2I, layer: int) -> None:
|
||||
"""Add a line to the edge cuts layer"""
|
||||
line = pcbnew.PCB_SHAPE(self.board)
|
||||
line.SetShape(pcbnew.SHAPE_T_SEGMENT)
|
||||
@@ -396,18 +388,12 @@ class BoardOutlineCommands:
|
||||
"""Add a rounded rectangle to the edge cuts layer"""
|
||||
if radius_nm <= 0:
|
||||
# If no radius, create regular rectangle
|
||||
top_left = pcbnew.VECTOR2I(
|
||||
center_x_nm - width_nm // 2, center_y_nm - height_nm // 2
|
||||
)
|
||||
top_right = pcbnew.VECTOR2I(
|
||||
center_x_nm + width_nm // 2, center_y_nm - height_nm // 2
|
||||
)
|
||||
top_left = pcbnew.VECTOR2I(center_x_nm - width_nm // 2, center_y_nm - height_nm // 2)
|
||||
top_right = pcbnew.VECTOR2I(center_x_nm + width_nm // 2, center_y_nm - height_nm // 2)
|
||||
bottom_right = pcbnew.VECTOR2I(
|
||||
center_x_nm + width_nm // 2, center_y_nm + height_nm // 2
|
||||
)
|
||||
bottom_left = pcbnew.VECTOR2I(
|
||||
center_x_nm - width_nm // 2, center_y_nm + height_nm // 2
|
||||
)
|
||||
bottom_left = pcbnew.VECTOR2I(center_x_nm - width_nm // 2, center_y_nm + height_nm // 2)
|
||||
|
||||
self._add_edge_line(top_left, top_right, layer)
|
||||
self._add_edge_line(top_right, bottom_right, layer)
|
||||
|
||||
@@ -6,7 +6,8 @@ import pcbnew
|
||||
import logging
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
logger = logging.getLogger('kicad_interface')
|
||||
logger = logging.getLogger("kicad_interface")
|
||||
|
||||
|
||||
class BoardSizeCommands:
|
||||
"""Handles board size operations"""
|
||||
@@ -22,7 +23,7 @@ class BoardSizeCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No board is loaded",
|
||||
"errorDetails": "Load or create a board first"
|
||||
"errorDetails": "Load or create a board first",
|
||||
}
|
||||
|
||||
width = params.get("width")
|
||||
@@ -33,41 +34,36 @@ class BoardSizeCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Missing dimensions",
|
||||
"errorDetails": "Both width and height are required"
|
||||
"errorDetails": "Both width and height are required",
|
||||
}
|
||||
|
||||
# Create board outline using BoardOutlineCommands
|
||||
# This properly creates edge cuts on Edge.Cuts layer
|
||||
from commands.board.outline import BoardOutlineCommands
|
||||
|
||||
outline_commands = BoardOutlineCommands(self.board)
|
||||
|
||||
# Create rectangular outline centered at origin
|
||||
result = outline_commands.add_board_outline({
|
||||
"shape": "rectangle",
|
||||
"centerX": width / 2, # Center X
|
||||
"centerY": height / 2, # Center Y
|
||||
"width": width,
|
||||
"height": height,
|
||||
"unit": unit
|
||||
})
|
||||
result = outline_commands.add_board_outline(
|
||||
{
|
||||
"shape": "rectangle",
|
||||
"centerX": width / 2, # Center X
|
||||
"centerY": height / 2, # Center Y
|
||||
"width": width,
|
||||
"height": height,
|
||||
"unit": unit,
|
||||
}
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Created board outline: {width}x{height} {unit}",
|
||||
"size": {
|
||||
"width": width,
|
||||
"height": height,
|
||||
"unit": unit
|
||||
}
|
||||
"size": {"width": width, "height": height, "unit": unit},
|
||||
}
|
||||
else:
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error setting board size: {str(e)}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Failed to set board size",
|
||||
"errorDetails": str(e)
|
||||
}
|
||||
return {"success": False, "message": "Failed to set board size", "errorDetails": str(e)}
|
||||
|
||||
@@ -10,7 +10,8 @@ from PIL import Image
|
||||
import io
|
||||
import base64
|
||||
|
||||
logger = logging.getLogger('kicad_interface')
|
||||
logger = logging.getLogger("kicad_interface")
|
||||
|
||||
|
||||
class BoardViewCommands:
|
||||
"""Handles board viewing operations"""
|
||||
@@ -26,7 +27,7 @@ class BoardViewCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No board is loaded",
|
||||
"errorDetails": "Load or create a board first"
|
||||
"errorDetails": "Load or create a board first",
|
||||
}
|
||||
|
||||
# Get board dimensions
|
||||
@@ -42,26 +43,24 @@ class BoardViewCommands:
|
||||
layers = []
|
||||
for layer_id in range(pcbnew.PCB_LAYER_ID_COUNT):
|
||||
if self.board.IsLayerEnabled(layer_id):
|
||||
layers.append({
|
||||
"name": self.board.GetLayerName(layer_id),
|
||||
"type": self._get_layer_type_name(self.board.GetLayerType(layer_id)),
|
||||
"id": layer_id
|
||||
})
|
||||
layers.append(
|
||||
{
|
||||
"name": self.board.GetLayerName(layer_id),
|
||||
"type": self._get_layer_type_name(self.board.GetLayerType(layer_id)),
|
||||
"id": layer_id,
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"board": {
|
||||
"filename": self.board.GetFileName(),
|
||||
"size": {
|
||||
"width": width_mm,
|
||||
"height": height_mm,
|
||||
"unit": "mm"
|
||||
},
|
||||
"size": {"width": width_mm, "height": height_mm, "unit": "mm"},
|
||||
"layers": layers,
|
||||
"title": self.board.GetTitleBlock().GetTitle()
|
||||
"title": self.board.GetTitleBlock().GetTitle(),
|
||||
# Note: activeLayer removed - GetActiveLayer() doesn't exist in KiCAD 9.0
|
||||
# Active layer is a UI concept not applicable to headless scripting
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
@@ -69,7 +68,7 @@ class BoardViewCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Failed to get board information",
|
||||
"errorDetails": str(e)
|
||||
"errorDetails": str(e),
|
||||
}
|
||||
|
||||
def get_board_2d_view(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
@@ -79,7 +78,7 @@ class BoardViewCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No board is loaded",
|
||||
"errorDetails": "Load or create a board first"
|
||||
"errorDetails": "Load or create a board first",
|
||||
}
|
||||
|
||||
# Get parameters
|
||||
@@ -126,17 +125,14 @@ class BoardViewCommands:
|
||||
|
||||
# Convert SVG to requested format
|
||||
if format == "svg":
|
||||
with open(temp_svg, 'r') as f:
|
||||
with open(temp_svg, "r") as f:
|
||||
svg_data = f.read()
|
||||
os.remove(temp_svg)
|
||||
return {
|
||||
"success": True,
|
||||
"imageData": svg_data,
|
||||
"format": "svg"
|
||||
}
|
||||
return {"success": True, "imageData": svg_data, "format": "svg"}
|
||||
else:
|
||||
# Use PIL to convert SVG to PNG/JPG
|
||||
from cairosvg import svg2png
|
||||
|
||||
png_data = svg2png(url=temp_svg, output_width=width, output_height=height)
|
||||
os.remove(temp_svg)
|
||||
|
||||
@@ -144,18 +140,18 @@ class BoardViewCommands:
|
||||
# Convert PNG to JPG
|
||||
img = Image.open(io.BytesIO(png_data))
|
||||
jpg_buffer = io.BytesIO()
|
||||
img.convert('RGB').save(jpg_buffer, format='JPEG')
|
||||
img.convert("RGB").save(jpg_buffer, format="JPEG")
|
||||
jpg_data = jpg_buffer.getvalue()
|
||||
return {
|
||||
"success": True,
|
||||
"imageData": base64.b64encode(jpg_data).decode('utf-8'),
|
||||
"format": "jpg"
|
||||
"imageData": base64.b64encode(jpg_data).decode("utf-8"),
|
||||
"format": "jpg",
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": True,
|
||||
"imageData": base64.b64encode(png_data).decode('utf-8'),
|
||||
"format": "png"
|
||||
"imageData": base64.b64encode(png_data).decode("utf-8"),
|
||||
"format": "png",
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
@@ -163,7 +159,7 @@ class BoardViewCommands:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Failed to get board 2D view",
|
||||
"errorDetails": str(e)
|
||||
"errorDetails": str(e),
|
||||
}
|
||||
|
||||
def _get_layer_type_name(self, type_id: int) -> str:
|
||||
@@ -172,61 +168,58 @@ class BoardViewCommands:
|
||||
pcbnew.LT_SIGNAL: "signal",
|
||||
pcbnew.LT_POWER: "power",
|
||||
pcbnew.LT_MIXED: "mixed",
|
||||
pcbnew.LT_JUMPER: "jumper"
|
||||
pcbnew.LT_JUMPER: "jumper",
|
||||
}
|
||||
# Note: LT_USER was removed in KiCAD 9.0
|
||||
return type_map.get(type_id, "unknown")
|
||||
|
||||
def get_board_extents(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Get the bounding box extents of the board"""
|
||||
try:
|
||||
if not self.board:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No board is loaded",
|
||||
"errorDetails": "Load or create a board first"
|
||||
}
|
||||
|
||||
# Get unit preference (default to mm)
|
||||
unit = params.get("unit", "mm")
|
||||
scale = 1000000 if unit == "mm" else 25400000 # nm to mm or inch
|
||||
|
||||
# Get board bounding box
|
||||
board_box = self.board.GetBoardEdgesBoundingBox()
|
||||
|
||||
# Extract bounds in nanometers, then convert
|
||||
left = board_box.GetLeft() / scale
|
||||
top = board_box.GetTop() / scale
|
||||
right = board_box.GetRight() / scale
|
||||
bottom = board_box.GetBottom() / scale
|
||||
width = board_box.GetWidth() / scale
|
||||
height = board_box.GetHeight() / scale
|
||||
|
||||
# Get center point
|
||||
center_x = board_box.GetCenter().x / scale
|
||||
center_y = board_box.GetCenter().y / scale
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"extents": {
|
||||
"left": left,
|
||||
"top": top,
|
||||
"right": right,
|
||||
"bottom": bottom,
|
||||
"width": width,
|
||||
"height": height,
|
||||
"center": {
|
||||
"x": center_x,
|
||||
"y": center_y
|
||||
},
|
||||
"unit": unit
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting board extents: {str(e)}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Failed to get board extents",
|
||||
"errorDetails": str(e)
|
||||
}
|
||||
|
||||
def get_board_extents(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Get the bounding box extents of the board"""
|
||||
try:
|
||||
if not self.board:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "No board is loaded",
|
||||
"errorDetails": "Load or create a board first",
|
||||
}
|
||||
|
||||
# Get unit preference (default to mm)
|
||||
unit = params.get("unit", "mm")
|
||||
scale = 1000000 if unit == "mm" else 25400000 # nm to mm or inch
|
||||
|
||||
# Get board bounding box
|
||||
board_box = self.board.GetBoardEdgesBoundingBox()
|
||||
|
||||
# Extract bounds in nanometers, then convert
|
||||
left = board_box.GetLeft() / scale
|
||||
top = board_box.GetTop() / scale
|
||||
right = board_box.GetRight() / scale
|
||||
bottom = board_box.GetBottom() / scale
|
||||
width = board_box.GetWidth() / scale
|
||||
height = board_box.GetHeight() / scale
|
||||
|
||||
# Get center point
|
||||
center_x = board_box.GetCenter().x / scale
|
||||
center_y = board_box.GetCenter().y / scale
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"extents": {
|
||||
"left": left,
|
||||
"top": top,
|
||||
"right": right,
|
||||
"bottom": bottom,
|
||||
"width": width,
|
||||
"height": height,
|
||||
"center": {"x": center_x, "y": center_y},
|
||||
"unit": unit,
|
||||
},
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting board extents: {str(e)}")
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Failed to get board extents",
|
||||
"errorDetails": str(e),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user