def buildFraming(preset, panel): """ Build frame according to the preset and return cuts """ try: type = preset["type"] if type == "none": return [] if type == "railstb": panel.makeRailsTb(preset["width"]) return [] if type == "railslr": panel.makeRailsLr(preset["width"]) return [] if type == "frame": cuts = panel.makeFrame(preset["width"], preset["hspace"], preset["vspace"]) return cuts if preset["cuts"] else [] if type == "tightframe": panel.makeTightFrame(preset["width"], preset["slotwidth"], preset["hspace"], preset["vspace"]) panel.boardSubstrate.removeIslands() return [] raise PresetError(f"Unknown type '{type}' of frame specification.") except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'framing'")
def buildText(preset, panel): """ Build text according to the preset """ try: type = preset["type"] if type == "none": return if type == "simple": origin = resolveAnchor(preset["anchor"])( panel.boardSubstrate.boundingBox()) origin += wxPoint(preset["hoffset"], preset["voffset"]) panel.addText(text=preset["text"], position=origin, orientation=preset["orientation"], width=preset["width"], height=preset["height"], thickness=preset["thickness"], hJustify=preset["hjustify"], vJustify=preset["vjustify"], layer=preset["layer"]) return raise PresetError(f"Unknown type '{type}' of text specification.") except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'text'")
def buildTabs(properties, panel, substrates, boundarySubstrates): """ Build tabs for the substrates in between the boards. Return a list of cuts. """ try: type = properties["type"] if type == "none": return [] if type == "fixed": panel.clearTabsAnnotations() panel.buildTabAnnotationsFixed(properties["hcount"], properties["vcount"], properties["hwidth"], properties["vwidth"], properties["mindistance"], boundarySubstrates) return panel.buildTabsFromAnnotations() if type == "spacing": panel.clearTabsAnnotations() panel.buildTabAnnotationsSpacing(properties["spacing"], properties["hwidth"], properties["vwidth"], boundarySubstrates) return panel.buildTabsFromAnnotations() if type == "corner": panel.clearTabsAnnotations() panel.buildTabAnnotationsCorners(properties["width"]) return panel.buildTabsFromAnnotations() if type == "full": return panel.buildFullTabs() if type == "annotation": return panel.buildTabsFromAnnotations() raise PresetError(f"Unknown type '{type}' of tabs specification.") except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'tabs'")
def validateSections(preset): """ Perform a logic validation of the given preset - e.g., if a style is applied, validate all required keys are present. Ignores excessive keys. """ VALID_SECTIONS = ["layout", "source", "tabs", "cuts", "framing", "tooling", "fiducials", "text", "post", "debug"] extraSections = set(preset.keys()).difference(VALID_SECTIONS) if len(extraSections) != 0: raise PresetError(f"Extra sections {', '.join(extraSections)} in preset") missingSections = set(VALID_SECTIONS).difference(preset.keys()) if len(missingSections) != 0: raise PresetError(f"Missing sections {', '.join(missingSections)} in preset")
def readVJustify(s): choices = { "top": EDA_TEXT_VJUSTIFY_T.GR_TEXT_VJUSTIFY_TOP, "center": EDA_TEXT_VJUSTIFY_T.GR_TEXT_VJUSTIFY_CENTER, "bottom": EDA_TEXT_VJUSTIFY_T.GR_TEXT_VJUSTIFY_BOTTOM } if s in choices: return choices[s] raise PresetError(f"'{s}' is not valid justification value")
def readHJustify(s): choices = { "left": EDA_TEXT_HJUSTIFY_T.GR_TEXT_HJUSTIFY_LEFT, "right": EDA_TEXT_HJUSTIFY_T.GR_TEXT_HJUSTIFY_RIGHT, "center": EDA_TEXT_HJUSTIFY_T.GR_TEXT_HJUSTIFY_CENTER } if s in choices: return choices[s] raise PresetError(f"'{s}' is not valid justification value")
def buildPostprocessing(preset, panel): """ Perform postprocessing operations """ try: type = preset["type"] if type != "auto": raise PresetError(f"Unknown type '{type}' of postprocessing specification.") if preset["millradius"] > 0: panel.addMillFillets(preset["millradius"]) if preset["copperfill"]: panel.copperFillNonBoardAreas() if preset["origin"]: origin = resolveAnchor(preset["origin"])(panel.boardSubstrate.boundingBox()) panel.setAuxiliaryOrigin(origin) panel.setGridOrigin(origin) except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'postprocessing'")
def buildBackBone(layout, panel, substrates, frameSpace): """ Append backbones to the panel. Return backbone cuts. """ try: return panel.renderBackbone(layout["vbackbone"], layout["hbackbone"], layout["vbonecut"], layout["hbonecut"]) except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'layout'")
def readSourceArea(specification, board): """ Extract source area based on preset and a board. """ try: type = specification["type"] tolerance = specification["tolerance"] if type == "auto": return expandRect(findBoardBoundingBox(board), tolerance) if type == "annotation": ref = specification["ref"] return expandRect(extractSourceAreaByAnnotation(board, ref), tolerance) if type == "rectangle": tl = wxPoint(specification["tlx"], specification["tly"]) br = wxPoint(specification["brx"], specification["bry"]) return expandRect(wxRect(tl, br), tolerance) raise PresetError(f"Unknown type '{type}' of source specification.") except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'source'")
def buildFiducials(preset, panel): """ Build tooling holes according to the preset """ try: type = preset["type"] if type == "none": return hoffset, voffset = preset["hoffset"], preset["voffset"] coppersize, opening = preset["coppersize"], preset["opening"] if type == "3fid": panel.addCornerFiducials(3, hoffset, voffset, coppersize, opening) return if type == "4fid": panel.addCornerFiducials(4, hoffset, voffset, coppersize, opening) return raise PresetError(f"Unknown type '{type}' of fiducial specification.") except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'fiducials'")
def readBool(s): if isinstance(s, bool): return s if isinstance(s, str): sl = str(s).lower() if sl in ["1", "true", "yes"]: return True if sl in ["0", "false", "no"]: return False raise PresetError(f"Uknown boolean value '{s}'") raise RuntimeError(f"Got {s}, expected boolean value")
def buildLayout(layout, panel, sourceBoard, sourceArea): """ Build layout for the boards - e.g., make a grid out of them. Return the list of created substrates. """ try: type = layout["type"] if type in ["grid"]: placementClass = getPlacementClass(layout["alternation"]) return panel.makeGrid( boardfile=sourceBoard, sourceArea=sourceArea, rows=layout["rows"], cols=layout["cols"], destination=wxPointMM(50, 50), rotation=layout["rotation"], verSpace=layout["vspace"], horSpace=layout["hspace"], placementClass=placementClass, netRenamePattern=layout["renamenet"], refRenamePattern=layout["renameref"]) raise PresetError(f"Unknown type '{type}' of layout specification.") except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'layout'")
def buildTooling(preset, panel): """ Build tooling holes according to the preset """ try: type = preset["type"] if type == "none": return hoffset, voffset = preset["hoffset"], preset["voffset"] diameter = preset["size"] paste = preset["paste"] if type == "3hole": panel.addCornerTooling(3, hoffset, voffset, diameter, paste) return if type == "4hole": panel.addCornerTooling(4, hoffset, voffset, diameter, paste) return raise PresetError(f"Unknown type '{type}' of tooling specification.") except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'tooling'")
def makeCuts(properties, panel, cuts, ignoreOffset): """ Perform cuts """ try: type = properties["type"] if type == "none": return if type == "vcuts": panel.makeVCuts(cuts, properties["cutcurves"]) panel.setVCutLayer(properties["layer"]) panel.setVCutClearance(properties["clearance"]) elif type == "mousebites": offset = 0 if ignoreOffset else properties["offset"] panel.makeMouseBites(cuts, properties["drill"], properties["spacing"], offset, properties["prolong"]) else: raise PresetError(f"Unknown type '{type}' of cuts specification.") except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'cuts'")
def frameOffset(framing): try: type = framing["type"] if type == "none": return None, None if type == "railstb": return framing["vspace"], None if type == "railslr": return None, framing["hspace"] return framing["vspace"], framing["hspace"] except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'framing'")
def buildDebugAnnotation(preset, panel): """ Add debug annotation to the panel """ try: if preset["drawPartitionLines"]: panel.debugRenderPartitionLines() if preset["drawBackboneLines"]: panel.debugRenderBackboneLines() if preset["drawboxes"]: panel.debugRenderBoundingBoxes() except KeyError as e: raise PresetError(f"Missing parameter '{e}' in section 'debug'")
def loadPreset(path): """ Load a preset from path and perform simple validation on its structure. Automatically resolves built-in styles (prefixed with :, omitting suffix). """ if path.startswith(":"): presetName = path path = os.path.join(PRESET_LIB, path[1:] + ".json") if not os.path.exists(path): raise RuntimeError(f"Uknown built-in preset '{presetName}'") try: with open(path, "r") as f: preset = commentjson.load(f) validatePresetLayout(preset) return preset except OSError as e: raise RuntimeError(f"Cannot open preset '{path}'") except PresetError as e: raise PresetError(f"{path}: {e}")
def validateChoice(sectionName, section, key, choices): if section[key] not in choices: c = ", ".join(choices) raise PresetError( f"'{section[key]}' is not allowed for {sectionName}.{key}. Use one of {c}." )
def validatePresetLayout(preset): if not isinstance(preset, dict): raise PresetError("Preset is not a dictionary") for name, section in preset.items(): if not isinstance(section, dict): raise PresetError(f"Section '{name}' is not a dictionary")