Fix instersection bug. Improve primary and secondary pin algo.

This commit is contained in:
Matt Guthaus 2018-12-04 16:53:04 -08:00
parent 7ce75398a8
commit 126d4a8d10
3 changed files with 102 additions and 103 deletions

View File

@ -441,10 +441,10 @@ class pin_layout:
"""
Given three co-linear points, determine if q lies on segment pr
"""
if q[0] <= max(p[0], r[0]) and \
q[0] >= min(p[0], r[0]) and \
q[1] <= max(p[1], r[1]) and \
q[1] >= min(p[1], r[1]):
if q.x <= max(p.x, r.x) and \
q.x >= min(p.x, r.x) and \
q.y <= max(p.y, r.y) and \
q.y >= min(p.y, r.y):
return True
return False
@ -473,8 +473,8 @@ class pin_layout:
x = (b2*c1 - b1*c2)/determinant
y = (a1*c2 - a2*c1)/determinant
r = [x,y]
r = vector(x,y).snap_to_grid()
if self.on_segment(a, r, b) and self.on_segment(c, r, d):
return [x, y]
return r
return None

View File

@ -561,15 +561,13 @@ class pin_group:
of any grid in the other set.
"""
# We could optimize this to just check the boundaries
g1_grids = set()
g2_grids = set()
adj_grids = set()
for g1 in self.grids:
for g2 in other.grids:
if g1.distance(g2) <= separation:
g1_grids.add(g1)
g2_grids.add(g2)
adj_grids.add(g1)
return g1_grids,g2_grids
return adj_grids
def convert_pin(self):
"""
@ -578,14 +576,16 @@ class pin_group:
should be either blocked or part of the pin.
"""
pin_set = set()
partial_set = set()
blockage_set = set()
for pin_list in self.pins:
for pin in pin_list:
debug.info(2," Converting {0}".format(pin))
# Determine which tracks the pin overlaps
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin)
pin_set.update(pin_in_tracks)
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin)
pin_set.update(sufficient)
partial_set.update(insufficient)
# Blockages will be a super-set of pins since it uses the inflated pin shape.
blockage_in_tracks = self.router.convert_blockage(pin)
@ -597,30 +597,35 @@ class pin_group:
if len(shared_set)>0:
debug.info(2,"Removing pins {}".format(shared_set))
pin_set.difference_update(shared_set)
shared_set = partial_set & self.router.blocked_grids
if len(shared_set)>0:
debug.info(2,"Removing pins {}".format(shared_set))
partial_set.difference_update(shared_set)
shared_set = blockage_set & self.router.blocked_grids
if len(shared_set)>0:
debug.info(2,"Removing blocks {}".format(shared_set))
blockage_set.difference_update(shared_set)
# At least one of the groups must have some valid tracks
if (len(pin_set)==0 and len(blockage_set)==0):
if (len(pin_set)==0 and len(partial_set)==0 and len(blockage_set)==0):
#debug.warning("Pin is very close to metal blockage.\nAttempting to expand blocked pin {}".format(self.pins))
for pin_list in self.pins:
for pin in pin_list:
debug.warning(" Expanding conversion {0}".format(pin))
# Determine which tracks the pin overlaps
pin_in_tracks=self.router.convert_pin_to_tracks(self.name, pin, expansion=1)
pin_set.update(pin_in_tracks)
(sufficient,insufficient)=self.router.convert_pin_to_tracks(self.name, pin, expansion=1)
pin_set.update(sufficient)
partial_set.update(insufficient)
if len(pin_set)==0:
if len(pin_set)==0 and len(partial_set)==0:
debug.error("Unable to find unblocked pin {} {}".format(self.name, self.pins))
self.router.write_debug_gds("blocked_pin.gds")
# We need to route each of the components, so don't combine the groups
self.grids = pin_set
# Remember the secondary grids for removing adjacent pins in wide metal spacing
self.secondary_grids = blockage_set - pin_set
# Consider all the grids that would be blocked
self.grids = pin_set | partial_set
# Remember the secondary grids for removing adjacent pins
self.secondary_grids = partial_set
debug.info(2," pins {}".format(self.grids))
debug.info(2," secondary {}".format(self.secondary_grids))

View File

@ -279,48 +279,55 @@ class router(router_tech):
debug.info(1,"Comparing {0} and {1} adjacency".format(pin_name1, pin_name2))
for index1,pg1 in enumerate(self.pin_groups[pin_name1]):
for index2,pg2 in enumerate(self.pin_groups[pin_name2]):
# FIgXME: Use separation distance and edge grids only
grids_g1, grids_g2 = pg1.adjacent_grids(pg2, separation)
adj_grids = pg1.adjacent_grids(pg2, separation)
# These should have the same length, so...
if len(grids_g1)>0:
debug.info(3,"Adjacent grids {0} {1} {2} {3}".format(index1,grids_g1,index2,grids_g2))
self.remove_adjacent_grid(pg1, grids_g1, pg2, grids_g2)
if len(adj_grids)>0:
debug.info(2,"Adjacent grids {0} {1} adj={2}".format(index1,index2,adj_grids))
self.remove_adjacent_grid(pg1, pg2, adj_grids)
def remove_adjacent_grid(self, pg1, grids1, pg2, grids2):
def remove_adjacent_grid(self, pg1, pg2, adj_grids):
"""
Remove one of the adjacent grids in a heuristic manner.
This will try to keep the groups similar sized by removing from the bigger group.
"""
# Determine the bigger and smaller group
if pg1.size()>pg2.size():
bigger = pg1
bigger_grids = grids1
smaller = pg2
smaller_grids = grids2
else:
bigger = pg2
bigger_grids = grids2
smaller = pg1
smaller_grids = grids1
# First, see if we can remove grids that are in the secondary grids
# i.e. they aren't necessary to the pin grids
if bigger_grids.issubset(bigger.secondary_grids):
debug.info(3,"Removing {} from bigger {}".format(str(bigger_grids), bigger))
bigger.grids.difference_update(bigger_grids)
self.blocked_grids.update(bigger_grids)
return
elif smaller_grids.issubset(smaller.secondary_grids):
debug.info(3,"Removing {} from smaller {}".format(str(smaller_grids), smaller))
smaller.grids.difference_update(smaller_grids)
self.blocked_grids.update(smaller_grids)
return
for adj in adj_grids:
# If that fails, just randomly remove from the bigger one and give a warning.
# This might fail later.
debug.info(1,"Removing arbitrary grids from a pin group {} {}".format(bigger, bigger_grids))
debug.check(len(bigger.grids)>len(bigger_grids),"Zero size pin group after adjacency removal {} {}".format(bigger, bigger_grids))
bigger.grids.difference_update(bigger_grids)
self.blocked_grids.update(bigger_grids)
# If the adjacent grids are a subset of the secondary grids (i.e. not necessary)
# remove them from each
removed_flag = False
if adj in bigger.secondary_grids:
debug.info(2,"Removing {} from bigger secondary {}".format(adj, bigger))
bigger.grids.remove(adj)
bigger.secondary_grids.remove(adj)
self.blocked_grids.add(adj)
removed_flag=True
if adj in smaller.secondary_grids:
debug.info(2,"Removing {} from smaller secondary {}".format(adj, smaller))
smaller.gris.remove(adj)
secondary.secondary_grids.remove(adj)
self.blocked_grids.add(adj)
removed_flag=True
# If we couldn't remove from a secondary grid, we must remove from the primary
# grid of at least one pin
if not removed_flag:
if adj in bigger.grids:
debug.info(2,"Removing {} from bigger primary {}".format(adj, bigger))
bigger.grids.remove(adj)
elif adj in smaller.grids:
debug.info(2,"Removing {} from smaller primary {}".format(adj, smaller))
smaller.grids.remove(adj)
@ -523,31 +530,16 @@ class router(router_tech):
zindex=self.get_zindex(pin.layer_num)
for x in range(int(ll[0])+expansion,int(ur[0])+1+expansion):
for y in range(int(ll[1]+expansion),int(ur[1])+1+expansion):
(full_overlap,partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex))
(full_overlap, partial_overlap) = self.convert_pin_coord_to_tracks(pin, vector3d(x,y,zindex))
if full_overlap:
sufficient_list.update([full_overlap])
if partial_overlap:
insufficient_list.update([partial_overlap])
debug.info(2,"Converting [ {0} , {1} ] full={2} partial={3}".format(x,y, full_overlap, partial_overlap))
debug.info(2,"Converting [ {0} , {1} ] full={2}".format(x,y, full_overlap))
# Return all grids with any potential overlap (sufficient or not)
return sufficient_list|insufficient_list
return (sufficient_list,insufficient_list)
# # Remove the blocked grids
# sufficient_list.difference_update(self.blocked_grids)
# insufficient_list.difference_update(self.blocked_grids)
# if len(sufficient_list)>0:
# return sufficient_list
# elif expansion==0 and len(insufficient_list)>0:
# best_pin = self.get_all_offgrid_pin(pin, insufficient_list)
# #print(best_pin)
# return best_pin
# elif expansion>0:
# nearest_pin = self.get_furthest_offgrid_pin(pin, insufficient_list)
# return nearest_pin
# else:
# return set()
def get_all_offgrid_pin(self, pin, insufficient_list):
"""
@ -623,47 +615,34 @@ class router(router_tech):
return set([best_coord])
def convert_pin_coord_to_minimal_tracks(self, pin, coord):
"""
Given a pin and a track coordinate, determine if the pin overlaps enough.
If it does, add additional metal to make the pin "on grid".
If it doesn't, add it to the blocked grid list.
"""
(width, spacing) = self.get_layer_width_space(coord.z)
# This is the rectangle if we put a pin in the center of the track
track_pin = self.convert_track_to_pin(coord)
overlap_length = pin.overlap_length(track_pin)
debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
# If it overlaps by more than the min width DRC, we can just use the track
if overlap_length==math.inf or snap_val_to_grid(overlap_length) >= snap_val_to_grid(width):
debug.info(3," Overlap: {0} >? {1}".format(overlap_length,spacing))
return (coord, None)
# Otherwise, keep track of the partial overlap grids in case we need to patch it later.
else:
debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_length,spacing))
return (None, coord)
def convert_pin_coord_to_tracks(self, pin, coord):
"""
Return all tracks that an inflated pin overlaps
"""
# This is the rectangle if we put a pin in the center of the track
track_pin = self.convert_track_to_inflated_pin(coord)
overlap_length = pin.overlap_length(track_pin)
# This is using the full track shape rather than a single track pin shape
# because we will later patch a connector if there isn't overlap.
track_pin = self.convert_track_to_shape_pin(coord)
# This is the normal pin inflated by a minimum design rule
inflated_pin = pin_layout(pin.name, pin.inflate(0.5*self.track_space), pin.layer)
debug.info(3,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
# If it overlaps by more than the min width DRC, we can just use the track
if overlap_length==math.inf or snap_val_to_grid(overlap_length) > 0:
debug.info(3," Overlap: {0} >? {1}".format(overlap_length,0))
return (coord, None)
# Otherwise, keep track of the partial overlap grids in case we need to patch it later.
overlap_length = pin.overlap_length(track_pin)
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, pin.rect, track_pin, overlap_length))
inflated_overlap_length = inflated_pin.overlap_length(track_pin)
debug.info(2,"Check overlap: {0} {1} . {2} = {3}".format(coord, inflated_pin.rect, track_pin, inflated_overlap_length))
# If it overlaps with the pin, it is sufficient
if overlap_length==math.inf or overlap_length > 0:
debug.info(2," Overlap: {0} >? {1}".format(overlap_length,0))
return (coord,None)
# If it overlaps with the inflated pin, it is partial
elif inflated_overlap_length==math.inf or inflated_overlap_length > 0:
debug.info(2," Partial overlap: {0} >? {1}".format(inflated_overlap_length,0))
return (None,coord)
else:
debug.info(3," Partial/no overlap: {0} >? {1}".format(overlap_length,0))
return (None, coord)
debug.info(2," No overlap: {0} {1}".format(overlap_length,0))
return (None,None)
@ -688,6 +667,21 @@ class router(router_tech):
p = pin_layout("", [ll, ur], self.get_layer(track[2]))
return p
def convert_track_to_shape_pin(self, track):
"""
Convert a grid point into a rectangle shape that occupies the entire centered
track.
"""
# to scale coordinates to tracks
x = track[0]*self.track_width - 0.5*self.track_width
y = track[1]*self.track_width - 0.5*self.track_width
# offset lowest corner object to to (-track halo,-track halo)
ll = snap_to_grid(vector(x,y))
ur = snap_to_grid(ll + vector(self.track_width,self.track_width))
p = pin_layout("", [ll, ur], self.get_layer(track[2]))
return p
def convert_track_to_shape(self, track):
"""
Convert a grid point into a rectangle shape that occupies the entire centered
@ -701,7 +695,7 @@ class router(router_tech):
ur = snap_to_grid(ll + vector(self.track_width,self.track_width))
return [ll,ur]
def convert_track_to_inflated_pin(self, track):
"""
Convert a grid point into a rectangle shape that is inflated by a half DRC space.