1# -*- coding: utf-8 -*- 2# 3# Copyright © 2010 Eugeniy Meshcheryakov <eugen@debian.org> 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU Lesser General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU Lesser General Public License for more details. 14# 15# You should have received a copy of the GNU Lesser General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17""" 18:mod:`gdsii.elements` -- interface to GDSII elements 19==================================================== 20 21This module contains definitions for classes representing 22various GDSII elements. Mapping between GDSII elements and 23classes is given in the following table: 24 25 +-------------------+-------------------+ 26 | GDSII Record | Class | 27 +===================+===================+ 28 | :const:`AREF` | :class:`ARef` | 29 +-------------------+-------------------+ 30 | :const:`BOUNDARY` | :class:`Boundary` | 31 +-------------------+-------------------+ 32 | :const:`BOX` | :class:`Box` | 33 +-------------------+-------------------+ 34 | :const:`NODE` | :class:`Node` | 35 +-------------------+-------------------+ 36 | :const:`PATH` | :class:`Path` | 37 +-------------------+-------------------+ 38 | :const:`SREF` | :class:`SRef` | 39 +-------------------+-------------------+ 40 | :const:`TEXT` | :class:`Text` | 41 +-------------------+-------------------+ 42 43This module implements the following GDS syntax: 44 .. productionlist:: 45 element: `aref` | 46 : `boundary` | 47 : `box` | 48 : `node` | 49 : `path` | 50 : `sref` | 51 : `text` 52Additional definitions: 53 .. productionlist:: 54 properties: `property`* 55 property: PROPATTR 56 : PROPVALUE 57 strans: STRANS 58 : [MAG] 59 : [ANGLE] 60 61.. moduleauthor:: Eugeniy Meshcheryakov <eugen@debian.org> 62""" 63from __future__ import absolute_import 64from . import exceptions, record, tags, _records 65 66__all__ = ( 67 'Boundary', 68 'Path', 69 'SRef', 70 'ARef', 71 'Text', 72 'Node', 73 'Box' 74) 75 76_ELFLAGS = _records.OptionalWholeRecord('elflags', tags.ELFLAGS) 77_PLEX = _records.SimpleOptionalRecord('plex', tags.PLEX) 78_LAYER = _records.SimpleRecord('layer', tags.LAYER) 79_DATATYPE = _records.SimpleRecord('data_type', tags.DATATYPE) 80_PATHTYPE = _records.SimpleOptionalRecord('path_type', tags.PATHTYPE) 81_WIDTH = _records.SimpleOptionalRecord('width', tags.WIDTH) 82_BGNEXTN = _records.SimpleOptionalRecord('bgn_extn', tags.BGNEXTN) 83_ENDEXTN = _records.SimpleOptionalRecord('end_extn', tags.ENDEXTN) 84_XY = _records.XYRecord('xy', tags.XY) 85_SNAME = _records.StringRecord('struct_name', tags.SNAME) 86_STRANS = _records.STransRecord('strans', tags.STRANS) 87_COLROW = _records.ColRowRecord('cols', 'rows') 88_TEXTTYPE = _records.SimpleRecord('text_type', tags.TEXTTYPE) 89_PRESENTATION = _records.OptionalWholeRecord('presentation', tags.PRESENTATION) 90_STRING = _records.StringRecord('string', tags.STRING) 91_NODETYPE = _records.SimpleRecord('node_type', tags.NODETYPE) 92_BOXTYPE = _records.SimpleRecord('box_type', tags.BOXTYPE) 93_PROPERTIES = _records.PropertiesRecord('properties') 94 95class _Base(object): 96 """Base class for all GDSII elements.""" 97 98 # dummy descriptors to silence pyckecker, should be set in derived classes 99 _gds_tag = None 100 _gds_objs = None 101 __slots__ = () 102 103 def __init__(self): 104 """Initialize the element.""" 105 self._init_optional() 106 107 def _init_optional(self): 108 """Initialize optional attributes to None.""" 109 raise NotImplementedError 110 111 @classmethod 112 def _load(cls, gen): 113 """ 114 Load an element from file using given generator `gen`. 115 116 :param gen: :class:`pygdsii.record.Record` generator 117 :returns: new element of class defined by `gen` 118 """ 119 element_class = cls._tag_to_class_map[gen.current.tag] 120 if not element_class: 121 raise exceptions.FormatError('unexpected element tag') 122 # do not call __init__() during reading from file 123 # __init__() should require some arguments 124 new_element = element_class._read_element(gen) 125 return new_element 126 127 @classmethod 128 def _read_element(cls, gen): 129 """Read element using `gen` generator.""" 130 self = cls.__new__(cls) 131 self._init_optional() 132 gen.read_next() 133 for obj in self._gds_objs: 134 obj.read(self, gen) 135 gen.current.check_tag(tags.ENDEL) 136 gen.read_next() 137 return self 138 139 def _save(self, stream): 140 record.Record(self._gds_tag).save(stream) 141 for obj in self._gds_objs: 142 obj.save(self, stream) 143 record.Record(tags.ENDEL).save(stream) 144 145class Boundary(_Base): 146 """ 147 Class for :const:`BOUNDARY` GDSII element. 148 149 GDS syntax: 150 .. productionlist:: 151 boundary: BOUNDARY 152 : [ELFLAGS] 153 : [PLEX] 154 : LAYER 155 : DATATYPE 156 : XY 157 : [`properties`] 158 : ENDEL 159 """ 160 _gds_tag = tags.BOUNDARY 161 _gds_objs = (_ELFLAGS, _PLEX, _LAYER, _DATATYPE, _XY, _PROPERTIES) 162 __slots__ = ('layer', 'data_type', 'xy', 'elflags', 'plex', 'properties') 163 164 def __init__(self, layer, data_type, xy): 165 _Base.__init__(self) 166 self.layer = layer 167 self.data_type = data_type 168 self.xy = xy 169 170 def _init_optional(self): 171 self.elflags = None 172 self.plex = None 173 self.properties = None 174 175class Path(_Base): 176 """ 177 Class for :const:`PATH` GDSII element. 178 179 GDS syntax: 180 .. productionlist:: 181 path: PATH 182 : [ELFLAGS] 183 : [PLEX] 184 : LAYER 185 : DATATYPE 186 : [PATHTYPE] 187 : [WIDTH] 188 : [BGNEXTN] 189 : [ENDEXTN] 190 : XY 191 : [`properties`] 192 : ENDEL 193 """ 194 _gds_tag = tags.PATH 195 _gds_objs = (_ELFLAGS, _PLEX, _LAYER, _DATATYPE, _PATHTYPE, _WIDTH, 196 _BGNEXTN, _ENDEXTN, _XY, _PROPERTIES) 197 __slots__ = ('layer', 'data_type', 'xy', 'elflags', 'plex', 'path_type', 198 'width', 'bgn_extn', 'end_extn', 'properties') 199 200 def __init__(self, layer, data_type, xy): 201 _Base.__init__(self) 202 self.layer = layer 203 self.data_type = data_type 204 self.xy = xy 205 206 def _init_optional(self): 207 self.elflags = None 208 self.plex = None 209 self.path_type = None 210 self.width = None 211 self.bgn_extn = None 212 self.end_extn = None 213 self.properties = None 214 215class SRef(_Base): 216 """ 217 Class for :const:`SREF` GDSII element. 218 219 GDS syntax: 220 .. productionlist:: 221 sref: SREF 222 : [ELFLAGS] 223 : [PLEX] 224 : SNAME 225 : [`strans`] 226 : XY 227 : [`properties`] 228 : ENDEL 229 """ 230 _gds_tag = tags.SREF 231 _gds_objs = (_ELFLAGS, _PLEX, _SNAME, _STRANS, _XY, _PROPERTIES) 232 __slots__ = ('struct_name', 'xy', 'elflags', 'strans', 'mag', 'angle', 233 'properties') 234 235 def __init__(self, struct_name, xy): 236 _Base.__init__(self) 237 self.struct_name = struct_name 238 self.xy = xy 239 240 def _init_optional(self): 241 self.elflags = None 242 self.strans = None 243 self.mag = None 244 self.angle = None 245 self.properties = None 246 247class ARef(_Base): 248 """ 249 Class for :const:`AREF` GDSII element. 250 251 GDS syntax: 252 .. productionlist:: 253 aref: AREF 254 : [ELFLAGS] 255 : [PLEX] 256 : SNAME 257 : [`strans`] 258 : COLROW 259 : XY 260 : [`properties`] 261 : ENDEL 262 """ 263 _gds_tag = tags.AREF 264 _gds_objs = (_ELFLAGS, _PLEX, _SNAME, _STRANS, _COLROW, _XY, _PROPERTIES) 265 __slots__ = ('struct_name', 'cols', 'rows', 'xy', 'elflags', 'plex', 266 'strans', 'mag', 'angle', 'properties') 267 268 def __init__(self, struct_name, cols, rows, xy): 269 _Base.__init__(self) 270 self.struct_name = struct_name 271 self.cols = cols 272 self.rows = rows 273 self.xy = xy 274 275 def _init_optional(self): 276 self.elflags = None 277 self.plex = None 278 self.strans = None 279 self.mag = None 280 self.angle = None 281 self.properties = None 282 283class Text(_Base): 284 """ 285 Class for :const:`TEXT` GDSII element. 286 287 GDS syntax: 288 .. productionlist:: 289 text: TEXT 290 : [ELFLAGS] 291 : [PLEX] 292 : LAYER 293 : TEXTTYPE 294 : [PRESENTATION] 295 : [PATHTYPE] 296 : [WIDTH] 297 : [`strans`] 298 : XY 299 : STRING 300 : [`properties`] 301 : ENDEL 302 """ 303 _gds_tag = tags.TEXT 304 _gds_objs = (_ELFLAGS, _PLEX, _LAYER, _TEXTTYPE, _PRESENTATION, _PATHTYPE, 305 _WIDTH, _STRANS, _XY, _STRING, _PROPERTIES) 306 __slots__ = ('layer', 'text_type', 'xy', 'string', 'elflags', 'plex', 307 'presentation', 'path_type', 'width', 'strans', 'mag', 'angle', 308 'properties') 309 310 def __init__(self, layer, text_type, xy, string): 311 _Base.__init__(self) 312 self.layer = layer 313 self.text_type = text_type 314 self.xy = xy 315 self.string = string 316 317 def _init_optional(self): 318 self.elflags = None 319 self.plex = None 320 self.presentation = None 321 self.path_type = None 322 self.width = None 323 self.strans = None 324 self.mag = None 325 self.angle = None 326 self.properties = None 327 328class Node(_Base): 329 """ 330 Class for :const:`NODE` GDSII element. 331 332 GDS syntax: 333 .. productionlist:: 334 node: NODE 335 : [ELFLAGS] 336 : [PLEX] 337 : LAYER 338 : NODETYPE 339 : XY 340 : [`properties`] 341 : ENDEL 342 """ 343 _gds_tag = tags.NODE 344 _gds_objs = (_ELFLAGS, _PLEX, _LAYER, _NODETYPE, _XY, _PROPERTIES) 345 __slots__ = ('layer', 'node_type', 'xy', 'elflags', 'plex', 'properties') 346 347 def __init__(self, layer, node_type, xy): 348 _Base.__init__(self) 349 self.layer = layer 350 self.node_type = node_type 351 self.xy = xy 352 353 def _init_optional(self): 354 self.elflags = None 355 self.plex = None 356 self.properties = None 357 358class Box(_Base): 359 """ 360 Class for :const:`BOX` GDSII element. 361 362 GDS syntax: 363 .. productionlist:: 364 box: BOX 365 : [ELFLAGS] 366 : [PLEX] 367 : LAYER 368 : BOXTYPE 369 : XY 370 : [`properties`] 371 : ENDEL 372 """ 373 _gds_tag = tags.BOX 374 _gds_objs = (_ELFLAGS, _PLEX, _LAYER, _BOXTYPE, _XY, _PROPERTIES) 375 __slots__ = ('layer', 'box_type', 'xy', 'elflags', 'plex', 'properties') 376 377 def __init__(self, layer, box_type, xy): 378 _Base.__init__(self) 379 self.layer = layer 380 self.box_type = box_type 381 self.xy = xy 382 383 def _init_optional(self): 384 self.elflags = None 385 self.plex = None 386 self.properties = None 387 388_all_elements = (Boundary, Path, SRef, ARef, Text, Node, Box) 389 390_Base._tag_to_class_map = (lambda: dict(((cls._gds_tag, cls) for cls in _all_elements)))() 391