Allow ViaStitching working on kicad 5.1

This commit is contained in:
Jean-Samuel Reynaud
2019-04-19 18:19:08 +02:00
parent f65c507ddc
commit 43116af07c

View File

@ -87,7 +87,7 @@ class FillArea:
REASON_PAD = 5 REASON_PAD = 5
REASON_DRAWING = 6 REASON_DRAWING = 6
REASON_STEP = 7 REASON_STEP = 7
def __init__(self, filename=None): def __init__(self, filename=None):
self.filename = None self.filename = None
self.clearance = 0 self.clearance = 0
@ -113,7 +113,7 @@ class FillArea:
break break
self.netname = None self.netname = None
self.debug = False self.debug = False
self.random = False self.random = True
self.star = False self.star = False
if self.netname is None: if self.netname is None:
self.SetNetname("GND") self.SetNetname("GND")
@ -126,6 +126,7 @@ class FillArea:
self.SetPCB(LoadBoard(self.filename)) self.SetPCB(LoadBoard(self.filename))
def SetDebug(self): def SetDebug(self):
print("Set debug")
self.debug = True self.debug = True
return self return self
@ -171,7 +172,7 @@ class FillArea:
def SetClearanceMM(self, s): def SetClearanceMM(self, s):
self.clearance = float(FromMM(s)) self.clearance = float(FromMM(s))
return self return self
def GetReasonSymbol(self, reason): def GetReasonSymbol(self, reason):
if isinstance(reason, ViaObject): if isinstance(reason, ViaObject):
return "X" return "X"
@ -189,9 +190,9 @@ class FillArea:
return "D" return "D"
if reason == self.REASON_STEP: if reason == self.REASON_STEP:
return "-" return "-"
return str(reason) return str(reason)
def PrintRect(self, rectangle): def PrintRect(self, rectangle):
"""debuging tool """debuging tool
Print board in ascii art Print board in ascii art
@ -221,7 +222,8 @@ STEP = '-'
m.SetViaType(VIA_THROUGH) m.SetViaType(VIA_THROUGH)
m.SetDrill(int(self.drill)) m.SetDrill(int(self.drill))
m.SetWidth(int(self.size)) m.SetWidth(int(self.size))
m.SetTimeStamp(33) # USE 33 as timestamp to mark this via as generated # No more possible to mark via as own since no timestamp_t binding
#m.SetTimeStamp(33) # USE 33 as timestamp to mark this via as generated
self.pcb.Add(m) self.pcb.Add(m)
def RefillBoardAreas(self): def RefillBoardAreas(self):
@ -229,8 +231,8 @@ STEP = '-'
area = self.pcb.GetArea(i) area = self.pcb.GetArea(i)
area.ClearFilledPolysList() area.ClearFilledPolysList()
area.UnFill() area.UnFill()
if not area.GetIsKeepout(): filler = ZONE_FILLER(self.pcb);
area.BuildFilledSolidAreasPolygons(self.pcb) filler.Fill(self.pcb.Zones())
def CheckViaInAllAreas(self, via, all_areas): def CheckViaInAllAreas(self, via, all_areas):
''' '''
@ -249,17 +251,17 @@ STEP = '-'
for dx in [-offset, offset]: for dx in [-offset, offset]:
for dy in [-offset, offset]: # All 4 corners of the via are testet (upper, lower, left, right) but not the center for dy in [-offset, offset]: # All 4 corners of the via are testet (upper, lower, left, right) but not the center
point_to_test = wxPoint(via.PosX + dx, via.PosY + dy) point_to_test = wxPoint(via.PosX + dx, via.PosY + dy)
hit_test_area = area.HitTestFilledArea(point_to_test) # Collides with a filled area hit_test_area = area.HitTestFilledArea(point_to_test) # Collides with a filled area
hit_test_edge = area.HitTestForEdge(point_to_test) # Collides with an edge/corner hit_test_edge = area.HitTestForEdge(point_to_test) # Collides with an edge/corner
hit_test_zone = area.HitTestInsideZone(point_to_test) # Is inside a zone (e.g. KeepOut) hit_test_zone = area.HitTestInsideZone(point_to_test) # Is inside a zone (e.g. KeepOut)
if is_keepout_area and (hit_test_area or hit_test_edge or hit_test_zone): if is_keepout_area and (hit_test_area or hit_test_edge or hit_test_zone):
return self.REASON_KEEPOUT # Collides with keepout return self.REASON_KEEPOUT # Collides with keepout
elif (hit_test_area or hit_test_edge): elif (hit_test_area or hit_test_edge):
return self.REASON_OTHER_SIGNAL # Collides with another signal (e.g. on another layer) return self.REASON_OTHER_SIGNAL # Collides with another signal (e.g. on another layer)
elif hit_test_zone: elif hit_test_zone:
# Check if the zone is higher priority than other zones of the target net in the same point # Check if the zone is higher priority than other zones of the target net in the same point
target_areas_on_same_layer = filter(lambda x: ((x.GetPriority() > area_priority) and (x.GetLayer() == area_layer) and (x.GetNetname().upper() == self.netname)), all_areas) target_areas_on_same_layer = filter(lambda x: ((x.GetPriority() > area_priority) and (x.GetLayer() == area_layer) and (x.GetNetname().upper() == self.netname)), all_areas)
@ -268,9 +270,9 @@ STEP = '-'
break # Area of target net has higher priority on this layer break # Area of target net has higher priority on this layer
else: else:
return self.REASON_OTHER_SIGNAL # Collides with another signal (e.g. on another layer) return self.REASON_OTHER_SIGNAL # Collides with another signal (e.g. on another layer)
return self.REASON_OK return self.REASON_OK
def ClearViaInStepSize(self, rectangle, x, y, distance): def ClearViaInStepSize(self, rectangle, x, y, distance):
''' '''
Stepsize==0 Stepsize==0
@ -293,11 +295,11 @@ STEP = '-'
Star Star
O O O O O O O O O O
O O O O O O O O
O O O O O O O O O O
O O O O O O O O
O O O O O O O O O O
O O O O O O O O
O O O O O O O O O O
''' '''
for x_pos in range(x-distance, x+distance+1): for x_pos in range(x-distance, x+distance+1):
@ -313,14 +315,17 @@ STEP = '-'
""" """
Launch the process Launch the process
""" """
target_tracks = self.pcb.GetTracks()
if self.delete_vias: if self.delete_vias:
target_tracks = filter(lambda x: (x.GetNetname().upper() == self.netname), self.pcb.GetTracks()) # timestmap no more available
for via in target_tracks: # target_tracks = filter(lambda x: (x.GetNetname().upper() == self.netname), self.pcb.GetTracks())
if via.Type() == PCB_VIA_T: # for via in target_tracks:
if via.GetTimeStamp() == 33: # pprint.pprint(via.GetTimeStamp())
self.pcb.RemoveNative(via) # if via.Type() == PCB_VIA_T:
self.RefillBoardAreas() # if via.GetTimeStamp() == 33:
# self.pcb.RemoveNative(via)
# self.RefillBoardAreas()
return # no need to run the rest of logic return # no need to run the rest of logic
lboard = self.pcb.ComputeBoundingBox(True) lboard = self.pcb.ComputeBoundingBox(True)
@ -331,7 +336,7 @@ STEP = '-'
l_clearance = self.clearance + self.size l_clearance = self.clearance + self.size
x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1 x_limit = int((lboard.GetWidth() + l_clearance) / l_clearance) + 1
y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1 y_limit = int((lboard.GetHeight() + l_clearance) / l_clearance) + 1
rectangle = [[self.REASON_NO_SIGNAL]*y_limit for i in xrange(x_limit)] rectangle = [[self.REASON_NO_SIGNAL]*y_limit for i in xrange(x_limit)]
all_pads = self.pcb.GetPads() all_pads = self.pcb.GetPads()
@ -342,60 +347,60 @@ STEP = '-'
via_list = [] # Create a list of existing vias => faster than scanning through the whole rectangle via_list = [] # Create a list of existing vias => faster than scanning through the whole rectangle
max_target_area_clearance = 0 max_target_area_clearance = 0
# Enum all target areas (Search possible positions for vias on the target net) # Enum all target areas (Search possible positions for vias on the target net)
for area in target_areas: for area in target_areas:
print ("Processing Target Area: %s, LayerName: %s..." % (area.GetNetname(), area.GetLayerName())) print ("Processing Target Area: %s, LayerName: %s..." % (area.GetNetname(), area.GetLayerName()))
is_selected_area = area.IsSelected() is_selected_area = area.IsSelected()
area_clearance = area.GetClearance() area_clearance = area.GetClearance()
if max_target_area_clearance < area_clearance: if max_target_area_clearance < area_clearance:
max_target_area_clearance = area_clearance max_target_area_clearance = area_clearance
if (not self.only_selected_area) or (self.only_selected_area and is_selected_area): # All areas or only the selected area if (not self.only_selected_area) or (self.only_selected_area and is_selected_area): # All areas or only the selected area
for x in xrange(len(rectangle)): # Check every possible point in the virtual coordinate system for x in xrange(len(rectangle)): # Check every possible point in the virtual coordinate system
for y in xrange(len(rectangle[0])): for y in xrange(len(rectangle[0])):
if rectangle[x][y] == self.REASON_NO_SIGNAL: # No other "target area" found yet => go on with processing if rectangle[x][y] == self.REASON_NO_SIGNAL: # No other "target area" found yet => go on with processing
current_x = origin.x + (x * l_clearance) # Center of the via current_x = origin.x + (x * l_clearance) # Center of the via
current_y = origin.y + (y * l_clearance) current_y = origin.y + (y * l_clearance)
test_result = True # Start with true, if a check fails, it is set to false test_result = True # Start with true, if a check fails, it is set to false
offset = max(self.clearance, area_clearance) + self.size / 2 # Offset is half the size of the via plus the clearance of the via or the area offset = max(self.clearance, area_clearance) + self.size / 2 # Offset is half the size of the via plus the clearance of the via or the area
for dx in [-offset, offset]: for dx in [-offset, offset]:
for dy in [-offset, offset]: # All 4 corners of the via are testet (upper, lower, left, right) but not the center for dy in [-offset, offset]: # All 4 corners of the via are testet (upper, lower, left, right) but not the center
point_to_test = wxPoint(current_x + dx, current_y + dy) point_to_test = wxPoint(current_x + dx, current_y + dy)
hit_test_area = area.HitTestFilledArea(point_to_test) # Collides with a filled area hit_test_area = area.HitTestFilledArea(point_to_test) # Collides with a filled area
hit_test_edge = area.HitTestForEdge(point_to_test) # Collides with an edge/corner hit_test_edge = area.HitTestForEdge(point_to_test,area_clearance) # Collides with an edge/corner
test_result &= (hit_test_area and not hit_test_edge) # test_result only remains true if the via is inside an area and not on an edge test_result &= (hit_test_area and not hit_test_edge) # test_result only remains true if the via is inside an area and not on an edge
if test_result: if test_result:
via_obj = ViaObject(x=x, y=y, pos_x=current_x, pos_y=current_y) # Create a via object with information about the via and place it in the rectangle via_obj = ViaObject(x=x, y=y, pos_x=current_x, pos_y=current_y) # Create a via object with information about the via and place it in the rectangle
rectangle[x][y] = via_obj rectangle[x][y] = via_obj
via_list.append(via_obj) via_list.append(via_obj)
if self.debug: if self.debug:
print("\nPost target areas:") print("\nPost target areas:")
self.PrintRect(rectangle) self.PrintRect(rectangle)
# Enum all vias # Enum all vias
print ("Processing all vias of target area...") print ("Processing all vias of target area...")
for via in via_list: for via in via_list:
reason = self.CheckViaInAllAreas(via, all_areas) reason = self.CheckViaInAllAreas(via, all_areas)
if reason != self.REASON_OK: if reason != self.REASON_OK:
rectangle[via.X][via.Y] = reason rectangle[via.X][via.Y] = reason
if self.debug: if self.debug:
print("\nPost areas:") print("\nPost areas:")
self.PrintRect(rectangle) self.PrintRect(rectangle)
# Same job with all pads => all pads on all layers # Same job with all pads => all pads on all layers
print ("Processing all pads...") print ("Processing all pads...")
for pad in all_pads: for pad in all_pads:
local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2) local_offset = max(pad.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2)
max_size = max(pad.GetSize().x, pad.GetSize().y) 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)) 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)) stop_x = int(ceil(((pad.GetPosition().x + (max_size / 2.0 + local_offset)) - origin.x) / l_clearance))
@ -410,11 +415,11 @@ STEP = '-'
size_rect = wxSize(2 * local_offset, 2 * local_offset) size_rect = wxSize(2 * local_offset, 2 * local_offset)
if pad.HitTest(EDA_RECT(start_rect, size_rect), False): if pad.HitTest(EDA_RECT(start_rect, size_rect), False):
rectangle[x][y] = self.REASON_PAD rectangle[x][y] = self.REASON_PAD
if self.debug: if self.debug:
print("\nPost pads:") print("\nPost pads:")
self.PrintRect(rectangle) self.PrintRect(rectangle)
# Same job with tracks => all tracks on all layers # Same job with tracks => all tracks on all layers
print ("Processing all tracks...") print ("Processing all tracks...")
for track in all_tracks: for track in all_tracks:
@ -440,7 +445,7 @@ STEP = '-'
opy = stop_y opy = stop_y
clearance = max(track.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2) + (track.GetWidth() / 2) clearance = max(track.GetClearance(), self.clearance, max_target_area_clearance) + (self.size / 2) + (track.GetWidth() / 2)
start_x = int(floor(((start_x - clearance) - origin.x) / l_clearance)) start_x = int(floor(((start_x - clearance) - origin.x) / l_clearance))
stop_x = int(ceil(((stop_x + clearance) - origin.x) / l_clearance)) stop_x = int(ceil(((stop_x + clearance) - origin.x) / l_clearance))
@ -455,17 +460,17 @@ STEP = '-'
size_rect = wxSize(2 * clearance, 2 * clearance) size_rect = wxSize(2 * clearance, 2 * clearance)
if track.HitTest(EDA_RECT(start_rect, size_rect), False): if track.HitTest(EDA_RECT(start_rect, size_rect), False):
rectangle[x][y] = self.REASON_TRACK rectangle[x][y] = self.REASON_TRACK
if self.debug: if self.debug:
print("\nPost tracks:") print("\nPost tracks:")
self.PrintRect(rectangle) self.PrintRect(rectangle)
# Same job with existing text # Same job with existing text
print ("Processing all existing drawings...") print ("Processing all existing drawings...")
for draw in all_drawings: for draw in all_drawings:
inter = float(self.clearance + self.size) inter = float(self.clearance + self.size)
bbox = draw.GetBoundingBox() bbox = draw.GetBoundingBox()
start_x = int(floor(((bbox.GetPosition().x - inter) - origin.x) / l_clearance)) start_x = int(floor(((bbox.GetPosition().x - inter) - origin.x) / l_clearance))
stop_x = int(ceil(((bbox.GetPosition().x + (bbox.GetSize().x + inter)) - origin.x) / l_clearance)) stop_x = int(ceil(((bbox.GetPosition().x + (bbox.GetSize().x + inter)) - origin.x) / l_clearance))
@ -475,32 +480,32 @@ STEP = '-'
for x in range(start_x, stop_x + 1): for x in range(start_x, stop_x + 1):
for y in range(start_y, stop_y + 1): for y in range(start_y, stop_y + 1):
rectangle[x][y] = self.REASON_DRAWING rectangle[x][y] = self.REASON_DRAWING
if self.debug: if self.debug:
print("Post Drawnings:") print("Post Drawnings:")
self.PrintRect(rectangle) self.PrintRect(rectangle)
print ("Remove vias to guarantee step size...") print ("Remove vias to guarantee step size...")
clear_distance = 0 clear_distance = 0
if self.step != 0.0: if self.step != 0.0:
clear_distance = int((self.step+l_clearance) / l_clearance) # How much "via steps" should be removed around a via (round up) clear_distance = int((self.step+l_clearance) / l_clearance) # How much "via steps" should be removed around a via (round up)
for x in xrange(len(rectangle)): for x in xrange(len(rectangle)):
for y in xrange(len(rectangle[0])): for y in xrange(len(rectangle[0])):
if isinstance(rectangle[x][y], ViaObject): if isinstance(rectangle[x][y], ViaObject):
if clear_distance: if clear_distance:
self.ClearViaInStepSize(rectangle, x, y, clear_distance) self.ClearViaInStepSize(rectangle, x, y, clear_distance)
via = rectangle[x][y] via = rectangle[x][y]
ran_x = 0 ran_x = 0
ran_y = 0 ran_y = 0
if self.random: if self.random:
ran_x = (random.random() * l_clearance / 2.0) - (l_clearance / 4.0) ran_x = (random.random() * l_clearance / 2.0) - (l_clearance / 4.0)
ran_y = (random.random() * l_clearance / 2.0) - (l_clearance / 4.0) ran_y = (random.random() * l_clearance / 2.0) - (l_clearance / 4.0)
self.AddVia(wxPoint(via.PosX + ran_x, via.PosY + ran_y), via.X, via.Y) self.AddVia(wxPoint(via.PosX + ran_x, via.PosY + ran_y), via.X, via.Y)
if self.debug: if self.debug:
print("\nFinal result:") print("\nFinal result:")
self.PrintRect(rectangle) self.PrintRect(rectangle)