lots of fixes to get test_rep running
This commit is contained in:
parent
92f7fce6ff
commit
b75c8de0c4
@ -1,103 +1,135 @@
|
|||||||
|
from pprint import pprint
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
from numpy import pi
|
from numpy import pi
|
||||||
|
|
||||||
import masque
|
import masque
|
||||||
import masque.file.gdsii
|
from masque import Pattern, Ref, Arc, WrapLibrary
|
||||||
import masque.file.klamath
|
|
||||||
import masque.file.dxf
|
|
||||||
import masque.file.oasis
|
|
||||||
from masque import shapes, Pattern, SubPattern
|
|
||||||
from masque.repetition import Grid
|
from masque.repetition import Grid
|
||||||
|
from masque.file import gdsii, dxf, oasis
|
||||||
|
|
||||||
from pprint import pprint
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
pat = masque.Pattern(name='ellip_grating')
|
lib = WrapLibrary()
|
||||||
|
|
||||||
|
cell_name = 'ellip_grating'
|
||||||
|
pat = masque.Pattern()
|
||||||
for rmin in numpy.arange(10, 15, 0.5):
|
for rmin in numpy.arange(10, 15, 0.5):
|
||||||
pat.shapes.append(shapes.Arc(
|
pat.shapes.append(Arc(
|
||||||
radii=(rmin, rmin),
|
radii=(rmin, rmin),
|
||||||
width=0.1,
|
width=0.1,
|
||||||
angles=(0*-numpy.pi/4, numpy.pi/4),
|
angles=(0 * -pi/4, pi/4),
|
||||||
annotations={'1': ['blah']},
|
annotations={'1': ['blah']},
|
||||||
))
|
))
|
||||||
|
|
||||||
pat.scale_by(1000)
|
pat.scale_by(1000)
|
||||||
# pat.visualize()
|
# pat.visualize()
|
||||||
pat2 = pat.copy()
|
lib[cell_name] = pat
|
||||||
pat2.name = 'grating2'
|
print(f'\nAdded {cell_name}:')
|
||||||
|
|
||||||
pat3 = Pattern('sref_test')
|
|
||||||
pat3.subpatterns = [
|
|
||||||
SubPattern(pat, offset=(1e5, 3e5), annotations={'4': ['Hello I am the base subpattern']}),
|
|
||||||
SubPattern(pat, offset=(2e5, 3e5), rotation=pi/3),
|
|
||||||
SubPattern(pat, offset=(3e5, 3e5), rotation=pi/2),
|
|
||||||
SubPattern(pat, offset=(4e5, 3e5), rotation=pi),
|
|
||||||
SubPattern(pat, offset=(5e5, 3e5), rotation=3*pi/2),
|
|
||||||
SubPattern(pat, mirrored=(True, False), offset=(1e5, 4e5)),
|
|
||||||
SubPattern(pat, mirrored=(True, False), offset=(2e5, 4e5), rotation=pi/3),
|
|
||||||
SubPattern(pat, mirrored=(True, False), offset=(3e5, 4e5), rotation=pi/2),
|
|
||||||
SubPattern(pat, mirrored=(True, False), offset=(4e5, 4e5), rotation=pi),
|
|
||||||
SubPattern(pat, mirrored=(True, False), offset=(5e5, 4e5), rotation=3*pi/2),
|
|
||||||
SubPattern(pat, mirrored=(False, True), offset=(1e5, 5e5)),
|
|
||||||
SubPattern(pat, mirrored=(False, True), offset=(2e5, 5e5), rotation=pi/3),
|
|
||||||
SubPattern(pat, mirrored=(False, True), offset=(3e5, 5e5), rotation=pi/2),
|
|
||||||
SubPattern(pat, mirrored=(False, True), offset=(4e5, 5e5), rotation=pi),
|
|
||||||
SubPattern(pat, mirrored=(False, True), offset=(5e5, 5e5), rotation=3*pi/2),
|
|
||||||
SubPattern(pat, mirrored=(True, True), offset=(1e5, 6e5)),
|
|
||||||
SubPattern(pat, mirrored=(True, True), offset=(2e5, 6e5), rotation=pi/3),
|
|
||||||
SubPattern(pat, mirrored=(True, True), offset=(3e5, 6e5), rotation=pi/2),
|
|
||||||
SubPattern(pat, mirrored=(True, True), offset=(4e5, 6e5), rotation=pi),
|
|
||||||
SubPattern(pat, mirrored=(True, True), offset=(5e5, 6e5), rotation=3*pi/2),
|
|
||||||
]
|
|
||||||
|
|
||||||
pprint(pat3)
|
|
||||||
pprint(pat3.subpatterns)
|
|
||||||
pprint(pat.shapes)
|
pprint(pat.shapes)
|
||||||
|
|
||||||
rep = Grid(a_vector=[1e4, 0],
|
new_name = lib.get_name(cell_name)
|
||||||
b_vector=[0, 1.5e4],
|
lib[new_name] = pat.copy()
|
||||||
a_count=3,
|
print(f'\nAdded a copy of {cell_name} as {new_name}')
|
||||||
b_count=2,)
|
|
||||||
pat4 = Pattern('aref_test')
|
pat3 = Pattern()
|
||||||
pat4.subpatterns = [
|
pat3.refs = [
|
||||||
SubPattern(pat, repetition=rep, offset=(1e5, 3e5)),
|
Ref(cell_name, offset=(1e5, 3e5), annotations={'4': ['Hello I am the base Ref']}),
|
||||||
SubPattern(pat, repetition=rep, offset=(2e5, 3e5), rotation=pi/3),
|
Ref(cell_name, offset=(2e5, 3e5), rotation=pi/3),
|
||||||
SubPattern(pat, repetition=rep, offset=(3e5, 3e5), rotation=pi/2),
|
Ref(cell_name, offset=(3e5, 3e5), rotation=pi/2),
|
||||||
SubPattern(pat, repetition=rep, offset=(4e5, 3e5), rotation=pi),
|
Ref(cell_name, offset=(4e5, 3e5), rotation=pi),
|
||||||
SubPattern(pat, repetition=rep, offset=(5e5, 3e5), rotation=3*pi/2),
|
Ref(cell_name, offset=(5e5, 3e5), rotation=3*pi/2),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, False), offset=(1e5, 4e5)),
|
Ref(cell_name, mirrored=(True, False), offset=(1e5, 4e5)),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, False), offset=(2e5, 4e5), rotation=pi/3),
|
Ref(cell_name, mirrored=(True, False), offset=(2e5, 4e5), rotation=pi/3),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, False), offset=(3e5, 4e5), rotation=pi/2),
|
Ref(cell_name, mirrored=(True, False), offset=(3e5, 4e5), rotation=pi/2),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, False), offset=(4e5, 4e5), rotation=pi),
|
Ref(cell_name, mirrored=(True, False), offset=(4e5, 4e5), rotation=pi),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, False), offset=(5e5, 4e5), rotation=3*pi/2),
|
Ref(cell_name, mirrored=(True, False), offset=(5e5, 4e5), rotation=3*pi/2),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(False, True), offset=(1e5, 5e5)),
|
Ref(cell_name, mirrored=(False, True), offset=(1e5, 5e5)),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(False, True), offset=(2e5, 5e5), rotation=pi/3),
|
Ref(cell_name, mirrored=(False, True), offset=(2e5, 5e5), rotation=pi/3),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(False, True), offset=(3e5, 5e5), rotation=pi/2),
|
Ref(cell_name, mirrored=(False, True), offset=(3e5, 5e5), rotation=pi/2),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(False, True), offset=(4e5, 5e5), rotation=pi),
|
Ref(cell_name, mirrored=(False, True), offset=(4e5, 5e5), rotation=pi),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(False, True), offset=(5e5, 5e5), rotation=3*pi/2),
|
Ref(cell_name, mirrored=(False, True), offset=(5e5, 5e5), rotation=3*pi/2),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, True), offset=(1e5, 6e5)),
|
Ref(cell_name, mirrored=(True, True), offset=(1e5, 6e5)),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, True), offset=(2e5, 6e5), rotation=pi/3),
|
Ref(cell_name, mirrored=(True, True), offset=(2e5, 6e5), rotation=pi/3),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, True), offset=(3e5, 6e5), rotation=pi/2),
|
Ref(cell_name, mirrored=(True, True), offset=(3e5, 6e5), rotation=pi/2),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, True), offset=(4e5, 6e5), rotation=pi),
|
Ref(cell_name, mirrored=(True, True), offset=(4e5, 6e5), rotation=pi),
|
||||||
SubPattern(pat, repetition=rep, mirrored=(True, True), offset=(5e5, 6e5), rotation=3*pi/2),
|
Ref(cell_name, mirrored=(True, True), offset=(5e5, 6e5), rotation=3*pi/2),
|
||||||
]
|
]
|
||||||
|
|
||||||
folder = 'layouts/'
|
lib['sref_test'] = pat3
|
||||||
masque.file.klamath.writefile((pat, pat2, pat3, pat4), folder + 'rep.gds.gz', 1e-9, 1e-3)
|
print('\nAdded sref_test:')
|
||||||
|
pprint(pat3)
|
||||||
|
pprint(pat3.refs)
|
||||||
|
|
||||||
cells = list(masque.file.klamath.readfile(folder + 'rep.gds.gz')[0].values())
|
rep = Grid(
|
||||||
masque.file.klamath.writefile(cells, folder + 'rerep.gds.gz', 1e-9, 1e-3)
|
a_vector=[1e4, 0],
|
||||||
|
b_vector=[0, 1.5e4],
|
||||||
|
a_count=3,
|
||||||
|
b_count=2,
|
||||||
|
)
|
||||||
|
pat4 = Pattern()
|
||||||
|
pat4.refs = [
|
||||||
|
Ref(cell_name, repetition=rep, offset=(1e5, 3e5)),
|
||||||
|
Ref(cell_name, repetition=rep, offset=(2e5, 3e5), rotation=pi/3),
|
||||||
|
Ref(cell_name, repetition=rep, offset=(3e5, 3e5), rotation=pi/2),
|
||||||
|
Ref(cell_name, repetition=rep, offset=(4e5, 3e5), rotation=pi),
|
||||||
|
Ref(cell_name, repetition=rep, offset=(5e5, 3e5), rotation=3*pi/2),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, False), offset=(1e5, 4e5)),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, False), offset=(2e5, 4e5), rotation=pi/3),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, False), offset=(3e5, 4e5), rotation=pi/2),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, False), offset=(4e5, 4e5), rotation=pi),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, False), offset=(5e5, 4e5), rotation=3*pi/2),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(False, True), offset=(1e5, 5e5)),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(False, True), offset=(2e5, 5e5), rotation=pi/3),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(False, True), offset=(3e5, 5e5), rotation=pi/2),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(False, True), offset=(4e5, 5e5), rotation=pi),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(False, True), offset=(5e5, 5e5), rotation=3*pi/2),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, True), offset=(1e5, 6e5)),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, True), offset=(2e5, 6e5), rotation=pi/3),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, True), offset=(3e5, 6e5), rotation=pi/2),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, True), offset=(4e5, 6e5), rotation=pi),
|
||||||
|
Ref(cell_name, repetition=rep, mirrored=(True, True), offset=(5e5, 6e5), rotation=3*pi/2),
|
||||||
|
]
|
||||||
|
|
||||||
masque.file.dxf.writefile(pat4, folder + 'rep.dxf.gz')
|
lib['aref_test'] = pat4
|
||||||
dxf, info = masque.file.dxf.readfile(folder + 'rep.dxf.gz')
|
print('\nAdded aref_test')
|
||||||
masque.file.dxf.writefile(dxf, folder + 'rerep.dxf.gz')
|
|
||||||
|
folder = Path('./layouts/')
|
||||||
|
print(f'...writing files to {folder}...')
|
||||||
|
|
||||||
|
gds1 = folder / 'rep.gds.gz'
|
||||||
|
gds2 = folder / 'rerep.gds.gz'
|
||||||
|
print(f'Initial write to {gds1}')
|
||||||
|
gdsii.writefile(lib, gds1, 1e-9, 1e-3)
|
||||||
|
|
||||||
|
print(f'Read back and rewrite to {gds2}')
|
||||||
|
readback_lib, _info = gdsii.readfile(gds1)
|
||||||
|
gdsii.writefile(readback_lib, gds2, 1e-9, 1e-3)
|
||||||
|
|
||||||
|
dxf1 = folder / 'rep.dxf.gz'
|
||||||
|
dxf2 = folder / 'rerep.dxf.gz'
|
||||||
|
print(f'Write aref_test to {dxf1}')
|
||||||
|
dxf.writefile(lib, 'aref_test', dxf1)
|
||||||
|
|
||||||
|
print(f'Read back and rewrite to {dxf2}')
|
||||||
|
dxf_lib, _info = dxf.readfile(dxf1)
|
||||||
|
print(WrapLibrary(dxf_lib))
|
||||||
|
dxf.writefile(dxf_lib, 'Model', dxf2)
|
||||||
|
|
||||||
layer_map = {'base': (0,0), 'mylabel': (1,2)}
|
layer_map = {'base': (0,0), 'mylabel': (1,2)}
|
||||||
masque.file.oasis.writefile((pat, pat2, pat3, pat4), folder + 'rep.oas.gz', 1000, layer_map=layer_map)
|
oas1 = folder / 'rep.oas'
|
||||||
oas, info = masque.file.oasis.readfile(folder + 'rep.oas.gz')
|
oas2 = folder / 'rerep.oas'
|
||||||
masque.file.oasis.writefile(list(oas.values()), folder + 'rerep.oas.gz', 1000, layer_map=layer_map)
|
print(f'Write lib to {oas1}')
|
||||||
print(info)
|
oasis.writefile(lib, oas1, 1000, layer_map=layer_map)
|
||||||
|
|
||||||
|
print(f'Read back and rewrite to {oas2}')
|
||||||
|
oas_lib, oas_info = oasis.readfile(oas1)
|
||||||
|
oasis.writefile(oas_lib, oas2, 1000, layer_map=layer_map)
|
||||||
|
|
||||||
|
print('OASIS info:')
|
||||||
|
pprint(oas_info)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -35,7 +35,9 @@ from .pattern import Pattern
|
|||||||
from .utils import layer_t, annotations_t
|
from .utils import layer_t, annotations_t
|
||||||
from .library import Library, MutableLibrary, WrapROLibrary, WrapLibrary, LazyLibrary, AbstractView
|
from .library import Library, MutableLibrary, WrapROLibrary, WrapLibrary, LazyLibrary, AbstractView
|
||||||
from .ports import Port, PortList
|
from .ports import Port, PortList
|
||||||
from .builder import Builder, Abstract, Tool
|
from .abstract import Abstract
|
||||||
|
from .builder import Builder, Tool
|
||||||
|
|
||||||
|
|
||||||
__author__ = 'Jan Petykiewicz'
|
__author__ = 'Jan Petykiewicz'
|
||||||
|
|
||||||
|
@ -3,13 +3,12 @@ from typing import MutableMapping, TYPE_CHECKING
|
|||||||
import copy
|
import copy
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from ..pattern import Pattern
|
from .pattern import Pattern
|
||||||
from ..library import MutableLibrary
|
from .ports import PortList, Port
|
||||||
from ..ports import PortList, Port
|
|
||||||
from .tools import Tool
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .builder import Builder
|
from .builder import Builder, Tool
|
||||||
|
from .library import MutableLibrary
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -34,8 +33,8 @@ class Abstract(PortList):
|
|||||||
|
|
||||||
def build(
|
def build(
|
||||||
self,
|
self,
|
||||||
library: MutableLibrary,
|
library: 'MutableLibrary',
|
||||||
tools: Union[None, Tool, MutableMapping[Optional[str], Tool]] = None,
|
tools: Union[None, 'Tool', MutableMapping[Optional[str], 'Tool']] = None,
|
||||||
) -> 'Builder':
|
) -> 'Builder':
|
||||||
"""
|
"""
|
||||||
Begin building a new device around an instance of the current device
|
Begin building a new device around an instance of the current device
|
@ -1,4 +1,3 @@
|
|||||||
from .builder import Builder
|
from .builder import Builder
|
||||||
from .abstract import Abstract
|
|
||||||
from .utils import ell
|
from .utils import ell
|
||||||
from .tools import Tool
|
from .tools import Tool
|
||||||
|
@ -12,9 +12,9 @@ from ..ref import Ref
|
|||||||
from ..library import MutableLibrary
|
from ..library import MutableLibrary
|
||||||
from ..error import PortError, BuildError
|
from ..error import PortError, BuildError
|
||||||
from ..ports import PortList, Port
|
from ..ports import PortList, Port
|
||||||
|
from ..abstract import Abstract
|
||||||
from .tools import Tool
|
from .tools import Tool
|
||||||
from .utils import ell
|
from .utils import ell
|
||||||
from .abstract import Abstract
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -14,27 +14,29 @@ import pathlib
|
|||||||
import gzip
|
import gzip
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
import ezdxf # type: ignore
|
import ezdxf
|
||||||
|
|
||||||
from .. import Pattern, Ref, PatternError, Label, Shape
|
from .. import Pattern, Ref, PatternError, Label
|
||||||
from ..shapes import Polygon, Path
|
from ..library import Library, WrapROLibrary
|
||||||
|
from ..shapes import Shape, Polygon, Path
|
||||||
from ..repetition import Grid
|
from ..repetition import Grid
|
||||||
from ..utils import rotation_matrix_2d, layer_t
|
from ..utils import rotation_matrix_2d, layer_t
|
||||||
|
from .utils import is_gzipped
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
logger.warning('DXF support is experimental and only slightly tested!')
|
logger.warning('DXF support is experimental!')
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_LAYER = 'DEFAULT'
|
DEFAULT_LAYER = 'DEFAULT'
|
||||||
|
|
||||||
|
|
||||||
def write(
|
def write(
|
||||||
|
library: Mapping[str, Pattern], # TODO could allow library=None for flat DXF
|
||||||
top_name: str,
|
top_name: str,
|
||||||
library: Mapping[str, Pattern],
|
stream: TextIO,
|
||||||
stream: io.TextIOBase,
|
|
||||||
*,
|
*,
|
||||||
dxf_version='AC1024',
|
dxf_version='AC1024',
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -65,17 +67,23 @@ def write(
|
|||||||
array with rotated instances must be manhattan _after_ having a compensating rotation applied.
|
array with rotated instances must be manhattan _after_ having a compensating rotation applied.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
top_name: Name of the top-level pattern to write.
|
|
||||||
library: A {name: Pattern} mapping of patterns. Only `top_name` and patterns referenced
|
library: A {name: Pattern} mapping of patterns. Only `top_name` and patterns referenced
|
||||||
by it are written.
|
by it are written.
|
||||||
|
top_name: Name of the top-level pattern to write.
|
||||||
stream: Stream object to write to.
|
stream: Stream object to write to.
|
||||||
disambiguate_func: Function which takes a list of patterns and alters them
|
disambiguate_func: Function which takes a list of patterns and alters them
|
||||||
to make their names valid and unique. Default is `disambiguate_pattern_names`.
|
to make their names valid and unique. Default is `disambiguate_pattern_names`.
|
||||||
WARNING: No additional error checking is performed on the results.
|
WARNING: No additional error checking is performed on the results.
|
||||||
"""
|
"""
|
||||||
#TODO consider supporting DXF arcs?
|
#TODO consider supporting DXF arcs?
|
||||||
|
if not isinstance(library, Library):
|
||||||
|
if isinstance(library, dict):
|
||||||
|
library = WrapROLibrary(library)
|
||||||
|
else:
|
||||||
|
library = WrapROLibrary(dict(library))
|
||||||
|
|
||||||
pattern = library[top_name]
|
pattern = library[top_name]
|
||||||
|
subtree = library.subtree(top_name)
|
||||||
|
|
||||||
# Create library
|
# Create library
|
||||||
lib = ezdxf.new(dxf_version, setup=True)
|
lib = ezdxf.new(dxf_version, setup=True)
|
||||||
@ -85,8 +93,11 @@ def write(
|
|||||||
_mrefs_to_drefs(msp, pattern.refs)
|
_mrefs_to_drefs(msp, pattern.refs)
|
||||||
|
|
||||||
# Now create a block for each referenced pattern, and add in any shapes
|
# Now create a block for each referenced pattern, and add in any shapes
|
||||||
for name, pat in library.items():
|
for name, pat in subtree.items():
|
||||||
assert pat is not None
|
assert pat is not None
|
||||||
|
if name == top_name:
|
||||||
|
continue
|
||||||
|
|
||||||
block = lib.blocks.new(name=name)
|
block = lib.blocks.new(name=name)
|
||||||
|
|
||||||
_shapes_to_elements(block, pat.shapes)
|
_shapes_to_elements(block, pat.shapes)
|
||||||
@ -97,8 +108,8 @@ def write(
|
|||||||
|
|
||||||
|
|
||||||
def writefile(
|
def writefile(
|
||||||
top_name: str,
|
|
||||||
library: Mapping[str, Pattern],
|
library: Mapping[str, Pattern],
|
||||||
|
top_name: str,
|
||||||
filename: Union[str, pathlib.Path],
|
filename: Union[str, pathlib.Path],
|
||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
@ -109,9 +120,9 @@ def writefile(
|
|||||||
Will automatically compress the file if it has a .gz suffix.
|
Will automatically compress the file if it has a .gz suffix.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
top_name: Name of the top-level pattern to write.
|
|
||||||
library: A {name: Pattern} mapping of patterns. Only `top_name` and patterns referenced
|
library: A {name: Pattern} mapping of patterns. Only `top_name` and patterns referenced
|
||||||
by it are written.
|
by it are written.
|
||||||
|
top_name: Name of the top-level pattern to write.
|
||||||
filename: Filename to save to.
|
filename: Filename to save to.
|
||||||
*args: passed to `dxf.write`
|
*args: passed to `dxf.write`
|
||||||
**kwargs: passed to `dxf.write`
|
**kwargs: passed to `dxf.write`
|
||||||
@ -181,19 +192,19 @@ def read(
|
|||||||
lib = ezdxf.read(stream)
|
lib = ezdxf.read(stream)
|
||||||
msp = lib.modelspace()
|
msp = lib.modelspace()
|
||||||
|
|
||||||
npat = _read_block(msp, clean_vertices)
|
npat = _read_block(msp)
|
||||||
patterns_dict = dict(
|
patterns_dict = dict(
|
||||||
[npat] + [_read_block(bb, clean_vertices) for bb in lib.blocks if bb.name != '*Model_Space']
|
[npat] + [_read_block(bb) for bb in lib.blocks if bb.name != '*Model_Space']
|
||||||
)
|
)
|
||||||
|
|
||||||
library_info = {
|
library_info = dict(
|
||||||
'layers': [ll.dxfattribs() for ll in lib.layers]
|
layers=[ll.dxfattribs() for ll in lib.layers],
|
||||||
}
|
)
|
||||||
|
|
||||||
return patterns_dict, library_info
|
return patterns_dict, library_info
|
||||||
|
|
||||||
|
|
||||||
def _read_block(block, clean_vertices: bool) -> Tuple[str, Pattern]:
|
def _read_block(block) -> Tuple[str, Pattern]:
|
||||||
name = block.name
|
name = block.name
|
||||||
pat = Pattern()
|
pat = Pattern()
|
||||||
for element in block:
|
for element in block:
|
||||||
@ -225,18 +236,13 @@ def _read_block(block, clean_vertices: bool) -> Tuple[str, Pattern]:
|
|||||||
else:
|
else:
|
||||||
shape = Path(layer=layer, width=width, vertices=points[:, :2])
|
shape = Path(layer=layer, width=width, vertices=points[:, :2])
|
||||||
|
|
||||||
if clean_vertices:
|
|
||||||
try:
|
|
||||||
shape.clean_vertices()
|
|
||||||
except PatternError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
pat.shapes.append(shape)
|
pat.shapes.append(shape)
|
||||||
|
|
||||||
elif eltype in ('TEXT',):
|
elif eltype in ('TEXT',):
|
||||||
args = {'offset': numpy.array(element.get_pos()[1])[:2],
|
args = dict(
|
||||||
'layer': element.dxfattribs().get('layer', DEFAULT_LAYER),
|
offset=numpy.array(element.get_pos()[1])[:2],
|
||||||
}
|
layer=element.dxfattribs().get('layer', DEFAULT_LAYER),
|
||||||
|
)
|
||||||
string = element.dxfattribs().get('text', '')
|
string = element.dxfattribs().get('text', '')
|
||||||
# height = element.dxfattribs().get('height', 0)
|
# height = element.dxfattribs().get('height', 0)
|
||||||
# if height != 0:
|
# if height != 0:
|
||||||
@ -257,20 +263,21 @@ def _read_block(block, clean_vertices: bool) -> Tuple[str, Pattern]:
|
|||||||
|
|
||||||
offset = numpy.array(attr.get('insert', (0, 0, 0)))[:2]
|
offset = numpy.array(attr.get('insert', (0, 0, 0)))[:2]
|
||||||
|
|
||||||
args = {
|
args = dict(
|
||||||
'target': (attr.get('name', None),),
|
target=attr.get('name', None),
|
||||||
'offset': offset,
|
offset=offset,
|
||||||
'scale': scale,
|
scale=scale,
|
||||||
'mirrored': mirrored,
|
mirrored=mirrored,
|
||||||
'rotation': rotation,
|
rotation=rotation,
|
||||||
'pattern': None,
|
)
|
||||||
}
|
|
||||||
|
|
||||||
if 'column_count' in attr:
|
if 'column_count' in attr:
|
||||||
args['repetition'] = Grid(a_vector=(attr['column_spacing'], 0),
|
args['repetition'] = Grid(
|
||||||
b_vector=(0, attr['row_spacing']),
|
a_vector=(attr['column_spacing'], 0),
|
||||||
a_count=attr['column_count'],
|
b_vector=(0, attr['row_spacing']),
|
||||||
b_count=attr['row_count'])
|
a_count=attr['column_count'],
|
||||||
|
b_count=attr['row_count'],
|
||||||
|
)
|
||||||
pat.ref(**args)
|
pat.ref(**args)
|
||||||
else:
|
else:
|
||||||
logger.warning(f'Ignoring DXF element {element.dxftype()} (not implemented).')
|
logger.warning(f'Ignoring DXF element {element.dxftype()} (not implemented).')
|
||||||
@ -286,12 +293,12 @@ def _mrefs_to_drefs(
|
|||||||
continue
|
continue
|
||||||
encoded_name = ref.target
|
encoded_name = ref.target
|
||||||
|
|
||||||
rotation = (ref.rotation * 180 / numpy.pi) % 360
|
rotation = numpy.rad2deg(ref.rotation) % 360
|
||||||
attribs = {
|
attribs = dict(
|
||||||
'xscale': ref.scale * (-1 if ref.mirrored[1] else 1),
|
xscale=ref.scale * (-1 if ref.mirrored[1] else 1),
|
||||||
'yscale': ref.scale * (-1 if ref.mirrored[0] else 1),
|
yscale=ref.scale * (-1 if ref.mirrored[0] else 1),
|
||||||
'rotation': rotation,
|
rotation=rotation,
|
||||||
}
|
)
|
||||||
|
|
||||||
rep = ref.repetition
|
rep = ref.repetition
|
||||||
if rep is None:
|
if rep is None:
|
||||||
@ -338,7 +345,7 @@ def _shapes_to_elements(
|
|||||||
' Please call library.wrap_repeated_shapes() before writing to file.'
|
' Please call library.wrap_repeated_shapes() before writing to file.'
|
||||||
)
|
)
|
||||||
|
|
||||||
attribs = {'layer': _mlayer2dxf(shape.layer)}
|
attribs = dict(layer=_mlayer2dxf(shape.layer))
|
||||||
for polygon in shape.to_polygons():
|
for polygon in shape.to_polygons():
|
||||||
xy_open = polygon.vertices + polygon.offset
|
xy_open = polygon.vertices + polygon.offset
|
||||||
xy_closed = numpy.vstack((xy_open, xy_open[0, :]))
|
xy_closed = numpy.vstack((xy_open, xy_open[0, :]))
|
||||||
@ -350,7 +357,7 @@ def _labels_to_texts(
|
|||||||
labels: List[Label],
|
labels: List[Label],
|
||||||
) -> None:
|
) -> None:
|
||||||
for label in labels:
|
for label in labels:
|
||||||
attribs = {'layer': _mlayer2dxf(label.layer)}
|
attribs = dict(layer=_mlayer2dxf(label.layer))
|
||||||
xy = label.offset
|
xy = label.offset
|
||||||
block.add_text(label.string, dxfattribs=attribs).set_pos(xy, align='BOTTOM_LEFT')
|
block.add_text(label.string, dxfattribs=attribs).set_pos(xy, align='BOTTOM_LEFT')
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ import string
|
|||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
from numpy.typing import NDArray, ArrayLike
|
from numpy.typing import ArrayLike, NDArray
|
||||||
import klamath
|
import klamath
|
||||||
from klamath import records
|
from klamath import records
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ path_cap_map = {
|
|||||||
|
|
||||||
|
|
||||||
def rint_cast(val: ArrayLike) -> NDArray[numpy.int32]:
|
def rint_cast(val: ArrayLike) -> NDArray[numpy.int32]:
|
||||||
return numpy.rint(val, dtype=numpy.int32, casting='unsafe')
|
return numpy.rint(val).astype(numpy.int32)
|
||||||
|
|
||||||
|
|
||||||
def write(
|
def write(
|
||||||
|
@ -39,7 +39,7 @@ from ..utils import layer_t, normalize_mirror, annotations_t
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
logger.warning('OASIS support is experimental and mostly untested!')
|
logger.warning('OASIS support is experimental!')
|
||||||
|
|
||||||
|
|
||||||
path_cap_map = {
|
path_cap_map = {
|
||||||
@ -51,7 +51,7 @@ path_cap_map = {
|
|||||||
#TODO implement more shape types?
|
#TODO implement more shape types?
|
||||||
|
|
||||||
def rint_cast(val: ArrayLike) -> NDArray[numpy.int64]:
|
def rint_cast(val: ArrayLike) -> NDArray[numpy.int64]:
|
||||||
return numpy.rint(val, dtype=numpy.int64, casting='unsafe')
|
return numpy.rint(val).astype(numpy.int64)
|
||||||
|
|
||||||
|
|
||||||
def build(
|
def build(
|
||||||
|
@ -22,7 +22,7 @@ from .error import LibraryError, PatternError
|
|||||||
from .utils import rotation_matrix_2d, normalize_mirror
|
from .utils import rotation_matrix_2d, normalize_mirror
|
||||||
from .shapes import Shape, Polygon
|
from .shapes import Shape, Polygon
|
||||||
from .label import Label
|
from .label import Label
|
||||||
from .builder.abstract import Abstract
|
from .abstract import Abstract
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .pattern import Pattern
|
from .pattern import Pattern
|
||||||
@ -37,7 +37,7 @@ ML = TypeVar('ML', bound='MutableLibrary')
|
|||||||
LL = TypeVar('LL', bound='LazyLibrary')
|
LL = TypeVar('LL', bound='LazyLibrary')
|
||||||
|
|
||||||
|
|
||||||
class Library(Mapping[str, Pattern], metaclass=ABCMeta):
|
class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
|
||||||
# inherited abstract functions
|
# inherited abstract functions
|
||||||
#def __getitem__(self, key: str) -> 'Pattern':
|
#def __getitem__(self, key: str) -> 'Pattern':
|
||||||
#def __iter__(self) -> Iterator[str]:
|
#def __iter__(self) -> Iterator[str]:
|
||||||
@ -61,7 +61,7 @@ class Library(Mapping[str, Pattern], metaclass=ABCMeta):
|
|||||||
return Abstract(name=name, ports=self[name].ports)
|
return Abstract(name=name, ports=self[name].ports)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return '<Library with keys ' + repr(list(self.keys())) + '>'
|
return '<Library with keys\n' + pformat(list(self.keys())) + '>'
|
||||||
|
|
||||||
def dangling_references(
|
def dangling_references(
|
||||||
self,
|
self,
|
||||||
@ -142,7 +142,11 @@ class Library(Mapping[str, Pattern], metaclass=ABCMeta):
|
|||||||
Returns:
|
Returns:
|
||||||
A `WrapROLibrary` containing only `tops` and the patterns they reference.
|
A `WrapROLibrary` containing only `tops` and the patterns they reference.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(tops, str):
|
||||||
|
tops = (tops,)
|
||||||
|
|
||||||
keep: Set[str] = self.referenced_patterns(tops) - set((None,)) # type: ignore
|
keep: Set[str] = self.referenced_patterns(tops) - set((None,)) # type: ignore
|
||||||
|
keep |= set(tops)
|
||||||
|
|
||||||
filtered = {kk: vv for kk, vv in self.items() if kk in keep}
|
filtered = {kk: vv for kk, vv in self.items() if kk in keep}
|
||||||
new = WrapROLibrary(filtered)
|
new = WrapROLibrary(filtered)
|
||||||
@ -405,7 +409,7 @@ class Library(Mapping[str, Pattern], metaclass=ABCMeta):
|
|||||||
VVV = TypeVar('VVV')
|
VVV = TypeVar('VVV')
|
||||||
|
|
||||||
|
|
||||||
class MutableLibrary(Generic[VVV], Library, metaclass=ABCMeta):
|
class MutableLibrary(Library, Generic[VVV], metaclass=ABCMeta):
|
||||||
# inherited abstract functions
|
# inherited abstract functions
|
||||||
#def __getitem__(self, key: str) -> 'Pattern':
|
#def __getitem__(self, key: str) -> 'Pattern':
|
||||||
#def __iter__(self) -> Iterator[str]:
|
#def __iter__(self) -> Iterator[str]:
|
||||||
@ -627,7 +631,11 @@ class MutableLibrary(Generic[VVV], Library, metaclass=ABCMeta):
|
|||||||
Returns:
|
Returns:
|
||||||
A `Library` containing only `tops` and the patterns they reference.
|
A `Library` containing only `tops` and the patterns they reference.
|
||||||
"""
|
"""
|
||||||
|
if isinstance(tops, str):
|
||||||
|
tops = (tops,)
|
||||||
|
|
||||||
keep: Set[str] = self.referenced_patterns(tops) - set((None,)) # type: ignore
|
keep: Set[str] = self.referenced_patterns(tops) - set((None,)) # type: ignore
|
||||||
|
keep |= set(tops)
|
||||||
|
|
||||||
new = type(self)()
|
new = type(self)()
|
||||||
for key in keep:
|
for key in keep:
|
||||||
@ -654,7 +662,7 @@ class WrapROLibrary(Library):
|
|||||||
return len(self.mapping)
|
return len(self.mapping)
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'<WrapROLibrary ({type(self.mapping)}) with keys ' + repr(list(self.keys())) + '>'
|
return f'<WrapROLibrary ({type(self.mapping)}) with keys\n' + pformat(list(self.keys())) + '>'
|
||||||
|
|
||||||
|
|
||||||
class WrapLibrary(MutableLibrary):
|
class WrapLibrary(MutableLibrary):
|
||||||
@ -662,9 +670,12 @@ class WrapLibrary(MutableLibrary):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
mapping: MutableMapping[str, 'Pattern'],
|
mapping: Optional[MutableMapping[str, 'Pattern']] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.mapping = mapping
|
if mapping is None:
|
||||||
|
self.mapping = {}
|
||||||
|
else:
|
||||||
|
self.mapping = mapping
|
||||||
|
|
||||||
def __getitem__(self, key: str) -> 'Pattern':
|
def __getitem__(self, key: str) -> 'Pattern':
|
||||||
return self.mapping[key]
|
return self.mapping[key]
|
||||||
@ -688,7 +699,7 @@ class WrapLibrary(MutableLibrary):
|
|||||||
self[key] = other[key]
|
self[key] = other[key]
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f'<WrapLibrary ({type(self.mapping)}) with keys ' + repr(list(self.keys())) + '>'
|
return f'<WrapLibrary ({type(self.mapping)}) with keys\n' + pformat(list(self.keys())) + '>'
|
||||||
|
|
||||||
|
|
||||||
class LazyLibrary(MutableLibrary):
|
class LazyLibrary(MutableLibrary):
|
||||||
@ -745,7 +756,7 @@ class LazyLibrary(MutableLibrary):
|
|||||||
self._set(key, other[key])
|
self._set(key, other[key])
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return '<LazyLibrary with keys ' + repr(list(self.keys())) + '>'
|
return '<LazyLibrary with keys\n' + pformat(list(self.keys())) + '>'
|
||||||
|
|
||||||
def precache(self: LL) -> LL:
|
def precache(self: LL) -> LL:
|
||||||
"""
|
"""
|
||||||
|
@ -88,7 +88,9 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable, metaclass=AutoSlots):
|
|||||||
self.refs = list(refs)
|
self.refs = list(refs)
|
||||||
|
|
||||||
if ports is not None:
|
if ports is not None:
|
||||||
ports = dict(copy.deepcopy(ports))
|
self.ports = dict(copy.deepcopy(ports))
|
||||||
|
else:
|
||||||
|
self.ports = {}
|
||||||
|
|
||||||
self.annotations = annotations if annotations is not None else {}
|
self.annotations = annotations if annotations is not None else {}
|
||||||
|
|
||||||
|
@ -178,8 +178,8 @@ class Ref(
|
|||||||
def get_bounds(
|
def get_bounds(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
pattern: Optional[Pattern] = None,
|
pattern: Optional['Pattern'] = None,
|
||||||
library: Optional[Mapping[str, Pattern]] = None,
|
library: Optional[Mapping[str, 'Pattern']] = None,
|
||||||
) -> Optional[NDArray[numpy.float64]]:
|
) -> Optional[NDArray[numpy.float64]]:
|
||||||
"""
|
"""
|
||||||
Return a `numpy.ndarray` containing `[[x_min, y_min], [x_max, y_max]]`, corresponding to the
|
Return a `numpy.ndarray` containing `[[x_min, y_min], [x_max, y_max]]`, corresponding to the
|
||||||
|
Loading…
Reference in New Issue
Block a user