various doc updates

This commit is contained in:
jan 2023-09-17 21:33:22 -07:00
commit e2c7f8c8cc
7 changed files with 132 additions and 41 deletions

View file

@ -495,12 +495,12 @@ def _labels_to_texts(labels: dict[layer_t, list[Label]]) -> list[klamath.element
xy=xy,
string=label.string.encode('ASCII'),
properties=properties,
presentation=0, # TODO maybe set some of these?
angle_deg=0,
invert_y=False,
width=0,
path_type=0,
mag=1,
presentation=0, # font number & alignment -- unused by us
angle_deg=0, # rotation -- unused by us
invert_y=False, # inversion -- unused by us
width=0, # stroke width -- unused by us
path_type=0, # text path endcaps, unused
mag=1, # size -- unused by us
)
texts.append(text)
return texts

View file

@ -2,7 +2,7 @@
Library classes for managing unique name->pattern mappings and
deferred loading or creation.
# TODO documentn all library classes
# TODO documennt all library classes
# TODO toplevel documentation of library, classes, and abstracts
"""
from typing import Callable, Self, Type, TYPE_CHECKING, cast

View file

@ -1,5 +1,6 @@
"""
Base object representing a lithography mask.
Object representing a one multi-layer lithographic layout.
A single level of hierarchical references is included.
"""
from typing import Callable, Sequence, cast, Mapping, Self, Any, Iterable, TypeVar, MutableMapping
import copy
@ -27,7 +28,7 @@ logger = logging.getLogger(__name__)
class Pattern(PortList, AnnotatableImpl, Mirrorable):
"""
2D layout consisting of some set of shapes, labels, and references to other Pattern objects
(via Ref). Shapes are assumed to inherit from masque.shapes.Shape or provide equivalent functions.
(via Ref). Shapes are assumed to inherit from `masque.shapes.Shape` or provide equivalent functions.
"""
__slots__ = (
'shapes', 'labels', 'refs', '_ports',
@ -864,6 +865,19 @@ TT = TypeVar('TT')
def chain_elements(*args: Mapping[Any, Iterable[TT]]) -> Iterable[TT]:
"""
Iterate over each element in one or more {layer: elements} mappings.
Useful when you want to do some operation on all shapes and/or labels,
disregarding which layer they are on.
Args:
*args: One or more {layer: [element0, ...]} mappings.
Can also be applied to e.g. {target: [ref0, ...]} mappings.
Returns:
An iterable containing all elements, regardless of layer.
"""
return chain(*(chain.from_iterable(aa.values()) for aa in args))
@ -871,6 +885,20 @@ def map_layers(
elements: Mapping[layer_t, Sequence[TT]],
map_layer: Callable[[layer_t], layer_t],
) -> defaultdict[layer_t, list[TT]]:
"""
Move all the elements from one layer onto a different layer.
Can also handle multiple such mappings simultaneously.
Args:
elements: Mapping of {old_layer: geometry_or_labels}.
map_layer: Callable which may be called with each layer present in `elements`,
and should return the new layer to which it will be mapped.
A simple example which maps `old_layer` to `new_layer` and leaves all others
as-is would look like `lambda layer: {old_layer: new_layer}.get(layer, layer)`
Returns:
Mapping of {new_layer: geometry_or_labels}
"""
new_elements: defaultdict[layer_t, list[TT]] = defaultdict(list)
for old_layer, seq in elements.items():
new_layer = map_layer(old_layer)
@ -882,6 +910,20 @@ def map_targets(
refs: Mapping[str | None, Sequence[Ref]],
map_target: Callable[[str | None], str | None],
) -> defaultdict[str | None, list[Ref]]:
"""
Change the target of all references to a given cell.
Can also handle multiple such mappings simultaneously.
Args:
refs: Mapping of {old_target: ref_objects}.
map_target: Callable which may be called with each target present in `refs`,
and should return the new target to which it will be mapped.
A simple example which maps `old_target` to `new_target` and leaves all others
as-is would look like `lambda target: {old_target: new_target}.get(target, target)`
Returns:
Mapping of {new_target: ref_objects}
"""
new_refs: defaultdict[str | None, list[Ref]] = defaultdict(list)
for old_target, seq in refs.items():
new_target = map_target(old_target)

View file

@ -1,9 +1,7 @@
"""
Ref provides basic support for nesting Pattern objects within each other, by adding
offset, rotation, scaling, and other such properties to the reference.
Ref provides basic support for nesting Pattern objects within each other.
It carries offset, rotation, mirroring, and scaling data for each individual instance.
"""
#TODO more top-level documentation for ref
from typing import Mapping, TYPE_CHECKING, Self
import copy
@ -28,10 +26,15 @@ class Ref(
PivotableImpl, Copyable, RepeatableImpl, AnnotatableImpl,
):
"""
`Ref` provides basic support for nesting Pattern objects within each other, by adding
offset, rotation, scaling, and associated methods.
`Ref` provides basic support for nesting Pattern objects within each other.
Note: Order is (mirror, rotate, scale, translate, repeat)
It containts the transformation (mirror, rotation, scale, offset, repetition)
and annotations for a single instantiation of a `Pattern`.
Note that the target (i.e. which pattern a `Ref` instantiates) is not stored within the
`Ref` itself, but is specified by the containing `Pattern`.
Order of operations is (mirror, rotate, scale, translate, repeat).
"""
__slots__ = (
'_mirrored',

View file

@ -26,6 +26,9 @@ class Path(Shape):
A path, consisting of a bunch of vertices (Nx2 ndarray), a width, an end-cap shape,
and an offset.
Note that the setter for `Path.vertices` may (but may not) create a copy of the
passed vertex coordinates. See `numpy.array(..., copy=False)` for details.
A normalized_form(...) is available, but can be quite slow with lots of vertices.
"""
__slots__ = (
@ -61,12 +64,14 @@ class Path(Shape):
def cap(self) -> PathCap:
"""
Path end-cap
Note that `cap_extensions` will be reset to default values if
`cap` is changed away from `PathCap.SquareCustom`.
"""
return self._cap
@cap.setter
def cap(self, val: PathCap) -> None:
# TODO: Document that setting cap can change cap_extensions
self._cap = PathCap(val)
if self.cap != PathCap.SquareCustom:
self.cap_extensions = None
@ -80,6 +85,9 @@ class Path(Shape):
"""
Path end-cap extension
Note that `cap_extensions` will be reset to default values if
`cap` is changed away from `PathCap.SquareCustom`.
Returns:
2-element ndarray or `None`
"""
@ -101,13 +109,16 @@ class Path(Shape):
@property
def vertices(self) -> Any: # mypy#3004 NDArray[numpy.float64]]:
"""
Vertices of the path (Nx2 ndarray: `[[x0, y0], [x1, y1], ...]`)
Vertices of the path (Nx2 ndarray: `[[x0, y0], [x1, y1], ...]`
When setting, note that a copy of the provided vertices may or may not be made,
following the rules from `numpy.array(.., copy=False)`.
"""
return self._vertices
@vertices.setter
def vertices(self, val: ArrayLike) -> None:
val = numpy.array(val, dtype=float) # TODO document that these might not be copied
val = numpy.array(val, dtype=float)
if len(val.shape) < 2 or val.shape[1] != 2:
raise PatternError('Vertices must be an Nx2 array')
if val.shape[0] < 2:
@ -218,7 +229,7 @@ class Path(Shape):
Returns:
The resulting Path object
"""
# TODO: needs testing
# TODO: Path.travel() needs testing
direction = numpy.array([1, 0])
verts = [numpy.zeros(2)]

View file

@ -18,7 +18,7 @@ class Polygon(Shape):
implicitly-closed boundary, and an offset.
Note that the setter for `Polygon.vertices` may (but may not) create a copy of the
passed vertex coordinates. See `numpy.array()` for details.
passed vertex coordinates. See `numpy.array(..., copy=False)` for details.
A `normalized_form(...)` is available, but can be quite slow with lots of vertices.
"""
@ -36,12 +36,15 @@ class Polygon(Shape):
def vertices(self) -> Any: # mypy#3004 NDArray[numpy.float64]:
"""
Vertices of the polygon (Nx2 ndarray: `[[x0, y0], [x1, y1], ...]`)
When setting, note that a copy of the provided vertices may or may not be made,
following the rules from `numpy.array(.., copy=False)`.
"""
return self._vertices
@vertices.setter
def vertices(self, val: ArrayLike) -> None:
val = numpy.array(val, dtype=float) # note that this hopefully won't create a copy
val = numpy.array(val, dtype=float)
if len(val.shape) < 2 or val.shape[1] != 2:
raise PatternError('Vertices must be an Nx2 array')
if val.shape[0] < 3: