You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

391 lines
12 KiB
Python

# -*- coding: utf-8 -*-
#
# Copyright © 2010 Eugeniy Meshcheryakov <eugen@debian.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
:mod:`gdsii.elements` -- interface to GDSII elements
====================================================
This module contains definitions for classes representing
various GDSII elements. Mapping between GDSII elements and
classes is given in the following table:
+-------------------+-------------------+
| GDSII Record | Class |
+===================+===================+
| :const:`AREF` | :class:`ARef` |
+-------------------+-------------------+
| :const:`BOUNDARY` | :class:`Boundary` |
+-------------------+-------------------+
| :const:`BOX` | :class:`Box` |
+-------------------+-------------------+
| :const:`NODE` | :class:`Node` |
+-------------------+-------------------+
| :const:`PATH` | :class:`Path` |
+-------------------+-------------------+
| :const:`SREF` | :class:`SRef` |
+-------------------+-------------------+
| :const:`TEXT` | :class:`Text` |
+-------------------+-------------------+
This module implements the following GDS syntax:
.. productionlist::
element: `aref` |
: `boundary` |
: `box` |
: `node` |
: `path` |
: `sref` |
: `text`
Additional definitions:
.. productionlist::
properties: `property`*
property: PROPATTR
: PROPVALUE
strans: STRANS
: [MAG]
: [ANGLE]
.. moduleauthor:: Eugeniy Meshcheryakov <eugen@debian.org>
"""
from __future__ import absolute_import
from . import exceptions, record, tags, _records
__all__ = (
'Boundary',
'Path',
'SRef',
'ARef',
'Text',
'Node',
'Box'
)
_ELFLAGS = _records.OptionalWholeRecord('elflags', tags.ELFLAGS)
_PLEX = _records.SimpleOptionalRecord('plex', tags.PLEX)
_LAYER = _records.SimpleRecord('layer', tags.LAYER)
_DATATYPE = _records.SimpleRecord('data_type', tags.DATATYPE)
_PATHTYPE = _records.SimpleOptionalRecord('path_type', tags.PATHTYPE)
_WIDTH = _records.SimpleOptionalRecord('width', tags.WIDTH)
_BGNEXTN = _records.SimpleOptionalRecord('bgn_extn', tags.BGNEXTN)
_ENDEXTN = _records.SimpleOptionalRecord('end_extn', tags.ENDEXTN)
_XY = _records.XYRecord('xy', tags.XY)
_SNAME = _records.StringRecord('struct_name', tags.SNAME)
_STRANS = _records.STransRecord('strans', tags.STRANS)
_COLROW = _records.ColRowRecord('cols', 'rows')
_TEXTTYPE = _records.SimpleRecord('text_type', tags.TEXTTYPE)
_PRESENTATION = _records.OptionalWholeRecord('presentation', tags.PRESENTATION)
_STRING = _records.StringRecord('string', tags.STRING)
_NODETYPE = _records.SimpleRecord('node_type', tags.NODETYPE)
_BOXTYPE = _records.SimpleRecord('box_type', tags.BOXTYPE)
_PROPERTIES = _records.PropertiesRecord('properties')
class _Base(object):
"""Base class for all GDSII elements."""
# dummy descriptors to silence pyckecker, should be set in derived classes
_gds_tag = None
_gds_objs = None
__slots__ = ()
def __init__(self):
"""Initialize the element."""
self._init_optional()
def _init_optional(self):
"""Initialize optional attributes to None."""
raise NotImplementedError
@classmethod
def _load(cls, gen):
"""
Load an element from file using given generator `gen`.
:param gen: :class:`pygdsii.record.Record` generator
:returns: new element of class defined by `gen`
"""
element_class = cls._tag_to_class_map[gen.current.tag]
if not element_class:
raise exceptions.FormatError('unexpected element tag')
# do not call __init__() during reading from file
# __init__() should require some arguments
new_element = element_class._read_element(gen)
return new_element
@classmethod
def _read_element(cls, gen):
"""Read element using `gen` generator."""
self = cls.__new__(cls)
self._init_optional()
gen.read_next()
for obj in self._gds_objs:
obj.read(self, gen)
gen.current.check_tag(tags.ENDEL)
gen.read_next()
return self
def _save(self, stream):
record.Record(self._gds_tag).save(stream)
for obj in self._gds_objs:
obj.save(self, stream)
record.Record(tags.ENDEL).save(stream)
class Boundary(_Base):
"""
Class for :const:`BOUNDARY` GDSII element.
GDS syntax:
.. productionlist::
boundary: BOUNDARY
: [ELFLAGS]
: [PLEX]
: LAYER
: DATATYPE
: XY
: [`properties`]
: ENDEL
"""
_gds_tag = tags.BOUNDARY
_gds_objs = (_ELFLAGS, _PLEX, _LAYER, _DATATYPE, _XY, _PROPERTIES)
__slots__ = ('layer', 'data_type', 'xy', 'elflags', 'plex', 'properties')
def __init__(self, layer, data_type, xy):
_Base.__init__(self)
self.layer = layer
self.data_type = data_type
self.xy = xy
def _init_optional(self):
self.elflags = None
self.plex = None
self.properties = None
class Path(_Base):
"""
Class for :const:`PATH` GDSII element.
GDS syntax:
.. productionlist::
path: PATH
: [ELFLAGS]
: [PLEX]
: LAYER
: DATATYPE
: [PATHTYPE]
: [WIDTH]
: [BGNEXTN]
: [ENDEXTN]
: XY
: [`properties`]
: ENDEL
"""
_gds_tag = tags.PATH
_gds_objs = (_ELFLAGS, _PLEX, _LAYER, _DATATYPE, _PATHTYPE, _WIDTH,
_BGNEXTN, _ENDEXTN, _XY, _PROPERTIES)
__slots__ = ('layer', 'data_type', 'xy', 'elflags', 'plex', 'path_type',
'width', 'bgn_extn', 'end_extn', 'properties')
def __init__(self, layer, data_type, xy):
_Base.__init__(self)
self.layer = layer
self.data_type = data_type
self.xy = xy
def _init_optional(self):
self.elflags = None
self.plex = None
self.path_type = None
self.width = None
self.bgn_extn = None
self.end_extn = None
self.properties = None
class SRef(_Base):
"""
Class for :const:`SREF` GDSII element.
GDS syntax:
.. productionlist::
sref: SREF
: [ELFLAGS]
: [PLEX]
: SNAME
: [`strans`]
: XY
: [`properties`]
: ENDEL
"""
_gds_tag = tags.SREF
_gds_objs = (_ELFLAGS, _PLEX, _SNAME, _STRANS, _XY, _PROPERTIES)
__slots__ = ('struct_name', 'xy', 'elflags', 'strans', 'mag', 'angle',
'properties')
def __init__(self, struct_name, xy):
_Base.__init__(self)
self.struct_name = struct_name
self.xy = xy
def _init_optional(self):
self.elflags = None
self.strans = None
self.mag = None
self.angle = None
self.properties = None
class ARef(_Base):
"""
Class for :const:`AREF` GDSII element.
GDS syntax:
.. productionlist::
aref: AREF
: [ELFLAGS]
: [PLEX]
: SNAME
: [`strans`]
: COLROW
: XY
: [`properties`]
: ENDEL
"""
_gds_tag = tags.AREF
_gds_objs = (_ELFLAGS, _PLEX, _SNAME, _STRANS, _COLROW, _XY, _PROPERTIES)
__slots__ = ('struct_name', 'cols', 'rows', 'xy', 'elflags', 'plex',
'strans', 'mag', 'angle', 'properties')
def __init__(self, struct_name, cols, rows, xy):
_Base.__init__(self)
self.struct_name = struct_name
self.cols = cols
self.rows = rows
self.xy = xy
def _init_optional(self):
self.elflags = None
self.plex = None
self.strans = None
self.mag = None
self.angle = None
self.properties = None
class Text(_Base):
"""
Class for :const:`TEXT` GDSII element.
GDS syntax:
.. productionlist::
text: TEXT
: [ELFLAGS]
: [PLEX]
: LAYER
: TEXTTYPE
: [PRESENTATION]
: [PATHTYPE]
: [WIDTH]
: [`strans`]
: XY
: STRING
: [`properties`]
: ENDEL
"""
_gds_tag = tags.TEXT
_gds_objs = (_ELFLAGS, _PLEX, _LAYER, _TEXTTYPE, _PRESENTATION, _PATHTYPE,
_WIDTH, _STRANS, _XY, _STRING, _PROPERTIES)
__slots__ = ('layer', 'text_type', 'xy', 'string', 'elflags', 'plex',
'presentation', 'path_type', 'width', 'strans', 'mag', 'angle',
'properties')
def __init__(self, layer, text_type, xy, string):
_Base.__init__(self)
self.layer = layer
self.text_type = text_type
self.xy = xy
self.string = string
def _init_optional(self):
self.elflags = None
self.plex = None
self.presentation = None
self.path_type = None
self.width = None
self.strans = None
self.mag = None
self.angle = None
self.properties = None
class Node(_Base):
"""
Class for :const:`NODE` GDSII element.
GDS syntax:
.. productionlist::
node: NODE
: [ELFLAGS]
: [PLEX]
: LAYER
: NODETYPE
: XY
: [`properties`]
: ENDEL
"""
_gds_tag = tags.NODE
_gds_objs = (_ELFLAGS, _PLEX, _LAYER, _NODETYPE, _XY, _PROPERTIES)
__slots__ = ('layer', 'node_type', 'xy', 'elflags', 'plex', 'properties')
def __init__(self, layer, node_type, xy):
_Base.__init__(self)
self.layer = layer
self.node_type = node_type
self.xy = xy
def _init_optional(self):
self.elflags = None
self.plex = None
self.properties = None
class Box(_Base):
"""
Class for :const:`BOX` GDSII element.
GDS syntax:
.. productionlist::
box: BOX
: [ELFLAGS]
: [PLEX]
: LAYER
: BOXTYPE
: XY
: [`properties`]
: ENDEL
"""
_gds_tag = tags.BOX
_gds_objs = (_ELFLAGS, _PLEX, _LAYER, _BOXTYPE, _XY, _PROPERTIES)
__slots__ = ('layer', 'box_type', 'xy', 'elflags', 'plex', 'properties')
def __init__(self, layer, box_type, xy):
_Base.__init__(self)
self.layer = layer
self.box_type = box_type
self.xy = xy
def _init_optional(self):
self.elflags = None
self.plex = None
self.properties = None
_all_elements = (Boundary, Path, SRef, ARef, Text, Node, Box)
_Base._tag_to_class_map = (lambda: dict(((cls._gds_tag, cls) for cls in _all_elements)))()