[sub-PCBs] Implemented the rectangle separation

- Notably faster
This commit is contained in:
Salvador E. Tropea 2022-12-27 12:37:33 -03:00
parent 6b432f3de6
commit b8dff52fa3
3 changed files with 65 additions and 8 deletions

View File

@ -89,6 +89,9 @@ class GS(object):
stackup = None
# Preprocessor definitions
cli_defines = {}
kikit_units_to_kicad = {'mm': pcbnew.IU_PER_MM, 'cm': 10*pcbnew.IU_PER_MM, 'dm': 100*pcbnew.IU_PER_MM,
'm': 1000*pcbnew.IU_PER_MM, 'mil': pcbnew.IU_PER_MILS, 'inch': 1000*pcbnew.IU_PER_MILS,
'in': 1000*pcbnew.IU_PER_MILS}
#
# Global defaults
#
@ -447,3 +450,7 @@ class GS(object):
return dir_name
logger.error('Missing resource directory `{}`'.format(name))
exit(WRONG_INSTALL)
@staticmethod
def create_eda_rect(tlx, tly, brx, bry):
return pcbnew.EDA_RECT(pcbnew.wxPoint(tlx, tly), pcbnew.wxSize(brx-tlx, bry-tly))

View File

@ -535,15 +535,20 @@ class PanelOptions(BaseOptions):
_num_regex = re.compile(r'([\d\.]+)(mm|cm|dm|m|mil|inch|in)')
_ang_regex = re.compile(r'([\d\.]+)(deg|°|rad)')
def add_units(self, ops, def_units=None):
def add_units(self, ops, def_units=None, convert=False):
if def_units is None:
def_units = self._parent._parent.units
for op in ops:
val = getattr(self, op)
_op = '_'+op
if val is None:
if convert:
setattr(self, _op, 0)
continue
if isinstance(val, (int, float)):
setattr(self, op, str(val)+def_units)
if convert:
setattr(self, _op, val*GS.kikit_units_to_kicad[def_units])
else:
m = PanelOptions._num_regex.match(val)
if m is None:
@ -555,6 +560,8 @@ class PanelOptions(BaseOptions):
num_d = None
if num_d is None:
raise KiPlotConfigurationError('Malformed number in `{}` ({})'.format(op, num))
if convert:
setattr(self, _op, num_d*GS.kikit_units_to_kicad[m.group(2)])
def add_angle(self, ops, def_units=None):
if def_units is None:

View File

@ -64,7 +64,8 @@ class SubPCBOptions(PanelOptions):
if (not self.reference and self.is_zero(self.tlx) and self.is_zero(self.tly) and self.is_zero(self.brx) and
self.is_zero(self.bry)):
raise KiPlotConfigurationError('No reference or rectangle specified for {} sub-PCB'.format(self.name))
self.add_units(('tlx', 'tly', 'brx', 'bry'), self.units)
self.add_units(('tlx', 'tly', 'brx', 'bry'), self.units, convert=True)
self.board_rect = GS.create_eda_rect(self._tlx, self._tly, self._brx, self._bry)
def get_separate_source(self):
if self.reference:
@ -86,7 +87,6 @@ class SubPCBOptions(PanelOptions):
run_command(cmd)
# Load this board
GS.load_board(dest, forced=True)
self._excl_by_sub_pcb = set()
# Now reflect the changes in the list of components
if comps_hash:
logger.debug('Removing components outside the sub-PCB')
@ -103,22 +103,65 @@ class SubPCBOptions(PanelOptions):
self._excl_by_sub_pcb.add(c)
logger.debugl(2, '- Removing '+c)
def _remove_items(self, iter):
""" Remove items outside the rectangle.
If the item has width (shapes and tracks) we discard it.
This produces something closer to KiKit. """
for m in iter:
with_width = hasattr(m, 'GetWidth')
if with_width:
width = m.GetWidth()
m.SetWidth(0)
if not self.board_rect.Contains(m.GetBoundingBox()):
GS.board.Remove(m)
self._removed.append(m)
if with_width:
m.SetWidth(width)
def _remove_modules(self, iter):
""" Remove modules outside the rectangle.
Footprints are added to the list of references to exclude.
We also check their position, not their BBox. """
for m in iter:
if not self.board_rect.Contains(m.GetPosition()):
GS.board.Remove(m)
self._removed.append(m)
self._excl_by_sub_pcb.add(m.GetReference())
def remove_outside(self):
self._removed = []
self._remove_modules(GS.get_modules())
self._remove_items(GS.board.GetDrawings())
self._remove_items(GS.board.GetTracks())
self._remove_items(list(GS.board.Zones()))
def apply(self, comps_hash):
if True:
self._excl_by_sub_pcb = set()
if self.reference:
self.separate_board(comps_hash)
else:
# Using a rectangle
self.remove_outside()
def unload_board(self, comps_hash):
# Undo the sub-PCB: just reload the PCB
GS.load_board(forced=True)
def restore_removed(self):
""" Restore the stuff we removed from the board """
for o in self._removed:
GS.board.Add(o)
def revert(self, comps_hash):
if self.reference:
self.unload_board(comps_hash)
else:
self.restore_removed()
# Restore excluded components
logger.debug('Restoring components outside the sub-PCB')
for c in self._excl_by_sub_pcb:
comps_hash[c].included = True
def revert(self, comps_hash):
if True:
self.unload_board(comps_hash)
class BaseVariant(RegVariant):
def __init__(self):