wip again
This commit is contained in:
parent
db9a6269a1
commit
7ca017d993
26 changed files with 273 additions and 336 deletions
|
|
@ -35,7 +35,6 @@ def write(
|
|||
*,
|
||||
modify_originals: bool = False,
|
||||
dxf_version='AC1024',
|
||||
disambiguate_func: Callable[[Iterable[str]], List[str]] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Write a `Pattern` to a DXF file, by first calling `.polygonize()` to change the shapes
|
||||
|
|
@ -73,20 +72,15 @@ def write(
|
|||
WARNING: No additional error checking is performed on the results.
|
||||
"""
|
||||
#TODO consider supporting DXF arcs?
|
||||
if disambiguate_func is None:
|
||||
disambiguate_func = lambda pats: disambiguate_pattern_names(pats)
|
||||
assert(disambiguate_func is not None)
|
||||
|
||||
#TODO name checking
|
||||
bad_keys = check_valid_names(library.keys())
|
||||
|
||||
if not modify_originals:
|
||||
library = library.deepcopy()
|
||||
|
||||
pattern = library[top_name]
|
||||
|
||||
old_names = list(library.keys())
|
||||
new_names = disambiguate_func(old_names)
|
||||
renamed_lib = {new_name: library[old_name]
|
||||
for old_name, new_name in zip(old_names, new_names)}
|
||||
|
||||
# Create library
|
||||
lib = ezdxf.new(dxf_version, setup=True)
|
||||
msp = lib.modelspace()
|
||||
|
|
@ -95,7 +89,7 @@ def write(
|
|||
_subpatterns_to_refs(msp, pattern.subpatterns)
|
||||
|
||||
# Now create a block for each referenced pattern, and add in any shapes
|
||||
for name, pat in renamed_lib.items():
|
||||
for name, pat in library.items():
|
||||
assert(pat is not None)
|
||||
block = lib.blocks.new(name=name)
|
||||
|
||||
|
|
@ -388,10 +382,6 @@ def disambiguate_pattern_names(
|
|||
|
||||
if sanitized_name == '':
|
||||
logger.warning(f'Empty pattern name saved as "{suffixed_name}"')
|
||||
elif suffixed_name != sanitized_name:
|
||||
if dup_warn_filter is None or dup_warn_filter(name):
|
||||
logger.warning(f'Pattern name "{name}" ({sanitized_name}) appears multiple times;\n'
|
||||
+ f' renaming to "{suffixed_name}"')
|
||||
|
||||
if len(suffixed_name) == 0:
|
||||
# Should never happen since zero-length names are replaced
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Notes:
|
|||
* Creation/modification/access times are set to 1900-01-01 for reproducibility.
|
||||
"""
|
||||
from typing import List, Any, Dict, Tuple, Callable, Union, Iterable, Optional
|
||||
from typing import Sequence, BinaryIO
|
||||
from typing import Sequence, BinaryIO, Mapping
|
||||
import re
|
||||
import io
|
||||
import mmap
|
||||
|
|
@ -40,7 +40,8 @@ from .. import Pattern, SubPattern, PatternError, Label, Shape
|
|||
from ..shapes import Polygon, Path
|
||||
from ..repetition import Grid
|
||||
from ..utils import layer_t, normalize_mirror, annotations_t
|
||||
from ..library import Library
|
||||
from ..library import LazyLibrary, WrapLibrary, MutableLibrary
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -65,7 +66,6 @@ def write(
|
|||
library_name: str = 'masque-klamath',
|
||||
*,
|
||||
modify_originals: bool = False,
|
||||
disambiguate_func: Callable[[Iterable[str]], List[str]] = None,
|
||||
) -> None:
|
||||
"""
|
||||
Convert a library to a GDSII stream, mapping data as follows:
|
||||
|
|
@ -100,24 +100,22 @@ def write(
|
|||
modify_originals: If `True`, the original pattern is modified as part of the writing
|
||||
process. Otherwise, a copy is made.
|
||||
Default `False`.
|
||||
disambiguate_func: Function which takes a list of pattern names and returns a list of names
|
||||
altered to be valid and unique. Default is `disambiguate_pattern_names`, which
|
||||
attempts to adhere to the GDSII standard reasonably well.
|
||||
WARNING: No additional error checking is performed on the results.
|
||||
"""
|
||||
if disambiguate_func is None:
|
||||
disambiguate_func = disambiguate_pattern_names
|
||||
# TODO check name errors
|
||||
bad_keys = check_valid_names(library.keys())
|
||||
|
||||
# TODO check all hierarchy present
|
||||
|
||||
if not modify_originals:
|
||||
library = copy.deepcopy(library)
|
||||
library = library.deepcopy() #TODO figure out best approach e.g. if lazy
|
||||
|
||||
for p in library.values():
|
||||
library.add(p.wrap_repeated_shapes())
|
||||
if not isinstance(library, MutableLibrary):
|
||||
if isinstance(library, dict):
|
||||
library = WrapLibrary(library)
|
||||
else:
|
||||
library = WrapLibrary(dict(library))
|
||||
|
||||
old_names = list(library.keys())
|
||||
new_names = disambiguate_func(old_names)
|
||||
renamed_lib = {new_name: library[old_name]
|
||||
for old_name, new_name in zip(old_names, new_names)}
|
||||
library.wrap_repeated_shapes()
|
||||
|
||||
# Create library
|
||||
header = klamath.library.FileHeader(
|
||||
|
|
@ -128,7 +126,7 @@ def write(
|
|||
header.write(stream)
|
||||
|
||||
# Now create a structure for each pattern, and add in any Boundary and SREF elements
|
||||
for name, pat in renamed_lib.items():
|
||||
for name, pat in library.items():
|
||||
elements: List[klamath.elements.Element] = []
|
||||
elements += _shapes_to_elements(pat.shapes)
|
||||
elements += _labels_to_texts(pat.labels)
|
||||
|
|
@ -162,7 +160,7 @@ def writefile(
|
|||
open_func = open
|
||||
|
||||
with io.BufferedWriter(open_func(path, mode='wb')) as stream:
|
||||
write(patterns, stream, *args, **kwargs)
|
||||
write(library, stream, *args, **kwargs)
|
||||
|
||||
|
||||
def readfile(
|
||||
|
|
@ -310,7 +308,7 @@ def _ref_to_subpat(ref: klamath.library.Reference) -> SubPattern:
|
|||
a_count=a_count, b_count=b_count)
|
||||
|
||||
subpat = SubPattern(
|
||||
pattern=ref.struct_name.decode('ASCII'),
|
||||
target=ref.struct_name.decode('ASCII'),
|
||||
offset=offset,
|
||||
rotation=numpy.deg2rad(ref.angle_deg),
|
||||
scale=ref.mag,
|
||||
|
|
@ -547,10 +545,6 @@ def disambiguate_pattern_names(
|
|||
|
||||
if sanitized_name == '':
|
||||
logger.warning(f'Empty pattern name saved as "{suffixed_name}"')
|
||||
elif suffixed_name != sanitized_name:
|
||||
if dup_warn_filter is None or dup_warn_filter(name):
|
||||
logger.warning(f'Pattern name "{name}" ({sanitized_name}) appears multiple times;\n'
|
||||
+ f' renaming to "{suffixed_name}"')
|
||||
|
||||
# Encode into a byte-string and perform some final checks
|
||||
encoded_name = suffixed_name.encode('ASCII')
|
||||
|
|
@ -569,7 +563,7 @@ def load_library(
|
|||
stream: BinaryIO,
|
||||
*,
|
||||
full_load: bool = False,
|
||||
) -> Tuple[Library, Dict[str, Any]]:
|
||||
) -> Tuple[LazyLibrary, Dict[str, Any]]:
|
||||
"""
|
||||
Scan a GDSII stream to determine what structures are present, and create
|
||||
a library from them. This enables deferred reading of structures
|
||||
|
|
@ -586,11 +580,11 @@ def load_library(
|
|||
will be faster than using the resulting library's `precache` method.
|
||||
|
||||
Returns:
|
||||
Library object, allowing for deferred load of structures.
|
||||
LazyLibrary object, allowing for deferred load of structures.
|
||||
Additional library info (dict, same format as from `read`).
|
||||
"""
|
||||
stream.seek(0)
|
||||
lib = Library()
|
||||
lib = LazyLibrary()
|
||||
|
||||
if full_load:
|
||||
# Full load approach (immediately load everything)
|
||||
|
|
@ -620,7 +614,7 @@ def load_libraryfile(
|
|||
*,
|
||||
use_mmap: bool = True,
|
||||
full_load: bool = False,
|
||||
) -> Tuple[Library, Dict[str, Any]]:
|
||||
) -> Tuple[LazyLibrary, Dict[str, Any]]:
|
||||
"""
|
||||
Wrapper for `load_library()` that takes a filename or path instead of a stream.
|
||||
|
||||
|
|
@ -638,7 +632,7 @@ def load_libraryfile(
|
|||
full_load: If `True`, immediately loads all data. See `load_library`.
|
||||
|
||||
Returns:
|
||||
Library object, allowing for deferred load of structures.
|
||||
LazyLibrary object, allowing for deferred load of structures.
|
||||
Additional library info (dict, same format as from `read`).
|
||||
"""
|
||||
path = pathlib.Path(filename)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ from fatamorgana.basic import PathExtensionScheme, AString, NString, PropStringR
|
|||
|
||||
from .utils import is_gzipped
|
||||
from .. import Pattern, SubPattern, PatternError, Label, Shape
|
||||
from ..library import WrapLibrary, MutableLibrary
|
||||
from ..shapes import Polygon, Path, Circle
|
||||
from ..repetition import Grid, Arbitrary, Repetition
|
||||
from ..utils import layer_t, normalize_mirror, annotations_t
|
||||
|
|
@ -57,7 +58,6 @@ def build(
|
|||
units_per_micron: int,
|
||||
layer_map: Optional[Dict[str, Union[int, Tuple[int, int]]]] = None,
|
||||
*,
|
||||
disambiguate_func: Optional[Callable[[Iterable[str]], List[str]]] = None,
|
||||
annotations: Optional[annotations_t] = None,
|
||||
) -> fatamorgana.OasisLayout:
|
||||
"""
|
||||
|
|
@ -90,15 +90,22 @@ def build(
|
|||
into numbers, omit this argument, and manually generate the required
|
||||
`fatamorgana.records.LayerName` entries.
|
||||
Default is an empty dict (no names provided).
|
||||
disambiguate_func: Function which takes a list of pattern names and returns a list of names
|
||||
altered to be valid and unique. Default is `disambiguate_pattern_names`.
|
||||
annotations: dictionary of key-value pairs which are saved as library-level properties
|
||||
|
||||
Returns:
|
||||
`fatamorgana.OasisLayout`
|
||||
"""
|
||||
if isinstance(patterns, Pattern):
|
||||
patterns = [patterns]
|
||||
|
||||
# TODO check names
|
||||
bad_keys = check_valid_names(library.keys())
|
||||
|
||||
# TODO check all hierarchy present
|
||||
|
||||
if not isinstance(library, MutableLibrary):
|
||||
if isinstance(library, dict):
|
||||
library = WrapLibrary(library)
|
||||
else:
|
||||
library = WrapLibrary(dict(library))
|
||||
|
||||
if layer_map is None:
|
||||
layer_map = {}
|
||||
|
|
@ -132,13 +139,8 @@ def build(
|
|||
else:
|
||||
layer2oas = _mlayer2oas
|
||||
|
||||
old_names = list(library.keys())
|
||||
new_names = disambiguate_func(old_names)
|
||||
renamed_lib = {new_name: library[old_name]
|
||||
for old_name, new_name in zip(old_names, new_names)}
|
||||
|
||||
# Now create a structure for each pattern
|
||||
for name, pat in renamed_lib.items():
|
||||
for name, pat in library.items():
|
||||
structure = fatamorgana.Cell(name=name)
|
||||
lib.cells.append(structure)
|
||||
|
||||
|
|
@ -152,7 +154,7 @@ def build(
|
|||
|
||||
|
||||
def write(
|
||||
patterns: Union[Sequence[Pattern], Pattern],
|
||||
library: Mapping[str, Pattern], # NOTE: Pattern here should be treated as immutable!
|
||||
stream: io.BufferedIOBase,
|
||||
*args,
|
||||
**kwargs,
|
||||
|
|
@ -162,17 +164,17 @@ def write(
|
|||
for details.
|
||||
|
||||
Args:
|
||||
patterns: A Pattern or list of patterns to write to file.
|
||||
library: A {name: Pattern} mapping of patterns to write.
|
||||
stream: Stream to write to.
|
||||
*args: passed to `oasis.build()`
|
||||
**kwargs: passed to `oasis.build()`
|
||||
"""
|
||||
lib = build(patterns, *args, **kwargs)
|
||||
lib = build(library, *args, **kwargs)
|
||||
lib.write(stream)
|
||||
|
||||
|
||||
def writefile(
|
||||
patterns: Union[Sequence[Pattern], Pattern],
|
||||
library: Mapping[str, Pattern], # NOTE: Pattern here should be treated as immutable!
|
||||
filename: Union[str, pathlib.Path],
|
||||
*args,
|
||||
**kwargs,
|
||||
|
|
@ -183,7 +185,7 @@ def writefile(
|
|||
Will automatically compress the file if it has a .gz suffix.
|
||||
|
||||
Args:
|
||||
patterns: `Pattern` or list of patterns to save
|
||||
library: A {name: Pattern} mapping of patterns to write.
|
||||
filename: Filename to save to.
|
||||
*args: passed to `oasis.write`
|
||||
**kwargs: passed to `oasis.write`
|
||||
|
|
@ -195,7 +197,7 @@ def writefile(
|
|||
open_func = open
|
||||
|
||||
with io.BufferedWriter(open_func(path, mode='wb')) as stream:
|
||||
write(patterns, stream, *args, **kwargs)
|
||||
write(library, stream, *args, **kwargs)
|
||||
|
||||
|
||||
def readfile(
|
||||
|
|
@ -281,11 +283,13 @@ def read(
|
|||
vertices = numpy.cumsum(numpy.vstack(((0, 0), element.get_point_list()[:-1])), axis=0)
|
||||
|
||||
annotations = properties_to_annotations(element.properties, lib.propnames, lib.propstrings)
|
||||
poly = Polygon(vertices=vertices,
|
||||
layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
annotations=annotations,
|
||||
repetition=repetition)
|
||||
poly = Polygon(
|
||||
vertices=vertices,
|
||||
layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
annotations=annotations,
|
||||
repetition=repetition,
|
||||
)
|
||||
|
||||
pat.shapes.append(poly)
|
||||
|
||||
|
|
@ -304,14 +308,16 @@ def read(
|
|||
element.get_extension_end()[1]))
|
||||
|
||||
annotations = properties_to_annotations(element.properties, lib.propnames, lib.propstrings)
|
||||
path = Path(vertices=vertices,
|
||||
layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
repetition=repetition,
|
||||
annotations=annotations,
|
||||
width=element.get_half_width() * 2,
|
||||
cap=cap,
|
||||
**path_args)
|
||||
path = Path(
|
||||
vertices=vertices,
|
||||
layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
repetition=repetition,
|
||||
annotations=annotations,
|
||||
width=element.get_half_width() * 2,
|
||||
cap=cap,
|
||||
**path_args,
|
||||
)
|
||||
|
||||
pat.shapes.append(path)
|
||||
|
||||
|
|
@ -319,12 +325,13 @@ def read(
|
|||
width = element.get_width()
|
||||
height = element.get_height()
|
||||
annotations = properties_to_annotations(element.properties, lib.propnames, lib.propstrings)
|
||||
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),
|
||||
annotations=annotations,
|
||||
)
|
||||
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),
|
||||
annotations=annotations,
|
||||
)
|
||||
pat.shapes.append(rect)
|
||||
|
||||
elif isinstance(element, fatrec.Trapezoid):
|
||||
|
|
@ -408,21 +415,24 @@ def read(
|
|||
vertices[0, 1] += width
|
||||
|
||||
annotations = properties_to_annotations(element.properties, lib.propnames, lib.propstrings)
|
||||
ctrapz = Polygon(layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
repetition=repetition,
|
||||
vertices=vertices,
|
||||
annotations=annotations,
|
||||
)
|
||||
ctrapz = Polygon(
|
||||
layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
repetition=repetition,
|
||||
vertices=vertices,
|
||||
annotations=annotations,
|
||||
)
|
||||
pat.shapes.append(ctrapz)
|
||||
|
||||
elif isinstance(element, fatrec.Circle):
|
||||
annotations = properties_to_annotations(element.properties, lib.propnames, lib.propstrings)
|
||||
circle = Circle(layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
repetition=repetition,
|
||||
annotations=annotations,
|
||||
radius=float(element.get_radius()))
|
||||
circle = Circle(
|
||||
layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
repetition=repetition,
|
||||
annotations=annotations,
|
||||
radius=float(element.get_radius()),
|
||||
)
|
||||
pat.shapes.append(circle)
|
||||
|
||||
elif isinstance(element, fatrec.Text):
|
||||
|
|
@ -432,11 +442,13 @@ def read(
|
|||
string = lib.textstrings[str_or_ref].string
|
||||
else:
|
||||
string = str_or_ref.string
|
||||
label = Label(layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
repetition=repetition,
|
||||
annotations=annotations,
|
||||
string=string)
|
||||
label = Label(
|
||||
layer=element.get_layer_tuple(),
|
||||
offset=element.get_xy(),
|
||||
repetition=repetition,
|
||||
annotations=annotations,
|
||||
string=string,
|
||||
)
|
||||
pat.labels.append(label)
|
||||
|
||||
else:
|
||||
|
|
@ -446,7 +458,7 @@ def read(
|
|||
for placement in cell.placements:
|
||||
pat.subpatterns.append(_placement_to_subpat(placement, lib))
|
||||
|
||||
patterns_dict[name] = pat
|
||||
patterns_dict[cell_name] = pat
|
||||
|
||||
return patterns_dict, library_info
|
||||
|
||||
|
|
@ -516,7 +528,8 @@ def _subpatterns_to_placements(
|
|||
properties=annotations_to_properties(subpat.annotations),
|
||||
x=offset[0],
|
||||
y=offset[1],
|
||||
repetition=frep)
|
||||
repetition=frep,
|
||||
)
|
||||
|
||||
refs.append(ref)
|
||||
return refs
|
||||
|
|
@ -605,7 +618,6 @@ def _labels_to_texts(
|
|||
|
||||
def disambiguate_pattern_names(
|
||||
names: Iterable[str],
|
||||
dup_warn_filter: Callable[[str], bool] = None, # If returns False, don't warn about this name
|
||||
) -> List[str]:
|
||||
new_names = []
|
||||
for name in names:
|
||||
|
|
@ -621,10 +633,6 @@ def disambiguate_pattern_names(
|
|||
|
||||
if sanitized_name == '':
|
||||
logger.warning(f'Empty pattern name saved as "{suffixed_name}"')
|
||||
elif suffixed_name != sanitized_name:
|
||||
if dup_warn_filter is None or dup_warn_filter(name):
|
||||
logger.warning(f'Pattern name "{name}" ({sanitized_name}) appears multiple times;\n'
|
||||
+ f' renaming to "{suffixed_name}"')
|
||||
|
||||
if len(suffixed_name) == 0:
|
||||
# Should never happen since zero-length names are replaced
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ def build(
|
|||
library_name: str = 'masque-gdsii-write',
|
||||
*,
|
||||
modify_originals: bool = False,
|
||||
disambiguate_func: Callable[[Iterable[str]], List[str]] = None,
|
||||
) -> gdsii.library.Library:
|
||||
"""
|
||||
Convert a `Pattern` or list of patterns to a GDSII stream, by first calling
|
||||
|
|
@ -97,22 +96,20 @@ def build(
|
|||
modify_originals: If `True`, the original pattern is modified as part of the writing
|
||||
process. Otherwise, a copy is made.
|
||||
Default `False`.
|
||||
disambiguate_func: Function which takes a list of pattern names and returns a list of names
|
||||
altered to be valid and unique. Default is `disambiguate_pattern_names`, which
|
||||
attempts to adhere to the GDSII standard reasonably well.
|
||||
WARNING: No additional error checking is performed on the results.
|
||||
|
||||
Returns:
|
||||
`gdsii.library.Library`
|
||||
"""
|
||||
if disambiguate_func is None:
|
||||
disambiguate_func = disambiguate_pattern_names
|
||||
# TODO check name errors
|
||||
bad_keys = check_valid_names(library.keys())
|
||||
|
||||
# TODO check all hierarchy present
|
||||
|
||||
|
||||
if not modify_originals:
|
||||
library = copy.deepcopy(library)
|
||||
library = library.deepcopy() #TODO figure out best approach e.g. if lazy
|
||||
|
||||
for p in library.values():
|
||||
library.add(p.wrap_repeated_shapes())
|
||||
library.wrap_repeated_shapes()
|
||||
|
||||
old_names = list(library.keys())
|
||||
new_names = disambiguate_func(old_names)
|
||||
|
|
@ -181,7 +178,7 @@ def writefile(
|
|||
open_func = open
|
||||
|
||||
with io.BufferedWriter(open_func(path, mode='wb')) as stream:
|
||||
write(patterns, stream, *args, **kwargs)
|
||||
write(library, stream, *args, **kwargs)
|
||||
|
||||
|
||||
def readfile(
|
||||
|
|
@ -248,7 +245,7 @@ def read(
|
|||
patterns_dict = {}
|
||||
for structure in lib:
|
||||
pat = Pattern()
|
||||
name=structure.name.decode('ASCII')
|
||||
name = structure.name.decode('ASCII')
|
||||
for element in structure:
|
||||
# Switch based on element type:
|
||||
if isinstance(element, gdsii.elements.Boundary):
|
||||
|
|
@ -260,9 +257,11 @@ def read(
|
|||
pat.shapes.append(path)
|
||||
|
||||
elif isinstance(element, gdsii.elements.Text):
|
||||
label = Label(offset=element.xy.astype(float),
|
||||
layer=(element.layer, element.text_type),
|
||||
string=element.string.decode('ASCII'))
|
||||
label = Label(
|
||||
offset=element.xy.astype(float),
|
||||
layer=(element.layer, element.text_type),
|
||||
string=element.string.decode('ASCII'),
|
||||
)
|
||||
pat.labels.append(label)
|
||||
|
||||
elif isinstance(element, (gdsii.elements.SRef, gdsii.elements.ARef)):
|
||||
|
|
@ -296,7 +295,7 @@ def _ref_to_subpat(
|
|||
gdsii.elements.ARef]
|
||||
) -> SubPattern:
|
||||
"""
|
||||
Helper function to create a SubPattern from an SREF or AREF. Sets subpat.target to struct_name.
|
||||
Helper function to create a SubPattern from an SREF or AREF. Sets `subpat.target` to `element.struct_name`.
|
||||
|
||||
NOTE: "Absolute" means not affected by parent elements.
|
||||
That's not currently supported by masque at all (and not planned).
|
||||
|
|
@ -330,13 +329,15 @@ def _ref_to_subpat(
|
|||
repetition = Grid(a_vector=a_vector, b_vector=b_vector,
|
||||
a_count=a_count, b_count=b_count)
|
||||
|
||||
subpat = SubPattern(pattern=None,
|
||||
offset=offset,
|
||||
rotation=rotation,
|
||||
scale=scale,
|
||||
mirrored=(mirror_across_x, False),
|
||||
annotations=_properties_to_annotations(element.properties),
|
||||
repetition=repetition)
|
||||
subpat = SubPattern(
|
||||
target=element.struct_name,
|
||||
offset=offset,
|
||||
rotation=rotation,
|
||||
scale=scale,
|
||||
mirrored=(mirror_across_x, False),
|
||||
annotations=_properties_to_annotations(element.properties),
|
||||
repetition=repetition,
|
||||
)
|
||||
return subpat
|
||||
|
||||
|
||||
|
|
@ -346,14 +347,15 @@ def _gpath_to_mpath(element: gdsii.elements.Path, raw_mode: bool) -> Path:
|
|||
else:
|
||||
raise PatternError(f'Unrecognized path type: {element.path_type}')
|
||||
|
||||
args = {'vertices': element.xy.astype(float),
|
||||
'layer': (element.layer, element.data_type),
|
||||
'width': element.width if element.width is not None else 0.0,
|
||||
'cap': cap,
|
||||
'offset': numpy.zeros(2),
|
||||
'annotations': _properties_to_annotations(element.properties),
|
||||
'raw': raw_mode,
|
||||
}
|
||||
args = {
|
||||
'vertices': element.xy.astype(float),
|
||||
'layer': (element.layer, element.data_type),
|
||||
'width': element.width if element.width is not None else 0.0,
|
||||
'cap': cap,
|
||||
'offset': numpy.zeros(2),
|
||||
'annotations': _properties_to_annotations(element.properties),
|
||||
'raw': raw_mode,
|
||||
}
|
||||
|
||||
if cap == Path.Cap.SquareCustom:
|
||||
args['cap_extensions'] = numpy.zeros(2)
|
||||
|
|
@ -511,7 +513,6 @@ def disambiguate_pattern_names(
|
|||
names: Iterable[str],
|
||||
max_name_length: int = 32,
|
||||
suffix_length: int = 6,
|
||||
dup_warn_filter: Optional[Callable[[str], bool]] = None,
|
||||
) -> List[str]:
|
||||
"""
|
||||
Args:
|
||||
|
|
@ -519,9 +520,6 @@ def disambiguate_pattern_names(
|
|||
max_name_length: Names longer than this will be truncated
|
||||
suffix_length: Names which get truncated are truncated by this many extra characters. This is to
|
||||
leave room for a suffix if one is necessary.
|
||||
dup_warn_filter: (optional) Function for suppressing warnings about cell names changing. Receives
|
||||
the cell name and returns `False` if the warning should be suppressed and `True` if it should
|
||||
be displayed. Default displays all warnings.
|
||||
"""
|
||||
new_names = []
|
||||
for name in names:
|
||||
|
|
@ -547,10 +545,6 @@ def disambiguate_pattern_names(
|
|||
|
||||
if sanitized_name == '':
|
||||
logger.warning(f'Empty pattern name saved as "{suffixed_name}"')
|
||||
elif suffixed_name != sanitized_name:
|
||||
if dup_warn_filter is None or dup_warn_filter(name):
|
||||
logger.warning(f'Pattern name "{name}" ({sanitized_name}) appears multiple times;\n'
|
||||
+ f' renaming to "{suffixed_name}"')
|
||||
|
||||
# Encode into a byte-string and perform some final checks
|
||||
encoded_name = suffixed_name.encode('ASCII')
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ def writefile_inverted(
|
|||
pattern = library[top]
|
||||
|
||||
# Polygonize and flatten pattern
|
||||
pattern.polygonize().flatten()
|
||||
pattern.polygonize().flatten(library)
|
||||
|
||||
bounds = pattern.get_bounds(library=library)
|
||||
if bounds is None:
|
||||
|
|
|
|||
|
|
@ -5,11 +5,16 @@ from typing import Set, Tuple, List, Iterable, Mapping
|
|||
import re
|
||||
import copy
|
||||
import pathlib
|
||||
import logging
|
||||
|
||||
from .. import Pattern, PatternError
|
||||
from ..library import Library, WrapROLibrary
|
||||
from ..shapes import Polygon, Path
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def mangle_name(name: str, dose_multiplier: float = 1.0) -> str:
|
||||
"""
|
||||
Create a new name using `name` and the `dose_multiplier`.
|
||||
|
|
@ -58,7 +63,7 @@ def make_dose_table(
|
|||
top_names: Iterable[str],
|
||||
library: Mapping[str, Pattern],
|
||||
dose_multiplier: float = 1.0,
|
||||
) -> Set[Tuple[int, float]]:
|
||||
) -> Set[Tuple[str, float]]:
|
||||
"""
|
||||
Create a set containing `(name, written_dose)` for each pattern (including subpatterns)
|
||||
|
||||
|
|
@ -104,7 +109,7 @@ def dtype2dose(pattern: Pattern) -> Pattern:
|
|||
|
||||
|
||||
def dose2dtype(
|
||||
library: List[Pattern],
|
||||
library: Mapping[str, Pattern],
|
||||
) -> Tuple[List[Pattern], List[float]]:
|
||||
"""
|
||||
For each shape in each pattern, set shape.layer to the tuple
|
||||
|
|
@ -128,6 +133,10 @@ def dose2dtype(
|
|||
and dose (float, list entry).
|
||||
"""
|
||||
logger.warning('TODO: dose2dtype() needs to be tested!')
|
||||
|
||||
if not isinstance(library, Library):
|
||||
library = WrapROLibrary(library)
|
||||
|
||||
# Get a table of (id(pat), written_dose) for each pattern and subpattern
|
||||
sd_table = make_dose_table(library.find_topcells(), library)
|
||||
|
||||
|
|
@ -161,8 +170,8 @@ def dose2dtype(
|
|||
|
||||
pat = old_pat.deepcopy()
|
||||
|
||||
if len(encoded_name) == 0:
|
||||
raise PatternError('Zero-length name after mangle+encode, originally "{name}"'.format(pat.name))
|
||||
if len(mangled_name) == 0:
|
||||
raise PatternError(f'Zero-length name after mangle, originally "{name}"')
|
||||
|
||||
for shape in pat.shapes:
|
||||
data_type = dose_vals_list.index(shape.dose * pat_dose)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue