Compare commits

..

No commits in common. "59e996e680ec2092f63f4de445c14431197ff9e0" and "d40bdb1cb2e7f5f49a4648a9ab8f9ec0e737fc74" have entirely different histories.

7 changed files with 18 additions and 74 deletions

View file

@ -18,14 +18,11 @@ Contents
* Design a pattern which is meant to plug into an existing pattern (via `.interface()`)
- [pather](pather.py)
* Use `Pather` to route individual wires and wire bundles
* Use `AutoTool` to generate paths
* Use `AutoTool` to automatically transition between path types
- [renderpather](renderpather.py)
* Use `BasicTool` to generate paths
* Use `BasicTool` to automatically transition between path types
- [renderpather](rendpather.py)
* Use `RenderPather` and `PathTool` to build a layout similar to the one in [pather](pather.py),
but using `Path` shapes instead of `Polygon`s.
- [port_pather](port_pather.py)
* Use `PortPather` and the `.at()` syntax for more concise routing
* Advanced port manipulation and connections
Additionaly, [pcgen](pcgen.py) is a utility module for generating photonic crystal lattices.

View file

@ -2,8 +2,9 @@
import numpy
from numpy import pi
from masque import layer_t, Pattern, Circle, Arc, Polygon, Ref
from masque.repetition import Grid
from masque import (
layer_t, Pattern, Circle, Arc, Polygon,
)
import masque.file.gdsii
@ -36,45 +37,6 @@ def hole(
return pat
def hole_array(
radius: float,
num_x: int = 5,
num_y: int = 3,
pitch: float = 2000,
layer: layer_t = (1, 0),
) -> Pattern:
"""
Generate an array of circular holes using `Repetition`.
Args:
radius: Circle radius.
num_x, num_y: Number of holes in x and y.
pitch: Center-to-center spacing.
layer: Layer to draw the holes on.
Returns:
Pattern containing a grid of holes.
"""
# First, make a pattern for a single hole
hpat = hole(radius, layer)
# Now, create a pattern that references it multiple times using a Grid
pat = Pattern()
pat.refs['hole'] = [
Ref(
offset=(0, 0),
repetition=Grid(a_vector=(pitch, 0), a_count=num_x,
b_vector=(0, pitch), b_count=num_y)
)]
# We can also add transformed references (rotation, mirroring, etc.)
pat.refs['hole'].append(
Ref(offset=(0, -pitch), rotation=pi / 4, mirrored=True)
)
return pat, hpat
def triangle(
radius: float,
layer: layer_t = (1, 0),
@ -96,7 +58,9 @@ def triangle(
]) * radius
pat = Pattern()
pat.polygon(layer, vertices=vertices)
pat.shapes[layer].extend([
Polygon(offset=(0, 0), vertices=vertices),
])
return pat
@ -145,13 +109,9 @@ def main() -> None:
lib['smile'] = smile(1000)
lib['triangle'] = triangle(1000)
# Use a Grid to make many holes efficiently
lib['grid'], lib['hole'] = hole_array(1000)
masque.file.gdsii.writefile(lib, 'basic_shapes.gds', **GDS_OPTS)
lib['triangle'].visualize()
lib['grid'].visualize(lib)
if __name__ == '__main__':

View file

@ -239,7 +239,7 @@ def main() -> None:
pather.path_to('GND', None, x=pather['VCC'].offset[0])
# Now, start using M1_tool for GND.
# Since we have defined an M2-to-M1 transition for Pather, we don't need to place one ourselves.
# Since we have defined an M2-to-M1 transition for BasicPather, we don't need to place one ourselves.
# If we wanted to place our via manually, we could add `pather.plug('m1_via', {'GND': 'top'})` here
# and achieve the same result without having to define any transitions in M1_tool.
# Note that even though we have changed the tool used for GND, the via doesn't get placed until

View file

@ -12,7 +12,7 @@ from pather import M1_WIDTH, V1_WIDTH, M2_WIDTH, map_layer, make_pad, make_via
def main() -> None:
#
# To illustrate the advantages of using `RenderPather`, we use `PathTool` instead
# of `AutoTool`. `PathTool` lacks some sophistication (e.g. no automatic transitions)
# of `BasicTool`. `PathTool` lacks some sophistication (e.g. no automatic transitions)
# but when used with `RenderPather`, it can consolidate multiple routing steps into
# a single `Path` shape.
#
@ -34,7 +34,7 @@ def main() -> None:
ptype_top = 'm2wire',
)
# `PathTool` is more limited than `AutoTool`. It only generates one type of shape
# `PathTool` is more limited than `BasicTool`. It only generates one type of shape
# (`Path`), so it only needs to know what layer to draw on, what width to draw with,
# and what port type to present.
M1_ptool = PathTool(layer='M1', width=M1_WIDTH, ptype='m1wire')
@ -77,7 +77,6 @@ def main() -> None:
# to account for it.
v1pat = library['v1_via']
via_size = abs(v1pat.ports['top'].x - v1pat.ports['bottom'].x)
# alternatively, via_size = v1pat.ports['top'].measure_travel(v1pat.ports['bottom'])[0][0]
# would take into account the port orientations if we didn't already know they're along x
rpather.path_to('VCC', None, -50_000 + via_size)

View file

@ -104,12 +104,10 @@ class Label(PositionableImpl, RepeatableImpl, AnnotatableImpl, Bounded, Pivotabl
def flip_across(self, axis: int | None = None, *, x: float | None = None, y: float | None = None) -> Self:
"""
Flip the label across a line in the pattern's coordinate system.
This operation mirrors the label's offset relative to the pattern's origin.
Mirror the object across a line.
Args:
axis: Axis to mirror across. 0 mirrors across y=0. 1 mirrors across x=0.
axis: Axis to mirror across. 0 mirrors across x=0. 1 mirrors across y=0.
x: Vertical line x=val to mirror across.
y: Horizontal line y=val to mirror across.

View file

@ -108,9 +108,7 @@ class Port(PivotableImpl, PositionableImpl, Mirrorable, Flippable, Copyable):
def flip_across(self, axis: int | None = None, *, x: float | None = None, y: float | None = None) -> Self:
"""
Mirror the object across a line in the container's coordinate system.
Note this operation is performed relative to the pattern's origin and modifies the port's offset.
Mirror the object across a line.
Args:
axis: Axis to mirror across. 0 mirrors across y=0. 1 mirrors across x=0.

View file

@ -18,11 +18,7 @@ class Mirrorable(metaclass=ABCMeta):
@abstractmethod
def mirror(self, axis: int = 0) -> Self:
"""
Mirror the entity across an axis through its origin.
This operation is performed relative to the object's internal origin (ignoring
its offset). For objects like `Polygon` and `Path` where the offset is forced
to (0, 0), this is equivalent to mirroring in the container's coordinate system.
Mirror the entity across an axis through its origin, ignoring its offset.
Args:
axis: Axis to mirror across (0: x-axis, 1: y-axis).
@ -74,14 +70,10 @@ class Flippable(Positionable, metaclass=ABCMeta):
@abstractmethod
def flip_across(self, axis: int | None = None, *, x: float | None = None, y: float | None = None) -> Self:
"""
Mirror the object across a line in the container's coordinate system.
Unlike `mirror()`, this operation is performed relative to the container's origin
(e.g. the `Pattern` origin, in the case of shapes) and takes the object's offset
into account.
Mirror the object across a line.
Args:
axis: Axis to mirror across. 0 mirrors across y=0. 1 mirrors across x=0.
axis: Axis to mirror across. 0 mirrors across x=0. 1 mirrors across y=0.
x: Vertical line x=val to mirror across.
y: Horizontal line y=val to mirror across.