AbstractGeometry

Any AbstractGeometry subtype will have a bounding box and associated methods. It will also support the transformation interface.

DeviceLayout.AbstractGeometryType
AbstractGeometry{S <: Coordinate}

Abstract supertype for things that have a geometric representation.

Abstract subtypes include GeometryStructure, GeometryEntity, and GeometryReference. Provides an interface for coordinate transformations and bounding boxes.

source
DeviceLayout.coordinatetypeFunction
coordinatetype(::Type{S}) where {T, S <: AbstractGeometry{T}}
coordinatetype(S) where {T, S <: AbstractGeometry{T}}

Return the coordinate type of the geometry.

source
DeviceLayout.boundsMethod
bounds(geo::AbstractGeometry)
bounds(geo0::AbstractGeometry, geo1::AbstractGeometry, geo::AbstractGeometry...)
bounds(geos)

Return the minimum bounding Rectangle for geo or a collection/iterator geos.

If geo is empty or has no extent, a rectangle with zero width and height is returned.

For a collection or a structure that may contain multiple entities and references to other structures, geometries with bounds having zero width and height are excluded from the calculation.

source
DeviceLayout.centerFunction
center(p::Polygon)

Return the center of a polygon's bounding box (Point object). Note that this point doesn't have to be in the polygon.

source
center(geo::AbstractGeometry)
center(geos)

Return the center of the bounding rectangle bounds(geo) or bounds(geos).

Will not throw an InexactError even if geo has integer coordinates, but instead return floating point coordinates.

See also: lowerleft, upperright.

source
center(sch::Schematic, node::ComponentNode)
center(sch::Schematic, node_idx::Int)

The center of the bounds of node's component in the global coordinate system of sch.

source
DeviceLayout.Points.lowerleftFunction
lowerleft(x::Polygon)

Return the lower-left-most corner of a rectangle bounding polygon x. Note that this point doesn't have to be in the polygon.

source
lowerleft{T}(A::AbstractArray{Point{T}})

Return the lower-left Point of the smallest bounding rectangle (with sides parallel to the x- and y-axes) that contains all points in A.

Example:

julia> lowerleft([Point(2, 0), Point(1, 1), Point(0, 2), Point(-1, 3)])
2-element Point{Int64} with indices SOneTo(2):
 -1
  0
source
lowerleft(r::Rectangle)

Return the lower-left corner of a rectangle (Point object).

source
lowerleft(ent::AbstractGeometry)
lowerleft(ents)

Return the lower-left-most corner of a rectangle bounding ent or ents. Note that this point doesn't have to be in ent.

For iterable ents, entities with bounding rectanges of zero width and height will be excluded.

source
DeviceLayout.Points.upperrightFunction
upperright(x::Polygon)

Return the upper-right-most corner of a rectangle bounding polygon x. Note that this point doesn't have to be in the polygon.

source
upperright{T}(A::AbstractArray{Point{T}})

Return the upper-right Point of the smallest bounding rectangle (with sides parallel to the x- and y-axes) that contains all points in A.

Example:

julia> upperright([Point(2, 0), Point(1, 1), Point(0, 2), Point(-1, 3)])
2-element Point{Int64} with indices SOneTo(2):
 2
 3
source
upperright(r::Rectangle)

Return the upper-right corner of a rectangle (Point object).

source
upperright(ent::AbstractGeometry)
upperright(ents)

Return the upper-right-most corner of a rectangle bounding ent or ents. Note that this point doesn't have to be in ent.

For iterable ents, entities with bounding rectanges of zero width and height will be excluded.

source
DeviceLayout.footprintFunction
footprint(geo::AbstractGeometry)
footprint(geos)

Return the footprint of geo.

By default, this falls back to bounds(geo), but it may be any single GeometryEntity fully containing geo.

The footprint of a collection or iterator geos is bounds(geos).

source

There are three important subtypes of AbstractGeometry: GeometryEntity, GeometryStructure, and GeometryReference.

Entities

Entities are "simple" geometric elements. An entity can be placed in a single layer and rendered to an output model. For example, rendering a Rectangle to a Cell creates a Polygon representation suitable for the GDSII format.

DeviceLayout.GeometryEntityType
GeometryEntity{T <: Coordinate}

A geometric entity that can be placed in a coordinate system.

New concrete GeometryEntity subtypes must implement the following:

to_polygons(::MyEntity)
transform(ent::MyEntity, f)

A subtype may also implement specialized transformations like transform(::MyEntity, ::ScaledIsometry), for example if special handling is possible for angle-preserving transformations, as well as specializations for

magnify
rotate
rotate90
reflect_across_xaxis
translate

which otherwise construct the corresponding ScaledIsometry and call transform.

New subtypes may also implement

footprint
halo
lowerleft
upperright

if there are better ways to calculate these than with to_polygons (the default), which may be slow and expensive. The bounding rectangle returned by bounds is derived from lowerleft and upperright. By default, halo is derived from footprint and offset.

New subtypes may also implement any application functions required for valid styles. Not all styles need be valid for any given entity type.

source
DeviceLayout.to_polygonsFunction
to_polygons(ent::GeometryEntity; kwargs...)

Return a single polygon, an iterator, or Vector of Polygons equivalent to ent.

If ent is a StyledEntity, all styles will be applied before conversion to polygons.

source
DeviceLayout.haloMethod
halo(ent::GeometryEntity{T}, outer_delta, inner_delta=nothing)

Return the "halo" of ent using an offset of outer_delta.

By default, the halo is a vector containing offset(footprint(ent), outer_delta), but it may contain any number of GeometryEntitys that together fully cover ent with a margin of outer_delta. It is not guaranteed to cover footprint(ent).

If inner_delta is provided, then the offset at inner_delta is subtracted from the result.

A GeometryEntity should implement a specialized halo if there is an efficient non-Polygon representation of the halo. If it does not, then by default offset will be used, which first resolves the entity into Polygons using to_polygons.

source

Entity subtypes include AbstractPolygon (Polygon and Rectangle) and the individual pieces ("nodes") of a Path.

Structures

Structures are "composite" geometric objects, containing any number of GeometryEntity elements and their metadata, accessed with the elements and element_metadata methods. They can also contain references to other structures, accessed with refs. Structures also have a name can be flattened. Metadata can be recursively changed in-place with map_metadata! or in a copy with map_metadata. The type parameter of a GeometryStructure determines the coordinate type of its elements.

DeviceLayout.elementsMethod
elements(s::GeometryStructure)

Return a vector of GeometryEntity in the structure.

For a Cell, these are Polygons. For a CoordinateSystem, these can be any GeometryEntity.

source
DeviceLayout.map_metadataFunction
function map_metadata(geom::GeometryStructure, map_meta)

Create a copy of geom and change original metadata m to map_meta(m) for all elements.

Recursive on the copies of referenced structures.

source
DeviceLayout.map_metadata!Function
function map_metadata!(geom::GeometryStructure, map_meta)

For every element in geom with original meta m, set its metadata to map_meta(m).

Recursive on referenced structures.

source
function map_metadata(comp::AbstractComponent, map_meta)

For every element in geometry(comp) with original meta m, set its metadata to map_meta(m).

Recursive on referenced structures.

source

Unique names

It's generally desirable to give unique names to structures. In particular, the GDSII format references cells by name, leading to errors or undefined behavior if different cells have the same name. The uniquename function makes it possible to ensure unique names on a per-Julia-session basis or until reset_uniquename! resets the name counter. Structures that are not constructed directly by the user will generally have names generated by uniquename.

DeviceLayout.uniquenameFunction
uniquename(str, dlm="\$"; modify_first=false, counter=GLOBAL_NAME_COUNTER)

Given string input str for the nth time, return str * dlm * string(n).

If str is already formatted as str0 * dlm * n, where n is an integer, then str0 will be used with the larger of n and the number of times str0 has been counted plus one.

If modify_first is false, then str will be returned the first time uniquename(str, dlm; modify_first=false) is called.

Useful if programmatically making Cells and all of them will eventually be saved into a GDSII file.

The uniqueness is expected on a per-Julia session basis or until reset_uniquename! is called, so if you load an existing GDSII file and try to save unique cells on top of that you may get an unlucky clash. Calling uniquename on all loaded Cell names will effectively "register" them, making subsequent uniquename calls aware of them.

Example

julia> reset_uniquename!();

julia> uniquename("name"; modify_first=true)
"name\$1"

julia> uniquename("name\$4")
"name\$4"

julia> uniquename("name\$3")
"name\$5"

julia> uniquename("name")
"name\$6"

counter is the Dict{String,Int} that counts how many times each name has been seen. The default is a global counter that persists until the end of the Julia session or until reset_uniquename! is called.

source
DeviceLayout.reset_uniquename!Function
reset_uniquename!(counter=GLOBAL_NAME_COUNTER)

Reset uniquename counters for all strings.

counter is the Dict{String,Int} that counts how many times each name has been seen. The default is the same default global counter used by uniquename.

source
reset_uniquename!(str::String, counter=GLOBAL_NAME_COUNTER)

Reset uniquename counter for str.

counter is the Dict{String,Int} that counts how many times each name has been seen. The default is the same default global counter used by uniquename.

source

References

References point to a structure together with a transformation that positions it relative to the structure holding the reference. An ArrayReference also contains parameters specifying a 2d grid of instantiations of the referenced structure. The methods sref and aref are convenient for creating StructureReferences and ArrayReferences, respectively.

DeviceLayout.GeometryReferenceType
GeometryReference{S<:Coordinate, T<:GeometryStructure} <: AbstractGeometry{S}

Abstract supertype for references to geometry structures.

Subtypes are StructureReference and ArrayReference.

source
DeviceLayout.StructureReferenceType
mutable struct StructureReference{S, T} <: GeometryReference{S, T}
    structure::T
    origin::Point{S}
    xrefl::Bool
    mag::Float64
    rot::Float64
end

Reference to a structure positioned at origin, with optional x-reflection xrefl, magnification factor mag, and rotation angle rot. If an angle is given without units it is assumed to be in radians.

That is, the transformation applied by the reference is the composition of the following transformations, ordered with reflection applied first:

  1. If xrefl(f) is true, a reflection across the x-axis
  2. Rotation by rotation(f)
  3. Magnification by mag(f)
  4. Translation by origin(f)

The type variable T is to avoid circular definitions.

source
DeviceLayout.ArrayReferenceType
mutable struct ArrayReference{S,T} <: GeometryReference{S,T}
    structure::T
    origin::Point{S}
    deltacol::Point{S}
    deltarow::Point{S}
    col::Int
    row::Int
    xrefl::Bool
    mag::Float64
    rot::Float64
end

Array of structure starting at origin with row rows and col columns, spanned by vectors deltacol and deltarow. Optional x-reflection xrefl, magnification factor mag, and rotation angle rot for the array as a whole. If an angle is given without units it is assumed to be in radians.

The type variable T is to avoid circular definitions.

source
Base.copyMethod
copy(x::GeometryReference)

Creates a shallow copy of x (does not copy the referenced structure).

source
DeviceLayout.arefFunction
aref(x::GeometryStructure{S}, origin::Point{T}=zero(Point{S}); kwargs...) where
    {S <: Coordinate, T <: Coordinate}

Construct a ArrayReference{float(T),typeof(x)} object.

Keyword arguments specify the column vector, row vector, number of columns, number of rows, x-reflection, magnification factor, and rotation.

Synonyms are accepted for these keywords:

  • Column vector dc::Point{T}: :deltacol, :dcol, :dc, :vcol, :colv, :colvec, :colvector, :columnv, :columnvec, :columnvector
  • Row vector: :deltarow, :drow, :dr, :vrow, :rv, :rowvec, :rowvector
  • Number of columns: :nc, :numcols, :numcol, :ncols, :ncol
  • Number of rows: :nr, :numrows, :numrow, :nrows, :nrow
  • X-reflection: :xrefl, :xreflection, :refl, :reflect, :xreflect, :xmirror, :mirror
  • Magnification: :mag, :magnification, :magnify, :zoom, :scale
  • Rotation: :rot, :rotation, :rotate, :angle
source
aref(x, c::AbstractRange, r::AbstractRange; kwargs...)

Construct an ArrayReference based on ranges (probably LinSpace or FloatRange). c specifies column coordinates and r for the rows. Pairs from c and r specify the origins of the repeated cells. The extrema of the ranges therefore do not specify the extrema of the resulting ArrayReference's bounding box; some care is required.

Keyword arguments specify x-reflection, magnification factor, and rotation, with synonyms allowed:

  • X-reflection: :xrefl, :xreflection, :refl, :reflect, :xreflect, :xmirror, :mirror
  • Magnification: :mag, :magnification, :magnify, :zoom, :scale
  • Rotation: :rot, :rotation, :rotate, :angle
source
DeviceLayout.srefFunction
sref(x::GeometryStructure{T}, origin=zero(Point{T}); kwargs...)

Convenience constructor for StructureReference{float(T), typeof(x)}.

Synonyms are accepted for these keywords:

- X-reflection: `:xrefl`, `:xreflection`, `:refl`, `:reflect`, `:xreflect`,
`:xmirror`, `:mirror`
- Magnification: `:mag`, `:magnification`, `:magnify`, `:zoom`, `:scale`
- Rotation: `:rot`, `:rotation`, `:rotate`, `:angle`
source
DeviceLayout.transformationMethod
transformation(c::GeometryReference)

Return the angle-preserving transformation to be applied to the referenced structure.

source
DeviceLayout.Transformations.originMethod
origin(ref::GeometryReference)

The origin of the structure that ref points to, in ref's parent coordinate system.

Equivalently, the translation part of transformation(ref) (the transformation that ref would apply to structure(ref)).

source
DeviceLayout.Transformations.rotationMethod
rotation(ref::GeometryReference; α0=0)

The change in angle when applying transformation(ref) to a line originally at α0 CCW from the x-axis.

Equivalent to rotation(transformation(ref); α0=α0).

source

Resolving references

Sometimes it can be helpful to transform between coordinate systems and the coordinate systems they reference. This package provides methods to generate affine transforms to do this as easily as possible.

DeviceLayout.transformationMethod
transformation(c::GeometryStructure, d::GeometryReference)

Given a GeometryStructure c containing GeometryReference d in its tree of references, this function returns a Transformations.ScaledIsometry object that lets you translate from the coordinate system of d to the coordinate system of c.

If the same exact GeometryReference (as in ===, same address in memory) is included multiple times in the tree of references, then the resulting transform will be based on the first time it is encountered. The tree is traversed one level at a time to find the reference (optimized for shallow references).

Example: You want to translate (2.0,3.0) in the coordinate system of the referenced coordinate system d to the coordinate system of c:

julia> trans = transformation(c,d)

julia> trans(Point(2.0,3.0))
source
DeviceLayout.transformationMethod
transformation(c::GeometryStructure, d::GeometryReference, e::GeometryReference, f::GeometryReference...)

Given a geometry structure c containing GeometryReference last(f) in its tree of references, this function returns a Transformations.ScaledIsometry object that lets you translate from the coordinate system of last(f) to the coordinate system of c. This method is needed when you want to specify intermediate GeometryReferences explicitly.

For example, suppose for instance you have a hierarchy of coordinate systems, where coordinate system A references B1 and B2, which both reference C. Schematically, it might look like this:

a -- b1 -- c
  \      /
   \ b2 /

Coordinate system C appears in two places inside coordinate system A, owing to the fact that it is referenced by both B1 and B2. If you need to get the coordinate system of C via B2, then you need to do transformation(coordinatesystemA, coordsysrefB2, coordsysrefC), rather than simply transform(coordinatesystemA, coordsysrefC), because the latter will just take the first path to C available, via B1.

source

Flattening

Sometimes it's also helpful use an operation called "flattening" to produce an equivalent coordinate system with no references—that is, with all its elements at the top level.

DeviceLayout.flattenMethod
flatten(c::GeometryStructure; depth::Integer=-1, name=uniquename("flatten_"*name(c)))

Return a new coordinate system with name name with recursively flattened references and arrays up to a hierarchical depth.

Flattening a CoordinateSystem or Cell produces a coordinate system of the same type (meaning these can also be flattened in-place with flatten!), while flattening other structures generally produces a CoordinateSystem with the same coordinate type.

Flattening adds the elements of references to the top-level structure with appropriate transformations, then discards those references. Deeper references and arrays are brought upwards and are not discarded.

This function has no effect on references for depth == 0, and unlimited depth by default.

source
DeviceLayout.flattenMethod
flatten(c::GeometryReference; depth::Integer=-1, name=uniquename("flatten_"*name(structure(c))), metadata_filter=nothing)

Return a new structure with name name with recursively flattened references and arrays up to a hierarchical depth.

Flattening adds the elements of references to the top-level coordinate system with appropriate transformations, then discards those references. Deeper references and arrays are brought upwards and are not discarded. If depth=0, a new coordinate system is returned containing only the reference.

metadata_filter can be a function that takes a DeviceLayout.Meta and returns a Bool, like a function returned by layer_inclusion. In that case, only elements whose metadata m have metadata_filter(m) == true will be retained while flattening. Elements of deeper references and arrays are not filtered.

The reference c remains unmodified.

source

These methods take a metadata_filter keyword argument, which is a function that can be generated using layer_inclusion and lists of layers to include or ignore:

DeviceLayout.layer_inclusionFunction
layer_inclusion(only_layers, ignore_layers)

Return a function f(m::Meta) that returns a Bool based on inclusion/exclusion rules.

Both only_layers and ignore_layers are DeviceLayout.Meta, layer name Symbols, and/or collections of either.

If only_layers is empty, then only ignore_layers is used, and f(m) checks that neither m nor layer(m) is in ignore_layers. Otherwise, f(m) also checks that m or layer(m) is in only_layers.

source

For convenience, if you want to get just the list of elements in a flattened structure that match a layer or set of layers, you can use flat_elements:

DeviceLayout.flat_elementsFunction
flat_elements(geom::Union{GeometryStructure,GeometryReference}, only_layers=[], ignore_layers=[])
flat_elements(geom_layer::Pair{<:Union{GeometryStructure,GeometryReference}})

Return a list of GeometryEntity elements in flatten(cs), optionally filtering metadata.

only_layers and ignore_layers can be layer name Symbols, DeviceLayout.Meta, or collections of either. The metadata filtering function is produced using layer_inclusion(only_layers, ignore_layers). This means that the default empty only_layers is the same as listing all layers.

Using an argument pair geom => layer is equivalent to flat_elements(geom, layer).

source

Indexing

For convenience, you can get referenced structures by indexing their parent with the structure name, as in cs["referenced_cs"]["deeper_cs"].

Base.getindexMethod
getindex(c::GeometryStructure, nom::AbstractString, index::Integer=1)

If c references a structure with name nom, this method will return the corresponding GeometryReference. If there are several references to that coordinate system, then index specifies which one is returned (in the order they are found in refs(c)). e.g. to specify an index of 2: myCS["myreferencedCS",2].

source
Base.getindexMethod
getindex(c::GeometryReference, nom::AbstractString, index::Integer=1)

If the structure referenced by c references a structure with name nom, this method will return the corresponding GeometryReference. If there are several references to that structure, then index specifies which one is returned (in the order they are found in refs(structure(c))).

This method is typically used so that we can type the first line instead of the second line in the following:

myCS["myreferencedCS"]["onedeeper"]
myCS["myreferencedCS"].structure["onedeeper"]
source