From 3dbebda168354c7b39e803e2b22b78f109148d52 Mon Sep 17 00:00:00 2001 From: qu1ck Date: Fri, 4 Sep 2020 15:58:29 -0700 Subject: [PATCH] Fix GetCustomShapeAsPolygon and add a unit test Fixes #5497 --- pcbnew/swig/pad.i | 4 +- qa/data/custom_pads.kicad_pcb | 116 ++++++++++++++++++++++++++++++++++ qa/data/custom_pads.kicad_prl | 71 +++++++++++++++++++++ qa/data/custom_pads.kicad_pro | 59 +++++++++++++++++ qa/testcases/test_003_pads.py | 34 ++++++++++ 5 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 qa/data/custom_pads.kicad_pcb create mode 100644 qa/data/custom_pads.kicad_prl create mode 100644 qa/data/custom_pads.kicad_pro create mode 100644 qa/testcases/test_003_pads.py diff --git a/pcbnew/swig/pad.i b/pcbnew/swig/pad.i index 492206fa94..9ef82d9ca9 100644 --- a/pcbnew/swig/pad.i +++ b/pcbnew/swig/pad.i @@ -43,9 +43,9 @@ raise TypeError("Arguments not recognized.") # GetCustomShapeAsPolygon() is the old accessor to get custom shapes - def GetCustomShapeAsPolygon(self): + def GetCustomShapeAsPolygon(self, layer=UNDEFINED_LAYER): polygon_set = SHAPE_POLY_SET() - self.MergePrimitivesAsPolygon(polygon_set) + self.MergePrimitivesAsPolygon(polygon_set, layer) return polygon_set %} } diff --git a/qa/data/custom_pads.kicad_pcb b/qa/data/custom_pads.kicad_pcb new file mode 100644 index 0000000000..77cae8b27b --- /dev/null +++ b/qa/data/custom_pads.kicad_pcb @@ -0,0 +1,116 @@ +(kicad_pcb (version 20200829) (generator pcbnew) + + (general + (thickness 1.6) + ) + + (paper "A4") + (layers + (0 "F.Cu" signal) + (31 "B.Cu" signal) + (32 "B.Adhes" user) + (33 "F.Adhes" user) + (34 "B.Paste" user) + (35 "F.Paste" user) + (36 "B.SilkS" user) + (37 "F.SilkS" user) + (38 "B.Mask" user) + (39 "F.Mask" user) + (40 "Dwgs.User" user) + (41 "Cmts.User" user) + (42 "Eco1.User" user) + (43 "Eco2.User" user) + (44 "Edge.Cuts" user) + (45 "Margin" user) + (46 "B.CrtYd" user) + (47 "F.CrtYd" user) + (48 "B.Fab" user) + (49 "F.Fab" user) + ) + + (setup + (pcbplotparams + (layerselection 0x010fc_ffffffff) + (usegerberextensions false) + (usegerberattributes true) + (usegerberadvancedattributes true) + (creategerberjobfile true) + (svguseinch false) + (svgprecision 6) + (excludeedgelayer true) + (linewidth 0.150000) + (plotframeref false) + (viasonmask false) + (mode 1) + (useauxorigin false) + (hpglpennumber 1) + (hpglpenspeed 20) + (hpglpendiameter 15.000000) + (psnegative false) + (psa4output false) + (plotreference true) + (plotvalue true) + (plotinvisibletext false) + (sketchpadsonfab false) + (subtractmaskfromsilk false) + (outputformat 1) + (mirror false) + (drillshape 1) + (scaleselection 1) + (outputdirectory "") + ) + ) + + + (net 0 "") + + (module "Jumper:SolderJumper-2_P1.3mm_Open_TrianglePad1.0x1.5mm" (layer "F.Cu") (tedit 5A64794F) (tstamp 45f71005-ae4b-4884-b6a3-eb67eece4a66) + (at 55 55) + (descr "SMD Solder Jumper, 1x1.5mm Triangular Pads, 0.3mm gap, open") + (tags "solder jumper open") + (attr exclude_from_pos_files exclude_from_bom) + (fp_text reference "SB1" (at 0 -1.8) (layer "F.SilkS") + (effects (font (size 1 1) (thickness 0.15))) + (tstamp 920d4adc-c967-4af0-8187-11eef43919bd) + ) + (fp_text value "SolderJumper-2_P1.3mm_Open_TrianglePad1.0x1.5mm" (at 0 1.9) (layer "F.Fab") + (effects (font (size 1 1) (thickness 0.15))) + (tstamp 9cbcb47a-cb17-49df-98a5-2ee0e09b9db2) + ) + (fp_line (start -1.4 1) (end -1.4 -1) (layer "F.SilkS") (width 0.12) (tstamp 421b6989-a0a8-4ca9-aba2-096742614893)) + (fp_line (start 1.4 -1) (end 1.4 1) (layer "F.SilkS") (width 0.12) (tstamp 9265368b-fb29-4426-9ff3-5e450c586e6f)) + (fp_line (start 1.4 1) (end -1.4 1) (layer "F.SilkS") (width 0.12) (tstamp abada1f4-9fef-41eb-a371-594b0c5ff159)) + (fp_line (start -1.4 -1) (end 1.4 -1) (layer "F.SilkS") (width 0.12) (tstamp fba79c0f-cbb9-4f82-9dc8-56afbd8e27fc)) + (fp_line (start 1.65 1.25) (end -1.65 1.25) (layer "F.CrtYd") (width 0.05) (tstamp 267383d2-2581-47eb-8bca-88b2ba619d19)) + (fp_line (start -1.65 -1.25) (end 1.65 -1.25) (layer "F.CrtYd") (width 0.05) (tstamp 5102f76a-c878-44bc-9d75-bfd6582ac9e4)) + (fp_line (start -1.65 -1.25) (end -1.65 1.25) (layer "F.CrtYd") (width 0.05) (tstamp 711987ed-ea86-4296-af4a-9fbd6d608e10)) + (fp_line (start 1.65 1.25) (end 1.65 -1.25) (layer "F.CrtYd") (width 0.05) (tstamp a9960b84-0016-42a2-9d36-98c678386c44)) + (pad "1" smd custom (at -0.725 0) (size 0.3 0.3) (layers "F.Cu" "F.Mask") + (zone_connect 2) + (options (clearance outline) (anchor rect)) + (primitives + (gr_poly (pts + (xy -0.5 -0.75) + (xy 0.5 -0.75) + (xy 1 0) + (xy 0.5 0.75) + (xy -0.5 0.75) +) (width 0)) + ) (tstamp e59d970d-034f-45b4-8ede-1d68d925f15c)) + (pad "2" smd custom (at 0.725 0) (size 0.3 0.3) (layers "F.Cu" "F.Mask") + (zone_connect 2) + (options (clearance outline) (anchor rect)) + (primitives + (gr_poly (pts + (xy -0.65 -0.75) + (xy 0.5 -0.75) + (xy 0.5 0.75) + (xy -0.65 0.75) + (xy -0.15 0) +) (width 0)) + ) (tstamp 9ac25e5d-8bf8-408a-8326-0eace0c875f1)) + ) + + (gr_rect (start 50 50) (end 100 100) (layer "Edge.Cuts") (width 0.05) (tstamp 140d541f-fd45-4b34-9b91-43b10f43e3f9)) + +) diff --git a/qa/data/custom_pads.kicad_prl b/qa/data/custom_pads.kicad_prl new file mode 100644 index 0000000000..f1d50d6ac7 --- /dev/null +++ b/qa/data/custom_pads.kicad_prl @@ -0,0 +1,71 @@ +{ + "board": { + "active_layer": 0, + "active_layer_preset": "", + "hidden_nets": [], + "high_contrast_mode": 0, + "net_color_mode": 1, + "opacity": { + "pads": 1.0, + "tracks": 1.0, + "vias": 1.0, + "zones": 1.0 + }, + "selection_filter": { + "dimensions": true, + "footprints": true, + "graphics": true, + "keepouts": true, + "lockedItems": true, + "otherItems": true, + "pads": true, + "text": true, + "tracks": true, + "vias": true, + "zones": true + }, + "visible_items": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 36, + 37 + ], + "visible_layers": "7ffff_ffffffff" + }, + "meta": { + "filename": "custom_pads.kicad_prl", + "version": 2 + }, + "project": { + "files": [] + } +} diff --git a/qa/data/custom_pads.kicad_pro b/qa/data/custom_pads.kicad_pro new file mode 100644 index 0000000000..464bea79ad --- /dev/null +++ b/qa/data/custom_pads.kicad_pro @@ -0,0 +1,59 @@ +{ + "board": { + "layer_presets": [] + }, + "boards": [], + "cvpcb": { + "equivalence_files": [] + }, + "libraries": { + "pinned_footprint_libs": [], + "pinned_symbol_libs": [] + }, + "meta": { + "filename": "custom_pads.kicad_pro", + "version": 1 + }, + "net_settings": { + "classes": [ + { + "bus_width": 12.0, + "clearance": 0.2, + "diff_pair_gap": 0.25, + "diff_pair_via_gap": 0.25, + "diff_pair_width": 0.2, + "line_style": 0, + "microvia_diameter": 0.3, + "microvia_drill": 0.1, + "name": "Default", + "pcb_color": "rgba(0, 0, 0, 0.000)", + "schematic_color": "rgba(0, 0, 0, 0.000)", + "track_width": 0.25, + "via_diameter": 0.8, + "via_drill": 0.4, + "wire_width": 6.0 + } + ], + "meta": { + "version": 0 + }, + "net_colors": null + }, + "pcbnew": { + "last_paths": { + "gencad": "", + "idf": "", + "netlist": "", + "specctra_dsn": "", + "step": "", + "vmrl": "" + }, + "page_layout_descr_file": "" + }, + "schematic": { + "legacy_lib_dir": "", + "legacy_lib_list": [] + }, + "sheets": [], + "text_variables": {} +} diff --git a/qa/testcases/test_003_pads.py b/qa/testcases/test_003_pads.py new file mode 100644 index 0000000000..893341042b --- /dev/null +++ b/qa/testcases/test_003_pads.py @@ -0,0 +1,34 @@ +import unittest +import pcbnew + +class TestPads(unittest.TestCase): + + def setUp(self): + self.pcb = pcbnew.LoadBoard("data/custom_pads.kicad_pcb") + + def test_custom_pads_outline(self): + custom_pad1 = self.pcb.FindModuleByReference("SB1").Pads()[0] + expected_polygons = [[ + [1000000, 0], + [500000, 750000], + [-500000, 750000], + [-500000, -750000], + [500000, -750000] + ]] + # test accessor without layer + polygon_set = custom_pad1.GetCustomShapeAsPolygon() + self.assertEqual(expected_polygons, self.parse_polygon_set(polygon_set)) + # test accessor with layer + polygon_set = custom_pad1.GetCustomShapeAsPolygon(pcbnew.F_Cu) + self.assertEqual(expected_polygons, self.parse_polygon_set(polygon_set)) + + def parse_polygon_set(self, polygon_set): + result = [] + for polygon_index in range(polygon_set.OutlineCount()): + outline = polygon_set.Outline(polygon_index) + parsed_outline = [] + for point_index in range(outline.PointCount()): + point = outline.CPoint(point_index) + parsed_outline.append([point.x, point.y]) + result.append(parsed_outline) + return result