Enable repeated shapes in gdsii and oasis

This commit is contained in:
Jan Petykiewicz 2020-07-27 01:32:34 -07:00
parent 629a6a9ba2
commit 7ce601dc1d
2 changed files with 75 additions and 50 deletions

View File

@ -103,6 +103,8 @@ def build(patterns: Union[Pattern, List[Pattern]],
if not modify_originals:
patterns = [p.deepunlock() for p in copy.deepcopy(patterns)]
patterns = [p.wrap_repeated_shapes() for p in patterns]
# Create library
lib = gdsii.library.Library(version=600,
name=library_name.encode('ASCII'),

View File

@ -260,18 +260,19 @@ def read(stream: io.BufferedIOBase,
for element in cell.geometry:
if isinstance(element, fatrec.XElement):
logger.warning('Skipping XElement record')
# note XELEMENT has no repetition
continue
if element.repetition is not None:
# note XELEMENT has no repetition
raise PatternError('masque OASIS reader does not implement repetitions for shapes yet')
repetition = repetition_fata2masq(element.repetition)
# Switch based on element type:
if isinstance(element, fatrec.Polygon):
vertices = numpy.cumsum(numpy.vstack(((0, 0), element.get_point_list())), axis=0)
poly = Polygon(vertices=vertices,
layer=element.get_layer_tuple(),
offset=element.get_xy())
offset=element.get_xy(),
repetition=repetition)
if clean_vertices:
try:
@ -297,6 +298,7 @@ def read(stream: io.BufferedIOBase,
path = Path(vertices=vertices,
layer=element.get_layer_tuple(),
offset=element.get_xy(),
repeition=repetition,
width=element.get_half_width() * 2,
cap=cap,
**path_args)
@ -314,6 +316,7 @@ def read(stream: io.BufferedIOBase,
height = element.get_height()
rect = Polygon(layer=element.get_layer_tuple(),
offset=element.get_xy(),
repetition=repetition,
vertices=numpy.array(((0, 0), (1, 0), (1, 1), (0, 1))) * (width, height),
)
pat.shapes.append(rect)
@ -345,6 +348,7 @@ def read(stream: io.BufferedIOBase,
trapz = Polygon(layer=element.get_layer_tuple(),
offset=element.get_xy(),
repetition=repetition,
vertices=vertices,
)
pat.shapes.append(trapz)
@ -396,20 +400,23 @@ def read(stream: io.BufferedIOBase,
vertices[0, 1] += width
ctrapz = Polygon(layer=element.get_layer_tuple(),
offset=element.get_xy(),
vertices=vertices,
)
offset=element.get_xy(),
repetition=repetition,
vertices=vertices,
)
pat.shapes.append(ctrapz)
elif isinstance(element, fatrec.Circle):
circle = Circle(layer=element.get_layer_tuple(),
offset=element.get_xy(),
repetition=repetition,
radius=float(element.get_radius()))
pat.shapes.append(circle)
elif isinstance(element, fatrec.Text):
label = Label(layer=element.get_layer_tuple(),
offset=element.get_xy(),
repetition=repetition,
string=str(element.get_string()))
pat.labels.append(label)
@ -467,24 +474,10 @@ def _placement_to_subpat(placement: fatrec.Placement) -> SubPattern:
'rotation': float(placement.angle * pi/180),
'scale': mag,
'identifier': (name,),
'repetition': repetition_fata2masq(placement.repetition),
}
mrep: Optional[Repetition]
rep = placement.repetition
if isinstance(rep, fatamorgana.GridRepetition):
mrep = Grid(a_vector=rep.a_vector,
b_vector=rep.b_vector,
a_count=rep.a_count,
b_count=rep.b_count)
elif isinstance(rep, fatamorgana.ArbitraryRepetition):
displacements = numpy.cumsum(numpy.column_stack((rep.x_displacements,
rep.y_displacements)))
displacements = numpy.vstack(([0, 0], displacements))
mrep = Arbitrary(displacements)
elif rep is None:
mrep = None
subpat = SubPattern(offset=xy, repetition=mrep, **args)
subpat = SubPattern(offset=xy, **args)
return subpat
@ -497,27 +490,14 @@ def _subpatterns_to_refs(subpatterns: List[SubPattern]
# Note: OASIS mirrors first and rotates second
mirror_across_x, extra_angle = normalize_mirror(subpat.mirrored)
xy = numpy.round(subpat.offset).astype(int)
args: Dict[str, Any] = {
'x': xy[0],
'y': xy[1],
}
frep, rep_offset = repetition_masq2fata(subpat.repetition)
rep = subpat.repetition
if isinstance(rep, Grid):
args['repetition'] = fatamorgana.GridRepetition(
a_vector=numpy.round(rep.a_vector).astype(int),
b_vector=numpy.round(rep.b_vector).astype(int),
a_count=numpy.round(rep.a_count).astype(int),
b_count=numpy.round(rep.b_count).astype(int))
elif isinstance(rep, Arbitrary):
diffs = numpy.diff(rep.displacements, axis=0)
diff_ints = numpy.round(diffs).astype(int)
args['repetition'] = fatamorgana.ArbitraryRepetition(diff_ints[:, 0], diff_ints[:, 1])
args['x'] += rep.displacements[0, 0]
args['y'] += rep.displacements[0, 1]
else:
assert(rep is None)
offset = numpy.round(subpat.offset + rep_offset).astype(int)
args: Dict[str, Any] = {
'x': offset[0],
'y': offset[1],
'repetition': frep,
}
angle = numpy.rad2deg(subpat.rotation + extra_angle) % 360
ref = fatrec.Placement(
@ -538,17 +518,19 @@ def _shapes_to_elements(shapes: List[Shape],
elements: List[Union[fatrec.Polygon, fatrec.Path, fatrec.Circle]] = []
for shape in shapes:
layer, datatype = layer2oas(shape.layer)
repetition, rep_offset = repetition_masq2fata(shape.repetition)
if isinstance(shape, Circle):
offset = numpy.round(shape.offset).astype(int)
offset = numpy.round(shape.offset + rep_offset).astype(int)
radius = numpy.round(shape.radius).astype(int)
circle = fatrec.Circle(layer=layer,
datatype=datatype,
radius=radius,
x=offset[0],
y=offset[1])
y=offset[1],
repetition=repetition)
elements.append(circle)
elif isinstance(shape, Path):
xy = numpy.round(shape.offset + shape.vertices[0]).astype(int)
xy = numpy.round(shape.offset + shape.vertices[0] + rep_offset).astype(int)
deltas = numpy.round(numpy.diff(shape.vertices, axis=0)).astype(int)
half_width = numpy.round(shape.width / 2).astype(int)
path_type = next(k for k, v in path_cap_map.items() if v == shape.cap) #reverse lookup
@ -562,17 +544,19 @@ def _shapes_to_elements(shapes: List[Shape],
y=xy[1],
extension_start=extension_start, #TODO implement multiple cap types?
extension_end=extension_end,
repetition=repetition,
)
elements.append(path)
else:
for polygon in shape.to_polygons():
xy = numpy.round(polygon.offset + polygon.vertices[0]).astype(int)
xy = numpy.round(polygon.offset + polygon.vertices[0] + rep_offset).astype(int)
points = numpy.round(numpy.diff(polygon.vertices, axis=0)).astype(int)
elements.append(fatrec.Polygon(layer=layer,
datatype=datatype,
x=xy[0],
y=xy[1],
point_list=points))
point_list=points,
repetition=repetition))
return elements
@ -582,12 +566,14 @@ def _labels_to_texts(labels: List[Label],
texts = []
for label in labels:
layer, datatype = layer2oas(label.layer)
xy = numpy.round(label.offset).astype(int)
repetition, rep_offset = repetition_masq2fata(shape.repetition)
xy = numpy.round(label.offset + rep_offset).astype(int)
texts.append(fatrec.Text(layer=layer,
datatype=datatype,
x=xy[0],
y=xy[1],
string=label.string))
string=label.string,
repetition=repetition))
return texts
@ -619,3 +605,40 @@ def disambiguate_pattern_names(patterns,
pat.name = suffixed_name
used_names.append(suffixed_name)
def repetition_fata2masq(rep: Union[fatamorgana.GridRepetition, fatamorgana.ArbitraryRepetition, None]
) -> Optional[Repetition]:
if isinstance(rep, fatamorgana.GridRepetition):
mrep = Grid(a_vector=rep.a_vector,
b_vector=rep.b_vector,
a_count=rep.a_count,
b_count=rep.b_count)
elif isinstance(rep, fatamorgana.ArbitraryRepetition):
displacements = numpy.cumsum(numpy.column_stack((rep.x_displacements,
rep.y_displacements)))
displacements = numpy.vstack(([0, 0], displacements))
mrep = Arbitrary(displacements)
elif rep is None:
mrep = None
return mrep
def repetition_masq2fata(rep: Optional[Repetition]):
if isinstance(rep, Grid):
frep = fatamorgana.GridRepetition(
a_vector=numpy.round(rep.a_vector).astype(int),
b_vector=numpy.round(rep.b_vector).astype(int),
a_count=numpy.round(rep.a_count).astype(int),
b_count=numpy.round(rep.b_count).astype(int))
offset = (0, 0)
elif isinstance(rep, Arbitrary):
diffs = numpy.diff(rep.displacements, axis=0)
diff_ints = numpy.round(diffs).astype(int)
frep = fatamorgana.ArbitraryRepetition(diff_ints[:, 0], diff_ints[:, 1])
offset = rep.displacements[0, :]
else:
assert(rep is None)
frep = None
offset = (0, 0)
return frep, offset