use pyclipper for polygon cutting

This commit is contained in:
Jan Petykiewicz 2017-10-15 11:39:37 -07:00
parent b3f99ee123
commit 87c2ef5948
3 changed files with 31 additions and 57 deletions

View File

@ -185,63 +185,37 @@ class Polygon(Shape):
:param cut_ys: list of y-coordinates to cut along (e.g., [1, 3, 5.4]) :param cut_ys: list of y-coordinates to cut along (e.g., [1, 3, 5.4])
:return: List of Polygon objects :return: List of Polygon objects
""" """
import float_raster import pyclipper
xy_complex = self.vertices[:, 0] + 1j * self.vertices[:, 1] from pyclipper import scale_to_clipper, scale_from_clipper
xy_cleaned = _clean_complex_vertices(xy_complex)
xy = numpy.vstack((numpy.real(xy_cleaned)[None, :],
numpy.imag(xy_cleaned)[None, :]))
if cut_xs is None: min_x, min_y = numpy.min(self.vertices, axis=0)
cut_xs = tuple() max_x, max_y = numpy.max(self.vertices, axis=0)
if cut_ys is None: range_x = max_x - min_x
cut_ys = tuple() range_y = max_y - min_y
mins, maxs = self.get_bounds() edge_xs = (min_x - range_x - 1,) + tuple(cut_xs) + (max_x + range_x + 1,)
dx, dy = maxs - mins edge_ys = (min_y - range_y - 1,) + tuple(cut_ys) + (max_y + range_y + 1,)
cx = numpy.hstack((min(tuple(cut_xs) + (mins[0],)) - dx, cut_xs, max((maxs[0],) + tuple(cut_xs)) + dx)) clipped_shapes = []
cy = numpy.hstack((min(tuple(cut_ys) + (mins[1],)) - dy, cut_ys, max((maxs[1],) + tuple(cut_ys)) + dy)) for i in range(2):
for j in range(2):
clipper = pyclipper.Pyclipper()
clipper.AddPath(scale_to_clipper(self.vertices), pyclipper.PT_SUBJECT, True)
all_verts = float_raster.create_vertices(xy, cx, cy) for start_x, stop_x in zip(edge_xs[i::2], edge_xs[(i+1)::2]):
for start_y, stop_y in zip(edge_ys[j::2], edge_ys[(j+1)::2]):
polygons = [] clipper.AddPath(scale_to_clipper((
for cx_min, cx_max in zip(cx, cx[1:]): (start_x, start_y),
for cy_min, cy_max in zip(cy, cy[1:]): (start_x, stop_y),
clipped_verts = (numpy.real(all_verts).clip(cx_min, cx_max) + 1j * (stop_x, stop_y),
numpy.imag(all_verts).clip(cy_min, cy_max)) (stop_x, start_y),
)), pyclipper.PT_CLIP, True)
cleaned_verts = _clean_complex_vertices(clipped_verts)
if len(cleaned_verts) == 0:
continue
final_verts = numpy.hstack((numpy.real(cleaned_verts)[:, None],
numpy.imag(cleaned_verts)[:, None]))
polygons.append(Polygon(
vertices=final_verts,
layer=self.layer,
dose=self.dose))
return polygons
def _clean_complex_vertices(vertices: numpy.ndarray) -> numpy.ndarray:
eps = numpy.finfo(vertices.dtype).eps
def cleanup(v):
# Remove duplicate points
dv = v - numpy.roll(v, 1)
v = v[numpy.abs(dv) > eps]
# Remove colinear points
dv = v - numpy.roll(v, 1)
m = numpy.angle(dv) % pi
diff_m = m - numpy.roll(m, -1)
return v[numpy.abs(diff_m) > eps]
n = len(vertices)
cleaned = cleanup(vertices)
while n != len(cleaned):
n = len(cleaned)
cleaned = cleanup(cleaned)
return cleaned
clipped_parts = scale_from_clipper(clipper.Execute(pyclipper.CT_INTERSECTION,
pyclipper.PFT_EVENODD,
pyclipper.PFT_EVENODD))
for part in clipped_parts:
poly = self.copy()
poly.vertices = part
clipped_shapes.append(poly)
return clipped_shapes

View File

@ -156,4 +156,3 @@ class SubPattern:
""" """
self.scale *= c self.scale *= c
return self return self

View File

@ -16,7 +16,8 @@ setup(name='masque',
'visualization': ['matplotlib'], 'visualization': ['matplotlib'],
'gdsii': ['python-gdsii'], 'gdsii': ['python-gdsii'],
'svg': ['svgwrite'], 'svg': ['svgwrite'],
'text': ['freetype-py', 'matplotlib'] 'text': ['freetype-py', 'matplotlib'],
'clipping': ['pyclipper'],
}, },
) )