Skip to content

Commit 70e2a5e

Browse files
committed
Add padstack support for kicad 9
Fixes #471
1 parent 011bdd3 commit 70e2a5e

File tree

2 files changed

+67
-21
lines changed

2 files changed

+67
-21
lines changed

InteractiveHtmlBom/ecad/easyeda.py

-2
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ def parse_track(self, shape):
114114
return layer, segments_json
115115

116116
def parse_via(self, shape):
117-
print('Parsing via', shape)
118117
shape = self.tilda_split(shape)
119118
assert len(shape) >= 5, 'Invalid via ' + str(shape)
120119
x, y = self.normalize(shape[0]), self.normalize(shape[1])
@@ -412,7 +411,6 @@ def parse_shapes(self, shapes):
412411
if parse_func:
413412
layer, json_list = parse_func(shape[1])
414413
drawings.setdefault(layer, []).extend(json_list)
415-
print(shape[0], layer, json_list)
416414
if shape[0] == 'VIA':
417415
drawings.setdefault(self.BOT_COPPER_LAYER, []).extend(json_list)
418416
if shape[0] == 'LIB':

InteractiveHtmlBom/ecad/kicad.py

+67-19
Original file line numberDiff line numberDiff line change
@@ -435,15 +435,45 @@ def get_all_drawings(self):
435435
return drawings
436436

437437
def parse_pad(self, pad):
438-
# type: (pcbnew.PAD) -> dict | None
439-
layers_set = list(pad.GetLayerSet().Seq())
438+
# type: (pcbnew.PAD) -> list[dict]
439+
custom_padstack = False
440+
outer_layers = [(pcbnew.F_Cu, "F"), (pcbnew.B_Cu, "B")]
441+
if hasattr(pad, 'Padstack'):
442+
padstack = pad.Padstack() # type: pcbnew.PADSTACK
443+
layers_set = list(padstack.LayerSet().Seq())
444+
custom_padstack = (
445+
padstack.Mode() != padstack.MODE_NORMAL or \
446+
padstack.UnconnectedLayerMode() == padstack.UNCONNECTED_LAYER_MODE_REMOVE_ALL
447+
)
448+
else:
449+
layers_set = list(pad.GetLayerSet().Seq())
440450
layers = []
441-
if pcbnew.F_Cu in layers_set:
442-
layers.append("F")
443-
if pcbnew.B_Cu in layers_set:
444-
layers.append("B")
451+
for layer, letter in outer_layers:
452+
if layer in layers_set:
453+
layers.append(letter)
454+
if not layers:
455+
return []
456+
457+
if custom_padstack:
458+
pads = []
459+
for layer, letter in outer_layers:
460+
if layer in layers_set and pad.FlashLayer(layer):
461+
pad_dict = self.parse_pad_layer(pad, layer)
462+
pad_dict["layers"] = [letter]
463+
pads.append(pad_dict)
464+
return pads
465+
else:
466+
pad_dict = self.parse_pad_layer(pad, layers_set[0])
467+
pad_dict["layers"] = layers
468+
return [pad_dict]
469+
470+
def parse_pad_layer(self, pad, layer):
471+
# type: (pcbnew.PAD, int) -> dict | None
445472
pos = self.normalize(pad.GetPosition())
446-
size = self.normalize(pad.GetSize())
473+
try:
474+
size = self.normalize(pad.GetSize(layer))
475+
except TypeError:
476+
size = self.normalize(pad.GetSize())
447477
angle = self.normalize_angle(pad.GetOrientation())
448478
shape_lookup = {
449479
pcbnew.PAD_SHAPE_RECT: "rect",
@@ -458,27 +488,36 @@ def parse_pad(self, pad):
458488
shape_lookup[pcbnew.PAD_SHAPE_CUSTOM] = "custom"
459489
if hasattr(pcbnew, "PAD_SHAPE_CHAMFERED_RECT"):
460490
shape_lookup[pcbnew.PAD_SHAPE_CHAMFERED_RECT] = "chamfrect"
461-
shape = shape_lookup.get(pad.GetShape(), "")
491+
try:
492+
pad_shape = pad.GetShape(layer)
493+
except TypeError:
494+
pad_shape = pad.GetShape()
495+
shape = shape_lookup.get(pad_shape, "")
462496
if shape == "":
463-
self.logger.info("Unsupported pad shape %s, skipping.",
464-
pad.GetShape())
497+
self.logger.info("Unsupported pad shape %s, skipping.", pad_shape)
465498
return None
466499
pad_dict = {
467-
"layers": layers,
468500
"pos": pos,
469501
"size": size,
470502
"angle": angle,
471503
"shape": shape
472504
}
473505
if shape == "custom":
474-
polygon_set = pad.GetCustomShapeAsPolygon()
506+
polygon_set = pcbnew.SHAPE_POLY_SET()
507+
try:
508+
pad.MergePrimitivesAsPolygon(layer, polygon_set)
509+
except TypeError:
510+
pad.MergePrimitivesAsPolygon(polygon_set)
475511
if polygon_set.HasHoles():
476512
self.logger.warn('Detected holes in custom pad polygons')
477513
pad_dict["polygons"] = self.parse_poly_set(polygon_set)
478514
if shape == "trapezoid":
479515
# treat trapezoid as custom shape
480516
pad_dict["shape"] = "custom"
481-
delta = self.normalize(pad.GetDelta())
517+
try:
518+
delta = self.normalize(pad.GetDelta(layer))
519+
except TypeError:
520+
delta = self.normalize(pad.GetDelta())
482521
pad_dict["polygons"] = [[
483522
[size[0] / 2 + delta[1] / 2, size[1] / 2 - delta[0] / 2],
484523
[-size[0] / 2 - delta[1] / 2, size[1] / 2 + delta[0] / 2],
@@ -487,10 +526,17 @@ def parse_pad(self, pad):
487526
]]
488527

489528
if shape in ["roundrect", "chamfrect"]:
490-
pad_dict["radius"] = pad.GetRoundRectCornerRadius() * 1e-6
529+
try:
530+
pad_dict["radius"] = pad.GetRoundRectCornerRadius(layer) * 1e-6
531+
except TypeError:
532+
pad_dict["radius"] = pad.GetRoundRectCornerRadius() * 1e-6
491533
if shape == "chamfrect":
492-
pad_dict["chamfpos"] = pad.GetChamferPositions()
493-
pad_dict["chamfratio"] = pad.GetChamferRectRatio()
534+
try:
535+
pad_dict["chamfpos"] = pad.GetChamferPositions(layer)
536+
pad_dict["chamfratio"] = pad.GetChamferRectRatio(layer)
537+
except TypeError:
538+
pad_dict["chamfpos"] = pad.GetChamferPositions()
539+
pad_dict["chamfratio"] = pad.GetChamferRectRatio()
494540
if hasattr(pcbnew, 'PAD_ATTRIB_PTH'):
495541
through_hole_attributes = [pcbnew.PAD_ATTRIB_PTH,
496542
pcbnew.PAD_ATTRIB_NPTH]
@@ -507,7 +553,10 @@ def parse_pad(self, pad):
507553
else:
508554
pad_dict["type"] = "smd"
509555
if hasattr(pad, "GetOffset"):
510-
pad_dict["offset"] = self.normalize(pad.GetOffset())
556+
try:
557+
pad_dict["offset"] = self.normalize(pad.GetOffset(layer))
558+
except TypeError:
559+
pad_dict["offset"] = self.normalize(pad.GetOffset())
511560
if self.config.include_nets:
512561
pad_dict["net"] = pad.GetNetname()
513562

@@ -561,8 +610,7 @@ def parse_footprints(self):
561610
# footprint pads
562611
pads = []
563612
for p in f.Pads():
564-
pad_dict = self.parse_pad(p)
565-
if pad_dict is not None:
613+
for pad_dict in self.parse_pad(p):
566614
pads.append((p.GetPadName(), pad_dict))
567615

568616
if pads:

0 commit comments

Comments
 (0)