AbstractGeometry
Any AbstractGeometry
subtype will have a bounding box and associated methods. It will also support the transformation interface.
DeviceLayout.AbstractGeometry
— TypeAbstractGeometry{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.
DeviceLayout.coordinatetype
— Functioncoordinatetype(::Type{S}) where {T, S <: AbstractGeometry{T}}
coordinatetype(S) where {T, S <: AbstractGeometry{T}}
Return the coordinate type of the geometry.
DeviceLayout.bounds
— Methodbounds(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.
DeviceLayout.center
— Functioncenter(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.
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
.
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
.
DeviceLayout.Points.lowerleft
— Functionlowerleft(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.
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
lowerleft(r::Rectangle)
Return the lower-left corner of a rectangle (Point object).
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.
DeviceLayout.Points.upperright
— Functionupperright(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.
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
upperright(r::Rectangle)
Return the upper-right corner of a rectangle (Point object).
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.
DeviceLayout.footprint
— Functionfootprint(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)
.
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.GeometryEntity
— TypeGeometryEntity{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.
DeviceLayout.to_polygons
— Functionto_polygons(ent::GeometryEntity; kwargs...)
Return a single polygon, an iterator, or Vector
of Polygon
s equivalent to ent
.
If ent
is a StyledEntity
, all styles will be applied before conversion to polygons.
DeviceLayout.halo
— Methodhalo(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 GeometryEntity
s 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 Polygon
s using to_polygons
.
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 flatten
ed. 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.GeometryStructure
— Typeabstract type GeometryStructure{S} <: AbstractGeometry{S}
Supertype for structures that may contain entities and references to other structures.
Subtypes include DeviceLayout.AbstractCoordinateSystem
and Path
.
DeviceLayout.elements
— Methodelements(s::GeometryStructure)
Return a vector of GeometryEntity
in the structure.
For a Cell
, these are Polygon
s. For a CoordinateSystem
, these can be any GeometryEntity
.
DeviceLayout.elementtype
— Methodelementtype(cs::GeometryStructure)
Return the type of elements in the structure.
DeviceLayout.element_metadata
— Methodelement_metadata(s::GeometryStructure)
Return a vector of metadata associated one-to-one with elements(s)
in the structure.
DeviceLayout.map_metadata
— Functionfunction 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.
DeviceLayout.map_metadata!
— Functionfunction 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.
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.
DeviceLayout.name
— Methodname(s::GeometryStructure)
Return a name String
for s
.
DeviceLayout.refs
— Methodrefs(s::GeometryStructure)
Return a vector of references to sub-structures.
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.uniquename
— Functionuniquename(str, dlm="\$"; modify_first=false, counter=GLOBAL_NAME_COUNTER)
Given string input str
for the n
th 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.
DeviceLayout.reset_uniquename!
— Functionreset_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
.
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
.
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 StructureReference
s and ArrayReference
s, respectively.
DeviceLayout.GeometryReference
— TypeGeometryReference{S<:Coordinate, T<:GeometryStructure} <: AbstractGeometry{S}
Abstract supertype for references to geometry structures.
Subtypes are StructureReference
and ArrayReference
.
DeviceLayout.StructureReference
— Typemutable 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:
- If
xrefl(f)
istrue
, a reflection across thex
-axis - Rotation by
rotation(f)
- Magnification by
mag(f)
- Translation by
origin(f)
The type variable T
is to avoid circular definitions.
DeviceLayout.ArrayReference
— Typemutable 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.
Base.copy
— Methodcopy(x::GeometryReference)
Creates a shallow copy of x
(does not copy the referenced structure).
DeviceLayout.aref
— Functionaref(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
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
DeviceLayout.sref
— Functionsref(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`
DeviceLayout.structure
— Functionstructure(ref::GeometryReference)
The GeometryStructure
that ref
points to.
DeviceLayout.transformation
— Methodtransformation(c::GeometryReference)
Return the angle-preserving transformation to be applied to the referenced structure.
DeviceLayout.Transformations.origin
— Methodorigin(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)
).
DeviceLayout.Transformations.mag
— Methodmag(ref::GeometryReference)
The magnification (uniform scaling factor) applied by transformation(ref)
.
DeviceLayout.Transformations.rotation
— Methodrotation(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)
.
DeviceLayout.Transformations.xrefl
— Methodxrefl(ref::GeometryReference)
A Bool
indicating whether transformation(ref)
includes a reflection.
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.transformation
— Methodtransformation(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))
DeviceLayout.transformation
— Methodtransformation(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 GeometryReference
s 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.
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.flatten
— Methodflatten(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.
DeviceLayout.flatten
— Methodflatten(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.
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_inclusion
— Functionlayer_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 Symbol
s, 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
.
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_elements
— Functionflat_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 Symbol
s, 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)
.
Indexing
For convenience, you can get referenced structures by indexing their parent with the structure name, as in cs["referenced_cs"]["deeper_cs"]
.
Base.getindex
— Methodgetindex(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]
.
Base.getindex
— Methodgetindex(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"]