use own code for checking if polygons intersect (as opposed to finding the intersection)

This commit is contained in:
jan 2022-04-07 16:14:31 -07:00
parent 5254bcd018
commit 260bf5c767
2 changed files with 108 additions and 5 deletions

View File

@ -11,7 +11,7 @@ from numpy.typing import NDArray, ArrayLike
from pyclipper import scale_to_clipper, scale_from_clipper, PyPolyNode from pyclipper import scale_to_clipper, scale_from_clipper, PyPolyNode
from .types import connectivity_t, layer_t, contour_t from .types import connectivity_t, layer_t, contour_t
from .poly import poly_contains_points from .poly import poly_contains_points, intersects
from .clipper import union_nonzero, union_evenodd, intersection_evenodd, difference_evenodd, hier2oriented from .clipper import union_nonzero, union_evenodd, intersection_evenodd, difference_evenodd, hier2oriented
from .tracker import NetsInfo, NetName from .tracker import NetsInfo, NetName
from .utils import connectivity2layers from .utils import connectivity2layers
@ -112,6 +112,7 @@ def trace_connectivity(
nets_info = NetsInfo() nets_info = NetsInfo()
for ii, (top_layer, via_layer, bot_layer) in enumerate(connectivity): for ii, (top_layer, via_layer, bot_layer) in enumerate(connectivity):
logger.info(f'{ii}, {top_layer}, {via_layer}, {bot_layer}')
for metal_layer in (top_layer, bot_layer): for metal_layer in (top_layer, bot_layer):
if metal_layer in loaded_layers: if metal_layer in loaded_layers:
continue continue
@ -142,7 +143,7 @@ def trace_connectivity(
)) ))
# Figure out which nets are shorted by vias, then merge them # Figure out which nets are shorted by vias, then merge them
merge_pairs = find_merge_pairs(nets_info.nets, top_layer, bot_layer, via_polys) merge_pairs = find_merge_pairs(nets_info.nets, top_layer, bot_layer, via_polys, clipper_scale_factor)
for net_a, net_b in merge_pairs: for net_a, net_b in merge_pairs:
nets_info.merge(net_a, net_b) nets_info.merge(net_a, net_b)
@ -286,6 +287,7 @@ def find_merge_pairs(
top_layer: layer_t, top_layer: layer_t,
bot_layer: layer_t, bot_layer: layer_t,
via_polys: Optional[Sequence[contour_t]], via_polys: Optional[Sequence[contour_t]],
clipper_scale_factor: int,
) -> Set[Tuple[NetName, NetName]]: ) -> Set[Tuple[NetName, NetName]]:
""" """
Given a collection of (possibly anonymous) nets, figure out which pairs of Given a collection of (possibly anonymous) nets, figure out which pairs of
@ -325,12 +327,23 @@ def find_merge_pairs(
if via_polys is not None: if via_polys is not None:
top_bot = intersection_evenodd(top_polys, bot_polys) top_bot = intersection_evenodd(top_polys, bot_polys)
overlap = intersection_evenodd(top_bot, via_polys) overlap = check_any_intersection(scale_from_clipper(top_bot, clipper_scale_factor),
via_polys = difference_evenodd(via_polys, overlap) # reduce set of via polys for future nets scale_from_clipper(via_polys, clipper_scale_factor))
# overlap = intersection_evenodd(top_bot, via_polys)
# via_polys = difference_evenodd(via_polys, overlap) # reduce set of via polys for future nets
else: else:
overlap = intersection_evenodd(top_polys, bot_polys) # TODO verify there aren't any suspicious corner cases for this # overlap = intersection_evenodd(top_polys, bot_polys) # TODO verify there aren't any suspicious corner cases for this
overlap = check_any_intersection(scale_from_clipper(top_polys, clipper_scale_factor), scale_from_clipper(bot_polys, clipper_scale_factor))
if overlap: if overlap:
merge_pairs.add(name_pair) merge_pairs.add(name_pair)
return merge_pairs return merge_pairs
def check_any_intersection(polys_a, polys_b) -> bool:
for poly_a in polys_a:
for poly_b in polys_b:
if intersects(poly_a, poly_b):
return True
return False

View File

@ -65,3 +65,93 @@ def poly_contains_points(
inside = nontrivial.copy() inside = nontrivial.copy()
inside[nontrivial] = nontrivial_inside inside[nontrivial] = nontrivial_inside
return inside return inside
def intersects(poly_a: ArrayLike, poly_b: ArrayLike) -> bool:
"""
Check if two polygons overlap and/or touch.
Args:
poly_a: List of vertices, implicitly closed: `[[x0, y0], [x1, y1], ...]`
poly_b: List of vertices, implicitly closed: `[[x0, y0], [x1, y1], ...]`
Returns:
`True` if the polygons overlap and/or touch.
"""
poly_a = numpy.array(poly_a, copy=False)
poly_b = numpy.array(poly_b, copy=False)
# Check bounding boxes
min_a = poly_a.min(axis=0)
min_b = poly_b.min(axis=0)
max_a = poly_a.max(axis=0)
max_b = poly_b.max(axis=0)
if ((min_a > max_b) | (min_b > max_a)).all():
return False
#TODO: Check against sorted coords?
#Check if edges intersect
if poly_edges_intersect(poly_a, poly_b):
return True
# Check if either polygon contains the other
if poly_contains_points(poly_b, poly_a).any():
return True
if poly_contains_points(poly_a, poly_b).any():
return True
return False
def poly_edges_intersect(
poly_a: NDArray[numpy.float64],
poly_b: NDArray[numpy.float64],
) -> NDArray[numpy.int_]:
"""
Check if the edges of two polygons intersect.
Args:
poly_a: NDArray of vertices, implicitly closed: `[[x0, y0], [x1, y1], ...]`
poly_b: NDArray of vertices, implicitly closed: `[[x0, y0], [x1, y1], ...]`
Returns:
`True` if the polygons' edges intersect.
"""
a_next = numpy.roll(poly_a, -1, axis=0)
b_next = numpy.roll(poly_b, -1, axis=0)
# Lists of initial/final coordinates for polygon segments
xi1 = poly_a[:, 0, None]
yi1 = poly_a[:, 1, None]
xf1 = a_next[:, 0, None]
yf1 = a_next[:, 1, None]
xi2 = poly_b[:, 0, None]
yi2 = poly_b[:, 1, None]
xf2 = b_next[:, 0, None]
yf2 = b_next[:, 1, None]
# Perform calculation
dxi = xi1 - xi2
dyi = yi1 - yi2
dx1 = xf1 - xi1
dx2 = xf2 - xi2
dy1 = yf1 - yi1
dy2 = yf2 - yi2
numerator_a = dx2 * dyi - dy2 * dxi
numerator_b = dx1 * dyi - dy1 * dxi
denominator = dy2 * dx1 - dx2 * dy1
# Avoid warnings since we may multiply eg. NaN*False
with numpy.errstate(invalid='ignore', divide='ignore'):
u_a = numerator_a / denominator
u_b = numerator_b / denominator
# Find the adjacency matrix
adjacency = numpy.logical_and.reduce((u_a >= 0, u_a <= 1, u_b >= 0, u_b <= 1))
return adjacency.any()