KiBot/kibot/PcbDraw
Salvador E. Tropea ae450b15a4 [KiKit Present] Now using the detected git binary
- Also added repository URL detection
2022-12-06 13:36:35 -03:00
..
pybars [Populate] Added pybars and pymeta 2022-10-28 07:16:05 -03:00
svgpathtools [PcbDraw] Added option to control the size detection 2022-10-19 08:05:06 -03:00
README.md [KiKit Present] Now using the detected git binary 2022-12-06 13:36:35 -03:00
__init__.py [Package] Moved all resources to a central place 2022-10-19 13:05:56 -03:00
mdrenderer.py [Populate] Documented the changes 2022-10-28 06:30:17 -03:00
np.py [PcbDraw] Removed numpy as dependency 2022-10-18 08:56:29 -03:00
pcbnew_transition.py [PcbDraw] Included pcbnreTransition 2022-10-18 08:51:25 -03:00
plot.py [PcbDraw] Applied the SVG patch like the upstream 2022-10-24 13:02:37 -03:00
populate.py [Populate] Handle missing mistune properly 2022-10-28 07:51:54 -03:00
present.py [KiKit Present] Now using the detected git binary 2022-12-06 13:36:35 -03:00
unit.py [PcbDraw] Replaced `unit` code 2022-10-18 09:57:56 -03:00

README.md

PcbDraw code

Why?

  • Important dependency: PcbDraw is currently a core functionality of KiBot because its used for the pcb_print output
  • Increased number of dependencies: The upstream code pulls too much dependencies, some of them optional, others that we don't need. This is a constant problem.
  • Incompatible interface and behavior: This should be fixed now that 1.0.0 is out, but I don't agree with the idea of doing small changes just because they look more elegant.
  • Now integrable: This is one of the changes in 1.0.0, now the code is easier to call as module.
  • Repeated functionality: The render stuff is already implemented by KiAuto.

Details

Currently only the plot module is included.

unit.py

  • Replaced unit code.
    • So we have only one units conversion
    • I think the only difference is that KiBot code currently supports the locales decimal point

plot.py

  • Made the pcbdraw import relative
  • Disabled shrink_svg by default
    • Pulls a problematic dependency: numpy
    • We keep the margin addition
    • The svgpathtool computation can be optionally enabled (plotter.compute_bbox)
  • Changed calls to ComputeBoundingBox() to optionally use aBoardEdgesOnly=True
    • To get the same behavior as 0.9.0-5
    • This changes the size of the SVG to the size of the board
    • Controlled by plotter.kicad_bb_only_edge
    • We now also store the bbox in the plotter.boardsize member, avoiding repeated calls to KiCad API
  • Added no_warn_back option to disable warnings on the opposite side
@@ -813,6 +813,7 @@
     highlight: Callable[[str], bool] = lambda x: False # References to highlight
     remapping: Callable[[str, str, str], Tuple[str, str]] = lambda ref, lib, name: (lib, name)
     resistor_values: Dict[str, ResistorValue] = field(default_factory=dict)
+    no_warn_back: bool = False

     def render(self, plotter: PcbPlotter) -> None:
         self._plotter = plotter
@@ -848,7 +849,8 @@
         else:
             ret = self._create_component(lib, name, ref, value)
             if ret is None:
-                self._plotter.yield_warning("component", f"Component {lib}:{name} has not footprint.")
+                if name[-5:] != '.back' or not self.no_warn_back:
+                    self._plotter.yield_warning("component", f"Component {lib}:{name} has not footprint.")
                 return
             component_element, component_info = ret
             self._used_components[unique_name] = component_info
  • Added option to plot only the solder mask. The PCB_Print output uses it and plotting all the stuff looks stupid. The patch added too much nested conditionals so I moved the information to data structures. The patch looks big, but is just a mechanism to skip the unneeded layers.
diff --git a/kibot/PcbDraw/plot.py b/kibot/PcbDraw/plot.py
index af473cdb..f8990722 100644
--- a/kibot/PcbDraw/plot.py
+++ b/kibot/PcbDraw/plot.py
@@ -648,35 +648,44 @@ class PlotInterface:
         raise NotImplementedError("Plot interface wasn't implemented")
 
 
+SUBSTRATE_ELEMENTS = {
+    "board": (pcbnew.Edge_Cuts, pcbnew.Edge_Cuts),
+    "clad": (pcbnew.F_Mask, pcbnew.B_Mask),
+    "copper": (pcbnew.F_Cu, pcbnew.B_Cu),
+    "pads": (pcbnew.F_Cu, pcbnew.B_Cu),
+    "pads-mask": (pcbnew.F_Mask, pcbnew.B_Mask),
+    "silk": (pcbnew.F_SilkS, pcbnew.B_SilkS),
+    "outline": (pcbnew.Edge_Cuts, pcbnew.Edge_Cuts)
+}
+ELEMENTS_USED = (
+    # Normal plot, all the elements
+    ("board", "clad", "copper", "pads", "pads-mask", "silk", "outline"),
+    # Solder mask plot
+    ("board", "pads-mask")
+)
+
+
 @dataclass
 class PlotSubstrate(PlotInterface):
     drill_holes: bool = True
     outline_width: int = mm2ki(0.1)
+    only_mask: bool = False
 
     def render(self, plotter: PcbPlotter) -> None:
         self._plotter = plotter # ...so we don't have to pass it explicitly
+        SUBSTRATE_PROCESS = {
+            "board": self._process_baselayer,
+            "clad": self._process_layer,
+            "copper": self._process_layer,
+            "pads": self._process_layer,
+            "pads-mask": self._process_mask,
+            "silk": self._process_layer,
+            "outline": self._process_outline
+        }
 
         to_plot: List[PlotAction] = []
-        if plotter.render_back:
-            to_plot = [
-                PlotAction("board", [pcbnew.Edge_Cuts], self._process_baselayer),
-                PlotAction("clad", [pcbnew.B_Mask], self._process_layer),
-                PlotAction("copper", [pcbnew.B_Cu], self._process_layer),
-                PlotAction("pads", [pcbnew.B_Cu], self._process_layer),
-                PlotAction("pads-mask", [pcbnew.B_Mask], self._process_mask),
-                PlotAction("silk", [pcbnew.B_SilkS], self._process_layer),
-                PlotAction("outline", [pcbnew.Edge_Cuts], self._process_outline)
-            ]
-        else:
-            to_plot = [
-                PlotAction("board", [pcbnew.Edge_Cuts], self._process_baselayer),
-                PlotAction("clad", [pcbnew.F_Mask], self._process_layer),
-                PlotAction("copper", [pcbnew.F_Cu], self._process_layer),
-                PlotAction("pads", [pcbnew.F_Cu], self._process_layer),
-                PlotAction("pads-mask", [pcbnew.F_Mask], self._process_mask),
-                PlotAction("silk", [pcbnew.F_SilkS], self._process_layer),
-                PlotAction("outline", [pcbnew.Edge_Cuts], self._process_outline)
-            ]
+        for e in ELEMENTS_USED[self.only_mask]:
+            to_plot.append(PlotAction(e, [SUBSTRATE_ELEMENTS[e][plotter.render_back]], SUBSTRATE_PROCESS[e]))
 
         self._container = etree.Element("g", id="substrate")
         self._container.attrib["clip-path"] = "url(#cut-off)"
  • Fixed the collect_holes function to support KiCad 5
    • pad.GetDrillSizeX() and pad.GetDrillSizeY() are KiCad 6 specific, you must use pad.GetDrillSize()
    • KiCad 5 vias were skipped
    • Vias detection crashed on KiCad 5
diff --git a/kibot/PcbDraw/plot.py b/kibot/PcbDraw/plot.py
index f8990722..17f90185 100644
--- a/kibot/PcbDraw/plot.py
+++ b/kibot/PcbDraw/plot.py
@@ -626,13 +626,15 @@ def collect_holes(board: pcbnew.BOARD) -> List[Hole]:
             continue
         for pad in module.Pads():
             pos = pad.GetPosition()
+            drs = pad.GetDrillSize()
             holes.append(Hole(
                 position=(pos[0], pos[1]),
                 orientation=pad.GetOrientation(),
-                drillsize=(pad.GetDrillSizeX(), pad.GetDrillSizeY())
+                drillsize=(drs.x, drs.y)
             ))
+    via_type = 'VIA' if not isV6(KICAD_VERSION) else 'PCB_VIA'
     for track in board.GetTracks():
-        if not isinstance(track, pcbnew.PCB_VIA) or not isV6(KICAD_VERSION):
+        if track.GetClass() != via_type:
             continue
         pos = track.GetPosition()
         holes.append(Hole(
  • Changed pcbnewTransition to be locally included.

    • Just 2.8 kiB no worth the effort of pulling a dependency
  • Replaced numpy by a very simple code

    • Currently svgpathtool is disabled, it really needs numpy
    • numpy is used to:
      • Multiply matrices (1 line code)
      • Find the index of the smaller element (1 line code)
      • I added a replacemt for the array function, it just makes all matrix elements float
  • Allow constructing PcbPlotter() using an already loaded board

    • So we don't load it again
  • Changed the margin to be a tuple, so the user can control the margins individually

  • Added KiCad 6 SVG precision.

    • Fixes issues with Browsers
    • A plotter member controls the precision
    • We adjust the ki2svg and svg2ki converters before plotting
    • This idea was also adopted by upstream and the code adapted to the way the upstream implemented it

mdrenderer.py

No current changes

populate.py

  • Removed the command line interface, just because it pulls click
  • Added create_renderer. Just creates the correct MD/HTML mistune renderer
  • Made mdrenderer import relative. So we get the mdrenderer from the same dir, not the system
  • Replicated find_data_file (from plot.py) to avoid cross dependencies

present.py

This file comes from KiKit, but it has too much in common with populate.py.

  • Removed click import, unused
  • Removed the try in boardpage, too broad, doesn't help
  • Removed kikit import, _renderBoards must be implemented in a different way
  • Imported local pybars
  • Added source_front, source_back and source_gerbers to the boards. So now the images and gerbers come from outside.
  • Adapted Template._renderBoards to just copy the files (keeping the extensions)
  • Added listResources, with some changes to copyRelativeTo and _copyResources
  • The command used for git is now configurable