Skip to content

Commit

Permalink
Merge pull request #846 from gdsfactory/fix_get_polygons
Browse files Browse the repository at this point in the history
get_polygons is backwards compatible by default
  • Loading branch information
joamatab committed Nov 11, 2022
2 parents 4f6845c + 64b391d commit efe98e9
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 53 deletions.
2 changes: 1 addition & 1 deletion gdsfactory/add_keepout.py
Expand Up @@ -26,7 +26,7 @@ def add_keepout(
c = Component()
c << component
for layer in target_layers:
polygons = component.get_polygons(by_spec=layer)
polygons = component.get_polygons(by_spec=layer, as_array=False)
if polygons:
for ko_layer in keepout_layers:
ko_layer = _parse_layer(ko_layer)
Expand Down
97 changes: 69 additions & 28 deletions gdsfactory/component.py
@@ -1,12 +1,13 @@
import datetime
import hashlib
import itertools
import math
import os
import pathlib
import tempfile
import uuid
import warnings
from collections import Counter
from collections import Counter, defaultdict
from collections.abc import Iterable
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, Tuple, Union
Expand Down Expand Up @@ -175,18 +176,21 @@ def name(self):
def name(self, value):
self._cell.name = value

def __iter__(self):
"""You can iterate over polygons, paths, labels and references."""
return itertools.chain(self.polygons, self.paths, self.labels, self.references)

def get_polygons(
self,
by_spec: Union[bool, Tuple[int, int]] = False,
depth: Optional[int] = None,
include_paths: bool = True,
as_array: bool = True,
) -> Union[List[Polygon], Dict[Tuple[int, int], List[Polygon]]]:
"""Return a list of polygons in this cell.
if by_spec is
Args:
by_spec: bool or tuple
by_spec: bool or layer
If True, the return value is a dictionary with the
polygons of each individual pair (layer, datatype), which
are used as keys. If set to a tuple of (layer, datatype),
Expand All @@ -196,11 +200,11 @@ def get_polygons(
retrieve polygons. References below this level will result
in a bounding box. If `by_spec` is True the key will be the
name of this cell.
include_paths: If True, polygonal representation of paths are also included in the result.
as_array: when as_array=false, return the Polygon objects instead. polygon objects have more information (especially when by_spec=False) and will be faster to retrieve.
Returns
out : list of array-like[N][2] or dictionary
out: list of array-like[N][2] or dictionary
List containing the coordinates of the vertices of each
polygon, or dictionary with with the list of polygons (if
`by_spec` is True).
Expand All @@ -213,27 +217,60 @@ def get_polygons(

if by_spec is True:
layers = self.get_layers()
return {
layer: self._cell.get_polygons(
depth=depth,
layer=layer[0],
datatype=layer[1],
include_paths=include_paths,
)
for layer in layers
}

layer_to_polygons = defaultdict(list)

if as_array:
for layer in layers:
for polygon in self._cell.get_polygons(
depth=depth,
layer=layer[0],
datatype=layer[1],
include_paths=include_paths,
):
layer_to_polygons[layer].append(polygon.points)
else:
for layer in layers:
for polygon in self._cell.get_polygons(
depth=depth,
layer=layer[0],
datatype=layer[1],
include_paths=include_paths,
):
layer_to_polygons[layer].append(polygon)
return layer_to_polygons

elif not by_spec:
return self._cell.get_polygons(depth=depth, include_paths=include_paths)
if as_array:
return [
polygon.points
for polygon in self._cell.get_polygons(
depth=depth, include_paths=include_paths
)
]

else:
return self._cell.get_polygons(depth=depth, include_paths=include_paths)

else:
layer = gf.get_layer(by_spec)
return self._cell.get_polygons(
depth=depth,
layer=layer[0],
datatype=layer[1],
include_paths=include_paths,
)
if as_array:
return [
polygon.points
for polygon in self._cell.get_polygons(
depth=depth,
layer=layer[0],
datatype=layer[1],
include_paths=include_paths,
)
]
else:
return self._cell.get_polygons(
depth=depth,
layer=layer[0],
datatype=layer[1],
include_paths=include_paths,
)

def get_dependencies(self, recursive: bool = False) -> List["Component"]:
"""Return a set of the cells included in this cell as references.
Expand Down Expand Up @@ -1068,7 +1105,7 @@ def flatten(self, single_layer: Optional[Tuple[int, int]] = None):
"""
component_flat = Component()

poly_dict = self.get_polygons(by_spec=True, include_paths=False)
poly_dict = self.get_polygons(by_spec=True, include_paths=False, as_array=False)
for layer, polys in poly_dict.items():
if polys:
component_flat.add_polygon(polys, layer=single_layer or layer)
Expand Down Expand Up @@ -1720,7 +1757,7 @@ def hash_geometry(self, precision: float = 1e-4) -> str:
(0.124, 1.748) to (0.12, 1.75).
"""
polygons_by_spec = self.get_polygons(by_spec=True)
polygons_by_spec = self.get_polygons(by_spec=True, as_array=False)
layers = np.array(list(polygons_by_spec.keys()))
sorted_layers = layers[np.lexsort((layers[:, 0], layers[:, 1]))]

Expand Down Expand Up @@ -2050,11 +2087,15 @@ def test_import_gds_settings():


if __name__ == "__main__":
import gdsfactory as gf
# import gdsfactory as gf
test_remap_layers()

c = gf.c.straight()
c.remove_labels()
print(c.labels)
# c = gf.c.mzi()
# c = c.flatten()
# c.show()

# c.remove_labels()
# print(c.labels)

# c = gf.components.straight(layer=(2, 0))
# remap = c.remap_layers(layermap={(2, 0): gf.LAYER.WGN})
Expand Down
28 changes: 24 additions & 4 deletions gdsfactory/component_reference.py
@@ -1,4 +1,5 @@
import typing
from collections import defaultdict
from typing import Any, Dict, List, Optional, Tuple, Union, cast

import gdstk
Expand Down Expand Up @@ -215,7 +216,13 @@ def x_reflection(self, value):
def parent(self, value):
self.ref_cell = value

def get_polygons(self, by_spec=False, depth=None, include_paths: bool = True):
def get_polygons(
self,
by_spec=False,
depth=None,
include_paths: bool = True,
as_array: bool = True,
):
"""Return the list of polygons created by this reference.
Args:
Expand All @@ -230,6 +237,7 @@ def get_polygons(self, by_spec=False, depth=None, include_paths: bool = True):
in a bounding box. If `by_spec` is True the key will be the
name of the referenced cell.
include_paths: If True, polygonal representation of paths are also included in the result.
as_array: when as_array=false, return the Polygon objects instead. polygon objects have more information (especially when by_spec=False) and will be faster to retrieve.
Returns
out : list of array-like[N][2] or dictionary
Expand All @@ -242,12 +250,12 @@ def get_polygons(self, by_spec=False, depth=None, include_paths: bool = True):
the result by computing their polygonal boundary.
"""
if not by_spec:
return self._reference.get_polygons(
polygons = self._reference.get_polygons(
depth=depth, include_paths=include_paths
)
elif by_spec is True:
layers = self.parent.get_layers()
return {
polygons = {
layer: self._reference.get_polygons(
depth=depth,
layer=layer[0],
Expand All @@ -258,13 +266,25 @@ def get_polygons(self, by_spec=False, depth=None, include_paths: bool = True):
}

else:
return self._reference.get_polygons(
polygons = self._reference.get_polygons(
depth=depth,
layer=by_spec[0],
datatype=by_spec[1],
include_paths=include_paths,
)

if as_array:
if by_spec:
layer_to_polygons = defaultdict(list)
for layer, polygons_list in polygons.items():
for polygon in polygons_list:
layer_to_polygons[layer].append(polygon.points)
return layer_to_polygons
else:
return [polygon.points for polygon in polygons]
else:
return polygons

def get_labels(self, depth=None, set_transform=False):
"""Return the list of labels created by this reference.
Expand Down
2 changes: 1 addition & 1 deletion gdsfactory/fill.py
Expand Up @@ -198,7 +198,7 @@ def fill_rectangle(
F = Component()

avoid_layers = [_parse_layer(layer) for layer in _loop_over(avoid_layers)]
exclude_polys = D.get_polygons(by_spec=True, depth=None)
exclude_polys = D.get_polygons(by_spec=True, depth=None, as_array=False)

if avoid_layers:
exclude_polys = {
Expand Down
4 changes: 1 addition & 3 deletions gdsfactory/quickplotter.py
Expand Up @@ -285,7 +285,7 @@ def quickplot(items, **kwargs): # noqa: C901
elif isinstance(item, Polygon):
layerprop = _get_layerprop(item.layer, item.datatype)
new_bbox = _draw_polygons(
item,
item.points,
ax,
facecolor=layerprop["color"],
edgecolor="k",
Expand Down Expand Up @@ -392,8 +392,6 @@ def _get_layerprop(layer, datatype):
def _draw_polygons(polygons, ax, **kwargs):
from matplotlib.collections import PolyCollection

polygons = [polygon.points for polygon in polygons]

coll = PolyCollection(polygons, **kwargs)
ax.add_collection(coll)
stacked_polygons = np.vstack(polygons)
Expand Down
19 changes: 8 additions & 11 deletions gdsfactory/routing/get_route_astar.py
Expand Up @@ -179,11 +179,7 @@ def get_route_astar(

def _extract_all_bbox(c: Component, avoid_layers: List[LayerSpec] = None):
"""Extract all polygons whose layer is in `avoid_layers`."""
return [
polygon.bounding_box()
for layer in avoid_layers
for polygon in c.get_polygons(layer)
]
return [c.get_polygons(layer) for layer in avoid_layers]


def _generate_grid(
Expand Down Expand Up @@ -225,12 +221,13 @@ def _generate_grid(
grid[xmin:xmax, ymin:ymax] = 1
else:
all_refs = _extract_all_bbox(c, avoid_layers)
for bbox in all_refs:
xmin = np.abs(x - bbox[0][0] + distance).argmin()
xmax = np.abs(x - bbox[2][0] - distance).argmin()
ymin = np.abs(y - bbox[0][1] + distance).argmin()
ymax = np.abs(y - bbox[2][1] - distance).argmin()
grid[xmin:xmax, ymin:ymax] = 1
for layer in all_refs:
for bbox in layer:
xmin = np.abs(x - bbox[0][0] + distance).argmin()
xmax = np.abs(x - bbox[2][0] - distance).argmin()
ymin = np.abs(y - bbox[0][1] + distance).argmin()
ymax = np.abs(y - bbox[2][1] - distance).argmin()
grid[xmin:xmax, ymin:ymax] = 1

return np.ndarray.round(grid, 3), np.ndarray.round(x, 3), np.ndarray.round(y, 3)

Expand Down
10 changes: 5 additions & 5 deletions gdsfactory/tests/test_shear_face_path.py
Expand Up @@ -262,7 +262,7 @@ def test_points_are_correct(shear_waveguide_symmetric):
)

layer = (1, 0)
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0].points
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0]
assert_polygon_equals(points_expected, poly_actual)


Expand All @@ -283,7 +283,7 @@ def test_points_are_correct_wide():
length=length, width=wg_width, shear_angle=shear_angle
)
layer = (1, 0)
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0].points
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0]
assert_polygon_equals(points_expected, poly_actual)


Expand All @@ -304,7 +304,7 @@ def test_points_are_correct_short():
length=length, width=wg_width, shear_angle=shear_angle
)
layer = (1, 0)
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0].points
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0]
assert_polygon_equals(points_expected, poly_actual)


Expand All @@ -325,7 +325,7 @@ def test_points_are_correct_long():
length=length, width=wg_width, shear_angle=shear_angle
)
layer = (1, 0)
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0].points
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0]
assert_polygon_equals(points_expected, poly_actual)


Expand All @@ -351,7 +351,7 @@ def test_points_are_correct_multi_layer():
points_expected = get_expected_shear_shape(
length=length, width=wg_width, shear_angle=shear_angle
)
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0].points
poly_actual = shear_waveguide_symmetric.get_polygons(by_spec=layer)[0]
assert_polygon_equals(points_expected, poly_actual)


Expand Down

0 comments on commit efe98e9

Please sign in to comment.