GithubHelp home page GithubHelp logo

heitzmann / gdspy Goto Github PK

View Code? Open in Web Editor NEW
335.0 39.0 127.0 2.5 MB

Python module for creating GDSII stream files, usually CAD layouts.

License: Boost Software License 1.0

Python 76.42% C++ 23.31% Batchfile 0.11% Shell 0.16%
python gdsii microfabrication cad

gdspy's Introduction

GDSPY README

Boost Software License - Version 1.0 Documentation Status tests Appveyor Status Downloads

Gdspy is a Python module for creation and manipulation of GDSII stream files. Key features for the creation of complex CAD layouts are included:

  • Boolean operations on polygons (AND, OR, NOT, XOR) based on clipping algorithm
  • Polygon offset (inward and outward rescaling of polygons)
  • Efficient point-in-polygon solutions for large array sets

Gdspy also includes a simple layout viewer.

Typical applications of Gdspy are in the fields of electronic chip design, planar lightwave circuit design, and mechanical engineering.

Future of Gdspy

In trying to improve the performance of Gdspy for large layouts, we ended up concluding that the best way to reach our goal was to rewrite the critical parts of the library as a C extension. It turns out that beside obvious functions, method calling has a big impact in performance due to the overhead it introduces. The best solution was to re-design the whole project as a C++ library with a thin Python wrapper: thus was born Gdstk, the GDSII Tool Kit.

Therefore, version 1.6 will be the last major release of Gdspy, with development focused only on bug fixes. Users are encouraged to move from Gdspy to Gdstk: although their API is not 100% compatible, the new module should be familiar enough to allow a quick transition.

Installation

Dependencies:

  • Python (tested with versions 2.7, 3.6, 3.7, and 3.8)
  • Numpy
  • C compiler (needed only if built from source)
  • Tkinter (optional: needed for the LayoutViewer GUI)
  • Sphinx (optional: to build the documentation)

Linux / OS X

Option 1: using pip:

python -m pip install --user gdspy

Option 2: download the source from github and build/install with:

python setup.py install

Windows

The preferred option is to install pre-compiled binaries from here.

Installation via pip and building from source as above are also possible, but an appropriate build environment is required for compilation of the C extension modules.

Documentation

The complete documentation is available here.

The source files can be found in the docs directory.

Support

Help support Gdspy development by donating via PayPal or sponsoring me on GitHub

History of changes

Version 1.6.13 (Apr 26, 2023)

  • Allow ill-formed GDSII label anchors to be correctly loaded.

Version 1.6.12 (Jun 2, 2022)

  • Fix in Cell.get_texttypes.
  • Allow labels to inherit transforms through get_labels.

Version 1.6.11 (Jan 14, 2022)

  • Fix in Cell.write_svg when missing references.
  • Speed improvements in Cell.remove_polygons (thanks Troy for the contribution).

Version 1.6.10 (Nov 14, 2021)

  • Fix in Cell.get_polygons

Version 1.6.9 (Sep 23, 2021)

  • Fix in Cell.get_polygons with specified layer and datatype.
  • Raise error for duplicate cells when reading a GDSII file.

Version 1.6.8 (Aug 2, 2021)

  • Fix in boolean for complex geometries that freeze the operation.

Version 1.6.7 (Jul 14, 2021)

  • Fixes in boolean for bugs with self-intersecting holes and holes horizontal edges.
  • Fix bug in warning message.

Version 1.6.6 (Jun 09, 2021)

  • Fix error in Path.smooth not finding _hobby function.
  • Allow precision specification in SVG output.

Version 1.6.5 (Jun 08, 2021)

  • Support GDSII files with 0-padding at the end.
  • Allow fixing and modifying GDSII file timestamps.
  • Thanks Troy Tamas and Joaquin Matres for the fixes

Version 1.6.4 (Apr 23, 2021)

  • Fix missing module import (thanks Troy Tamas for the fix).

Version 1.6.3 (Dec 28, 2020)

  • Fix bounding box edge case (thanks Troy Tamas for the fix).

Version 1.6.2 (Dec 18, 2020)

  • More efficient bounding box calculation (thanks to Troy Tamas for the contribution).
  • Fix Label creation bug.

Version 1.6.1 (Oct 22, 2020)

  • Fix SVG output when Label contains special characters.

Version 1.6 (Aug 12, 2020)

  • Added support for element properties.
  • Added transformation support to Cell.copy.
  • Layer/datatype filtering in get_polygons for Cell, CellReference and CellArray.
  • Layer/datatype filtering in LayoutViewer.
  • Removed global cache _bounding_boxes. Only cells cache their bounding boxes.
  • Bug fixes (thanks Daniel Hwang for the contributions).
  • Bug fix in Cell.copy where the whole dependency tree would be copied on a deep copy creation.

Version 1.5.2 (Feb 01, 2020)

  • Added support for importing GDSII files containing BOX elements.
  • Bug fix in GdsLibrary.extract (thanks collineps for finding the problem).

Version 1.5 (Dec 20, 2019)

  • New Cell.write_svg function to export an SVG image of the cell.
  • New GdsLibrary.new_cell function to quickly create and add cells to a library.
  • GdsLibrary.add can update references when a cell is overwritten.
  • Added GdsLibrary.remove to allow cells to be properly removed from libraries.
  • Added GdsLibrary.rename_cell to rename cells in libraries.
  • Added GdsLibrary.replace_references to easily replace referenced cells in libraries.
  • GdsLibrary.add can add dependencies recursively.
  • Iterating over GdsLibrary objects yields all its cells.
  • Iterating over Cell objects yield all its polygons, paths, labels and references.
  • Breaking change to *.to_gds functions in order to improve write efficiency (this should not be a problem for most users, since gdspy.write_gds and Cell.write_gds remain the same).
  • Breaking change: renamed GdsLibrary.cell_dict to GdsLibrary.cells.
  • Deprecated: gdspy.current_library, gdspy.write_gds, gdspy.fast_boolen, GdsLibrary.extract.
  • Bug fixes and better tests for FlexPath and RobustPath.

Version 1.4.3 (Nov 11, 2019)

  • Bug fix for FlexPath and RobustPath references.

Version 1.4.2 (Oct 01, 2019)

  • Bug fix in FlexPath.

Version 1.4.1 (Sep 20, 2019)

  • Bug fixes (thanks to DerekK88 and Sequencer for the patches).

Version 1.4 (May 18, 2019)

  • Revised documentation.
  • New FlexPath and RobustPath classes: more efficient path generation when using the original GDSII path specification.
  • New Curve class: SVG-like polygon creation.
  • Added PolygonSet.mirror (thanks to Daan Waardenburg for the contribution).
  • Added Path.bezier to create paths based on Bézier curves.
  • Added Path.smooth to create paths based on smooth interpolating curves.
  • Added get_gds_units to get units used in a GDSII file without loading.
  • Added get_binary_cells to load only the binary GDSII representation of cell from a file.
  • Added argument tolerance to Round, Path.arc, Path.turn, and Path.parametric to automatically control the number of points in the final polygons.
  • Added argument binary_cells to GDSII writing functions to support get_binary_cells.
  • Added argument rename_template to GdsLibrary.read_gds for flexible cell renaming (thanks to @yoshi74ls181 for the contribution).
  • Changed return value of slice to avoid creating empty PolygonSet.
  • Added argument timestamp to GDSII writing functions.
  • Improved Round to support creating ellipses.
  • Added support for unlimited number of points per polygon.
  • Added support for BGNEXTN and ENDEXTN when reading a GDSII file.
  • Polygon creation warnings are now controlled by poly_warnings.
  • Incorrect anchor in Label now raises an error, instead of emitting a warning.
  • Added correct support for radius in PolygonSet.fillet on a per-vertex basis.
  • Speed improvements in GDSII file generation (thanks to @fbeutel for the contribution) and geometry creation.
  • Font rendering example using matplotlib (thanks Hernan Pastoriza for the contribution).
  • Expanded test suite.

Version 1.3.2 (Mar 14, 2019)

  • Small fix for building on Mac OS X Mojave.

Version 1.3.1 (Jun 29, 2018)

  • PolygonSet becomes the base class for all polygons, in particular Polygon and Rectangle.
  • Added Cell.remove_polygons and Cell.remove_labels functions to allow filtering a cell contents based, for example, on each element's layer.
  • Added PolygonSet.scale utility method.
  • Added PolygonSet.get_bounding_box utility method.
  • Added argument timestamp to Cell.to_gds, GdsLibrary.write_gds and GdsWriter.
  • Added unit and precision arguments to GdsLibrary initialization and removed from its write_gds method.
  • Changed the meaning of argument unit in GdsLibrary.read_gds.
  • Improved slice to avoid errors when slicing in multiple positions at once.
  • Improved PolygonSet.fracture to reduce number of function calls.
  • Removed incorrect absolute flags for magnification and rotation in CellReference and CellArray.
  • Minor bug fixes.
  • Documentation fixes.
  • Removed deprecated classes and functions.

Version 1.2.1 (Dec 5, 2017)

  • GdsLibrary can be created directly from a GDSII file
  • Added return value to GdsLibrary.read_gds
  • Fixed return value of GdsLibrary.add

Version 1.2 (Oct 21, 2017)

  • Added new gdsii_hash function.
  • Added precision parameter to _chop, Polygon.fracture, Polygon.fillet, PolygonSet.fracture, PolygonSet.fillet, and slice.
  • Included labels in flatten operations (added get_labels to Cell, CellReference, and CellArray).
  • Fixed bug in the bounding box cache of reference copies.
  • Fixed bug in _chop that affected Polygon.fracture, PolygonSet.fracture, and slice.
  • Other minor bug fixes.

Version 1.1.2 (Mar 19, 2017)

  • Update clipper library to 6.4.2 to fix bugs introduced in the last update.
  • License change to Boost Software License v1.0.

Version 1.1.1 (Jan 27, 2017)

  • Patch to fix installation issue (missing README file in zip).

Version 1.1 (Jan 20, 2017)

  • Introduction of GdsLibrary to allow user to work with multiple library simultaneously.
  • Deprecated GdsImport in favor of GdsLibrary.
  • Renamed gds_print to write_gds and GdsPrint to GdsWriter.
  • Development changed to Python 3 (Python 2 supported via python-future).
  • Added photonics example.
  • Added test suite.
  • Clipper library updated to last version.
  • Fixed inside function sometimes reversing the order of the output.
  • Fixed rounding error in fast_boolean.
  • Fixed argument deep_copy being inverted in Cell.copy.
  • Bug fixes introduced by numpy (thanks to Adam McCaughan for the contribution).

Version 1.0 (Sep 11, 2016)

  • Changed to "new style" classes (thanks to Adam McCaughan for the contribution).
  • Added a per-point radius specification for Polygon.fillet (thanks to Adam McCaughan for the contribution).
  • Added inside fucntion to perform point-in-polygon tests (thanks to @okianus for the contribution).
  • Moved from distutils to setuptools for better Windows support.

Version 0.9 (Jul 17, 2016)

  • Added option to join polygons before applying an offset.
  • Added a translate method to geometric entities (thanks John Bell for the commit).
  • Bug fixes.

Version 0.8.1 (May 6, 2016)

  • New fast_boolean function based on the Clipper library with much better performance than the old boolean.
  • Changed offset signature to also use the Clipper library (this change breaks compatibility with previous versions).
  • Bug fix for error when importing some labels from GDSII files.

Version 0.7.1 (June 26, 2015)

  • Rebased to GitHub.
  • Changed source structure and documentation.

Version 0.7 (June 12, 2015)

  • New feature: offset function.
  • New GdsPrint class for incremental GDSII creation (thanks to Jack Sankey for the contribution).

Version 0.6 (March 31, 2014)

  • Default number of points for Round, Path.arc, and Path.turn changed to resolution of 0.01 drawing units.
  • Path.parametric accepts callable final_distance and final_width for non-linear tapering.
  • Added argument ends to PolyPath.
  • Added (limited) support for PATHTYPE in GdsImport.
  • A warning is issued when a Path curve has width larger than twice its radius (self-intersecting polygon).
  • Added a random offset to the patterns in LayoutViewer.
  • LayoutViewer shows cell labels for referenced cells.
  • get_polygons returns (referenced) cell name if depth < 1 and by_spec is True.
  • Bug fix in get_bounding_box when empty cells are referenced.
  • Bug fixes in GdsImport and many speed improvements in bounding box calculations (thanks to Gene Hilton for the patch).

Version 0.5 (October 30, 2013) - NOT COMPATIBLE WITH PREVIOUS VERSIONS

  • Major LayoutViewer improvements (not backwards compatible).
  • The layer argument has been repositioned in the argument list in all functions (not backwards compatible).
  • Renamed argument by_layer to by_spec (not backwards compatible).
  • Error is raised for polygons with more vertices than possible in the GDSII format.
  • Removed the global state variable for default datatype.
  • Added get_datatypes to Cell.
  • Added argument single_datatype to Cell.flatten.
  • Removed gds_image and dropped the optional PIL dependency.

Version 0.4.1 (June 5, 2013)

  • Added argument axis_offset to Path.segment allowing creation of asymmetric tapers.
  • Added missing argument x_reflection to Label.
  • Created a global state variable to override the default datatype.
  • Bug fix in CellArray.get_bounding_box (thanks to George McLean for the fix)

Version 0.4 (October 25, 2012)

  • Cell.get_bounding_box returns None for empty cells.
  • Added a cache for bounding boxes for faster computation, especially for references.
  • Added support for text elements with Label class.
  • Improved the emission of warnings.
  • Added a tolerance parameter to boolean.
  • Added better print descriptions to classes.
  • Bug fixes in boolean involving results with multiple holes.

Version 0.3.1 (May 24, 2012)

  • Bug fix in the fracture method for PolygonSet.

Version 0.3a (May 03, 2012)

  • Bug fix in the fracture method for Polygon and PolygonSet.

Version 0.3 (April 25, 2012)

  • Support for Python 3.2 and 2.7
  • Further improvements to the boolean function via caching.
  • Added methods get_bounding_box and get_layers to Cell.
  • Added method top_level to GdsImport.
  • Added support for importing GDSII path elements.
  • Added an argument to control the verbosity of the import function.
  • Layer -1 (referenced cells) sent to the bottom of the layer list by default in LayoutViewer
  • The text and background of the layer list in LayoutViewer now reflect the colors of the outlines and canvas backgroung.
  • Changed default background color in LayoutViewer
  • Thanks to Gene Hilton for the contributions!

Version 0.2.9 (December 14, 2011)

  • Attribute Cell.cell_list changed to Cell.cell_dict.
  • Changed the signature of the operation in boolean.
  • Order of cells passed to LayoutViewer is now respected in the GUI.
  • Complete re-implementation of the boolean function as a C extension for improved performance.
  • Removed precision argument in boolean. It is fixed at 1e-13 for merging close points, otherwise machine precision is used.
  • gds_image now accepts cell names as input.
  • Added optional argument depth to get_polygons
  • Added option to convert layers and datatypes in imported GDSII cells.
  • Argument exclude_layers from LayoutViewer changed to hidden_layers and behavior changed accordingly.
  • Shift + Right-clicking on a layer the layer-list of LayoutVIewer hides/unhides all other layers.
  • New buttons to zoom in and out in LayoutViewer.
  • Referenced cells below a configurable depth are now represented by theirs bounding boxes in LayoutViewer.

Version 0.2.8 (June 21, 2011)

  • GDSII file import
  • GDSII output automatically include required referenced cells.
  • gds_print also accepts file name as input.
  • Outlines are visible by default in LayoutViewer.
  • Added background color option in LayoutViewer.
  • Right-clicking on the layer list hides/unhides the target layer in LayoutViewer.
  • Cell.cell_list is now a dictionary indexed by name, instead of a list.
  • Added option to exclude created cells from the global list of cells kept in Cell.cell_list.
  • CellReference and CellArray accept name of cells as input.
  • Submodules lost their own __version__.

Version 0.2.7 (April 2, 2011)

  • Bug fixed in the boolean, which affected the way polygons with more vertices then the maximum were fractured.
  • gds_image accepts an extra color argument for the image background.
  • Screenshots takes from LayoutViewer have the same background color as the viewer.
  • The functions boolean and slice now also accept CellReference and CellArray as input.
  • Added the method fracture to Polygon and PolygonSet to automatically slice polygons into parts with a predefined maximal number of vertices.
  • Added the method fillet to Polygon and PolygonSet to round corners of polygons.

Version 0.2.6 (February 28, 2011)

  • When saving a GDSII file, ValueError is raised if cell names are duplicated.
  • Save screenshot from LayoutViewer.
  • gds_image accepts cells, instead of lists.
  • Outlines supported by gds_image.
  • LayoutViewer stores bounding box information for all visited layers to save rendering time.

Version 0.2.5 (December 10, 2010)

  • Empty cells no longer break the LayoutViewer.
  • Removed the gds_view function, superseded by the LayoutViewer, along with all dependencies to matplotlib.
  • Fixed a bug in boolean which affected polygons with series of collinear vertices.
  • Added a function to slice polygons along straight lines parallel to an axis.

Version 0.2.4 (September 04, 2010)

  • Added shortcut to Extents in LayoutViewer: Home or a keys.
  • PolygonSet is the new base class for Round, which might bring some incompatibility issues with older scripts.
  • Round elements, PolyPath, L1Path, and Path arc, turn and parametric sections are now automatically fractured into pieces defined by a maximal number of points.
  • Default value for max_points in boolean changed to 199.
  • Removed the flag to disable the warning about polygons with more than 199 vertices. The warning is shown only for Polygon and PolygonSet.
  • Fixed a bug impeding parallel parametric paths to change their distance to each other.

Version 0.2.3 (August 09, 2010)

  • Added the PolyPath class to easily create paths with sharp corners.
  • Allow None as item in the colors parameter of LayoutViewer to make layers invisible.
  • Added color outline mode to LayoutViewer (change outline color with the shift key pressed)
  • Increased the scroll region of the LayoutViewer canvas
  • Added a fast scroll mode: control + drag 2nd mouse button
  • Created a new sample script

Version 0.2.2 (July 29, 2010)

  • Changed the cursor inside LayoutViewer to standard arrow.
  • Fixed bugs with the windows version of LayoutViewer (mouse wheel and ruler tool).

Version 0.2.1 (July 29, 2010)

  • Bug fix: gds_image displays an error message instead of crashing when PIL is not found.
  • Added class LayoutViewer, which uses Tkinter (included in all Python distributions) to display the GDSII layout with better controls then the gds_view function. This eliminates the matplotlib requirement for the viewer functionality.
  • New layer colors extending layers 0 to 63.

Version 0.2.0 (July 19, 2010)

  • Fixed a bug on the turn method of Path.
  • Fixed a bug on the boolean function that would give an error when not using Polygon or PolygonSet as input objects.
  • Added the method get_polygons to Cell, CellReference and CellArray.
  • Added a copy method to Cell.
  • Added a flatten method to Cell to remove references (or array references) to other cells.
  • Fracture boolean output polygons based on the number of vertices to respect the 199 GDSII limit.

Version 0.1.9 (June 04, 2010)

  • Added L1Path class for Manhattan geometry (L1 norm) paths.

Version 0.1.8 (May 10, 2010)

  • Removed the argument fill from gds_view and added a more flexible one: style.
  • Fixed a rounding error on the boolean operator affecting polygons with holes.
  • Added a rotate method to PolygonSet.
  • Added a warning when PolygonSet has more than 199 points
  • Added a flag to disable the warning about polygons with more than 199 points.
  • Added a turn method to Path, which is easier to use than arc.
  • Added a direction attribute to Path to keep the information used by the segment and turn methods.

Version 0.1.7 (April 12, 2010)

  • New visualization option: save the geometry directly to an image file (lower memory use).
  • New functionality added: boolean operations on polygons (polygon clipping).
  • All classes were adapted to work with the boolean operations.
  • The attribute size in the initializer of class Text does not have a default value any longer.
  • The name of the argument format in the function gds_view was changed to fill (to avoid confusion with the built-in function format).

Version 0.1.6 (December 15, 2009)

  • Sample script now include comments and creates an easier to understand GDSII example.
  • Improved floating point to integer rounding, which fixes the unit errors at the last digit of the precision in the GDSII file.
  • Fixed the font for character 5.
  • Added a flag to gds_view to avoid the automatic call to matplotlib.pyplot.show().
  • In gds_view, if a layer number is greater than the number of formats defined, the formats are cycled.

Version 0.1.5a (November 15, 2009)

  • Class Text correctly interprets \n and \t characters.
  • Better documentation format, using the Sphinx engine and the numpy format.

Version 0.1.4 (October 5, 2009)

  • Class Text re-written with a different font with no overlaps and correct size.

Version 0.1.3a (July 29 2009)

  • Fixed the function to_gds of class Rectangle.

Version 0.1.3 (July 27, 2009)

  • Added the datatype field to all elements of the GDSII structure.

Version 0.1.2 (July 11, 2009)

  • Added the gds_view function to display the GDSII structure using the matplotlib module.
  • Fixed a rotation bug in the CellArray class.
  • Module published under the GNU General Public License (GPL)

Version 0.1.1 (May 12, 2009)

  • Added attribute cell_list to class Cell to hold a list of all Cell created.
  • Set the default argument cells=Cell.cell_list in the function gds_print.
  • Added member to calculate the area for each element type.
  • Added member to calculate the total area of a Cell or the area by layer.
  • Included the possibility of creating objects in user-defined units, not only nanometers.

Version 0.1.0 (May 1, 2009)

  • Initial release.

gdspy's People

Contributors

amccaugh avatar derekk44 avatar faustincarter avatar felixonmars avatar gnawhleinad avatar heitzmann avatar joamatab avatar johnlb avatar nicoulaj avatar sequencer avatar tvt173 avatar yoshi74ls181 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gdspy's Issues

Python v3.5

FYI, I've started developing with this on Python 3.5 and I haven't had any trouble so far.

Had to get VS14 for pip to install (I'm on Win10), but it was fine after that. Probably could generate a wheel for it though, if you wanted?

GDS Timestamps

The present implementation seems to use current date and time for GDS cell and library timestamps. As a result, GDS files created from the same layout at different points in time will have different binary headers. While appropriate in most situations, this behaviour complicates some use cases that involve binary comparison of GDS files (e.g. regression testing).

I would like to propose to add an optional timestamp=None argument to Cell.to_gds(), GdsLibrary.write_gds(), and GdsWriter() constructor. If set to None (the default), the functions would use the current date and time, otherwise the user-supplied timestamp would be used.

Boolean subtraction errors

@heitzmann I am observing errors in the boolean subtraction algorithm in the latest gdspy 1.1.1.

Errors seem to occur with any structures that contain holes. An example below creates two polygon sets, in a shape of the digits 8 and 6. It then subtracts two identical cells. gdspy 1.0 produces an empty result, as expected. On the other hand, the boolean not algorithm in gdspy 1.1.1 generates incorrect triangular structures.

import gdspy

coords8 = [[[-1.16635, -0.5    ], [-1.16635,  0.5    ], [-0.99945,  0.5    ], [-0.99945, -0.5    ]],
           [[-0.99945,  0.3331 ], [-0.99945,  0.5    ], [-0.50005,  0.5    ], [-0.50005, -0.5    ],
            [-0.99945, -0.5    ], [-0.99945, -0.3331 ], [-0.66695, -0.3331 ], [-0.66695, -0.08345],
            [-0.99945, -0.08345], [-0.99945,  0.08345], [-0.66695,  0.08345], [-0.66695,  0.3331 ]]]
coords6 = [[[ 0.50005, -0.5    ], [ 0.50005,  0.5    ], [ 1.16635,  0.5    ], [ 1.16635,  0.3331 ], [ 0.66695,  0.3331 ], [ 0.66695, -0.5    ]],
           [[ 0.66695, -0.5    ], [ 1.16635, -0.5    ], [ 1.16635,  0.08345], [ 0.66695,  0.08345], [ 0.66695, -0.08345], [ 0.99945, -0.08345], [ 0.99945, -0.3331 ], [ 0.66695, -0.3331 ]]]
poly8_layer1 = gdspy.PolygonSet(coords8, 1)
poly6_layer1 = gdspy.PolygonSet(coords6, 1)
poly8_layer2 = gdspy.PolygonSet(coords8, 2)
poly6_layer2 = gdspy.PolygonSet(coords6, 2)

cell1 = gdspy.Cell('CELL1')
cell2 = gdspy.Cell('CELL2')
cell1.add(poly8_layer1)
cell1.add(poly6_layer1)
cell2.add(poly8_layer2)
cell2.add(poly6_layer2)
cell_ref1 = gdspy.CellReference(cell1)
cell_ref2 = gdspy.CellReference(cell2)

result = gdspy.fast_boolean(cell_ref1, cell_ref2, 'not')
result_cell = gdspy.Cell('DIFF_CELL')
result_cell.add(result)
gdspy.write_gds('boolean_subtract_test_example.gds', cells=[cell1, cell2, result_cell])   # for gdspy 1.1.1
gdspy.print_gds('boolean_subtract_test_example.gds', cells=[result_cell])               # for gdspy 1.0

Using DEPLOF font

I'd like to add the DEPLOF font to gdspy.

4441325253959

It's a font used on other layout editors (e.g. LayoutEditor CleWin ), and is purpose-built for 2D layout/fab. I received permission from the creator of the MATLAB gdsii-toolbox (Ulf Griesmann) to adapt his implementation, and have it basically ready to go. My question is whether how I should write the commit--I was thinking of adding an additional argument font to the init argument of the Text class. So that instead of

def __init__(self, text, size, position=(0, 0), horizontal=True, angle=0, layer=0, datatype=0)

it would now be

def __init__(self, text, size, position=(0, 0), horizontal=True, angle=0, font = 'block', layer=0, datatype=0)

where font could be chosen to be either 'block' (the current font) or 'deplof' (the proposed font), so the change would be transparent and no one's layouts would be changed, but users would now have the option to select the DEPLOF font. (and perhaps down the road the default could be changed to DEPLOF)

Does sound reasonable?

call for Ellipse support

Hello. I am wondering if you could add Class: Ellipse support? Since Round is supported perfectly, I think this will not be a big problem. Thanks very much!

How to properly write hierarchical Cells to GDS?

I'm currently having an issue with properly writing hierarchical Cells (with references to other cells that have their own geometric objects) with write_gds(). For example, see the minimum working example below:

import gdspy
top = gdspy.Cell("top")
top.add(gdspy.Rectangle((0,0), (15000, 15000), layer=10, datatype=0))

ex = gdspy.Cell("exclusion_region")
ex.add(gdspy.Rectangle((0, 13000), (15000, 15000), layer=7, datatype=0))
top.add(ex)

# gdspy.LayoutViewer()
gdspy.write_gds('test.gds', unit=1.0e-6, precision=1.0e-9)

with the following intended Cell hierarchy:

top (Cell)
   |_ Rectangle
   |_ ex (Cell)
         |_ Rectangle

In the above, the gdspy.LayoutViewer() shows the correct hierarchy of Cells and objects. However, the GDSII file it creates (test.gds), seems to be broken. When I try to open with Klayout, I get the error:
Invalid record or data type (position=194, record number=11, cell=top)

Any idea how I can properly write these Cells to GDS so it will show up correctly? Am I missing something pretty obvious?

Thanks!

Rectangle fillet precision being ignored

Value entered for precision doesn't seem to affect the result in any way. Expected result would be all points being on a grid of size precision but that doesn't seem to be the case.

Descriptor improvements / installation instructions

I would like to propose some improvements to the description of Gdspy and clarifications to the installation instructions.

GDSPY README

Gdspy is a Python module for creating/importing/merging of GDSII stream files. It includes key libraries for creating complex CAD layouts:

  • Boolean operations on polygons (AND, OR, NOT, XOR) based on clipping algorithm
  • Polygon offset (inward and outward rescaling of polygons)
  • Efficient point-in-polygon solutions for large array sets

Gdspy also includes a simple layout viewer. Typical applications of Gdspy are in the fields of electronic chip design, planar lightwave circuit design, and mechanical engineering.

Installation

Dependencies:

  • Python (tested with versions 2.7 and 3.5)
  • Numpy (tested with 1.11.1)
  • C compiler (needed only if built from source)

LINUX / OS X

Option 1: Download Gdspy and build from source using the following command:

python setup.py install

Option 2: Install Gdspy with pip:

pip install gdspy

WINDOWS

Option 1: The preferred option is to install Gdspy using pre-compiled binaries that can be downloaded here for 32-bit or 64-bit systems. First, download a portable WinPython (tested with WinPython-64bit-3.5.2.2), run the executable to unpack the files to a directory. In the directory, run "WinPython Control Panel.exe" and click "Add packages". Select the downloaded Gdspy binary executable and click on "Install packages".

Option 2: Gdspy can also be built from source using a development environment to compile the boolean extension module using python setup.py install command.

Compiling to exe with gdspy import

Good day.

I seem to be spamming the forums a bit. Sorry for that. I am currently trying to compile my .py script to an exe. The script containt gdspy of course. I can't seem to find a way to do this properly and keep getting the following error when using pyinstaller (pyinstaller doesn't officially support gdspy, I believe).

untitled

Has anyone tried to compile gdspy dependent files? Please let me know if I need to provide any other details. My code is listed below and I have confirmed that pyinstaller is working and I have compile just a small "print("hallo world")" script and it worked 100%

import gdspy

print('Please enter file name:')
filename = raw_input()+ str('.gds')

file1 = gdspy.GdsImport('Dcsfq.gds')
file2 = gdspy.GdsImport('Conf2.gds')
file3 = gdspy.GdsImport('Tff4b.gds')

cell1 = file1.extract(file1.top_level()[0])
cell2 = file2.extract(file2.top_level()[0])
cell3 = file3.extract(file3.top_level()[0])

ref_cell = gdspy.Cell('TRANSLATED')

ref_cell.add(gdspy.CellReference(cell2, (150,0)))
ref_cell.add(gdspy.CellReference(cell1,(0,0)))
ref_cell.add(gdspy.CellReference(cell3, (225,-150), rotation=90))

gdspy.gds_print(filename, cells=[ref_cell], unit=1.0e-6, precision=1.0e-9)

gdspy.LayoutViewer(cells = ref_cell)

Any help will be greatly appreciated.
Thanks

Adding a Cell directly within a Cell (without using a CellReference) causes "missing ENDSTR record" error when trying to open the GDS file that is written out

Calling Cell.add() works fine with the LayoutViewer, but when the layout is then written to a GDS file, trying to open it up in Clewin 5 causes a "missing ENDSTR record" error. Trying to open it up in KLayout also causes an error.

Suggested fix is that trying to add a Cell directly to another Cell just inserts a CellReference at position (0,0), or something similar. Or maybe just throw an error? I'm sure trying to get the file to write correctly would take more time than either of these other two options.

distinguish relative vs absolute transform

gdspy doesn't seem to distinguish between relative vs absolute transform for AREF/SREF records. For example, CellReference.to_gds() contains the following lines:

    if self.x_reflection:
        word += 0x8000
    if not (self.magnification is None):
        word += 0x0004
        values += struct.pack('>2h', 12, 0x1B05) \
            + _eight_byte_real(self.magnification)
    if not (self.rotation is None):
        word += 0x0002
        values += struct.pack('>2h', 12, 0x1C05) \
            + _eight_byte_real(self.rotation)

0x0004 (absolute magnification) and 0x0002 (absolute rotation) flags in STRANS are always set when there's magnification or rotation.

Unfortunately, absolute mag/rot should be avoided in hierarchical designs with many nested levels, where absolute transforms quickly get out of control. In most cases, we should only use relative magnify/rotate in designs. This is done by clearing these two flags, while still appending the MAG and/or ANGLE records.

In short, gdspy should support and distinguish between absolute and relative transforms, with relative transform being the default.

The following page documents this matter with great details:
http://boolean.klaasholwerda.nl/interface/bnf/gdsformat.html#rec_strans

Error in transformation of label coordinates

In the definition of CellReference, polygons are (correctly) transformed according to

polygons[kk][ii] = polygons[kk][ii] * ct \
                                + polygons[kk][ii][:, ::-1] * st

(e.g. x<- cos(theta) x - sin(theta) y, but labels are transformed according to:

lbl.position = lbl.position * ct + lbl.position * st

(e.g. x<- cos(theta) x - sin(theta) x), which is not consistent or unitary. The label formula should be corrected to follow the same formula as the polygons.

lbl.position = lbl.position * ct + lbl.position[::-1] * st

This correction fixed the disagreement I was seeing with a layout viewed in klayout.

Problem with 'boolext'

Hi!

I'm a new user of gdspy and I have some issues with the latest version. I'm using Anaconda with Python 3.5 and every time I try to run my script I have this error prompting :

File "C:\Users\Mathieu\Documents\Python\gdspy-1.0\gdspy__init__.py", line 44, in from gdspy import boolext

ImportError: cannot import name 'boolext'

And I have no idea why. Do you ?

Behaviour of PolygonSet.fillet on non-trivial polygon

I created a new PolygonSet by applying
shape=gdspy.fast_boolean(Rectangle, Circle, 'not')
where Rectangle and Circle are partially overlapping. After that I merged all resulting polygons via merged=gdspy.fast_boolean(shape, None, 'or')
and applied the fillet method
merged.fillet(20, 100).
In the resulting shape, corners along the overlap path of the original shapes are not rounded accordingly or an erroneous shape is being generated.

Layer patterning does not work on Mac

screen shot 2018-05-20 at 2 05 43 pm

As shown in the attached figure, the layer patterning doesn't work on macOS Sierra. I have tried to solve this issue myself, but was unable to do so. This becomes extreme tedious for large circuits.

tkinter dependency

If tkinter is not present on the system then LayoutViewer fails to import at all:

 >>> import gdspy
 >>> gdspy.LayoutViewer()
 Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    AttributeError: 'module' object has no attribute 'LayoutViewer'

Just thought I would let you know that it fails without indicating that a dependency is missing.

Binary comparison and SHA-1 hashing

@heitzmann As we go between gdspy versions and our own software versions, we validate each transition by regenerating all .gds file masks and comparing if their content has changed compared to when they were originally created. This allows us to detect any software/packages bugs. In order to achieve this, .gds files are hashed using SHA-1 and then the hashes are compared. However, we have encountered the following challenge: .gds files appear to be always different even if they are generated by the same code. The difference was traced to the timestamp that is embedded by gdspy when .gds files are written. Our attempts to exclude timestamps within the binary files, and compare the rest of binary content, runs into difficulties because of structural differences of various files. Could you please advise on how best to tackle this issue?

how to load a gds file, flatten it, and extract all polygons

Hi

Great software and appear to have all the things I need. However, I can not figure out how to load a gds file (not very big, about 2MB), flatten its hierarchy, and extract all polygons in a given layer.

I am sorry for such an elementary question.

Thanks
enuinc

Validity of bounding box after cell deep copy

gdspy.Cell.copy() provides the ability to create a deep copy of a cell. It was noticed that when this is done for nested cells, any CellReferences within the cell have a their _bb_valid flags set to True. Hence, if you perform a deep copy of a cell, and then try to get its bounding box using get_bounding_box(), the algorithm fails, generating a KeyError at the return statement of gdspy.Cell.get_bounding_box() method.

I do not know all the implications of this, but at the very least, I believe the _bb_valid flags for the dependencies have to be explicitly set to False within cell.copy() to allow recalculation of the bounding boxes:

for ref in new_cell.get_dependencies(True):
            if ref._bb_valid:
                print('Reference ' + str(ref) + ' bb_valid flag is True, set to False')
                ref._bb_valid = False

Unable to install gdspy v1.0 on Windows

Having some issues installing gdspy v1.0 on Windows, my version is Python 3.5.2 :: Anaconda 4.0.0 (64-bit).
Tried pip install, and got a " Failed building wheel for gdspy" error.
Tried the pre-compiled binaries install option using gdspy-1.0.win-amd64-py3.5.exe, and get "Python version 3.5 -32 required, which was not found in the registry" error. Made sure I did execute the 64-bit version.

Gdspy 1.1 installation on windows

Following up on release 1.1 on Windows 7, python 3.5 64bit:

  1. Installer (gdspy-1.1.win-amd64-py3.5.exe) doesn't work for me, error: Python 3.5-32 is required for this package.

  2. When using pip I get the following error:
    line 26, in with open('README.md') as fin: FileNotFoundError: [Errno 2] No such file or directory: 'README.md'

Using Setuptools v34 and ez-setup 0.9.

Note that Installing gdspy1.0 works flawlessly with pip on this setup.

Thanks for the new version, really appreciate your work!

Adding metadata to gds or cells / Saving cell-libraries in hard-drive for future use

Hi Lucas,

Two questions:

  1. Is there a way to add metadata to cells or gds? Metadata such as 'name', 'creator', 'version' ...
  2. I have a bunch of common external .gds from manufacturers that i need to import for every .gds i draw. Is there a way to import just once, then save them in a file in hard-drive, and simply just import that saved file in every one of my gdspy scripts (avoid importing the external gds one-by-one everytime I write a new gdspy script)?

Thanks,
Lawrence Tzuang

Exporting to gds by layer

Hello Lucas,

I am looking for a way to export to gds specific layers from a larger gds file. Alternatively, is there a way to import only a particular layer using gds_import?

Shreyas Shah

how to write all CellReference in the topcell into the gds?

@heitzmann Hi, I use write_gds function, but all CellReference in the topcell are missing in the gds file.
Now, I use two method to solve this issue.
1: gdspy.wirte_gds('.gds',cells=None), this method, other topcell are wirted into the gds file too.
2: gdspy.write_gds('
.gds',list(topcell.get_dependencies(True))+[topcell]), this method seems to work very well.
Do you have any other better suggestion?
thanks very much!

write_gds(outfile,cells) can't export the CellReference in the cells

I use conder python 3.6 and gdspy 1.3.1, I found if I set cells=[topcell], write_gds can't export the CellReference in the topcell, I must set cells=None, but the other cell will be exported too.

so I update the gdspy init code as below, for your reference.
I add one more function.
def CellList(cell,celllist=[],First=True):
if isinstance(cell,Cell):
if First==True:
celllist.append(cell)

    for r in cell.elements:
        if isinstance(r,CellReference):
            celllist.append(r.ref_cell)
            CellList(r.ref_cell,celllist=celllist,First=False)
    return celllist
else:
    return None

and also, I update def wirte_gds() as below:
def write_gds(outfile,
cells=None,
name='library',
unit=1.0e-6,
precision=1.0e-9):
current_library.name = name
current_library.unit = unit
current_library.precision = precision

current_library.write_gds(outfile, cells)

totalcell=[]
if isinstance(cells,Cell):
    totalcell=cellList(cells,celllist=[])
    current_library.write_gds(outfile, totalcell)
elif isinstance(cells,list):
    for cell in cells:
        totalcell=totalcell+cellList(cell,celllist=[])
    totalcell=set(totalcell)
    current_library.write_gds(outfile, totalcell)

and then, if my code is gdspy.write_gds('a.gds',topcell), all the cellreference in the topcell can be exported successfully.

Layer Isolation and cells Boolean operation

Hi
I wanted to export a single layer from the gds file but I couldn't find the way for it so I have added a method using the flatten method to do it for me, but here is the problem when the file is slightly big(10MB) and I want to use my hand made method It becomes very time consuming so I wanted to ask how could I do Boolean operation with two cells from each other?
I am sure that what I have done could become more efficient using the appropriate library function but I don't know how.

I add class Ellipse in gdspy, it is very useful

Hi, based on class Round(), I add class Ellipse(), it is very usefule for me.
class Ellipse(PolygonSet):

__slots__ = 'layers', 'datatypes', 'polygons'

def __init__(self,
             center,
             radius_x,
             radius_y,
             inner_radius_x=0,
             inner_radius_y=0,
             initial_angle=0,
             final_angle=0,
             number_of_points=100,
             max_points=199,
             layer=0,
             datatype=0):
    radius=max(radius_x,radius_y)
    if isinstance(number_of_points, float):
        if inner_radius_x <= 0 and inner_radius_y<=0:
            if final_angle == initial_angle:
                number_of_points = int(
                    2 * radius * numpy.pi / number_of_points + 0.5)
            else:
                number_of_points = int(
                    abs(final_angle - initial_angle) * radius /
                    number_of_points + 0.5) + 2
        else:
            if final_angle == initial_angle:
                number_of_points = 2 * int(
                    2 * radius * numpy.pi / number_of_points + 0.5) + 2
            else:
                number_of_points = 2 * int(
                    abs(final_angle - initial_angle) * radius /
                    number_of_points + 0.5) + 2
    number_of_points = max(number_of_points, 3)
    pieces = int(numpy.ceil(number_of_points / float(max_points)))
    number_of_points = number_of_points // pieces
    self.layers = [layer] * pieces
    self.datatypes = [datatype] * pieces
    self.polygons = [
        numpy.zeros((number_of_points, 2)) for _ in range(pieces)
    ]
    if final_angle == initial_angle and pieces > 1:
        final_angle += 2 * numpy.pi
    angles = numpy.linspace(initial_angle, final_angle, pieces + 1)
    for ii in range(pieces):
        if angles[ii + 1] == angles[ii]:
            if inner_radius_x <= 0 and inner_radius_y<=0:
                angle = numpy.arange(
                    number_of_points) * 2.0 * numpy.pi / number_of_points
                self.polygons[ii][:, 0] = numpy.cos(angle)*radius_x
                self.polygons[ii][:, 1] = numpy.sin(angle)*radius_y
                self.polygons[ii] = (
                    self.polygons[ii] + numpy.array(center))
            else:
                n2 = number_of_points // 2
                n1 = number_of_points - n2
                angle = numpy.arange(n1) * 2.0 * numpy.pi / (n1 - 1.0)
                self.polygons[ii][:n1, 0] = (
                    numpy.cos(angle) * radius_x + center[0])
                self.polygons[ii][:n1, 1] = (
                    numpy.sin(angle) * radius_y + center[1])
                angle = numpy.arange(n2) * -2.0 * numpy.pi / (n2 - 1.0)
                self.polygons[ii][n1:, 0] = (
                    numpy.cos(angle) * inner_radius_x + center[0])
                self.polygons[ii][n1:, 1] = (
                    numpy.sin(angle) * inner_radius_y + center[1])
        else:
            if inner_radius_x <= 0 and inner_radius_y<=0:
                angle = numpy.linspace(angles[ii], angles[ii + 1],
                                       number_of_points - 1)
                self.polygons[ii][1:, 0] = numpy.cos(angle)* radius_x
                self.polygons[ii][1:, 1] = numpy.sin(angle)* radius_y
                self.polygons[ii] = (
                    self.polygons[ii]  + numpy.array(center))
            else:
                n2 = number_of_points // 2
                n1 = number_of_points - n2
                angle = numpy.linspace(angles[ii], angles[ii + 1], n1)
                self.polygons[ii][:n1, 0] = (
                    numpy.cos(angle) * radius_x + center[0])
                self.polygons[ii][:n1, 1] = (
                    numpy.sin(angle) * radius_y + center[1])
                angle = numpy.linspace(angles[ii + 1], angles[ii], n2)
                self.polygons[ii][n1:, 0] = (
                    numpy.cos(angle) * inner_radius_x + center[0])
                self.polygons[ii][n1:, 1] = (
                    numpy.sin(angle) * inner_radius_y + center[1])

def __str__(self):
    return ("Round ({} polygons, {} vertices, layers {}, datatypes "
            "{})").format(
                len(self.polygons), sum([len(p) for p in self.polygons]),
                list(set(self.layers)), list(set(self.datatypes)))

Copy cells layers

Having a cell with different layers and references, is it possible to copy/translate one o multiple layers?

I have a "main cell" which is a set of multiple cells and cell references. These contain different elements in seven different layers. I wonder if it's possible to make a copy/translation of the whole "main cell", with the same set of cells and references, but just containing one of the layers.

Wrong results from fast_boolean()

Using production layouts, we have observed wrong results using fast_boolean() using the "and" operation with gdspy 0.9. The error seems to be related to fracturing in such way that if the clipper results are to be fractured, the results may be wrong.

Is it possible that clipper results violate some condition implicit to gdspy?

Unfortunately, I cannot provide a test case by now. If I can spare some time in the coming weeks, I'll try to find a simple example useful for hunting down the bug.

Adding all elements to an array

Good day

I want to add every element in a GDS file to an array. Currently I am doing this:

file1 = gdspy.GdsImport('Dcsfq.gds')
cell = file1.extract(file1.top_level()[0])

//Found this at another issue topic
references = []
for element in cell.elements:
if isinstance(element, gdspy.CellReference):
print 'Cell ' + element.ref_cell.name + ' referenced at ' + str(element.origin)
references.append((element.ref_cell, element.origin))
elif isinstance(element, gdspy.CellArray):
print 'Array of cells ' + element.ref_cell.name + ' referenced at ' + str(element.origin)
references.append((element.ref_cell, element.origin))

This gives me the list of all the element references as it should, but I need to know the locations of the polys and other basic elements as well. I think the problem lies with the fact that I am only getting the top layer. Is there a way to loop through the file to obtain the location and type (polys, slices etc) and put it all on an array.

For instance if I basically want to replicate an entire gds file (I know I use simpler methods, this is just for explaining purposes) and i want to find the location of each element in the file and make a new cell containing all the elements and their original locations.

The reason I want to do this, is because I have multiple files that I want to merge, but they contain elements with the same names so i cant just use

ref_cell.add(gdspy.CellReference(cell2, (150,0)))
ref_cell.add(gdspy.CellReference(cell1,(0,0)))
ref_cell.add(gdspy.CellReference(cell3, (225,-150), rotation=90))

as then I get double naming. So if there is an easier way then I am proposing, I am open to try anything. Also let me know if I should post any of my files or more information.

Sorry for the long post and thanks for any feedback.

Nested Cells

Is it possible to nest cells using gdspy? I've poured over the documentation/examples but haven't found any explicit reference to nesting or cell hierarchy.

I'm building a library of function components that return cells. I would like more complex cells to call simpler cell routines. The GDS format obviously works really well with this recursive framework.

Offset method robustness for complex shapes

The offset method for shapes that "close" upon themselves (i.e. enlarged such that the resulting polygon structure has overlapping portions) results in segmentation fault (SIGSEGV).

As a simple example -- letter C, drawn as a single polygon, and then enlarged using the offset method:

import gdspy
import numpy

cell = gdspy.Cell('CELL')
c_coords = numpy.array([  [ 0.6663    ,  0.32629112],
                          [ 0.6663    ,  0.1669    ],
                          [ 0.4994    ,  0.        ],
                          [ 0.1669    ,  0.        ],
                          [ 0.        ,  0.1669    ],
                          [ 0.        ,  0.8331    ],
                          [ 0.1669    ,  1.        ],
                          [ 0.4994    ,  1.        ],
                          [ 0.6663    ,  0.8331    ],
                          [ 0.6663    ,  0.67370888],
                          [ 0.4994    ,  0.67370888],
                          [ 0.4994    ,  0.76396776],
                          [ 0.43026776,  0.8331    ],
                          [ 0.23603224,  0.8331    ],
                          [ 0.1669    ,  0.76396776],
                          [ 0.1669    ,  0.23603224],
                          [ 0.23603224,  0.1669    ],
                          [ 0.43026776,  0.1669    ],
                          [ 0.4994    ,  0.23603224],
                          [ 0.4994    ,  0.32629112]])
poly = gdspy.Polygon(c_coords)
cell.add(poly)
offset_result = gdspy.offset(gdspy.CellReference(cell), distance=0.1)
offset_cell = gdspy.Cell('CELL_OFFSET')
offset_cell.add(offset_result)

gdspy.LayoutViewer(cells=[offset_cell])

For distance=0.1 (as above), the offset method returns the expected result. The moment the C-shape "closes" upon itself (distance >= 0.18), the call returns SIGSEGV.

Could you please suggest what can be done to avoid this? One workaround would be to break the shape into multiple polygons, but it is not a generic solution. Thank you.

Polygon enlargement

@heitzmann : Our chip design workflow is based on gdspy 0.7 and is built on gdspy geometry objects and gdspy boolean operations. There is one feature, however, that requires us to use additional packages to complete the design cycle. In our mask layouts, it is critical to have the ability to introduce CD bias to account for the linewidth reduction during the fabrication process. In mathematical terms, one needs to have the ability to enlarge polygons by a predefined amount in the direction that is normal to the polygon surface... thus a request for this feature. Thank you.

Gdspy 1.1 write_gds() for hierarchical files

@heitzmann I have installed the latest release (Patch 1.1.1) on Mac OSX, and am observing a different behaviour for the GDSII writing functionality compared to previous releases.

In the past (release 1.0), gds_print() would accept a list of cells to be included in the output file, and then append any cell dependencies to the list of cells to be written. Here's the relevant code:

if cells == None:
        cells = iter(Cell.cell_dict.values())
    else:
        cells = [Cell.cell_dict.get(c, c) for c in cells]
        i = 0
        while i < len(cells):
            for cell in cells[i].get_dependencies():
                if cell not in cells:
                    cells.append(cell)
            i += 1
        ...
        for cell in cells:
             outfile.write(cell.to_gds(unit / precision))

This worked flawlessly for deeply hierarchical cell structures.

The implementation of this functionality in 1.1.1 (write_gds() function), however, does not explicitly add the dependencies:

if cells is None:
        cells = self.cell_dict.values()
    else:
        cells = [self.cell_dict.get(c, c) for c in cells]
        for cell in cells:
             outfile.write(cell.to_gds(unit / precision))

resulting in an empty GDSII file. If I add the while / for block (the part in bold above), the dependencies are indeed added, and the resulting file contains all intended hierarchy.

Should the dependencies be explicitly added here, as before? Or am I missing something in the new implementation of GdsLibrary?

Path widths not conserved for number_of_paths higher than 1

I noticed that when I use a number_of_paths higher than 1 when I change the path distance between the paths this does not conserve the widths of the paths it draws. Only the widths of the paths at the beginning and the end of the tapered section. I would say that these two parameters could be simultaneously the width of the line and would strongly suggest this should be fixed, as for the effect can be difficult to observe but lead to errors none the less.

How to get lpp or layer datatype pair?

get_layers only output layers number
get_datatypes only output datatype number
The real useful info is the pair of layer and datatype, or lpp.
get_lpp() should be a valuable function

polygon in clockwise or counterclockwise

Hi

maybe not totally related to gdspy, but I just wonder if there is a common convention regarding the polygon vertices orientation in GDS file. The file I am opening has counter-clockwise but I read somewhere that GDS format does not dictate one way or the other. Is this true? How to express holes in a polygon then?

Thanks
enuinc

Saving only 1 cell + references to file

Hay there

I currently have 3 GDSII files that I am combining into one layout. I have managed to get all 3 cells into one cell and transposed and rotated them as necessary. Now I would only like to save one the one cell I have to a new GDS file.

import gdspy

file1 = gdspy.GdsImport('Dcsfq.gds')
file2 = gdspy.GdsImport('Conf2.gds')
file3 = gdspy.GdsImport('Tff4b.gds')

cell1 = file1.extract(file1.top_level()[0])
cell2 = file2.extract(file2.top_level()[0])
cell3 = file3.extract(file3.top_level()[0])

ref_cell = gdspy.Cell('TRANSLATED')
ref_cell.add(gdspy.CellReference(cell2, (150,0)))
ref_cell.add(gdspy.CellReference(cell1, (0,0)))
ref_cell.add(gdspy.CellReference(cell3, (225,-150), rotation=90))

newgds = gdspy.GdsPrint('new_gds.gds', unit=1.0e-6, precision=1.0e-9)
newgds.write_cell(ref_call)
newgds.close()

This however gives me an empty GDSII file. Am I doing the translations/rotation wrong, or is it the way I save the file that is not done properly? If someone could assist me with this I would be very greatful

Thanks

Problem importing in Anaconda on Ubuntu, python 3.6

I've tried:

pip install gdspy

and also

git clone github:gdspy.git

followed by

pip install -e gdspy

The install goes fine, but the importing fails every time with the following message:

gdspy/clipper.cpython-36m-x86_64-linux-gnu.so: undefined symbol: _ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_createERmm

This works fine under Anaconda on OS X with python 3.6.

I tried installing the pyclipper package from PyPI and it works fine (it is also a python wrapper for the C++ clipper library).

LayoutViewer hangs when I try to close it.

Im using Conda ipython with python version 3.6.3 on MacOS 10.13 to run code which opens a LayoutViewer. The code successfully opens a viewer. However when I try to close the viewer, either by clicking the red button at the upper left of the window or by selecting python>"quit python", I get a spinning beachball. The ipython command prompt returns (is no longer blocked) despite the spinning beachball.

I have the same problem in my python 2.7 conda environment.

Additionally, if I ignore the spinning beachball and hanging LayoutViewer, and continue working in the ipython shell, then the next time I call a layout viewer, the one that was hanging finally closes and a new layout viewer window opens.

I have noticed that if I open ipython, specifying tk backend i.e. "ipython --pylab=tk", then the viewer window will eventually close after first python>"quit python", followed by two (2) clicks of thew red button. This works both in the 3.6.3 main env and the 2.7 env. I say eventually because it usually fails (i.e. beachball) on the first invocation of "ipython --pylab=tk", but then starts to the work on the second or third. The default backend is 'MacOSX'.

depth argument of Cell.get_labels() is confusing

I'm referring to the following code segment.

    def get_labels(self, depth=None):
        labels = libCopy.deepcopy(self.labels)
        if depth is None or depth >= 0:
            for element in self.elements:
                if isinstance(element, CellReference):
                    labels.extend(
                        element.get_labels(None if depth is None else depth -
                                           1))
                elif isinstance(element, CellArray):
                    labels.extend(
                        element.get_labels(None if depth is None else depth -
                                           1))
        return labels

Passing in depth=0, one gets labels from the top-level cell, plus labels from the first-level child elements.
In order to get labels from the top-level cell only, one has to pass in depth=-1.

This behavior was confusing to my colleagues. After reading the code, I think it's better to change one line:

        if depth is None or depth > 0:

coordinate precision

Hi,

I have another question about the polygon coordinate precision extracted from GDS.

I am using the following code to get all polygons from a GDS file.

import gdspy
gdsii = gdspy.GdsLibrary()
gdsii.read_gds('out-file.gds')
main_cell = gdsii.top_level()[0]
pol_dict = main_cell.get_polygons(by_spec=True)
polygons = pol_dict[(41, 0)]

When I print out the values in polygons, I saw the following

[array([[2.16, 1.82],
[2.16, 0.98],
[1.82, 0.98],
[1.82, 0.54],
[2.26, 0.54],
[2.26, 0.76],
[2.34, 0.76],
[2.34, 1.82]]),
....

It seems I have to multiply 1000 to get the integer coordinates. Is this as expected?

I don't mind to multiply 1000 but I thought all numbers in GDS file is integer

Also, if I want to draw some polygons to output them to a GDS file, should I divide my coordinates by 1000?

Thanks
enuinc

Why do polygons have dtype('O') rather than something numeric?

When using gds_read, I found that the polygons are represented as numpy.ndarray of dtype('O'), i.e. object, not, say float or 'float64'.

For feeding the polygons to programs downstream, sometimes this matters, sometimes not. For example matplotlib and FreeCAD recognize the coordinates as numbers but PyGmsh doesn't.

To demonstrate, take any gds, say tutorial.gds from here, and

gds = GdsLibrary()
gds.read_gds(argv[1])

for layer, v in gds.top_level()[0].get_polygons(True).iteritems():
    print(layer, map(lambda p: (p.shape, p.dtype), v))

The workaround is trivial of course, just p.astype(float) (as in Polygon.fillet) or np.asarray(p, dtype=float) if a function is preferred to a method, but I was curious as to why the coordinates weren't numeric in the first place.

Problem in copy and relocate the object after rotation.

theta_small
thetha_large_100

@heitzmann

I am trying to make rectangular shape array structure (all rectangular shape are same size), whose rotation angle is decided by formula. I am directly calculating the rotate value using a formula in radian. When the rotation angle is small, everything is ok, rectangular shaped fixed at particular location, but if theta values is large, it is making mistake to fixed the location of rectangular shape, more precisely the coordinate of each rectangular location changes with large theta values. I do not understand the reason, I am quite new in Python. Attaching both files for reference. I am not sure that it's my programming mistake or related to this package.
I will be happy if you could answer. personal mail Id [email protected]

`

coding: utf-8

In[1]:

import numpy
import gdspy
import math
print('Using gdspy module version ' + gdspy.version)

------------------------------------------------------------------

POLYGONS

------------------------------------------------------------------

First we need a cell to add the polygons to.

poly_cell = gdspy.Cell('POLYGONS')

Polygon points for blue. (220 by 22 nm with periodicity = 250 nm).

points = [(0.015, 0.136), (0.114, 0.136), (0.114, 0.235), (0.136, 0.235), (0.136, 0.136), (0.235, 0.136), (0.235, 0.114),(0.136, 0.114), (0.136, 0.015), (0.114, 0.015), (0.114, 0.114), (0.015, 0.114)]

Create the polygon on layer 1.

trans_cell = gdspy.Cell('TRANS')

oper_cell = gdspy.Cell('OPERATIONS')

poly1 = gdspy.Polygon(points, 2) # add first polygon to layer 1

poly1 = gdspy.Polygon(points, 2).rotate(numpy.pi) # Rotate by 45 degree (numpy.pi/4)

nm=1e-9;
um=1e-6;

#rect_1 = gdspy.Rectangle( (0.0, 0.0), (250nm, 95nm), 1 ).rotate(3.14/6) # Define horigontal rectangle

ncells = 5
P = 325nm
Lambda = 532
nm
c = 3e8
f = 50*um
#A = 10

for iind in xrange (-ncells, ncells):
for jind in xrange(-ncells, ncells):
#print( jind)
rel_x1 = iindP # New location of the next polygons.
rel_y1 = jind
P
print(rel_x1,rel_y1)
temp = (rel_x12) + (rel_y12)
print(temp)
temp1 = ((rel_x12) + (rel_y12) + (f2))(0.5)
print(temp1)
Theta = 100numpy.pi(f-temp1)/Lambda # When 100 times, the location of rect changes.
print(Theta)
rect_1 = gdspy.Rectangle( (0.0, 0.0), (250nm, 95nm), 1 ).rotate(Theta)
poly1 = gdspy.copy(rect_1, rel_x1,rel_y1) # Copy the first polygons into new location rel_x and rel_y.
trans_cell.add(poly1) # Adding them in layer. If you dont add them nothing will appear.

Same goes for Labels & Text

#text1 = gdspy.Text('BLUE 220 X 22 ' , 6, (15, -10), horizontal=True, angle=0, layer=1) # Horizontal is false meaning vertical text.

#trans_cell.add(text1)

Addisional label can be created from here.

#label1 = gdspy.Label('BLUE 220 X 22 ',(15, -15), 'nw', layer=1)
#trans_cell.add(label1)

------------------------------------------------------------------

OUTPUT

------------------------------------------------------------------

Output the layout to a GDSII file (default to all created cells).

Set the units we used to micrometers and the precision to nanometers.

gdspy.write_gds('lens.gds', unit=1.0, precision=1.0e-12)

------------------------------------------------------------------

IMPORT

------------------------------------------------------------------

------------------------------------------------------------------

VIEWER

------------------------------------------------------------------

View the layout using a GUI. Full description of the controls can

be found in the online help at http://gdspy.sourceforge.net/

gdspy.LayoutViewer()

In[ ]:

`

Output Error while generating large number of fine slices

I need to make fine slices of the polygons for my application and I wrote a script for the same. While the script itself doesn't throw any error, I see that polygons generated after slice operation are shifted from the original in a specific pattern. Here is original polygons superimposed.

image

The slices are aligned with the original in the left and right edges, but shifted down in the middle of the polygon. The deviation is more prominent when the slice is finer.
Here is the same output zoomed in with original polygon highlighted in white.

image

And here is one of the slices highlighted in white.

image

This is the code that generates this result.
`#!/usr/bin/python
import numpy
import gdspy

def frange(start, stop, step):
i = start
while i < stop:
yield i
i += step

poly_cell = gdspy.Cell('POLYGONS')
points = [(10.43631016, -35.44995495), (20.43478711, -35.27543088), (20.41733471, -34.27558319), (10.41885775, -34.45010725)]

polylist = []

poly2 = gdspy.Polygon(points, 0)
poly_cell.add(poly2)
polylist.append(poly2)

bbox = poly_cell.get_bounding_box()
print (bbox)
sl = []

for i in frange(bbox[0][0]+0.005, bbox[1][0]+0.005, .01):
sl.append(i)

result = gdspy.slice(polylist, (sl), 0)
poly_cell.add(result)
gdspy.LayoutViewer()
`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.