Beispiel #1
0
    def get_modules_bounding_box(modules):
        # get the pivot bounding box
        bounding_box = modules[0].mod.GetFootprintRect()
        top = bounding_box.GetTop()
        bottom = bounding_box.GetBottom()
        left = bounding_box.GetLeft()
        right = bounding_box.GetRight()
        for mod in modules:
            mod_box = mod.mod.GetFootprintRect()
            top = min(top, mod_box.GetTop())
            bottom = max(bottom, mod_box.GetBottom())
            left = min(left, mod_box.GetLeft())
            right = max(right, mod_box.GetRight())

        position = pcbnew.wxPoint(left, top)
        size = pcbnew.wxSize(right - left, bottom - top)
        bounding_box = pcbnew.EDA_RECT(position, size)
        return bounding_box
Beispiel #2
0
def getFootprintRect(module, upright=True):
    """ module.GetFootprintRect() includes edge items
    in calculating bounding rectangle instead of the just the
    pads. This function does the module rectangle using
    only the pads. By default it calculates the true
    footprint size of the module before it was rotated.
    """
    area = PN.EDA_RECT()
    area.SetOrigin(module.GetPosition())
    area.SetEnd(module.GetPosition())
    rot_center = module.GetPosition()
    if upright:
        rot_angle = -(module.GetOrientation())
    else:
        rot_angle = 0
    for pad in module.Pads():
        pad_bb = pad.GetBoundingBox().GetBoundingBoxRotated(
            rot_center, rot_angle)
        area.Merge(pad_bb)
    return area
def get_bounding_box(module_list):
    top = None
    bottom = None
    left = None
    right = None
    for mod in module_list:
        if top == None:
            bounding_box = mod.GetBoundingBox()
            top = bounding_box.GetTop()
            bottom = bounding_box.GetBottom()
            left = bounding_box.GetLeft()
            right = bounding_box.GetRight()
        else:
            mod_box = mod.GetBoundingBox()
            top = min(top, mod_box.GetTop())
            bottom = max(bottom, mod_box.GetBottom())
            left = min(left, mod_box.GetLeft())
            right = max(right, mod_box.GetRight())

    position = pcbnew.wxPoint(left, top)
    size = pcbnew.wxSize(right - left, bottom - top)
    bounding_box = pcbnew.EDA_RECT(position, size)
    return bounding_box
Beispiel #4
0
def get_bounding_box_of_modules(module_list):
    """ get bounding box encompasing all modules """
    top = None
    bottom = None
    left = None
    right = None
    for mod in module_list:
        if top is None:
            bounding_box = mod.GetFootprintRect()
            top = bounding_box.GetTop()
            bottom = bounding_box.GetBottom()
            left = bounding_box.GetLeft()
            right = bounding_box.GetRight()
        else:
            mod_box = mod.GetFootprintRect()
            top = min(top, mod_box.GetTop())
            bottom = max(bottom, mod_box.GetBottom())
            left = min(left, mod_box.GetLeft())
            right = max(right, mod_box.GetRight())

    position = pcbnew.wxPoint(left, top)
    size = pcbnew.wxSize(right - left, bottom - top)
    bounding_box = pcbnew.EDA_RECT(position, size)
    return bounding_box
Beispiel #5
0
    def checkTracks(self):
        ##Check vias collisions with all tracks
        #self.clearance = 0 #TBF
        self.clearance = self.boardObj.GetDesignSettings().GetDefault(
        ).GetClearance()
        #lboard = self.boardObj.ComputeBoundingBox(False)
        #origin = lboard.GetPosition()
        # Create an initial rectangle: all is set to "REASON_NO_SIGNAL"
        # get a margin to avoid out of range
        l_clearance = self.clearance + self.viaSize  #+ self.size
        #wxLogDebug(str(l_clearance),True)
        #x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1
        #y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1
        viasToRemove = []
        removed = False
        expansion = 2  # extra expansion to fix HitTest
        for track in self.boardObj.GetTracks():
            #wx.LogMessage(str(self.viaPointsSafe))
            #wx.LogMessage(str(pad.GetPosition()))
            #local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2)
            local_offset = max(track.GetClearance(),
                               self.clearance) + (self.viaSize / 2)
            #wxLogDebug(str(max_size),True)
            #max_size = max(pad.GetSize().x, pad.GetSize().y)

            #start_x = int(floor(((pad.GetPosition().x - (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))
            #stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))

            #start_y = int(floor(((pad.GetPosition().y - (max_size / 2.0 + local_offset)) - origin.y) / l_clearance))
            #stop_y = int(ceil(((pad.GetPosition().y + (max_size / 2.0 + local_offset)) - origin.y) / l_clearance))

            #for x in range(start_x, stop_x + 1):
            #    for y in range(start_y, stop_y + 1):
            #wx.LogMessage(str(getTrackAngleRadians(track)))
            angle = abs(math.degrees(getTrackAngleRadians(track)))
            if (angle > 15
                    and angle < 75) or (angle > 105 and angle < 165) or (
                        angle > 195 and angle < 255) or (angle > 285
                                                         and angle < 345):
                expansion = 1.4  # extra expansion to fix HitTest
                #wx.LogMessage(str(angle)+'::'+str(expansion))
            else:
                expansion = 2.0  # extra expansion to fix HitTest
                #wx.LogMessage(str(angle)+'::'+str(expansion))
            for viaPos in self.viaPointsSafe:
                if 1:  #try:
                    #if isinstance(rectangle[x][y], ViaObject):
                    #start_rect = wxPoint(origin.x + (l_clearance * x) - local_offset,
                    #                     origin.y + (l_clearance * y) - local_offset)
                    #start_rect = pcbnew.wxPoint(viaPos[0] + (l_clearance * viaPos[0]) - local_offset,
                    #                    viaPos[1] + (l_clearance * viaPos[1]) - local_offset)
                    start_rect = pcbnew.wxPoint(
                        viaPos[0] - local_offset * expansion,
                        viaPos[1] - local_offset * expansion)
                    size_rect = pcbnew.wxSize(2 * expansion * local_offset,
                                              2 * expansion * local_offset)
                    wxLogDebug(
                        str(pcbnew.ToMM(start_rect)) + '::' +
                        str(pcbnew.ToMM(size_rect)), debug)
                    #wxLogDebug(str(track.GetNetCode()),True)
                    #wxLogDebug(str(self.viaNetId),True)
                    #wxLogDebug(str(type(track)),True)
                    if track.GetNetCode() != self.viaNetId or type(
                            track) != pcbnew.TRACK:  #PCB_VIA_T:
                        #wxLogDebug('here',True)
                        #if track.HitTest(pcbnew.EDA_RECT(start_rect, size_rect), False):
                        aContained = False
                        aAccuracy = 0
                        if track.HitTest(
                                pcbnew.EDA_RECT(start_rect, size_rect),
                                aContained, aAccuracy):
                            #rectangle[x][y] = self.REASON_PAD
                            wxLogDebug('Hit on Track: viaPos:' + str(viaPos),
                                       debug)
                            #self.viaPointsSafe.pop(i)
                            #self.viaPointsSafe.remove(viaPos)
                            viasToRemove.append(viaPos)
                            removed = True
                        #else:
                        #    viaPSafe.append(viaPos)
                else:  #except:
                    wx.LogMessage("exception on Processing all tracks...")
                #i+=1
            #self.viaPointSafe = viaPSafe
        #wx.LogMessage(str(viasToRemove))
        newPoints = [p for p in self.viaPointsSafe if p not in viasToRemove]
        #wx.LogMessage(str(newPoints))
        #wx.LogMessage(str(len(newPoints)))
        self.viaPointsSafe = newPoints
        return removed
Beispiel #6
0
    def checkPads(self):
        ##Check vias collisions with all pads => all pads on all layers
        #wxPrint("Processing all pads...")
        #self.clearance = 0 #TBF
        self.clearance = self.boardObj.GetDesignSettings().GetDefault(
        ).GetClearance()
        #lboard = self.boardObj.ComputeBoundingBox(False)
        #origin = lboard.GetPosition()
        # Create an initial rectangle: all is set to "REASON_NO_SIGNAL"
        # get a margin to avoid out of range
        l_clearance = self.clearance + self.viaSize  #+ self.size
        #x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1
        #y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1
        viasToRemove = []
        removed = False
        expansion = 1.6  # extra expansion to fix HitTest
        for pad in self.boardObj.GetPads():
            #wx.LogMessage(str(self.viaPointsSafe))
            #wx.LogMessage(str(pad.GetPosition()))
            #local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2)
            local_offset = max(pad.GetClearance(),
                               self.clearance) + (self.viaSize / 2)
            max_size = max(pad.GetSize().x, pad.GetSize().y)

            #start_x = int(floor(((pad.GetPosition().x - (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))
            #stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))

            #start_y = int(floor(((pad.GetPosition().y - (max_size / 2.0 + local_offset)) - origin.y) / l_clearance))
            #stop_y = int(ceil(((pad.GetPosition().y + (max_size / 2.0 + local_offset)) - origin.y) / l_clearance))

            #for x in range(start_x, stop_x + 1):
            #    for y in range(start_y, stop_y + 1):
            for viaPos in self.viaPointsSafe:
                if 1:  #try:
                    #if isinstance(rectangle[x][y], ViaObject):
                    #start_rect = wxPoint(origin.x + (l_clearance * x) - local_offset,
                    #                     origin.y + (l_clearance * y) - local_offset)
                    #start_rect = pcbnew.wxPoint(viaPos[0] + (l_clearance * viaPos[0]) - local_offset,
                    #                    viaPos[1] + (l_clearance * viaPos[1]) - local_offset)
                    start_rect = pcbnew.wxPoint(
                        viaPos[0] - local_offset * expansion,
                        viaPos[1] - local_offset * expansion)
                    size_rect = pcbnew.wxSize(2 * expansion * local_offset,
                                              2 * expansion * local_offset)
                    wxLogDebug(
                        str(pcbnew.ToMM(start_rect)) + '::' +
                        str(pcbnew.ToMM(size_rect)), debug)
                    if pad.HitTest(pcbnew.EDA_RECT(start_rect, size_rect),
                                   False):
                        #rectangle[x][y] = self.REASON_PAD
                        wxLogDebug('Hit on Pad: viaPos:' + str(viaPos), debug)
                        #self.viaPointsSafe.pop(i)
                        #self.viaPointsSafe.remove(viaPos)
                        viasToRemove.append(viaPos)
                        removed = True
                    #else:
                    #    viaPSafe.append(viaPos)
                else:  #except:
                    wx.LogMessage("exception on Processing all pads...")
                #i+=1
            #self.viaPointSafe = viaPSafe
        #wx.LogMessage(str(viasToRemove))
        newPoints = [p for p in self.viaPointsSafe if p not in viasToRemove]
        #wx.LogMessage(str(newPoints))
        #wx.LogMessage(str(len(newPoints)))
        self.viaPointsSafe = newPoints
        return removed
    def __init__(self, board, pivot_module_reference, only_within_boundingbox):
        """ initialize base object needed to replicate module layout, track layout and zone layout"""
        # take care of different APIs
        if hasattr(pcbnew, "LAYER_ID_COUNT"):
            pcbnew.PCB_LAYER_ID_COUNT = pcbnew.LAYER_ID_COUNT

        self.board = board

        self.only_within_bbox = only_within_boundingbox

        # load all modules
        self.modules = board.GetModules()

        # find pivodmodule
        self.pivot_mod = board.FindModuleByReference(pivot_module_reference)

        # find sheet ID on which the module is on
        self.pivot_sheet_id = get_sheet_id(self.pivot_mod)

        # while at it, get the pivot module ID
        self.pivot_mod_id = get_module_id(self.pivot_mod)

        # find all modules on the same sheet
        self.pivot_modules = []
        self.pivot_modules_id = []
        for mod in self.modules:
            module_id = get_module_id(mod)
            sheet_id = get_sheet_id(mod)
            if sheet_id == self.pivot_sheet_id:
                self.pivot_modules.append(mod)
                self.pivot_modules_id.append(module_id)

        # find all sheets to replicate
        self.sheets_to_clone = []
        for mod in self.modules:
            module_id = get_module_id(mod)
            sheet_id = get_sheet_id(mod)
            if (module_id == self.pivot_mod_id) and (sheet_id != self.pivot_sheet_id) \
                    and (sheet_id not in self.sheets_to_clone):
                self.sheets_to_clone.append(sheet_id)
        pass

        # get bounding bounding box of all modules
        bounding_box = self.pivot_mod.GetBoundingBox()
        top = bounding_box.GetTop()
        bottom = bounding_box.GetBottom()
        left = bounding_box.GetLeft()
        right = bounding_box.GetRight()
        for mod in self.pivot_modules:
            mod_box = mod.GetBoundingBox()
            top = min(top, mod_box.GetTop())
            bottom = max(bottom, mod_box.GetBottom())
            left = min(left, mod_box.GetLeft())
            right = max(right, mod_box.GetRight())

        position = pcbnew.wxPoint(left, top)
        size = pcbnew.wxSize(right - left, bottom - top)
        self.pivot_bounding_box = pcbnew.EDA_RECT(position, size)

        # find all tracks within the pivot bounding box
        all_tracks = board.GetTracks()
        # keep only tracks that are within our bounding box
        self.pivot_tracks = []
        for track in all_tracks:
            track_bb = track.GetBoundingBox()
            if only_within_boundingbox:
                if self.pivot_bounding_box.Contains(track_bb):
                    self.pivot_tracks.append(track)
            else:
                if self.pivot_bounding_box.Intersects(track_bb):
                    self.pivot_tracks.append(track)
        # get all zones
        all_zones = []
        for zoneid in range(board.GetAreaCount()):
            all_zones.append(board.GetArea(zoneid))
        # find all zones which are completely within the pivot bounding box
        self.pivot_zones = []
        for zone in all_zones:
            zone_bb = zone.GetBoundingBox()
            if only_within_boundingbox:
                if self.pivot_bounding_box.Contains(zone_bb):
                    self.pivot_zones.append(zone)
            else:
                if self.pivot_bounding_box.Intersects(zone_bb):
                    self.pivot_zones.append(zone)
Beispiel #8
0
def clone():
    """ Clone traces, zones, drawing, and location of equivalent components from selected components
  """
    __helper = _helper()

    # PCB file specification
    sch_rootfile = ''  #r"C:\Projects\svn\Cricket\ECG\Rev0\PCB_KiCad\ModECG.sch"
    sch_dir = ''
    sch_root = ''
    pcb_file = ''

    # clone Zone configuration
    #   cloneZoneLoc help identify which clone zone amount many
    cloneZoneLayer = pcbnew.Cmts_User  # one of pcbnew.LAYER_ID
    cloneZoneLoc = None  # a pcbnew.wxPoint

    # Clone configuration
    cloneX = None
    cloneY = None
    cloneArrayXdim = None
    cloneArraydX = None
    cloneArraydY = None
    cloneHorMirror = None  # True or False
    cloneVerMirror = None  # True or False

    #if len(sys.argv)>=2:
    #  sch_rootfile = sys.argv[1]
    #else:
    #  s = raw_input("Please enter LIB_DIR [" + sch_rootfile + "] ")
    #  if s: sch_rootfile = s

    if not sch_rootfile:
        board = pcbnew.GetBoard()
        cur_pcb_file = board.GetFileName()
        cur_pcb_file = cur_pcb_file.replace('/', os.sep)
        sch_rootfile = os.path.splitext(cur_pcb_file)[0] + '.sch'
        del board, cur_pcb_file
    else:
        sch_rootfile = sch_rootfile.replace('\\', os.sep)

    if not sch_dir: sch_dir = os.path.dirname(sch_rootfile)
    if not sch_root: sch_root = os.path.basename(sch_rootfile)
    if not pcb_file: pcb_file = os.path.splitext(sch_root)[0] + '.kicad_pcb'

    ToUnit = ToInch if pcbnew.GetAbbreviatedUnitsLabel() == u'in' else ToMM
    FromUnit = FromInch if pcbnew.GetAbbreviatedUnitsLabel(
    ) == u'in' else FromMM

    if cloneZoneLoc is not None: cloneZoneLoc = FromUnit(cloneZoneLoc)

    del sch_rootfile

    #
    # Figure out switch PCB file we going to work on, and load it if not
    # already loaded
    #
    board = pcbnew.GetBoard()
    cur_pcb_file = board.GetFileName()
    cur_pcb_file = cur_pcb_file.replace('/', os.sep)
    pcb_fullpath = sch_dir + os.sep + pcb_file
    if pcb_fullpath.lower() != cur_pcb_file.lower():
        board = pcbnew.LoadBoard(pcb_file)
    else:
        pcb_file = os.path.basename(cur_pcb_file)
        sch_dir = os.path.dirname(cur_pcb_file)
    del pcb_fullpath, cur_pcb_file
    print 'This clone script will apply on', pcb_file

    #
    # Find source areas for cloning
    #
    print 'Finding Cmts.User Zones for clone source'
    srcZones = []
    for i in range(0, board.GetAreaCount()):
        zone = board.GetArea(i)
        if zone.GetLayer() == cloneZoneLayer:
            srcZone = None
            if cloneZoneLoc is None:
                srcZone = zone
            elif zone.HitTestInsideZone(cloneZoneLoc):
                srcZone = zone

            if srcZone is not None:
                srcZones.append(srcZone)
                rect = srcZone.GetBoundingBox()
                print "Found source zone #" + str(len(srcZones)) \
                    , "within", ToUnit(rect.GetOrigin()) \
                    , "to", ToUnit(rect.GetEnd()) \

    if len(srcZones) == 0:
        print "Can't find any source zone of %s Layer to clone" \
            % pcbnew.BOARD_GetStandardLayerName(cloneZoneLayer)
        return

    if len(srcZones) > 1:
        i = int(raw_input("Please choose a zone #"))
        srcZone = srcZones[i]
    else:
        srcZone = srcZones[0]
    del srcZones
    srcRect = srcZone.GetBoundingBox()

    boardRect = board.ComputeBoundingBox(True)

    # Find components in srcRect and collect them into srcModules
    srcModules = {}  # Dict of { Reference : pcbnew.MODULE }
    for module in board.GetModules():
        if module.HitTest(srcRect):
            ref = module.GetReference()
            srcModules[ref] = module

    print "Found following %d components in clone zone:" % len(srcModules)
    print "  " + ', '.join(srcModules.keys()) + "\n"

    #
    # Extract REFToPath from schematic for figure out equivalent component for replicate
    #
    print "Read schematic to find equivalent components for clone", sch_root
    eesch = eeschematic.schematic(sch_dir, True)
    eesch.LoadAllScheets(sch_root)
    #pp.pprint(eesch.GetSheets())
    eesch.LinkSheets()
    #pp.pprint(eesch.GetSheets())

    #eesch.GenREFToPathDict()
    #pp.pprint(eesch._REFToARPath)
    #pp.pprint(eesch._IDsToRefs)

    #
    # Figure out equivalent components
    #
    print "Figure out equivalent components and group them by channels"
    # Build AR Tree which contains equivalent REFs map
    arTree = eesch.BuildEqvRefsARTree(
        map(lambda x: x.encode(), srcModules.keys()))
    #pp.pprint(arTree._tree)

    # Group eqv REFs into channels
    channels = arTree.groupByChannel(srcModules.keys())

    # Show WARNING to user if there is any
    for arPath, warnMsg in channels['WARN'].iteritems():
        print "*** WARN ***:", eesch.convertARPathToUserPath(arPath), warnMsg

    channels = channels['MAP']

    # Ask user what channel to clone ==> cloneChs (list of string)
    if len(channels) == 0:
        print "*** ERROR *** Cannot find equivalent components for cloning"
        # TODO: Get a customized REFtoREF map from user some how
        cloneChs = []

    elif len(channels) > 1:
        channel_names = channels.keys()
        channel_names = map(lambda x: [x, eesch.convertARPathToUserPath(x)],
                            channel_names)
        channel_names.sort(key=lambda x: x[1])
        print "Found", len(channel_names), "channels: "
        for ch_idx, ch_name in enumerate(channel_names):
            print " ", ch_idx, " -- ", ch_name[1]

        tmp = __helper.getInputList(
            "Enter set of channels will be cloned [all channels if empty]: ")

        if tmp:
            cloneChs = []
            for ch in tmp.split(' '):
                if ch:
                    cloneChs.append(channel_names[int(ch)][0])
        else:
            cloneChs = map(lambda x: x[0], channel_names)

    else:
        cloneChs = channels.keys()

    # ASK USER WHICH COMPONENT CAN BE USE AS CLONE ORIGIN ==> RefOfOrigin,
    # ModuleOfOrigin
    # (string)
    RefOfOrigin = raw_input(
        "Which component can be use as clone origin? [None]")
    if RefOfOrigin.lower() in ('none'):
        RefOfOrigin = ''
        ModuleOfOrigin = None
    else:
        RefOfOrigin = RefOfOrigin.decode()
        if not RefOfOrigin in srcModules:
            print "*** ERROR *** Cannot find " + RefOfOrigin + " in list of components for cloning"
            RefOfOrigin = ''
            ModuleOfOrigin = None
            return
        ModuleOfOrigin = board.FindModuleByReference(RefOfOrigin)
        cloneX = srcRect.GetPosition().x
        cloneY = srcRect.GetPosition().y

    if not RefOfOrigin:
        # ASK USER HOW TO PUT CLONE IN TO ARRAY ==> cloneArrayXdim,
        # cloneArraydX, cloneArraydY (int)
        ask = set()
        if cloneArrayXdim is None:
            ask.add('Xdim')
            cloneArrayXdim = round(math.sqrt(len(cloneChs)))

        if cloneArraydX is None:
            ask.add('dY')
            cloneArraydX = srcRect.GetWidth() + FromInch(0.1)

        if cloneArraydY is None:
            ask.add('dX')
            cloneArraydY = srcRect.GetHeight() + FromInch(0.1)

        if len(cloneChs) > 1:
            if 'Xdim' in ask:
                tmp = __helper.getInputList(
                    "Enter number of clones in X direction [%d]:" \
                    % (cloneArrayXdim))
                if tmp: cloneArrayXdim = int(tmp)

            tmp = ['', '']
            if cloneArrayXdim < len(cloneChs):
                if cloneArrayXdim > 1:
                    #Ask for X and Y spacing between clone
                    if ('dX' in ask) or ('dY' in ask):
                        tmp = __helper.getInputList(
                            "X and Y spacing between clones [%f, %f]: " \
                            % (ToUnit(cloneArraydX), ToUnit(cloneArraydY)) )
                        tmp = tmp.split(' ') + ['', '']
                else:
                    #Ask for Y spacing between clone
                    if ('dY' in ask):
                        tmp = __helper.getInputList(
                            "Y spacing between clones [%f]: " \
                            % (ToUnit(cloneArraydY)) )
                        tmp = ['', tmp]
            else:
                if cloneArrayXdim > 1:
                    # Ask for X spacing between clone
                    if ('dX' in ask):
                        tmp = __helper.getInputList(
                            "X spacing between clones [%f]: " %
                            (ToUnit(cloneArraydX)))
                        tmp = [tmp, '']

            if tmp[0]: cloneArraydX = FromUnit(float(tmp[0]))
            if tmp[1]: cloneArraydY = FromUnit(float(tmp[1]))

        # ASK USER CLONE START LOCATION ==> cloneX, cloneY (int)
        ask = False
        if cloneX is None:
            ask = True
            cloneX = srcRect.GetPosition().x + cloneArraydX

        if cloneY is None:
            ask = True
            cloneY = srcRect.GetPosition().y

        if ask:
            tmp = __helper.getInputList("Clone start point (%f, %f): " %
                                        (ToUnit(cloneX), ToUnit(cloneY)))
            tmp = tmp.split(' ') + ['', '']

            if tmp[0]: cloneX = FromUnit(float(tmp[0]))
            if tmp[1]: cloneY = FromUnit(float(tmp[1]))

        if (cloneVerMirror is None) or (cloneHorMirror is None):
            tmp = raw_input("Ver/Hor/Dia Mirror? (Ver, Hor, Dia, [None]) :")
            if not tmp: tmp = 'no'
            tmp2 = tmp.lower()
            if tmp2 in ('no', 'none'):
                cloneVerMirror = False
                cloneHorMirror = False
            elif tmp2 in ('ver', 'vertical'):
                cloneHorMirror = False
                cloneVerMirror = True
            elif tmp2 in ('hor', 'horizontal'):
                cloneHorMirror = True
                cloneVerMirror = False
            elif tmp2 in ('dia', 'diagonal'):
                cloneVerMirror = True
                cloneHorMirror = True
            else:
                print "*** ERROR *** Not recognized answer of", tmp
                return

    # ASK USER TO CLEANUP THE CLONING AREAS ==> CleanUp (True/False)
    CleanUp = raw_input(
        "Do you want to cleanup the clone target areas? (Yes/[No]/Cleanup Only) "
    ).lower()
    NoClone = False
    if not CleanUp:
        CleanUp = False
    elif CleanUp in ('no'):
        CleanUp = False
    elif CleanUp in ("yes"):
        CleanUp = True
    elif CleanUp in ("cleanup only"):
        CleanUp = True
        NoClone = True
    else:
        print "*** ERROR *** Not recognized answer of", CleanUp
        CleanUp = False
        return

    # Collecting tracks that belong clone zone
    tracks = board.GetTracks()
    allTracks = []
    srcTracks = []
    for track in tracks:
        if track.HitTest(srcRect):
            srcTracks.append(track)
        else:
            allTracks.append(track)
    print "Found %d track in clone zone" % len(srcTracks)

    # Collecting Zones that belong clone zone
    srcZoneIdx = board.GetAreaIndex(srcZone)
    allZones = []
    srcZones = []
    for i in range(0, board.GetAreaCount()):
        if i != srcZoneIdx:
            zone = board.GetArea(i)
            if zone != srcZone:
                if zone.HitTest(srcRect):
                    srcZones.append(zone)
                else:
                    allZones.append(zone)
    print "Found %d zones in clone zone" % len(srcZones)

    # Collecting Drawings that belong clone zone
    srcDrawings = []
    allDraws = []
    for drawing in board.GetDrawings():
        if drawing.HitTest(srcRect):
            srcDrawings.append(drawing)
        else:
            allDraws.append(drawing)
    print "Found %d drawings in clone zone" % len(srcDrawings)

    #
    # Start to do cloning work
    #
    if not RefOfOrigin:
        curCloneX = cloneX - srcRect.GetPosition().x
        curCloneY = cloneY - cloneArraydY - srcRect.GetPosition().y

    srcSize = pcbnew.wxSize(srcRect.GetWidth(), srcRect.GetHeight())
    srcSize90Deg = pcbnew.wxSize(srcRect.GetHeight(), srcRect.GetWidth())

    #CloneLayers = set([pcbnew.B_Cu, pcbnew.F_Cu])

    xCnt = 0
    wxPointX0Y0 = pcbnew.wxPoint(0, 0)
    for cloneCh in cloneChs:
        print "Cloning channel", eesch.convertARPathToUserPath(cloneCh)
        REFtoREF = channels[cloneCh]

        # Figure out the clone origin
        if RefOfOrigin:
            # Using RefOfOrigin if supplied by user
            #
            cloneRefOfOrigin = REFtoREF.get(RefOfOrigin, None)
            if cloneRefOfOrigin is None:
                print "   *** WARN *** Cannot find equivalent origin reference in channel", cloneCh
                continue
            cloneModuleOfOrigin = board.FindModuleByReference(cloneRefOfOrigin)

            rotation = round(cloneModuleOfOrigin.GetOrientation() -
                             ModuleOfOrigin.GetOrientation())
            while (rotation < -1800):
                rotation += 3600
            while (rotation > +1800):
                rotation -= 3600

            cloneRotOrigin = cloneModuleOfOrigin.GetPosition()
            curCloneOfs = cloneRotOrigin - ModuleOfOrigin.GetPosition()

        else:
            # Using CloneX and CloneY supplied by user
            #
            if xCnt == 0:
                xCnt = 0
                curCloneX = cloneX - srcRect.GetPosition().x
                curCloneY += cloneArraydY
            else:
                curCloneX += cloneArraydX

            curCloneOfs = pcbnew.wxPoint(curCloneX, curCloneY)
            rotation = 0
            cloneRotOrigin = srcRect.GetPosition()
        #EndOf if RefOfOrigin

        if CleanUp:
            cloneRect = pcbnew.EDA_RECT(srcRect.GetPosition() + curCloneOfs,
                                        srcSize)
            if rotation != 0:
                cloneRect = cloneRect.GetBoundingBoxRotated(
                    cloneRotOrigin, rotation)

            # Clean the Traces in cloning target
            for idx in range(len(allTracks) - 1, -1, -1):
                track = allTracks[idx]
                if track.HitTest(cloneRect):
                    #if track.GetLayer() in CloneLayers:
                    allTracks.pop(idx)
                    tracks.Remove(track)

            # Clean zones that belong cloning target
            for idx in range(len(allZones) - 1, -1, -1):
                zone = allZones[idx]
                if zone.HitTest(cloneRect):
                    allZones.pop(idx)
                    board.Delete(zone)

            # Clean drawings that belong cloning target
            for idx in range(len(allDraws) - 1, -1, -1):
                drawing = allDraws[idx]
                if drawing.HitTest(cloneRect):
                    allDraws.pop(idx)
                    board.Delete(drawing)
        #Endof if CleanUp

        if not NoClone:
            # Cloning the components
            print "  Moved Eqv. Modules"
            pairs = []
            for ref, module in srcModules.iteritems():
                cloneRef = REFtoREF.get(ref, None)

                if cloneRef is None:
                    print "   *** WARN *** %s don't have equivalent components. Skip clone" \
                        % ref
                    continue

                cloneModule = board.FindModuleByReference(cloneRef)
                if cloneModule is None:
                    print "    *** ERROR *** Cannot find module with reference of", cloneRef
                    continue

                if cloneHorMirror:
                    if cloneVerMirror:
                        __helper.cloneComponentDiaMirror(
                            module, cloneModule, curCloneOfs, srcRect)
                    else:
                        __helper.cloneComponentHorMirror(
                            module, cloneModule, curCloneOfs, srcRect)
                elif cloneVerMirror:
                    __helper.cloneComponentVerMirror(module, cloneModule,
                                                     curCloneOfs, srcRect)
                else:
                    __helper.cloneComponentNormal(module, cloneModule,
                                                  curCloneOfs, rotation,
                                                  cloneRotOrigin)
                pairs.append([module, cloneModule])

            eqvNets = equivalentNetlist(pairs)

            # Cloning the Traces
            print "  Clone traces"
            for track in srcTracks:
                cloneNetCode = eqvNets.getEqvNetCode(track.GetNetCode(),
                                                     track.GetShortNetname())
                if cloneNetCode is not None:
                    #if track.GetLayer() in CloneLayers:
                    cloneTrack = track.Duplicate()
                    cloneTrack.SetNetCode(cloneNetCode)
                    if cloneHorMirror:
                        if cloneVerMirror:
                            __helper.cloneTrackDiaMirror(
                                cloneTrack, curCloneOfs, srcRect)
                        else:
                            __helper.cloneTrackHorMirror(
                                cloneTrack, curCloneOfs, srcRect)
                    elif cloneVerMirror:
                        __helper.cloneTrackVerMirror(cloneTrack, curCloneOfs,
                                                     srcRect)
                    else:
                        __helper.cloneTrackNormal(cloneTrack, curCloneOfs,
                                                  rotation, cloneRotOrigin)
                    tracks.Append(cloneTrack)

            # Cloning the drawing
            print "  Clone drawings"
            for drawing in srcDrawings:
                cloneDrawing = drawing.Duplicate()
                cloneDrawing.Move(curCloneOfs)
                board.Add(cloneDrawing)

            # Cloning the Zones
            print "  Clone zones"
            curPairsIdx = len(pairs)
            for zone in srcZones:
                # Figure out what is appropriate eqv netname for copper filled zone
                if zone.IsOnCopperLayer():
                    cloneNetCode = eqvNets.getEqvNetCode(
                        zone.GetNetCode(), zone.GetShortNetname())
                    if cloneNetCode is not None:
                        cloneZone = zone.Duplicate()
                        cloneZone.SetNetCode(cloneNetCode)
                    else:
                        continue
                else:
                    cloneZone = zone.Duplicate()

                if cloneHorMirror:
                    if cloneVerMirror:
                        __helper.cloneZoneDiaMirror(cloneZone, curCloneOfs,
                                                    srcRect)
                    else:
                        __helper.cloneZoneHorMirror(cloneZone, curCloneOfs,
                                                    srcRect)
                elif cloneVerMirror:
                    __helper.cloneZoneVerMirror(cloneZone, curCloneOfs,
                                                srcRect)
                else:
                    __helper.cloneZoneNormal(cloneZone, curCloneOfs, rotation,
                                             cloneRotOrigin)
                board.Add(cloneZone)
        #Endof if not NoClone

        # Advancing to next clone location
        xCnt += 1
        if xCnt >= cloneArrayXdim:
            xCnt = 0
Beispiel #9
0
    def __init__(self, board, pivot_module_reference):
        """ initialize base object needed to replicate module layout, track layout and zone layout"""
        # take care of different APIs
        if hasattr(pcbnew, "LAYER_ID_COUNT"):
            pcbnew.PCB_LAYER_ID_COUNT = pcbnew.LAYER_ID_COUNT

        self.board = board

        # load all modules
        self.modules = board.GetModules()

        # find pivodmodule
        self.pivot_mod = board.FindModuleByReference(pivot_module_reference)

        # find sheet ID on which the module is on
        self.pivot_sheet_id = get_sheet_id(self.pivot_mod)

        # while at it, get the pivot module ID
        self.pivot_mod_id = get_module_id(self.pivot_mod)

        # find all modules on the same sheet
        self.pivot_modules = []
        self.pivot_modules_id = []
        self.pivot_modules_ref = []
        for mod in self.modules:
            module_id = get_module_id(mod)
            sheet_id = get_sheet_id(mod)
            if sheet_id == self.pivot_sheet_id:
                self.pivot_modules.append(mod)
                self.pivot_modules_id.append(module_id)
                self.pivot_modules_ref.append(mod.GetReference())

        # find all local nets
        other_modules = []
        other_modules_ref = []
        for mod in self.modules:
            if mod.GetReference() not in self.pivot_modules_ref:
                other_modules.append(mod)
                other_modules_ref.append(mod.GetReference())
        other_nets = self.get_nets_from_modules(other_modules)
        pivot_nets = self.get_nets_from_modules(self.pivot_modules)
        self.pivot_local_nets = []
        for net in pivot_nets:
            if net not in other_nets:
                self.pivot_local_nets.append(net)

        # find all sheets to replicate
        self.sheets_to_clone = []
        for mod in self.modules:
            module_id = get_module_id(mod)
            sheet_id = get_sheet_id(mod)
            if (module_id == self.pivot_mod_id) and (sheet_id != self.pivot_sheet_id) \
                    and (sheet_id not in self.sheets_to_clone):
                self.sheets_to_clone.append(sheet_id)
        pass

        # get bounding bounding box of all modules
        bounding_box = self.pivot_mod.GetFootprintRect()
        top = bounding_box.GetTop()
        bottom = bounding_box.GetBottom()
        left = bounding_box.GetLeft()
        right = bounding_box.GetRight()
        for mod in self.pivot_modules:
            mod_box = mod.GetFootprintRect()
            top = min(top, mod_box.GetTop())
            bottom = max(bottom, mod_box.GetBottom())
            left = min(left, mod_box.GetLeft())
            right = max(right, mod_box.GetRight())

        position = pcbnew.wxPoint(left, top)
        size = pcbnew.wxSize(right - left, bottom - top)
        self.pivot_bounding_box = pcbnew.EDA_RECT(position, size)

        # get corner points for the pivot bunding box - might need them for proper rotated bounding box
        #
        top_left = (self.pivot_bounding_box.GetLeft(), self.pivot_bounding_box.GetTop())
        top_right = (self.pivot_bounding_box.GetRight(), self.pivot_bounding_box.GetTop())
        bottom_right = (self.pivot_bounding_box.GetRight(), self.pivot_bounding_box.GetBottom())
        bottom_left = (self.pivot_bounding_box.GetLeft(), self.pivot_bounding_box.GetBottom())
        self.pivot_bounding_box_corners = (top_left, top_right, bottom_right, bottom_left)

        # get radius for polar replication
        middle = (right + left)/2
        self.polar_center = (middle, bottom)

        # get minimal radius - used by GUI to autofill in case of polar replication
        # could be improved with proper formulae, this is just a rough estimae
        number_of_all_sheets = 1 + len(self.sheets_to_clone)
        width_of_sheet = (right - left) / SCALE
        circumference = number_of_all_sheets * width_of_sheet
        self.minimum_radius = circumference / (2 * math.pi)
        self.minimum_angle = 360.0 / number_of_all_sheets

        # get minimal width - GUI assumes horizontal replication
        self.minimum_width = (right - left) / SCALE

        self.pivot_tracks = []
        self.pivot_zones = []
        self.only_within_bbox = False