chore: set up pre-commit framework with general hooks
Add .pre-commit-config.yaml with pre-commit-hooks v5.0.0 (trailing whitespace, end-of-file fixer, yaml/json checks, large file guard, merge conflict detection). Add minimal pyproject.toml. Auto-fix trailing whitespace and missing end-of-file newlines across the codebase. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -752,14 +752,14 @@ class ComponentCommands:
|
||||
count = params.get("count")
|
||||
reference_prefix = params.get("referencePrefix", "U")
|
||||
value = params.get("value")
|
||||
|
||||
|
||||
if not component_id or not count:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Missing parameters",
|
||||
"errorDetails": "componentId and count are required"
|
||||
}
|
||||
|
||||
|
||||
if pattern == "grid":
|
||||
start_position = params.get("startPosition")
|
||||
rows = params.get("rows")
|
||||
@@ -768,21 +768,21 @@ class ComponentCommands:
|
||||
spacing_y = params.get("spacingY")
|
||||
rotation = params.get("rotation", 0)
|
||||
layer = params.get("layer", "F.Cu")
|
||||
|
||||
|
||||
if not start_position or not rows or not columns or not spacing_x or not spacing_y:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Missing grid parameters",
|
||||
"errorDetails": "For grid pattern, startPosition, rows, columns, spacingX, and spacingY are required"
|
||||
}
|
||||
|
||||
|
||||
if rows * columns != count:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Invalid grid parameters",
|
||||
"errorDetails": "rows * columns must equal count"
|
||||
}
|
||||
|
||||
|
||||
placed_components = self._place_grid_array(
|
||||
component_id,
|
||||
start_position,
|
||||
@@ -795,7 +795,7 @@ class ComponentCommands:
|
||||
rotation,
|
||||
layer
|
||||
)
|
||||
|
||||
|
||||
elif pattern == "circular":
|
||||
center = params.get("center")
|
||||
radius = params.get("radius")
|
||||
@@ -803,14 +803,14 @@ class ComponentCommands:
|
||||
angle_step = params.get("angleStep")
|
||||
rotation_offset = params.get("rotationOffset", 0)
|
||||
layer = params.get("layer", "F.Cu")
|
||||
|
||||
|
||||
if not center or not radius or not angle_step:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Missing circular parameters",
|
||||
"errorDetails": "For circular pattern, center, radius, and angleStep are required"
|
||||
}
|
||||
|
||||
|
||||
placed_components = self._place_circular_array(
|
||||
component_id,
|
||||
center,
|
||||
@@ -823,7 +823,7 @@ class ComponentCommands:
|
||||
rotation_offset,
|
||||
layer
|
||||
)
|
||||
|
||||
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
@@ -844,7 +844,7 @@ class ComponentCommands:
|
||||
"message": "Failed to place component array",
|
||||
"errorDetails": str(e)
|
||||
}
|
||||
|
||||
|
||||
def align_components(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Align multiple components along a line or distribute them evenly"""
|
||||
try:
|
||||
@@ -859,14 +859,14 @@ class ComponentCommands:
|
||||
alignment = params.get("alignment", "horizontal") # horizontal, vertical, or edge
|
||||
distribution = params.get("distribution", "none") # none, equal, or spacing
|
||||
spacing = params.get("spacing")
|
||||
|
||||
|
||||
if not references or len(references) < 2:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Missing references",
|
||||
"errorDetails": "At least two component references are required"
|
||||
}
|
||||
|
||||
|
||||
# Find all referenced components
|
||||
components = []
|
||||
for ref in references:
|
||||
@@ -878,7 +878,7 @@ class ComponentCommands:
|
||||
"errorDetails": f"Could not find component: {ref}"
|
||||
}
|
||||
components.append(module)
|
||||
|
||||
|
||||
# Perform alignment based on selected option
|
||||
if alignment == "horizontal":
|
||||
self._align_components_horizontally(components, distribution, spacing)
|
||||
@@ -929,7 +929,7 @@ class ComponentCommands:
|
||||
"message": "Failed to align components",
|
||||
"errorDetails": str(e)
|
||||
}
|
||||
|
||||
|
||||
def duplicate_component(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Duplicate an existing component"""
|
||||
try:
|
||||
@@ -944,14 +944,14 @@ class ComponentCommands:
|
||||
new_reference = params.get("newReference")
|
||||
position = params.get("position")
|
||||
rotation = params.get("rotation")
|
||||
|
||||
|
||||
if not reference or not new_reference:
|
||||
return {
|
||||
"success": False,
|
||||
"message": "Missing parameters",
|
||||
"errorDetails": "reference and newReference are required"
|
||||
}
|
||||
|
||||
|
||||
# Find the source component
|
||||
source = self.board.FindFootprintByReference(reference)
|
||||
if not source:
|
||||
@@ -960,7 +960,7 @@ class ComponentCommands:
|
||||
"message": "Component not found",
|
||||
"errorDetails": f"Could not find component: {reference}"
|
||||
}
|
||||
|
||||
|
||||
# Check if new reference already exists
|
||||
if self.board.FindFootprintByReference(new_reference):
|
||||
return {
|
||||
@@ -968,7 +968,7 @@ class ComponentCommands:
|
||||
"message": "Reference already exists",
|
||||
"errorDetails": f"A component with reference {new_reference} already exists"
|
||||
}
|
||||
|
||||
|
||||
# Create new footprint with the same properties
|
||||
new_module = pcbnew.FOOTPRINT(self.board)
|
||||
# For KiCAD 9.x compatibility, use SetFPID instead of SetFootprintName
|
||||
@@ -976,13 +976,13 @@ class ComponentCommands:
|
||||
new_module.SetValue(source.GetValue())
|
||||
new_module.SetReference(new_reference)
|
||||
new_module.SetLayer(source.GetLayer())
|
||||
|
||||
|
||||
# Copy pads and other items
|
||||
for pad in source.Pads():
|
||||
new_pad = pcbnew.PAD(new_module)
|
||||
new_pad.Copy(pad)
|
||||
new_module.Add(new_pad)
|
||||
|
||||
|
||||
# Set position if provided, otherwise use offset from original
|
||||
if position:
|
||||
scale = 1000000 if position.get("unit", "mm") == "mm" else 25400000
|
||||
@@ -993,17 +993,17 @@ class ComponentCommands:
|
||||
# Offset by 5mm
|
||||
source_pos = source.GetPosition()
|
||||
new_module.SetPosition(pcbnew.VECTOR2I(source_pos.x + 5000000, source_pos.y))
|
||||
|
||||
|
||||
# Set rotation if provided, otherwise use same as original
|
||||
if rotation is not None:
|
||||
rotation_angle = pcbnew.EDA_ANGLE(rotation, pcbnew.DEGREES_T)
|
||||
new_module.SetOrientation(rotation_angle)
|
||||
else:
|
||||
new_module.SetOrientation(source.GetOrientation())
|
||||
|
||||
|
||||
# Add to board
|
||||
self.board.Add(new_module)
|
||||
|
||||
|
||||
# Get final position in mm
|
||||
pos = new_module.GetPosition()
|
||||
|
||||
@@ -1031,32 +1031,32 @@ class ComponentCommands:
|
||||
"message": "Failed to duplicate component",
|
||||
"errorDetails": str(e)
|
||||
}
|
||||
|
||||
def _place_grid_array(self, component_id: str, start_position: Dict[str, Any],
|
||||
|
||||
def _place_grid_array(self, component_id: str, start_position: Dict[str, Any],
|
||||
rows: int, columns: int, spacing_x: float, spacing_y: float,
|
||||
reference_prefix: str, value: str, rotation: float, layer: str) -> List[Dict[str, Any]]:
|
||||
"""Place components in a grid pattern and return the list of placed components"""
|
||||
placed = []
|
||||
|
||||
|
||||
# Convert spacing to nm
|
||||
unit = start_position.get("unit", "mm")
|
||||
scale = 1000000 if unit == "mm" else 25400000 # mm or inch to nm
|
||||
spacing_x_nm = int(spacing_x * scale)
|
||||
spacing_y_nm = int(spacing_y * scale)
|
||||
|
||||
|
||||
# Get layer ID
|
||||
layer_id = self.board.GetLayerID(layer)
|
||||
|
||||
|
||||
for row in range(rows):
|
||||
for col in range(columns):
|
||||
# Calculate position
|
||||
x = start_position["x"] + (col * spacing_x)
|
||||
y = start_position["y"] + (row * spacing_y)
|
||||
|
||||
|
||||
# Generate reference
|
||||
index = row * columns + col + 1
|
||||
component_reference = f"{reference_prefix}{index}"
|
||||
|
||||
|
||||
# Place component
|
||||
result = self.place_component({
|
||||
"componentId": component_id,
|
||||
@@ -1066,37 +1066,37 @@ class ComponentCommands:
|
||||
"rotation": rotation,
|
||||
"layer": layer
|
||||
})
|
||||
|
||||
|
||||
if result["success"]:
|
||||
placed.append(result["component"])
|
||||
|
||||
|
||||
return placed
|
||||
|
||||
def _place_circular_array(self, component_id: str, center: Dict[str, Any],
|
||||
radius: float, count: int, angle_start: float,
|
||||
angle_step: float, reference_prefix: str,
|
||||
|
||||
def _place_circular_array(self, component_id: str, center: Dict[str, Any],
|
||||
radius: float, count: int, angle_start: float,
|
||||
angle_step: float, reference_prefix: str,
|
||||
value: str, rotation_offset: float, layer: str) -> List[Dict[str, Any]]:
|
||||
"""Place components in a circular pattern and return the list of placed components"""
|
||||
placed = []
|
||||
|
||||
|
||||
# Get unit
|
||||
unit = center.get("unit", "mm")
|
||||
|
||||
|
||||
for i in range(count):
|
||||
# Calculate angle for this component
|
||||
angle = angle_start + (i * angle_step)
|
||||
angle_rad = math.radians(angle)
|
||||
|
||||
|
||||
# Calculate position
|
||||
x = center["x"] + (radius * math.cos(angle_rad))
|
||||
y = center["y"] + (radius * math.sin(angle_rad))
|
||||
|
||||
|
||||
# Generate reference
|
||||
component_reference = f"{reference_prefix}{i+1}"
|
||||
|
||||
|
||||
# Calculate rotation (pointing outward from center)
|
||||
component_rotation = angle + rotation_offset
|
||||
|
||||
|
||||
# Place component
|
||||
result = self.place_component({
|
||||
"componentId": component_id,
|
||||
@@ -1106,114 +1106,114 @@ class ComponentCommands:
|
||||
"rotation": component_rotation,
|
||||
"layer": layer
|
||||
})
|
||||
|
||||
|
||||
if result["success"]:
|
||||
placed.append(result["component"])
|
||||
|
||||
|
||||
return placed
|
||||
|
||||
def _align_components_horizontally(self, components: List[pcbnew.FOOTPRINT],
|
||||
|
||||
def _align_components_horizontally(self, components: List[pcbnew.FOOTPRINT],
|
||||
distribution: str, spacing: Optional[float]) -> None:
|
||||
"""Align components horizontally and optionally distribute them"""
|
||||
if not components:
|
||||
return
|
||||
|
||||
|
||||
# Find the average Y coordinate
|
||||
y_sum = sum(module.GetPosition().y for module in components)
|
||||
y_avg = y_sum // len(components)
|
||||
|
||||
|
||||
# Sort components by X position
|
||||
components.sort(key=lambda m: m.GetPosition().x)
|
||||
|
||||
|
||||
# Set Y coordinate for all components
|
||||
for module in components:
|
||||
pos = module.GetPosition()
|
||||
module.SetPosition(pcbnew.VECTOR2I(pos.x, y_avg))
|
||||
|
||||
|
||||
# Handle distribution if requested
|
||||
if distribution == "equal" and len(components) > 1:
|
||||
# Get leftmost and rightmost X coordinates
|
||||
x_min = components[0].GetPosition().x
|
||||
x_max = components[-1].GetPosition().x
|
||||
|
||||
|
||||
# Calculate equal spacing
|
||||
total_space = x_max - x_min
|
||||
spacing_nm = total_space // (len(components) - 1)
|
||||
|
||||
|
||||
# Set X positions with equal spacing
|
||||
for i in range(1, len(components) - 1):
|
||||
pos = components[i].GetPosition()
|
||||
new_x = x_min + (i * spacing_nm)
|
||||
components[i].SetPosition(pcbnew.VECTOR2I(new_x, pos.y))
|
||||
|
||||
|
||||
elif distribution == "spacing" and spacing is not None:
|
||||
# Convert spacing to nanometers
|
||||
spacing_nm = int(spacing * 1000000) # assuming mm
|
||||
|
||||
|
||||
# Set X positions with the specified spacing
|
||||
x_current = components[0].GetPosition().x
|
||||
for i in range(1, len(components)):
|
||||
pos = components[i].GetPosition()
|
||||
x_current += spacing_nm
|
||||
components[i].SetPosition(pcbnew.VECTOR2I(x_current, pos.y))
|
||||
|
||||
def _align_components_vertically(self, components: List[pcbnew.FOOTPRINT],
|
||||
|
||||
def _align_components_vertically(self, components: List[pcbnew.FOOTPRINT],
|
||||
distribution: str, spacing: Optional[float]) -> None:
|
||||
"""Align components vertically and optionally distribute them"""
|
||||
if not components:
|
||||
return
|
||||
|
||||
|
||||
# Find the average X coordinate
|
||||
x_sum = sum(module.GetPosition().x for module in components)
|
||||
x_avg = x_sum // len(components)
|
||||
|
||||
|
||||
# Sort components by Y position
|
||||
components.sort(key=lambda m: m.GetPosition().y)
|
||||
|
||||
|
||||
# Set X coordinate for all components
|
||||
for module in components:
|
||||
pos = module.GetPosition()
|
||||
module.SetPosition(pcbnew.VECTOR2I(x_avg, pos.y))
|
||||
|
||||
|
||||
# Handle distribution if requested
|
||||
if distribution == "equal" and len(components) > 1:
|
||||
# Get topmost and bottommost Y coordinates
|
||||
y_min = components[0].GetPosition().y
|
||||
y_max = components[-1].GetPosition().y
|
||||
|
||||
|
||||
# Calculate equal spacing
|
||||
total_space = y_max - y_min
|
||||
spacing_nm = total_space // (len(components) - 1)
|
||||
|
||||
|
||||
# Set Y positions with equal spacing
|
||||
for i in range(1, len(components) - 1):
|
||||
pos = components[i].GetPosition()
|
||||
new_y = y_min + (i * spacing_nm)
|
||||
components[i].SetPosition(pcbnew.VECTOR2I(pos.x, new_y))
|
||||
|
||||
|
||||
elif distribution == "spacing" and spacing is not None:
|
||||
# Convert spacing to nanometers
|
||||
spacing_nm = int(spacing * 1000000) # assuming mm
|
||||
|
||||
|
||||
# Set Y positions with the specified spacing
|
||||
y_current = components[0].GetPosition().y
|
||||
for i in range(1, len(components)):
|
||||
pos = components[i].GetPosition()
|
||||
y_current += spacing_nm
|
||||
components[i].SetPosition(pcbnew.VECTOR2I(pos.x, y_current))
|
||||
|
||||
|
||||
def _align_components_to_edge(self, components: List[pcbnew.FOOTPRINT], edge: str) -> None:
|
||||
"""Align components to the specified edge of the board"""
|
||||
if not components:
|
||||
return
|
||||
|
||||
|
||||
# Get board bounds
|
||||
board_box = self.board.GetBoardEdgesBoundingBox()
|
||||
left = board_box.GetLeft()
|
||||
right = board_box.GetRight()
|
||||
top = board_box.GetTop()
|
||||
bottom = board_box.GetBottom()
|
||||
|
||||
|
||||
# Align based on specified edge
|
||||
if edge == "left":
|
||||
for module in components:
|
||||
|
||||
Reference in New Issue
Block a user