mirror of https://github.com/KLayout/klayout.git
API enhanced for new properties ID scheme, updated doc and tests
This commit is contained in:
parent
e6ac66f8aa
commit
f2dc78f438
|
|
@ -331,12 +331,6 @@ static tl::Variant get_layout_property (const db::Layout *l, const tl::Variant &
|
|||
return props.value (key);
|
||||
}
|
||||
|
||||
// @@@ should not be needed
|
||||
static tl::Variant get_properties_hash (const db::Layout * /*layout*/, db::properties_id_type id)
|
||||
{
|
||||
return db::properties (id).to_dict_var ();
|
||||
}
|
||||
|
||||
static tl::Variant get_layout_properties (const db::Layout *layout)
|
||||
{
|
||||
const db::PropertiesSet &props = db::properties (layout->prop_id ());
|
||||
|
|
@ -565,8 +559,7 @@ static std::vector<db::LayerProperties> layer_infos (const db::Layout *l)
|
|||
return layers;
|
||||
}
|
||||
|
||||
// @@@ Should be static
|
||||
static db::properties_id_type properties_id (db::Layout * /*layout*/, const std::vector<tl::Variant> &properties)
|
||||
static db::properties_id_type properties_id_from_list (const std::vector<tl::Variant> &properties)
|
||||
{
|
||||
db::PropertiesSet props;
|
||||
|
||||
|
|
@ -580,8 +573,13 @@ static db::properties_id_type properties_id (db::Layout * /*layout*/, const std:
|
|||
return db::properties_id (props);
|
||||
}
|
||||
|
||||
// @@@ Should be static
|
||||
static db::properties_id_type properties_id_from_hash (db::Layout * /*layout*/, const std::map<tl::Variant, tl::Variant> &properties)
|
||||
// for backward compatibility
|
||||
static db::properties_id_type properties_id_from_list_meth (const db::Layout *, const std::vector<tl::Variant> &properties)
|
||||
{
|
||||
return properties_id_from_list (properties);
|
||||
}
|
||||
|
||||
static db::properties_id_type properties_id_from_hash (const std::map<tl::Variant, tl::Variant> &properties)
|
||||
{
|
||||
db::PropertiesSet props;
|
||||
|
||||
|
|
@ -592,13 +590,40 @@ static db::properties_id_type properties_id_from_hash (db::Layout * /*layout*/,
|
|||
return db::properties_id (props);
|
||||
}
|
||||
|
||||
// @@@ Should be static
|
||||
static tl::Variant properties (const db::Layout * /*layout*/, db::properties_id_type id)
|
||||
// for backward compatibility
|
||||
static db::properties_id_type properties_id_from_hash_meth (const db::Layout *, const std::map<tl::Variant, tl::Variant> &properties)
|
||||
{
|
||||
return properties_id_from_hash (properties);
|
||||
}
|
||||
|
||||
static tl::Variant get_properties_list (db::properties_id_type id)
|
||||
{
|
||||
return db::properties (id).to_list_var ();
|
||||
}
|
||||
|
||||
static void
|
||||
// for backward compatibility
|
||||
static tl::Variant get_properties_list_meth (const db::Layout *, db::properties_id_type id)
|
||||
{
|
||||
return db::properties (id).to_list_var ();
|
||||
}
|
||||
|
||||
static tl::Variant get_properties_hash (db::properties_id_type id)
|
||||
{
|
||||
return db::properties (id).to_dict_var ();
|
||||
}
|
||||
|
||||
// for backward compatibility
|
||||
static tl::Variant get_properties_hash_meth (const db::Layout *, db::properties_id_type id)
|
||||
{
|
||||
return db::properties (id).to_dict_var ();
|
||||
}
|
||||
|
||||
static tl::Variant get_property_from_id (db::properties_id_type id, const tl::Variant &key)
|
||||
{
|
||||
return db::properties (id).value (key);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_cells (db::Layout *layout, const std::vector<db::cell_index_type> &cell_indices)
|
||||
{
|
||||
layout->delete_cells (cell_indices.begin (), cell_indices.end ());
|
||||
|
|
@ -1309,18 +1334,40 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.29.5."
|
||||
) +
|
||||
gsi::method_ext ("properties_id", &properties_id, gsi::arg ("properties"),
|
||||
// backward-compatible version as method
|
||||
gsi::method_ext ("properties_id", &properties_id_from_list_meth, gsi::arg ("properties"),
|
||||
"@hide"
|
||||
) +
|
||||
gsi::method ("properties_id", &properties_id_from_list, gsi::arg ("properties"),
|
||||
"@brief Gets the properties ID for a given properties set\n"
|
||||
"\n"
|
||||
"Before a set of properties can be attached to a shape, it must be converted into an ID that "
|
||||
"is unique for that set. The properties set must be given as a list of pairs of variants, "
|
||||
"each pair describing a name and a value. The name acts as the key for the property and does not need to be a string (it can be an integer or double value as well).\n"
|
||||
"The backward conversion can be performed with the 'properties' method.\n"
|
||||
"In most places within the system, properties are stored as properties IDs. These are numbers representative for "
|
||||
"a specific set of properties. This method allows deriving a properties ID from a list of key/value pairs.\n"
|
||||
"It delivers a unique number for this set. A variant exists that takes a dict object instead of a list of key/value pairs.\n"
|
||||
"\n"
|
||||
"The \\properties_array and \\properties_hash methods allow converting the properties ID back into a list or dict object.\n"
|
||||
"Individual values for a given key can be extracted using \\property in the static (class) method variant.\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"pid = RBA::Layout::properties_id([[1, \"one\"], [\"key\", \"value\"]])\n"
|
||||
"# same as:\n"
|
||||
"# pid = RBA::Layout::properties_id({ 1 => \"one\", \"key\" => \"value\" })\n"
|
||||
"\n"
|
||||
"RBA::Layout::properties_hash(pid) # -> { 1 => \"one\", \"key\" => \"value\" }\n"
|
||||
"RBA::Layout::property(pid, 1) # -> \"one\"\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"In previous versions, these function were methods of the Layout object. Since version 0.30, they are static (class) methods. "
|
||||
"This means, that they provide a universal way of converting property sets into IDs and back, without need for a Layout object.\n"
|
||||
"\n"
|
||||
"@param properties The array of pairs of variants (both elements can be integer, double or string)\n"
|
||||
"@return The unique properties ID for that set"
|
||||
) +
|
||||
gsi::method_ext ("properties_id", &properties_id_from_hash, gsi::arg ("properties"),
|
||||
// backward-compatible version as method
|
||||
gsi::method_ext ("properties_id", &properties_id_from_hash_meth, gsi::arg ("properties"),
|
||||
"@hide"
|
||||
) +
|
||||
gsi::method ("properties_id", &properties_id_from_hash, gsi::arg ("properties"),
|
||||
"@brief Gets the properties ID for a given properties set\n"
|
||||
"\n"
|
||||
"This variant accepts a hash of value vs. key for the properties instead of array of key/value pairs. "
|
||||
|
|
@ -1329,9 +1376,26 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"@param properties A hash of property keys/values (both keys and values can be integer, double or string)\n"
|
||||
"@return The unique properties ID for that set\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.29.7."
|
||||
"This variant has been introduced in version 0.29.7 and was turned in a static (class) method in 0.30."
|
||||
) +
|
||||
gsi::method_ext ("properties_array|#properties", &properties, gsi::arg ("properties_id"),
|
||||
gsi::method ("property", &get_property_from_id, gsi::arg ("properties_id"), gsi::arg ("key"),
|
||||
"@brief Extracts a property value for a given key from the properties ID\n"
|
||||
"\n"
|
||||
"From a given properties ID, retrieves the value for a given key. If no value for this particular "
|
||||
"key exists, 'nil' is returned.\n"
|
||||
"\n"
|
||||
"For details about the properties ID concept see \\properties_id.\n"
|
||||
"\n"
|
||||
"Note, that this is a static (class) method that provides a universal way of extracting property values "
|
||||
"from IDs without need for a Layout object.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.30."
|
||||
) +
|
||||
// backward-compatible version as method
|
||||
gsi::method_ext ("properties_array|properties", &get_properties_list_meth, gsi::arg ("properties_id"),
|
||||
"@hide"
|
||||
) +
|
||||
gsi::method ("properties_array", &get_properties_list, gsi::arg ("properties_id"),
|
||||
"@brief Gets the properties set for a given properties ID\n"
|
||||
"\n"
|
||||
"Basically this method performs the backward conversion of the 'properties_id' method. "
|
||||
|
|
@ -1340,22 +1404,32 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"If the properties ID is not valid, an empty array is returned.\n"
|
||||
"A version that returns a hash instead of pairs of key/values, is \\properties_hash.\n"
|
||||
"\n"
|
||||
"For details about the properties ID concept see \\properties_id.\n"
|
||||
"\n"
|
||||
"@param properties_id The properties ID to get the properties for\n"
|
||||
"@return An array of key/value pairs (see \\properties_id)\n"
|
||||
"\n"
|
||||
"The 'properties_array' alias was introduced in version 0.29.7 and the plain 'properties' alias was deprecated."
|
||||
"The 'properties_array' alias was introduced in version 0.29.7 and the plain 'properties' alias was deprecated. "
|
||||
"In version 0.30, this method was turned into a static (class method), providing universal conversions without need for a Layout object."
|
||||
) +
|
||||
gsi::method_ext ("properties_hash", &get_properties_hash, gsi::arg ("properties_id"),
|
||||
// backward-compatible version as method
|
||||
gsi::method_ext ("properties_hash", &get_properties_hash_meth, gsi::arg ("properties_id"),
|
||||
"@hide"
|
||||
) +
|
||||
gsi::method ("properties_hash", &get_properties_hash, gsi::arg ("properties_id"),
|
||||
"@brief Gets the properties set for a given properties ID as a hash\n"
|
||||
"\n"
|
||||
"Returns the properties for a given properties ID as a hash.\n"
|
||||
"It is a convenient alternative to \\properties_array, which returns "
|
||||
"an array of key/value pairs.\n"
|
||||
"\n"
|
||||
"For details about the properties ID concept see \\properties_id.\n"
|
||||
"\n"
|
||||
"@param properties_id The properties ID to get the properties for\n"
|
||||
"@return The hash representing the properties for the given ID (values vs. key)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.29.7."
|
||||
"This method has been introduced in version 0.29.7. "
|
||||
"In version 0.30, this method was turned into a static (class method), providing universal conversions without need for a Layout object."
|
||||
) +
|
||||
gsi::method ("unique_cell_name", &db::Layout::uniquify_cell_name, gsi::arg ("name"),
|
||||
"@brief Creates a new unique cell name from the given name\n"
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ cell.shapes(layer_index).insert(RBA::Box::new(0, 0, 1000, 2000))
|
|||
layout.write("my_layout.gds")</pre>
|
||||
|
||||
<h3>Overview over the Layout object</h3>
|
||||
<keyword name="Layout Overview"/>
|
||||
|
||||
<p>
|
||||
The basic building blocks of layouts are layers and cells. Layers are not individual objects. Instead, a layer
|
||||
|
|
@ -101,6 +102,30 @@ layout.write("my_layout.gds")</pre>
|
|||
but requires some careful consideration.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
KLayout provides certain "working objects" - i.e. standalone geometry primitives that can be used in a number
|
||||
of low-level algorithms. For example, for rectangles, the <class_doc href="Box"/> object is provided. These objects
|
||||
represent coordinates as integer units as they are compatible with the internal objects from the database.
|
||||
By convention, these coordinates are interpreted as multiple of database units, i.e. a width of "100" for a box
|
||||
converts to "100 nm" for a database unit of 1 nm.
|
||||
These working objects are described in the "Geometry API" section.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In parallel to these objects, there exist floating-point coordinate objects. They are identified by a "D" prefix in
|
||||
the class name. For example, the floating-point twin of "Box" is <class_doc href="DBox"/>. By convention, the
|
||||
coordinates of these objects are interpreted as micrometers. Hence, these objects represent physical dimensions
|
||||
without needing a database unit.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Some algorithms, as the ones provided by the "Region" class, cannot act on floating-point objects. Hence their
|
||||
use is somewhat limited. Still is it convenient to work with such objects in coding layout generators for example.
|
||||
The Layout database allows retrieving primitives in both integer (database unit) and floating-point (micrometer forms)
|
||||
and also accepts both forms in most places. Conversion to the internal integer-coordinate representation happens
|
||||
automatically.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Layout object keeps shapes (texts, polygons, boxes, paths etc.) on "layers". A layer is a collection of
|
||||
shapes. A layout features a set of layers and each cell provides space for each layer. The shapes are stored
|
||||
|
|
@ -207,6 +232,7 @@ t = RBA::Trans::new(RBA::Trans::r90, 0, 0)
|
|||
pcell_inst = ly.cell(top).insert(RBA::CellInstArray::new(pcell_var, t))</pre>
|
||||
|
||||
<h3>Editable mode</h3>
|
||||
<keyword name="Editable Mode"/>
|
||||
|
||||
<p>
|
||||
A layout can exist in two flavors: editable and non-editable. In editable mode, some optimisations
|
||||
|
|
@ -232,8 +258,10 @@ non_editable_layout = RBA::Layout.new(false)</pre>
|
|||
</p>
|
||||
|
||||
<h3>Meta information</h3>
|
||||
<keyword name="Meta"/>
|
||||
<keyword name="Meta Information"/>
|
||||
|
||||
<p>A layout object can keep arbitrary meta data in the form of key/value pairs. This meta data is
|
||||
<p>A layout object and cell objects can keep arbitrary meta data in the form of key/value pairs. This meta data is
|
||||
extracted during the reading of a layout and will reflect special properties of the layout file.
|
||||
For example, the GDS2 library name is available as meta information with key "libname".
|
||||
</p>
|
||||
|
|
@ -242,13 +270,25 @@ non_editable_layout = RBA::Layout.new(false)</pre>
|
|||
iterate over the meta data (returning a <class_doc href="LayoutMetaInfo"/> object). <class_doc href="Layout#meta_info_value"/>
|
||||
will get the value for a given name. <class_doc href="Layout#add_meta_info"/> will add a new meta information object
|
||||
and <class_doc href="Layout#remove_meta_info"/> will delete one.
|
||||
Equivalent methods exist for the "Cell" class.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Meta information is a different concept than properties.
|
||||
Meta information is a different concept than properties. While properties are native to the stream format
|
||||
used, meta information is a KLayout extension. It is mapped to properties in OASIS in the same way, PCell
|
||||
context information is stored. For GDS2, KLayout provides a special context container inside the GDS2 file
|
||||
to store that information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Meta information is not subject to the stream format's limitations. For example, keys can be of any type
|
||||
and values can be arrays, dicts or even higher-level, string-serializable objects such as "Box".
|
||||
There is also no restriction on size of the attached data, in contrast to properties, where GDS2 imposes
|
||||
some limitations on the string length for example.
|
||||
</p>
|
||||
|
||||
<h3>Cell related methods</h3>
|
||||
<keyword name="Cell"/>
|
||||
|
||||
<p>Cells can be created using the <class_doc href="Layout#create_cell"/> method. This method expects a cell name. If a cell with that
|
||||
name already exists, a new name is generated by appending a suffix. The method returns the Cell object of the new
|
||||
|
|
@ -287,6 +327,7 @@ non_editable_layout = RBA::Layout.new(false)</pre>
|
|||
</p>
|
||||
|
||||
<h3>Layer related methods</h3>
|
||||
<keyword name="Layer"/>
|
||||
|
||||
<p><class_doc href="Layout#insert_layer"/> creates a new layer in the layout. The layer will be available to all cells. This method
|
||||
receives a <class_doc href="LayerInfo"/> object which holds the information about the layer's name, layer
|
||||
|
|
@ -330,6 +371,8 @@ lv.remove_unused_layers</pre>
|
|||
</p>
|
||||
|
||||
<h3>Recursive full or region queries</h3>
|
||||
<keyword name="Region Query"/>
|
||||
<keyword name="Recursive Region Query"/>
|
||||
|
||||
<p>
|
||||
A layout provides methods to retrieve shapes recursively. That means, that the shapes are delivered from all
|
||||
|
|
@ -400,84 +443,116 @@ end</pre>
|
|||
</p>
|
||||
|
||||
<h3>Properties</h3>
|
||||
<keyword name="Properties"/>
|
||||
|
||||
<p>
|
||||
As stated earlier, shapes can carry an arbitrary number of user properties in form of key/value pairs.
|
||||
For efficiency, these properties are not stored directly but in form of a property ID which identifies
|
||||
a unique set of properties. Retrieving a property hence requires an indirection over the property ID:
|
||||
</p>
|
||||
|
||||
<pre>layout = RBA::Application::instance.main_window.current_view.active_cellview.layout
|
||||
# first shape of cell "TOP", layer index 0
|
||||
layer_index = 0
|
||||
iter = layout.begin_shapes(layout.cell("TOP").cell_index, layer_index)
|
||||
shape = iter.shape
|
||||
# create a hash from the properties of that shape
|
||||
props = Hash[*layout.properties(shape.prop_id).flatten]
|
||||
# print the value of the property with key 1
|
||||
puts props[1]</pre>
|
||||
|
||||
<p>
|
||||
Since that scheme is somewhat tedious to use, a nice shortcut exists by using the
|
||||
"properties" method on the shape reference. This method implicitly modifies the property
|
||||
set and assigns a new property ID:
|
||||
</p>
|
||||
|
||||
<pre>layout = RBA::Application::instance.main_window.current_view.active_cellview.layout
|
||||
# first shape of cell "TOP", layer index 0
|
||||
layer_index = 0
|
||||
iter = layout.begin_shapes(layout.cell("TOP").cell_index, layer_index)
|
||||
shape = iter.shape
|
||||
# print the value of the property with key 1
|
||||
puts shape.properties(1)</pre>
|
||||
|
||||
<p>
|
||||
Changing a property requires to obtain a new property ID for the changed set:
|
||||
</p>
|
||||
|
||||
<pre>layout = RBA::Application::instance.main_window.current_view.active_cellview.layout
|
||||
# first shape of cell "TOP", layer index 0
|
||||
layer_index = 0
|
||||
iter = layout.begin_shapes(layout.cell("TOP").cell_index, layer_index)
|
||||
shape = iter.shape
|
||||
cell = layout.cell(iter.cell_index)
|
||||
# create a hash from the properties of that shape
|
||||
props = Hash[*layout.properties(shape.prop_id).flatten]
|
||||
# change or add a property with key 1
|
||||
props[1] = "NewValue"
|
||||
# store the new properties
|
||||
shape.prop_id = layout.properties_id(props.to_a)</pre>
|
||||
|
||||
<p>
|
||||
For that problem also a shortcut exists. Use the "set_properties" method on the
|
||||
shape reference. This method implicitly modifies the property
|
||||
set and assigns a new property ID:
|
||||
</p>
|
||||
|
||||
<pre>layout = RBA::Application::instance.main_window.current_view.active_cellview.layout
|
||||
# first shape of cell "TOP", layer index 0
|
||||
layer_index = 0
|
||||
iter = layout.begin_shapes(layout.cell("TOP").cell_index, layer_index)
|
||||
shape = iter.shape
|
||||
# change or add a property with key 1 and value "NewValue"
|
||||
shape.set_property(1, "NewValue")</pre>
|
||||
|
||||
<p>
|
||||
A property ID of 0 in general indicates that no properties are attached. Please note that replacing a property ID
|
||||
and modifying the properties also invalidates any iterators and should not be done in a loop over shapes.
|
||||
As stated earlier, shapes and other objects can carry an arbitrary number of user properties in form of key/value pairs.
|
||||
For efficiency, these properties are not stored directly, but in form of a properties ID, which identifies
|
||||
a unique set of properties.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Cell instances and cells also carry a properties ID which can be used to assign user properties to cell instances.
|
||||
The cell instance properties ID is used like the shape properties ID. The shortcut methods "property", "set_property"
|
||||
and "delete_property" also are provided for cells and cell instances (<class_doc href="Cell"/> and <class_doc href="Instance"/>).
|
||||
The objects that can carry properties are shapes (<class_doc href="Shape"/>), instances (<class_doc href="Instance"/>),
|
||||
Cells (<class_doc href="Cell"/>) and the Layout object itself (<class_doc href="Layout"/>). All these objects
|
||||
have a "prop_id" method that allows retrieving the properties ID. There is also a setter to change the properties ID.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> The GDS format does not have string names for properties. As a result GDS only supports numeric property keys.
|
||||
OASIS, on the other hand, can handle string and numeric property "names". When saving layouts in GDS format, KLayout tries
|
||||
As it is not quite convenient to work with properties IDs, there are methods to get or manipulate the properties directly.
|
||||
Those are:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> "property" (<class_doc href="Shape#property"/>, <class_doc href="Instance#property"/>,
|
||||
<class_doc href="Cell#property"/> and <class_doc href="Layout#property"/>) to get the property value
|
||||
for a specific key.
|
||||
</li>
|
||||
<li> "set_property" (<class_doc href="Shape#set_property"/>, <class_doc href="Instance#set_property"/>,
|
||||
<class_doc href="Cell#set_property"/> and <class_doc href="Layout#set_property"/>) to change or set the property value
|
||||
for a specific key.
|
||||
</li>
|
||||
<li> "delete_property" (<class_doc href="Shape#delete_property"/>, <class_doc href="Instance#delete_property"/>,
|
||||
<class_doc href="Cell#delete_property"/> and <class_doc href="Layout#delete_property"/>) to remove a specific key
|
||||
from the properties.
|
||||
</li>
|
||||
<li> "properties" (<class_doc href="Shape#properties"/>, <class_doc href="Instance#properties"/>,
|
||||
and <class_doc href="Cell#properties"/>) to get the properties as a hash (dict).
|
||||
For the "Layout" object this method is called "properties_hash" (<class_doc href="Layout#properties_hash"/>).
|
||||
For historical reasons, this class also has a method "properties_array" (<class_doc href="Layout#properties_array"/>)
|
||||
that delivers the properties as an array of key/value pairs.
|
||||
</li>
|
||||
<li> "has_prop_id?" (<class_doc href="Shape#has_prop_id?"/>, <class_doc href="Instance#has_prop_id?"/>,
|
||||
<class_doc href="Cell#has_prop_id?"/> and <class_doc href="Layout#has_prop_id?"/>) is a predicate indicating
|
||||
that properties are attached to the object.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Properties IDs identify a property set uniquely, so identity of the IDs implies identity of the properties set.
|
||||
In the same fashion, different IDs mean different properties sets.
|
||||
The ID is an arbitrary integer value and will change between invocations of the program.
|
||||
The ID value 0 is reserved for "no properties" or an empty property set.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Sometimes it is required to work with properties IDs directly.
|
||||
The Layout object provides four class methods to convert properties IDs to hashes (dicts) or lists
|
||||
back and forth:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> "properties_id" gets the properties ID from an array or hash of properties (<class_doc href="Layout#properties_id"/>).
|
||||
If used with an array, the array elements need to be key/value pairs.</li>
|
||||
<li> "properties_array" gets the properties as an array of key/value pairs from a properties ID (<class_doc href="Layout#properties_array"/>).</li>
|
||||
<li> "properties_dict" gets the properties as a hash (dict) from a properties ID (<class_doc href="Layout#properties_dict"/>).</li>
|
||||
<li> "property" gets a property value for a given key from a properties ID (<class_doc href="Layout#property"/>).</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Here is a sample for working with properties IDs:
|
||||
</p>
|
||||
|
||||
<pre>layout = RBA::Layout::new
|
||||
|
||||
# Populate the layout with a layer, a cell and one shape
|
||||
|
||||
l1 = layout.layer(1, 0)
|
||||
top = layout.create_cell("TOP")
|
||||
box = top.shapes(l1).insert(RBA::Box::new(0, 0, 100, 200))
|
||||
|
||||
# Use properties IDs to set initial properties
|
||||
|
||||
props = { 1 => "value for key #1", 2 => "value for key #2" }
|
||||
prop_id = RBA::Layout::properties_id(props)
|
||||
|
||||
# same as:
|
||||
# box.set_property(1, "value for key #1")
|
||||
# box.set_property(2, "value for key #2")
|
||||
box.prop_id = prop_id
|
||||
|
||||
# Change key 1 property
|
||||
# same as:
|
||||
# box.set_property(1, "one")
|
||||
|
||||
props = RBA::Layout::properties_hash(box.prop_id)
|
||||
props[1] = "one"
|
||||
box.prop_id = RBA::Layout::properties_id(props)</pre>
|
||||
|
||||
<p>
|
||||
Please note that replacing a property ID and modifying the properties usually invalidates any iterators and should
|
||||
not be done in a loop over shapes.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Note:</b> Although property keys can basically be any type, the GDS2 format does not have string names for properties.
|
||||
Property keys should be positive integers for GDS2.
|
||||
OASIS, on the other hand, can handle string and numeric property "names". When saving layouts in GDS2 format, KLayout tries
|
||||
to convert the properties' names into numbers if possible (i.e. if it sees that the string is a number). If it can't, then
|
||||
the property is not saved. When the layout is read by KLayout upon opening, it gets converted to integer.
|
||||
the property is not saved. When the layout is read by KLayout upon opening, the property keys will be read as integers.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Values can be strings or numerical for OASIS. In GDS2, values are converted to strings always.
|
||||
</p>
|
||||
|
||||
<h2>The LayerInfo class</h2>
|
||||
|
|
@ -485,13 +560,13 @@ shape.set_property(1, "NewValue")</pre>
|
|||
<keyword name="LayerInfo"/>
|
||||
<p>
|
||||
The <class_doc href="LayerInfo"/> object encapsulates the layer's naming properties.
|
||||
In GDS, a layer is described by a layer number and datatype number. In OASIS, a text name can be added
|
||||
In GDS2, a layer is described by a layer number and datatype number. In OASIS, a text name can be added
|
||||
to that description. In other formats like DXF, a layer has just a text name.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The LayerInfo object thus has a twofold identity: a numeric identity (layer and datatype number) and
|
||||
a text layer name. Both properties can be specified. In that case, the numeric identity has precendence
|
||||
a text layer name. Both properties can be specified. In that case, the numeric identity has precedence
|
||||
over the text name.
|
||||
</p>
|
||||
|
||||
|
|
@ -512,7 +587,7 @@ shape.set_property(1, "NewValue")</pre>
|
|||
attribute for the datatype number. <class_doc href="LayerInfo#name"/> gives access to the text name. <class_doc href="LayerInfo#is_named?"/> returns
|
||||
true, if the LayerInfo object represents a named layer (no layer or datatype number are specified).
|
||||
<class_doc href="LayerInfo#is_equivalent?"/> compares two LayerInfo objects and returns true, if both denote the same
|
||||
layer. This is not exact equivalence but follows the logical precendence: two layers are equivalent
|
||||
layer. This is not exact equivalence but follows the logical precedence: two layers are equivalent
|
||||
if layer or datatype number match (in that case the text name is ignored) or, if no layer and datatype
|
||||
number are specified, the name matches exactly.
|
||||
</p>
|
||||
|
|
@ -562,7 +637,7 @@ shape.set_property(1, "NewValue")</pre>
|
|||
<p>
|
||||
A cell can be a "ghost cell". A ghost cell is an empty cell which is not written to a layout write and
|
||||
created when a layout file is read with an unsatisfied reference. Unsatisfied references are present
|
||||
in some GDS files which represent partial layouts. By simple merging of two GDS files, such references can be
|
||||
in some GDS2 files which represent partial layouts. By simple merging of two GDS2 files, such references can be
|
||||
made true instances, when another file contributes the cell for that reference. KLayout supports such
|
||||
unsatisfied references by providing the "ghost cells" which serve as a instance target but are not written.
|
||||
Ghost cells are simply cells where the <class_doc href="Cell#is_ghost_cell?"/> attribute is true. An empty cell can be made
|
||||
|
|
@ -578,7 +653,7 @@ shape.set_property(1, "NewValue")</pre>
|
|||
|
||||
<p>
|
||||
Cells can be marked as "ghost cells" using the <class_doc href="Cell#ghost_cell="/>. Ghost cells
|
||||
are not saved into GDS files (but their references are). Also, ghost cells act as "placeholders" for cells -
|
||||
are not saved into GDS2 files (but their references are). Also, ghost cells act as "placeholders" for cells -
|
||||
for example if a cell is pasted into a layout, it will replace any ghost cell with the same name.
|
||||
If a normal cell with the same name exists, a copy will be created instead. A cell can be asked whether
|
||||
it is a ghost cell using <class_doc href="Cell#is_ghost_cell?"/>.
|
||||
|
|
@ -586,8 +661,8 @@ shape.set_property(1, "NewValue")</pre>
|
|||
|
||||
<p>
|
||||
Starting with version 0.23, cells can have properties as well, but writing cell properties to layout
|
||||
files is subject to some restrictions. Properties are only written to GDS if a special option is enabled
|
||||
because a potentially incompatible extension of GDS is used to store the properties. OASIS files
|
||||
files is subject to some restrictions. Properties are only written to GDS2 if a special option is enabled
|
||||
because a potentially incompatible extension of GDS2 is used to store the properties. OASIS files
|
||||
support cell properties without restrictions.
|
||||
</p>
|
||||
|
||||
|
|
@ -829,7 +904,7 @@ end</pre>
|
|||
|
||||
<p>
|
||||
The CellInstArray object represents either single instances or array instances. Array instances correspond
|
||||
to GDS AREF records and are regular, two-dimensional (not necessarily orthogonal) arrays of instances.
|
||||
to GDS2 AREF records and are regular, two-dimensional (not necessarily orthogonal) arrays of instances.
|
||||
A single instance consist of a cell index, denoting the cell that is instantiated and a single transformation,
|
||||
which can be either a simple, orthogonal affine transformation without a magnification (a Trans object, see
|
||||
<class_doc href="Trans"/>) or a general affine transformation (a CplxTrans object, see
|
||||
|
|
@ -913,7 +988,7 @@ end</pre>
|
|||
</p>
|
||||
|
||||
<p>
|
||||
An instance has an equality operator. That operator returns true, if the Instances indentify the same object.
|
||||
An instance has an equality operator. That operator returns true, if the Instances identify the same object.
|
||||
</p>
|
||||
|
||||
<h2>The Shapes class</h2>
|
||||
|
|
@ -1239,7 +1314,7 @@ end</pre>
|
|||
<p>
|
||||
A Shape object represents an edge if it returns true on <class_doc href="Shape#is_edge?"/>.
|
||||
Edge objects in general are not well supported in KLayout currently. They can be created and manipulated
|
||||
by scripts, but cannot be drawn or modified on the user interface. In GDS files, edges
|
||||
by scripts, but cannot be drawn or modified on the user interface. In GDS2 files, edges
|
||||
are represented by zero-width paths which is sometimes breaking the conventions of other tools.
|
||||
</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -1229,6 +1229,35 @@ class DBLayoutTest(unittest.TestCase):
|
|||
l2 = ly2.layer(1, 0)
|
||||
self.assertEqual(ly2.top_cell().bbox().to_s(), "(0,10;20,30)")
|
||||
|
||||
# Properties IDs
|
||||
def test_issue1549(self):
|
||||
|
||||
ly = pya.Layout.new()
|
||||
|
||||
ps1 = { 1: "one", "key": 17 }
|
||||
ps2 = [ ( 2, "two" ), ( "key", 42 ) ]
|
||||
|
||||
pid1 = pya.Layout.properties_id(ps1)
|
||||
# deprecated, for backward compatibility:
|
||||
self.assertEqual(ly.properties_array(pid1).__repr__(), "[[1, 'one'], ['key', 17]]")
|
||||
self.assertEqual(ly.properties_hash(pid1).__repr__(), "{1: 'one', 'key': 17}")
|
||||
self.assertEqual(pid1, ly.properties_id(ps1))
|
||||
# static method versions
|
||||
self.assertEqual(pya.Layout.properties_array(pid1).__repr__(), "[[1, 'one'], ['key', 17]]")
|
||||
self.assertEqual(pya.Layout.properties_hash(pid1).__repr__(), "{1: 'one', 'key': 17}")
|
||||
self.assertEqual(pya.Layout.property(pid1, 42).__repr__(), "None")
|
||||
self.assertEqual(pya.Layout.property(pid1, 1).__repr__(), "'one'")
|
||||
|
||||
pid2 = pya.Layout.properties_id(ps2)
|
||||
# deprecated, for backward compatibility:
|
||||
self.assertEqual(pid2, ly.properties_id(ps2))
|
||||
self.assertEqual(ly.properties_array(pid2).__repr__(), "[[2, 'two'], ['key', 42]]")
|
||||
self.assertEqual(ly.properties_hash(pid2).__repr__(), "{2: 'two', 'key': 42}")
|
||||
# static method versions
|
||||
self.assertEqual(pya.Layout.properties_array(pid2).__repr__(), "[[2, 'two'], ['key', 42]]")
|
||||
self.assertEqual(pya.Layout.properties_hash(pid2).__repr__(), "{2: 'two', 'key': 42}")
|
||||
self.assertEqual(pya.Layout.property(pid2, 42).__repr__(), "None")
|
||||
self.assertEqual(pya.Layout.property(pid2, 2).__repr__(), "'two'")
|
||||
|
||||
# run unit tests
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
|
|
@ -2334,6 +2334,38 @@ class DBLayoutTests1_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
# Properties IDs
|
||||
def test_issue1549
|
||||
|
||||
ly = RBA::Layout::new
|
||||
|
||||
ps1 = { 1 => "one", "key" => 17 }
|
||||
ps2 = [ [ 2, "two" ], [ "key", 42 ] ]
|
||||
|
||||
pid1 = RBA::Layout::properties_id(ps1)
|
||||
# deprecated, for backward compatibility:
|
||||
assert_equal(ly.properties_array(pid1).inspect, "[[1, \"one\"], [\"key\", 17]]")
|
||||
assert_equal(ly.properties_hash(pid1).inspect, "{1=>\"one\", \"key\"=>17}")
|
||||
assert_equal(pid1, ly.properties_id(ps1))
|
||||
# static method versions
|
||||
assert_equal(RBA::Layout::properties_array(pid1).inspect, "[[1, \"one\"], [\"key\", 17]]")
|
||||
assert_equal(RBA::Layout::properties_hash(pid1).inspect, "{1=>\"one\", \"key\"=>17}")
|
||||
assert_equal(RBA::Layout::property(pid1, 42).inspect, "nil")
|
||||
assert_equal(RBA::Layout::property(pid1, 1).inspect, "\"one\"")
|
||||
|
||||
pid2 = RBA::Layout::properties_id(ps2)
|
||||
# deprecated, for backward compatibility:
|
||||
assert_equal(pid2, ly.properties_id(ps2))
|
||||
assert_equal(ly.properties_array(pid2).inspect, "[[2, \"two\"], [\"key\", 42]]")
|
||||
assert_equal(ly.properties_hash(pid2).inspect, "{2=>\"two\", \"key\"=>42}")
|
||||
# static method versions
|
||||
assert_equal(RBA::Layout::properties_array(pid2).inspect, "[[2, \"two\"], [\"key\", 42]]")
|
||||
assert_equal(RBA::Layout::properties_hash(pid2).inspect, "{2=>\"two\", \"key\"=>42}")
|
||||
assert_equal(RBA::Layout::property(pid2, 42).inspect, "nil")
|
||||
assert_equal(RBA::Layout::property(pid2, 2).inspect, "\"two\"")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
load("test_epilogue.rb")
|
||||
|
|
|
|||
Loading…
Reference in New Issue