Merge branch 'master-upstream'

This commit is contained in:
Kazunari Sekigawa 2022-12-09 06:51:52 +09:00
commit b1f87d6a07
58 changed files with 28697 additions and 116 deletions

129
Changelog
View File

@ -1,5 +1,132 @@
0.28
Changes (list may not be complete):
* Bugfix: %GITHUB%/issues/989 "Layout#convert_pcell_to_static" does not handle"defunct" cells
* Bugfix: %GITHUB%/issues/991 Basic library not available in Python module
* Bugfix: %GITHUB%/issues/1059 Cleanup of PCell orphans after re-evaluation on load
* Bugfix: %GITHUB%/issues/1081 Using a layer properties file from recent list without layout loaded crashes KLayout
* Bugfix: %GITHUB%/issues/1138 Provide a way to suppress or redirect log output or disable warnings, specifically from file readers, in Python module
* Bugfix: %GITHUB%/issues/1178 technology-data xml results in SEGV
* Bugfix: %GITHUB%/issues/1190 General compatibility issue of Edges#extended/extended_* with deep mode
* Enhacnement: %GITHUB%/issues/1056 X2 net names
* Enhancement: %GITHUB%/issues/1052 Pdf documentation
* Enhancement: %GITHUB%/issues/1053 Lefdef enhancements
* Enhancement: Support for Qt6
* Enhancement: KLayout paths
- $KLAYOUT_HOME can now be empty string (no home folder used)
- $KLAYOUT_PATH can now be empty string (no further and implicit search paths)
* Enhancement: Python typehints
- Python include files are generated for Python module
* Enhancement: Properties dialog now features object list on left side (select and change)
* Enhancement: Compute area and perimeter from selection (Edit/Selection/Area and Perimeter)
* Enhancement: Callbacks for PCells
- Allow dynamic change of some attributes (visibility, enabled etc.)
- By implementing "callback_impl" in PCellDeclarationHelper subclasses
* Enhancement: Report browser
- Shape user properties are turned into RDB values
- Scanning of text objects
* Enhancement: Support for high-DPI modes (scale factor 200%)
- "Highres" option to fully exploit resolution, normally follows screen scaling
* Enhancement: Multiple tech stacks for net tracer per technology
* Enhancement: New rulers
- Angle
- Radius (%GITHUB%/issues/906)
- Multi-segment
* Enhancement: LVS
- Generates a log view which may have useful hints
- Schematic and extracted netlists are available as separate tabs for LVS view
* Enhancement: DRC
- Antenna DRC measured values output on edge pair properties and into report file
- inside, not_inside, outside and not_outside also for edge/edge and edge/polygon layers
- split_inside, split_outside for edge/edge and edge/polygon layers
- andnot (edge/edge)
- inside_outside_part (edge/polygon)
- angle-class selectors (multiples or 90 or 45 degree)
- performance enhancements
- in_and_out (edge and polygon layers)
* Enhancement: "data:" URL schemes to pass direct base-64 encoded data
* Enhancement: "Close all except", "left of", "right of" etc. in layout tabs and macro editor tabs
* Enhancmennt: Drop-down list to select tab in layout views
* Enhancement: Setting for disabling "Save needed" dialog box
* Enhancement: File details are shown (dump of file header) for unknown file formats
* Enhancement: NoQt option for LayoutView
- PixelBuffer object instead of QImage
- LayoutView can be build without Qt
- Functions exist to emulate mouse events
- Included in standalone Python module
- Allows implementation of KLayout backend in web server
* Enhancement: New command "-rr" (like -r but keeps application running, for UI macros)
* Enhancement: PCell errors are shown on a special error layer which is visible together with guiding shapes
* Enhancement: custom queries support micron-unit attributes (dbbox, path_dtrans etc.)
* Enhancement: custom queries highlight results of queries when selected
* Enhancement: scale and snap improvements (edge pair support, properties maintained, arrays not always flattened)
* Enhancement: auto-run macros can not be given a priority in which they are executed
* Enhancement: D25 module overhauled
- Uses a DRC subset to generate layers
- Allows booleans and specific color assignments
- Supports edges and edge pairs (will build walls)
- Not backward compatible!
* Python/Ruby API:
- DText/Text: bbox, alignment enums
- Polygon#size with vector arguments
- DBox/Box#world
- Layout#unique_cell_name
- RecursiveShapeIterator#each, RecursiveInstanceIterator#each
- Layout#clip with DBox and Cell arguments
- Better automatic conversion of enum to int and vice versa
- CellInstArray constructor with Cell argument
- AbstractMenu#insert_menu, #clear_menu
- ActionBase#icon=, #on_menu_opening, #on_triggered
- CellMapping convinience methods
- Cell#read for easy importing of a layout into a cell + subtree
- LayerMap#map and #mmap: logical layer is optional now (needed to be incremental)
- Shapes#cell and #layout
- Edges#andnot, #split_interacting, #inside, #not_inside, #outside, #not_outside and related (for Region and Edges arguments)
- GenericDeviceExtractor#define_terminal convenience methods
- Box/DBox square and rectangle convenience constructor
- Box#enlarge convenience isotropic variant
- Region#in_and_out, Edges#in_and_out
0.28 (2022-xx-xx):
0.27.13 (2022-11-30):
* Bugfixes:
- selection did not work in non-editable mode
- partial selection did not work for guiding shapes
- compile issue: NDEBUG is not usable after ruby.h
0.27.12 (2022-11-01):
* Bugfix: %GITHUB%/issues/1173 DXF SPLINE implementation not compatible with ezdxf
* Bugfix: %GITHUB%/issues/1167 delete_cells slow in some cases
* Bugfix: %GITHUB%/issues/1164 Deleting cells: 'basic_string: construction from null is not valid'
* Bugfix: %GITHUB%/issues/1145 Crash when clearing a Shapes container by script while a shape is selected
* Bugfix: %GITHUB%/issues/1144 Copy layer not choosing the right "new" target layer sometimes
* Bugfix: %GITHUB%/issues/1143 DBU not taken from technology by default
* Bugfix: %GITHUB%/issues/1097 Change oasis writer defaults to strict + cblocks, discourage the usage of oas.gz
* Bugfix: Incorrect behavior of some deep-mode DRC functions
- deep edges "and" with Region: incorrect behavior if region is empty or non-deep
- deep edges "inside_part" with Region: incorrect behavior if region is empty or non-deep
- deep edges "outside_part" with Region: incorrect behavior if region is empty or non-deep
* Enhancement: Python include files are now provided for the Python package. This will add type information to the methods.
0.27.11 (2022-08-10):
* Bugfix: %GITHUB%/issues/1098 Normalize zero dimension when generating regular array instance
* Enhancement: %GITHUB%/issues/1103 Add setting to disable Save Needed dialog box
* Bugfix: %GITHUB%/issues/1106 "move by" does not move instances from partial selection
* Bugfix: %GITHUB%/issues/1111 GenericDeviceExtractor#define_opt_layer not working
* Bugfix: %GITHUB%/issues/1114 MSYS2 compatibility with latest revision (based on gcc 12.1)
* Bugfix: %GITHUB%/issues/1126 Internal error on DRC operation
* Bugfix: %GITHUB%/issues/1135 LVS mismatch on parallel devices and issue on ambiguity resolution
* Enhancement: Support for Python 3.11
* Enhancement: L2N and LVSDB readers made compatible with potential future extensions
* Enhancement: DRC Antenna check now can be given a text layer which receives output describing the measured and computed values
* Bugfix: *= method (e.g. Point, DPoint) properly listed in help and reflection API
* Bugfixes: Fixed a number of potential segfaults due to memory corruption found during master branch refactoring
0.27.10 (2022-06-04):
* Bugfix: %GITHUB%/issues/1081 Using a layer properties file from recent list without layout loaded crashes KLayout
* Enhancement: %GITHUB%/issues/1079 PCell update: Library#refresh should call coerce_parameters_impl
* Bugfix: %GITHUB%/issues/1075 Edit layer specification doesn't work well with PCells
* Bugfix: %GITHUB%/issues/1071 Issues with GDS text format and "Save As"
* Bugfix: %GITHUB%/issues/1068 Circle handle not shown sometimes
* Bugfixes: two potential segfaults fixed due to early delete of LayoutView and access to non-initialized memory
0.27.9 (2022-04-23):
* Bugfix: %GITHUB%/issues/1008 Don't optimize away points on path edit

View File

@ -26,6 +26,7 @@
#include "layDispatcher.h"
#include "layAbstractMenu.h"
#include "tlColor.h"
#include "tlLog.h"
#if defined(HAVE_QT)
# include "layConfigurationDialog.h"
#endif
@ -217,7 +218,8 @@ PluginDeclaration::initialized (lay::Dispatcher *root)
bool any_missing = false;
auto std_templates = make_standard_templates ();
for (auto t = std_templates.begin (); ! any_missing && t != std_templates.end (); ++t) {
if (! t->category ().empty () && cat_names.find (t->category ()) == cat_names.end ()) {
if (! t->category ().empty () &&
(cat_names.find (t->category ()) == cat_names.end () || cat_names.find (t->category ())->second->version () != ant::Template::current_version ())) {
any_missing = true;
}
}
@ -225,6 +227,9 @@ PluginDeclaration::initialized (lay::Dispatcher *root)
if (cat_names.empty ()) {
// full initial configuration
if (tl::verbosity () >= 20) {
tl::info << "Resetting annotation templates";
}
root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (make_standard_templates ()));
root->config_end ();
@ -235,9 +240,12 @@ PluginDeclaration::initialized (lay::Dispatcher *root)
for (auto t = std_templates.begin (); t != std_templates.end (); ++t) {
if (! t->category ().empty ()) {
auto tt = cat_names.find (t->category ());
if (tt != cat_names.end ()) {
if (tt != cat_names.end () && tt->second->version () == ant::Template::current_version ()) {
new_templates.push_back (*tt->second);
} else {
if (tl::verbosity () >= 20) {
tl::info << "Resetting annotation template: " << t->title ();
}
new_templates.push_back (*t);
}
}
@ -248,6 +256,11 @@ PluginDeclaration::initialized (lay::Dispatcher *root)
}
}
// upgrade
for (auto i = new_templates.begin (); i != new_templates.end (); ++i) {
i->version (ant::Template::current_version ());
}
root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (new_templates));
root->config_end ();

View File

@ -30,6 +30,12 @@
namespace ant
{
int
Template::current_version ()
{
return 1;
}
ant::Template
Template::from_object (const ant::Object &a, const std::string &title, int mode)
{
@ -57,7 +63,8 @@ Template::from_object (const ant::Object &a, const std::string &title, int mode)
}
Template::Template ()
: m_title (tl::to_string (tr ("Ruler"))),
: m_version (current_version ()),
m_title (tl::to_string (tr ("Ruler"))),
m_fmt_x ("$X"), m_fmt_y ("$Y"), m_fmt ("$D"),
m_style (ant::Object::STY_ruler), m_outline (ant::Object::OL_diag),
m_snap (true), m_angle_constraint (lay::AC_Global),
@ -74,7 +81,8 @@ Template::Template (const std::string &title,
const std::string &fmt_x, const std::string &fmt_y, const std::string &fmt,
style_type style, outline_type outline, bool snap, lay::angle_constraint_type angle_constraint,
const std::string &cat)
: m_title (title),
: m_version (current_version ()),
m_title (title),
m_category (cat),
m_fmt_x (fmt_x), m_fmt_y (fmt_y), m_fmt (fmt),
m_style (style), m_outline (outline),
@ -89,7 +97,8 @@ Template::Template (const std::string &title,
}
Template::Template (const ant::Template &d)
: m_title (d.m_title),
: m_version (d.m_version),
m_title (d.m_title),
m_category (d.m_category),
m_fmt_x (d.m_fmt_x), m_fmt_y (d.m_fmt_y), m_fmt (d.m_fmt),
m_style (d.m_style), m_outline (d.m_outline),
@ -107,6 +116,7 @@ Template &
Template::operator= (const ant::Template &d)
{
if (this != &d) {
m_version = d.m_version;
m_title = d.m_title;
m_category = d.m_category;
m_fmt_x = d.m_fmt_x;
@ -132,7 +142,7 @@ std::vector<Template>
Template::from_string (const std::string &s)
{
std::vector<Template> r;
try {
tl::Extractor ex (s.c_str ());
@ -140,10 +150,18 @@ Template::from_string (const std::string &s)
if (! ex.at_end ()) {
r.push_back (Template ());
r.back ().version (0);
while (! ex.at_end ()) {
if (ex.test ("mode=")) {
if (ex.test ("version=")) {
int v = 0;
ex.read (v);
r.back ().version (v);
ex.test (",");
} else if (ex.test ("mode=")) {
std::string s;
ex.read_word_or_quoted (s);
@ -299,11 +317,17 @@ Template::from_string (const std::string &s)
ex.expect (";");
r.push_back (Template ());
r.back ().version (0);
}
}
// downgrade version
if (r.back ().version () > current_version ()) {
r.back ().version (current_version ());
}
}
} catch (tl::Exception &ex) {
@ -338,6 +362,9 @@ Template::to_string (const std::vector<Template> &v)
r += "category=";
r += tl::to_word_or_quoted_string (t->category ());
r += ",";
r += "version=";
r += tl::to_string (t->version ());
r += ",";
r += "fmt=";
r += tl::to_word_or_quoted_string (t->fmt ());
r += ",";

View File

@ -107,6 +107,27 @@ public:
*/
Template &operator= (const ant::Template &d);
/**
* @brief Gets the current version
*/
static int current_version ();
/**
* @brief Gets the version
* The version is used to provide a migration path for KLayout versions.
*/
int version () const
{
return m_version;
}
/**
* @brief Sets the version
*/
void version (int v)
{
m_version = v;
}
/**
* @brief Gets the category string
* The category string is used to label the rulers generated from this template.
@ -424,6 +445,7 @@ public:
static std::string to_string (const std::vector<Template> &v);
private:
int m_version;
std::string m_title;
std::string m_category;
std::string m_fmt_x;

View File

@ -581,7 +581,8 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Polygon> > others;
others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ());
// NOTE: with counting the other region needs to be merged
others.push_back (counting ? other.begin_merged () : other.begin ());
proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
@ -1069,7 +1070,6 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
#if defined(USE_LOCAL_PROCESSOR)
bool needs_merged_primary = different_polygons || options.needs_merged ();
needs_merged_primary = true; // @@@
db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();

View File

@ -56,7 +56,7 @@ class ArrayRepository;
* coordinates box).
*/
template <class C, class R = C>
template <class C, class R>
struct DB_PUBLIC_TEMPLATE box
{
typedef C coord_type;

View File

@ -1561,7 +1561,7 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
tl_assert (input == 0); // input is a dummy parameter
m_has_other = other->has_external_inputs ();
// @@@ needs a concept to deal with merged/non-merged inputs
// TODO: needs a concept to deal with merged/non-merged inputs
m_is_other_merged = other->is_merged ();
set_description ("check");
@ -1588,8 +1588,8 @@ CompoundRegionCheckOperationNode::computed_dist () const
void
CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const
{
// @@@ needs a concept to deal with merged/non-merged primary
bool is_merged = true;
// TODO: needs a concept to deal with merged/non-merged inputs
bool is_merged = true;
db::check_local_operation<db::Polygon, db::Polygon> op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
tl_assert (results.size () == 1);
@ -1606,8 +1606,8 @@ bool is_merged = true;
void
CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const
{
// @@@ needs a concept to deal with merged/non-merged primary
bool is_merged = true;
// TODO: needs a concept to deal with merged/non-merged inputs
bool is_merged = true;
db::check_local_operation<db::PolygonRef, db::PolygonRef> op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
tl_assert (results.size () == 1);

View File

@ -171,7 +171,7 @@ DeepEdges::DeepEdges (const DeepEdges &other)
m_is_merged (other.m_is_merged)
{
if (m_merged_edges_valid) {
m_merged_edges = other.m_merged_edges;
m_merged_edges = other.m_merged_edges.copy ();
}
}
@ -186,7 +186,7 @@ DeepEdges::operator= (const DeepEdges &other)
m_merged_edges_valid = other.m_merged_edges_valid;
m_is_merged = other.m_is_merged;
if (m_merged_edges_valid) {
m_merged_edges = other.m_merged_edges;
m_merged_edges = other.m_merged_edges.copy ();
}
}
@ -227,20 +227,52 @@ void DeepEdges::do_insert (const db::Edge &edge)
template <class Trans>
static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
{
// TODO: this is a pretty cheap implementation. At least a plain move can be done with orientation variants.
if (t.equal (Trans (db::Disp (t.disp ())))) {
db::Layout &layout = deep_layer.layout ();
if (layout.begin_top_down () != layout.end_top_down ()) {
// Plain move
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
// build cell variants for different orientations
db::OrientationReducer same_orientation;
db::VariantsCollectorBase vars (&same_orientation);
vars.collect (deep_layer.layout (), deep_layer.initial_cell ());
deep_layer.separate_variants (vars);
// process the variants
db::Layout &layout = deep_layer.layout ();
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const std::map<db::ICplxTrans, size_t> &v = vars.variants (c->cell_index ());
tl_assert (v.size () == size_t (1));
db::Trans tr (v.begin ()->first.inverted () * t.disp ());
db::Shapes &shapes = c->shapes (deep_layer.layer ());
db::Shapes new_shapes (layout.manager (), c.operator-> (), layout.is_editable ());
new_shapes.insert_transformed (shapes, tr);
shapes.swap (new_shapes);
db::Shapes flat_shapes (layout.is_editable ());
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer.layer ()); !iter.at_end (); ++iter) {
flat_shapes.insert (iter->edge ().transformed (iter.trans ()).transformed (t));
}
layout.clear_layer (deep_layer.layer ());
top_cell.shapes (deep_layer.layer ()).swap (flat_shapes);
} else {
// General transformation -> note that this is a flat implementation!
db::Layout &layout = deep_layer.layout ();
if (layout.begin_top_down () != layout.end_top_down ()) {
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
db::Shapes flat_shapes (layout.is_editable ());
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer.layer ()); !iter.at_end (); ++iter) {
flat_shapes.insert (iter->edge ().transformed (iter.trans ()).transformed (t));
}
layout.clear_layer (deep_layer.layer ());
top_cell.shapes (deep_layer.layer ()).swap (flat_shapes);
}
}
}
@ -248,24 +280,36 @@ static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
void DeepEdges::do_transform (const db::Trans &t)
{
transform_deep_layer (deep_layer (), t);
if (m_merged_edges_valid && m_merged_edges.layer () != deep_layer ().layer ()) {
transform_deep_layer (m_merged_edges, t);
}
invalidate_bbox ();
}
void DeepEdges::do_transform (const db::ICplxTrans &t)
{
transform_deep_layer (deep_layer (), t);
if (m_merged_edges_valid && m_merged_edges.layer () != deep_layer ().layer ()) {
transform_deep_layer (m_merged_edges, t);
}
invalidate_bbox ();
}
void DeepEdges::do_transform (const db::IMatrix2d &t)
{
transform_deep_layer (deep_layer (), t);
if (m_merged_edges_valid && m_merged_edges.layer () != deep_layer ().layer ()) {
transform_deep_layer (m_merged_edges, t);
}
invalidate_bbox ();
}
void DeepEdges::do_transform (const db::IMatrix3d &t)
{
transform_deep_layer (deep_layer (), t);
if (m_merged_edges_valid && m_merged_edges.layer () != deep_layer ().layer ()) {
transform_deep_layer (m_merged_edges, t);
}
invalidate_bbox ();
}

View File

@ -174,7 +174,7 @@ DeepRegion::DeepRegion (const DeepRegion &other)
m_is_merged (other.m_is_merged)
{
if (m_merged_polygons_valid) {
m_merged_polygons = other.m_merged_polygons;
m_merged_polygons = other.m_merged_polygons.copy ();
}
}
@ -189,7 +189,7 @@ DeepRegion::operator= (const DeepRegion &other)
m_merged_polygons_valid = other.m_merged_polygons_valid;
m_is_merged = other.m_is_merged;
if (m_merged_polygons_valid) {
m_merged_polygons = other.m_merged_polygons;
m_merged_polygons = other.m_merged_polygons.copy ();
}
}
@ -235,22 +235,56 @@ void DeepRegion::do_insert (const db::Polygon &polygon)
template <class Trans>
static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
{
// TODO: this is a pretty cheap implementation. At least a plain move can be done with orientation variants.
if (t.equal (Trans (db::Disp (t.disp ())))) {
db::Layout &layout = deep_layer.layout ();
if (layout.begin_top_down () != layout.end_top_down ()) {
// Plain move
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
// build cell variants for different orientations
db::OrientationReducer same_orientation;
db::VariantsCollectorBase vars (&same_orientation);
vars.collect (deep_layer.layout (), deep_layer.initial_cell ());
deep_layer.separate_variants (vars);
// process the variants
db::Layout &layout = deep_layer.layout ();
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const std::map<db::ICplxTrans, size_t> &v = vars.variants (c->cell_index ());
tl_assert (v.size () == size_t (1));
db::Trans tr (v.begin ()->first.inverted () * t.disp ());
db::Shapes &shapes = c->shapes (deep_layer.layer ());
db::Shapes new_shapes (layout.manager (), c.operator-> (), layout.is_editable ());
new_shapes.insert_transformed (shapes, tr);
shapes.swap (new_shapes);
db::Shapes flat_shapes (layout.is_editable ());
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer.layer ()); !iter.at_end (); ++iter) {
db::Polygon poly;
iter->polygon (poly);
flat_shapes.insert (poly.transformed (iter.trans ()).transformed (t));
}
layout.clear_layer (deep_layer.layer ());
top_cell.shapes (deep_layer.layer ()).swap (flat_shapes);
} else {
// General transformation -> note that this is a flat implementation!
db::Layout &layout = deep_layer.layout ();
if (layout.begin_top_down () != layout.end_top_down ()) {
db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
db::Shapes flat_shapes (layout.manager (), &top_cell, layout.is_editable ());
for (db::RecursiveShapeIterator iter (layout, top_cell, deep_layer.layer ()); !iter.at_end (); ++iter) {
db::Polygon poly;
iter->polygon (poly);
poly.transform (iter.trans ());
poly.transform (t);
flat_shapes.insert (db::PolygonRef (poly, layout.shape_repository ()));
}
layout.clear_layer (deep_layer.layer ());
top_cell.shapes (deep_layer.layer ()).swap (flat_shapes);
}
}
}
@ -258,24 +292,36 @@ static void transform_deep_layer (db::DeepLayer &deep_layer, const Trans &t)
void DeepRegion::do_transform (const db::Trans &t)
{
transform_deep_layer (deep_layer (), t);
if (m_merged_polygons_valid && m_merged_polygons.layer () != deep_layer ().layer ()) {
transform_deep_layer (m_merged_polygons, t);
}
invalidate_bbox ();
}
void DeepRegion::do_transform (const db::ICplxTrans &t)
{
transform_deep_layer (deep_layer (), t);
if (m_merged_polygons_valid && m_merged_polygons.layer () != deep_layer ().layer ()) {
transform_deep_layer (m_merged_polygons, t);
}
invalidate_bbox ();
}
void DeepRegion::do_transform (const db::IMatrix2d &t)
{
transform_deep_layer (deep_layer (), t);
if (m_merged_polygons_valid && m_merged_polygons.layer () != deep_layer ().layer ()) {
transform_deep_layer (m_merged_polygons, t);
}
invalidate_bbox ();
}
void DeepRegion::do_transform (const db::IMatrix3d &t)
{
transform_deep_layer (deep_layer (), t);
if (m_merged_polygons_valid && m_merged_polygons.layer () != deep_layer ().layer ()) {
transform_deep_layer (m_merged_polygons, t);
}
invalidate_bbox ();
}
@ -1952,6 +1998,7 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
}
}
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
// with these flag set to true, the resulting polygons are broken again.
@ -1966,9 +2013,8 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
}
const db::DeepLayer &polygons = merged_deep_layer ();
// NOTE: on "inside" or with counting, the other polygons must be merged
bool other_needs_merged = (mode < 0 || counting);
const db::DeepLayer &other_polygons = other_needs_merged ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
// NOTE: with counting, the other polygons must be merged
const db::DeepLayer &other_polygons = counting ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
db::InteractingLocalOperation op (mode, touching, output_mode, min_count, max_count, true);
@ -2011,6 +2057,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputM
}
}
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
// with these flag set to true, the resulting polygons are broken again.
@ -2181,6 +2228,8 @@ DeepRegion::selected_interacting_generic (const Texts &other, InteractingOutputM
}
}
min_count = std::max (size_t (1), min_count);
// with these flag set to true, the resulting polygons are broken again.
bool split_after = false;

View File

@ -63,6 +63,7 @@ public:
typedef db::coord_traits<C> coord_traits;
typedef typename coord_traits::distance_type distance_type;
typedef typename coord_traits::area_type area_type;
typedef typename coord_traits::perimeter_type perimeter_type;
typedef db::object_tag< edge_pair<C> > tag;
/**
@ -379,6 +380,30 @@ public:
return box_type (m_first.p1 (), m_first.p2 ()) + box_type (m_second.p1 (), m_second.p2 ());
}
/**
* @brief Gets the perimeter of the edge pair
*
* The perimeter is defined by then sum of the lengths of the edges ("active perimeter")
*/
perimeter_type perimeter () const
{
return m_first.length () + m_second.length ();
}
/**
* @brief Gets the area of the edge pair
*
* This is the area covered between the edges.
*/
area_type area () const
{
vector_type v12 = m_first.p2 () - m_first.p1 ();
vector_type v13 = m_second.p1 () - m_first.p1 ();
vector_type v14 = m_second.p2 () - m_first.p1 ();
area_type a = (db::vprod (v12, v13) + db::vprod (v13, v14)) / 2;
return a < 0 ? -a : a;
}
/**
* @brief Test if the edges are orthogonal (vertical or horizontal)
*/

View File

@ -1264,7 +1264,7 @@ connected_clusters<T>::join_cluster_with (typename local_cluster<T>::id_type id,
}
connections_type &target = m_connections [id];
target.splice (target.end (), to_join, to_join.begin (), to_join.end ());
target.splice (to_join);
m_connections.erase (tc);

View File

@ -32,6 +32,7 @@
#include "dbInstElement.h"
#include "tlEquivalenceClusters.h"
#include "tlAssert.h"
#include "tlSList.h"
#include <map>
#include <list>
@ -1040,7 +1041,7 @@ public:
private:
typename local_clusters<T>::const_iterator m_lc_iter;
typedef std::list<ClusterInstance> connections_type;
typedef tl::slist<ClusterInstance> connections_type;
typename std::map<typename local_cluster<T>::id_type, connections_type>::const_iterator m_x_iter, m_x_iter_end;
};
@ -1060,7 +1061,7 @@ class DB_PUBLIC_TEMPLATE connected_clusters
{
public:
typedef typename local_clusters<T>::id_type id_type;
typedef std::list<ClusterInstance> connections_type;
typedef tl::slist<ClusterInstance> connections_type;
typedef typename local_clusters<T>::box_type box_type;
typedef connected_clusters_iterator<T> all_iterator;
typedef typename std::map<typename local_cluster<T>::id_type, connections_type>::const_iterator connections_iterator;

View File

@ -1097,10 +1097,16 @@ private:
const db::Cell &cell1 = mp_subject_layout->cell (inst1->object ().cell_index ());
const db::Cell &cell2 = mp_intruder_layout->cell (inst2->object ().cell_index ());
db::box_convert <db::CellInst, true> inst2_bc (*mp_intruder_layout, m_intruder_layer);
db::box_convert <db::CellInst, true> inst1_bc (*mp_subject_layout, m_subject_layer);
db::Box iibox2 = inst2->bbox (inst2_bc).enlarged (db::Vector (m_dist, m_dist));
if (iibox2.empty ()) {
return;
}
std::unordered_map<db::ICplxTrans, std::list<std::pair<db::cell_index_type, db::ICplxTrans> > > interactions_cache;
for (db::CellInstArray::iterator n = inst1->begin (); ! n.at_end (); ++n) {
for (db::CellInstArray::iterator n = inst1->begin_touching (safe_box_enlarged (iibox2, -1, -1), inst1_bc); ! n.at_end (); ++n) {
db::ICplxTrans tn1 = inst1->complex_trans (*n);
db::ICplxTrans tni1 = tn1.inverted ();

View File

@ -194,6 +194,9 @@ typedef object_with_properties<DPath> DPathWithProperties;
typedef object_with_properties<PathRef> PathRefWithProperties;
typedef object_with_properties<DPathRef> DPathRefWithProperties;
typedef object_with_properties<Point> PointWithProperties;
typedef object_with_properties<DPoint> DPointWithProperties;
typedef object_with_properties<Edge> EdgeWithProperties;
typedef object_with_properties<DEdge> DEdgeWithProperties;

View File

@ -28,6 +28,7 @@
#include "dbCommon.h"
#include "dbTypes.h"
#include "dbObjectTag.h"
#include "tlString.h"
#include "tlTypeTraits.h"
#include "tlVector.h"
@ -37,6 +38,9 @@
namespace db {
template <class C> class vector;
template <class C, class R = C> struct box;
template <class C> class generic_repository;
class ArrayRepository;
/**
* @brief A point class
@ -51,6 +55,9 @@ public:
typedef db::vector<C> vector_type;
typedef typename coord_traits::distance_type distance_type;
typedef typename coord_traits::area_type area_type;
typedef db::object_tag< point<C> > tag;
typedef db::box<C> box_type;
typedef db::point<C> point_type;
/**
* @brief Default constructor
@ -321,6 +328,24 @@ public:
*/
bool less (const point<C> &p) const;
/**
* @brief The (dummy) translation operator
*/
void translate (const point<C> &d, db::generic_repository<C> &, db::ArrayRepository &)
{
*this = d;
}
/**
* @brief The (dummy) translation operator
*/
template <class T>
void translate (const point<C> &d, const T &t, db::generic_repository<C> &, db::ArrayRepository &)
{
*this = d;
transform (t);
}
private:
C m_x, m_y;
};

View File

@ -317,7 +317,7 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
++nn;
}
// @@@ Use edges directly
// TODO: Use edges directly
polygons.clear ();
db::polygon_ref_generator<TI> ps (layout, polygons);
@ -402,7 +402,7 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
++nn;
}
// @@@ Use edges directly
// TODO: Use edges directly
spolygons.clear ();
db::polygon_ref_generator<TS> ps (layout, spolygons);
@ -836,7 +836,10 @@ void interacting_local_operation<TS, TI, TR>::do_compute_local (db::Layout * /*l
}
tl_assert (nstart > 0);
if (nstart == 0) {
// should not happen - but for safety we return here.
return;
}
db::InteractionDetector id (m_mode, nstart - 1);
id.set_include_touching (m_touching);

View File

@ -95,6 +95,8 @@ db::properties_id_type Shape::prop_id () const
return (**((pedge_iter_type *) m_generic.iter)).properties_id ();
case EdgePair:
return (**((pedge_pair_iter_type *) m_generic.iter)).properties_id ();
case Point:
return (**((ppoint_iter_type *) m_generic.iter)).properties_id ();
case Path:
return (**((ppath_iter_type *) m_generic.iter)).properties_id ();
case PathRef:
@ -144,6 +146,8 @@ db::properties_id_type Shape::prop_id () const
return m_generic.pedge->properties_id ();
case EdgePair:
return m_generic.pedge_pair->properties_id ();
case Point:
return m_generic.ppoint->properties_id ();
case Path:
return m_generic.ppath->properties_id ();
case PathRef:
@ -564,6 +568,9 @@ Shape::box_type Shape::box () const
return m_trans * basic_ptr (box_array_type::tag ())->object ();
} else if (m_type == ShortBoxArrayMember) {
return m_trans * basic_ptr (short_box_array_type::tag ())->object ();
} else if (m_type == Point) {
point_type pt = point ();
return m_trans * box_type (pt, pt);
} else {
raise_no_box ();
}
@ -614,6 +621,12 @@ Shape::perimeter_type Shape::perimeter () const
const short_box_array_type *arr = basic_ptr (short_box_array_type::tag ());
return arr->size () * arr->object ().perimeter ();
}
case Point:
return 0;
case Edge:
return edge ().length ();
case EdgePair:
return edge_pair ().perimeter ();
case Box:
case ShortBox:
case BoxArrayMember:
@ -629,6 +642,9 @@ size_t Shape::array_size () const
switch (m_type) {
case Null:
return 0;
case Point:
case Edge:
case EdgePair:
case Polygon:
case PolygonRef:
case PolygonPtrArrayMember:
@ -681,6 +697,11 @@ Shape::area_type Shape::area () const
switch (m_type) {
case Null:
return area_type ();
case Point:
case Edge:
return 0;
case EdgePair:
return edge_pair ().area ();
case Polygon:
return polygon ().area ();
case PolygonRef:
@ -761,6 +782,8 @@ Shape::box_type Shape::bbox () const
return box_type (edge ().p1 (), edge ().p2 ());
case EdgePair:
return edge_pair ().bbox ();
case Point:
return box_type (point (), point ());
case Path:
return path ().box ();
case PathRef:
@ -835,6 +858,9 @@ Shape::to_string () const
case EdgePair:
r = "edge_pair " + edge_pair ().to_string ();
break;
case Point:
r = "point " + point ().to_string ();
break;
case Path:
case PathRef:
case PathPtrArrayMember:

View File

@ -645,6 +645,7 @@ public:
typedef tl::reuse_vector<db::array<path_ptr_type, disp_type> >::const_iterator path_ptr_array_iter_type;
typedef tl::reuse_vector<db::edge<coord_type> >::const_iterator edge_iter_type;
typedef tl::reuse_vector<db::edge_pair<coord_type> >::const_iterator edge_pair_iter_type;
typedef tl::reuse_vector<db::point<coord_type> >::const_iterator point_iter_type;
typedef tl::reuse_vector<db::text<coord_type> >::const_iterator text_iter_type;
typedef tl::reuse_vector<db::text_ref<text_type, disp_type> >::const_iterator text_ref_iter_type;
typedef tl::reuse_vector<db::text_ref<text_type, unit_trans_type> >::const_iterator text_ptr_iter_type;
@ -669,6 +670,7 @@ public:
typedef tl::reuse_vector<db::object_with_properties<db::array<path_ptr_type, disp_type> > >::const_iterator ppath_ptr_array_iter_type;
typedef tl::reuse_vector<db::object_with_properties<db::edge<coord_type> > >::const_iterator pedge_iter_type;
typedef tl::reuse_vector<db::object_with_properties<db::edge_pair<coord_type> > >::const_iterator pedge_pair_iter_type;
typedef tl::reuse_vector<db::object_with_properties<db::point<coord_type> > >::const_iterator ppoint_iter_type;
typedef tl::reuse_vector<db::object_with_properties<db::text<coord_type> > >::const_iterator ptext_iter_type;
typedef tl::reuse_vector<db::object_with_properties<db::text_ref<text_type, disp_type> > >::const_iterator ptext_ref_iter_type;
typedef tl::reuse_vector<db::object_with_properties<db::text_ref<text_type, unit_trans_type> > >::const_iterator ptext_ptr_iter_type;
@ -709,6 +711,7 @@ public:
TextRef,
TextPtrArray,
TextPtrArrayMember,
Point,
UserObject
};
@ -1029,6 +1032,14 @@ public:
m_type = EdgePair;
}
/**
* @brief Construct a shape proxy as a reference to a point
*/
void init (point_type::tag)
{
m_type = Point;
}
/**
* @brief Construct a shape proxy as a reference to a box
*/
@ -1373,6 +1384,22 @@ public:
}
}
/**
* @brief Return the actual object that this shape reference is pointing to
*
* This is a generalization of the polygon (), etc. methods using a tag to identify the
* target object.
*/
const point_type *basic_ptr (point_type::tag) const
{
tl_assert (m_type == Point);
if (m_stable) {
return m_with_props ? &**(((ppoint_iter_type *) m_generic.iter)) : &**(((point_iter_type *) m_generic.iter));
} else {
return m_with_props ? m_generic.ppoint : m_generic.point;
}
}
/**
* @brief Return the actual object that this shape reference is pointing to
*
@ -1682,6 +1709,23 @@ public:
}
}
/**
* @brief Return the actual object that this shape reference is pointing to for objects with properties
*
* This is a generalization of the polygon (), etc. methods using a tag to identify the
* target object.
*/
const db::object_with_properties<point_type> *basic_ptr (db::object_with_properties<point_type>::tag) const
{
tl_assert (m_type == Point);
tl_assert (m_with_props);
if (m_stable) {
return &**(((ppoint_iter_type *) m_generic.iter));
} else {
return m_generic.ppoint;
}
}
/**
* @brief Return the actual object that this shape reference is pointing to for objects with properties
*
@ -1917,6 +1961,15 @@ public:
return *(((edge_pair_iter_type *) m_generic.iter));
}
/**
* @brief Return the iterator (in stable reference mode) by tag
*/
point_iter_type basic_iter (point_type::tag) const
{
tl_assert (m_type == Point && ! m_with_props);
return *(((point_iter_type *) m_generic.iter));
}
/**
* @brief Return the iterator (in stable reference mode) by tag
*/
@ -2088,6 +2141,15 @@ public:
return *(((pedge_pair_iter_type *) m_generic.iter));
}
/**
* @brief Return the iterator (in stable reference mode) by tag for objects with properties
*/
ppoint_iter_type basic_iter (db::object_with_properties<point_type>::tag) const
{
tl_assert (m_type == Point && m_with_props);
return *(((ppoint_iter_type *) m_generic.iter));
}
/**
* @brief Return the iterator (in stable reference mode) by tag for objects with properties
*/
@ -2395,6 +2457,49 @@ public:
return edge_pair (p);
}
/**
* @brief Return a reference to the point if one is referenced
*/
const point_type &point () const
{
tl_assert (m_type == Point);
return *basic_ptr (point_type::tag ());
}
/**
* @brief Test if the shape proxy points to a point
*/
bool is_point () const
{
return (m_type == Point);
}
/**
* @brief Instantiate the edge object
*
* If a edge is referenced, this object is instantiated
* by this method.
* Returns true, if the conversion was successful.
*/
bool point (point_type &p) const
{
if (is_point ()) {
p = point ();
return true;
} else {
return false;
}
}
/**
* @brief Alias for polymorphic expansion
* Returns true, if the conversion was successful.
*/
bool instantiate (point_type &p) const
{
return point (p);
}
/**
* @brief Return a reference to the text if one is referenced
*/
@ -2675,6 +2780,7 @@ public:
const text_ptr_array_type *text_aref;
const edge_type *edge;
const edge_pair_type *edge_pair;
const point_type *point;
const path_type *path;
const path_ref_type *path_ref;
const path_ptr_array_type *path_aref;
@ -2695,6 +2801,7 @@ public:
const db::object_with_properties<text_ptr_array_type> *ptext_aref;
const db::object_with_properties<edge_type> *pedge;
const db::object_with_properties<edge_pair_type> *pedge_pair;
const db::object_with_properties<point_type> *ppoint;
const db::object_with_properties<path_type> *ppath;
const db::object_with_properties<path_ref_type> *ppath_ref;
const db::object_with_properties<path_ptr_array_type> *ppath_aref;

View File

@ -641,6 +641,9 @@ ShapeIterator::advance_generic (int mode)
case EdgePair:
if (advance_shape<edge_pair_type, StableTag, RegionTag> (mode)) return;
break;
case Point:
if (advance_shape<point_type, StableTag, RegionTag> (mode)) return;
break;
case Path:
if (advance_shape<path_type, StableTag, RegionTag> (mode)) return;
break;
@ -767,6 +770,8 @@ ShapeIterator::quad_box_generic () const
return (quad_box_by_shape<edge_type, StableTag> (region_tag));
case EdgePair:
return (quad_box_by_shape<edge_pair_type, StableTag> (region_tag));
case Point:
return (quad_box_by_shape<point_type, StableTag> (region_tag));
case Path:
return (quad_box_by_shape<path_type, StableTag> (region_tag));
case PathRef:

View File

@ -375,6 +375,8 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Shapes::unit_trans_typ
return (insert_by_tag (shape_type::edge_type::tag (), shape, pm));
case shape_type::EdgePair:
return (insert_by_tag (shape_type::edge_pair_type::tag (), shape, pm));
case shape_type::Point:
return (insert_by_tag (shape_type::point_type::tag (), shape, pm));
case shape_type::Path:
return (insert_by_tag (shape_type::path_type::tag (), shape, pm));
case shape_type::PathRef:
@ -531,6 +533,16 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Trans &t, tl::func_del
return insert (db::object_with_properties<shape_type::edge_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::Point:
{
shape_type::point_type p (shape.point ());
p = t.trans (p);
if (! shape.has_prop_id ()) {
return insert (p);
} else {
return insert (db::object_with_properties<shape_type::point_type> (p, pm (shape.prop_id ())));
}
}
case shape_type::EdgePair:
{
shape_type::edge_pair_type p (shape.edge_pair ());
@ -658,6 +670,8 @@ Shapes::find (const Shapes::shape_type &shape) const
return find_shape_by_tag (shape_type::edge_type::tag (), shape);
case shape_type::EdgePair:
return find_shape_by_tag (shape_type::edge_pair_type::tag (), shape);
case shape_type::Point:
return find_shape_by_tag (shape_type::point_type::tag (), shape);
case shape_type::Path:
return find_shape_by_tag (shape_type::path_type::tag (), shape);
case shape_type::PathRef:
@ -727,6 +741,9 @@ Shapes::replace_prop_id (const Shapes::shape_type &ref, db::properties_id_type p
case shape_type::EdgePair:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::edge_pair_type>::tag ()), prop_id);
break;
case shape_type::Point:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::point_type>::tag ()), prop_id);
break;
case shape_type::Path:
replace_prop_id (ref.basic_ptr (object_with_properties<shape_type::path_type>::tag ()), prop_id);
break;
@ -789,6 +806,8 @@ Shapes::replace_prop_id (const Shapes::shape_type &ref, db::properties_id_type p
return replace_prop_id_iter (shape_type::simple_polygon_ptr_array_type::tag (), ref.basic_iter (shape_type::simple_polygon_ptr_array_type::tag ()), prop_id);
case shape_type::Edge:
return replace_prop_id_iter (shape_type::edge_type::tag (), ref.basic_iter (shape_type::edge_type::tag ()), prop_id);
case shape_type::Point:
return replace_prop_id_iter (shape_type::point_type::tag (), ref.basic_iter (shape_type::point_type::tag ()), prop_id);
case shape_type::EdgePair:
return replace_prop_id_iter (shape_type::edge_pair_type::tag (), ref.basic_iter (shape_type::edge_pair_type::tag ()), prop_id);
case shape_type::Path:
@ -874,6 +893,12 @@ Shapes::transform (const Shapes::shape_type &ref, const Trans &t)
p.transform (t);
return replace_member_with_props (shape_type::edge_pair_type::tag (), ref, p);
}
case shape_type::Point:
{
shape_type::point_type p (ref.point ());
p = t.trans (p);
return replace_member_with_props (shape_type::point_type::tag (), ref, p);
}
case shape_type::Path:
{
shape_type::path_type p (ref.path ());
@ -962,6 +987,8 @@ Shapes::replace (const Shapes::shape_type &ref, const Sh &sh)
return replace_member_with_props (shape_type::edge_type::tag (), ref, sh);
case shape_type::EdgePair:
return replace_member_with_props (shape_type::edge_pair_type::tag (), ref, sh);
case shape_type::Point:
return replace_member_with_props (shape_type::point_type::tag (), ref, sh);
case shape_type::Path:
return replace_member_with_props (shape_type::path_type::tag (), ref, sh);
case shape_type::PathRef:
@ -1347,6 +1374,7 @@ template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const SimplePolygon &)
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Text &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Edge &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const EdgePair &);
template DB_PUBLIC Shape Shapes::replace<>(const Shape &, const Point &);
template DB_PUBLIC Shape Shapes::transform<> (const Shape &, const ICplxTrans &);
template DB_PUBLIC Shape Shapes::transform<> (const Shape &, const Trans &);
@ -1376,6 +1404,8 @@ template class DB_PUBLIC layer_op<db::Shape::edge_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::edge_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::edge_pair_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::edge_pair_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::point_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::point_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_type, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::text_type>, db::stable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_ref_type, db::stable_layer_tag>;
@ -1414,6 +1444,8 @@ template class DB_PUBLIC layer_op<db::Shape::edge_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::edge_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::edge_pair_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::edge_pair_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::point_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::point_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_type, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::object_with_properties<db::Shape::text_type>, db::unstable_layer_tag>;
template class DB_PUBLIC layer_op<db::Shape::text_ref_type, db::unstable_layer_tag>;

View File

@ -138,8 +138,9 @@ public:
Text = 15,
TextRef = 16,
TextPtrArray = 17,
UserObject = 18,
Null = 19 // must be last!
Point = 18,
UserObject = 19,
Null = 20 // must be last!
};
enum flags_type
@ -154,6 +155,7 @@ public:
| (1 << SimplePolygonPtrArray),
Edges = (1 << Edge),
EdgePairs = (1 << EdgePair),
Points = (1 << Point),
Paths = (1 << Path)
| (1 << PathRef)
| (1 << PathPtrArray),
@ -392,6 +394,7 @@ private:
char sz17 [sizeof (per_shape_iter_size <text_ref_type>)];
char sz18 [sizeof (per_shape_iter_size <text_ptr_array_type>)];
char sz19 [sizeof (per_shape_iter_size <user_object_type>)];
char sz20 [sizeof (per_shape_iter_size <point_type>)];
};
// this union is simply there to determine the maximum size required for all

View File

@ -679,6 +679,12 @@ inline unsigned int iterator_type_mask (ShapeIterator::edge_pair_type::tag)
return 1 << ShapeIterator::EdgePair;
}
/// @brief Internal: ShapeIterator masks per shape type
inline unsigned int iterator_type_mask (ShapeIterator::point_type::tag)
{
return 1 << ShapeIterator::Point;
}
/// @brief Internal: ShapeIterator masks per shape type
inline unsigned int iterator_type_mask (ShapeIterator::path_type::tag)
{
@ -917,6 +923,8 @@ template class layer_class<db::Shape::path_ptr_array_type, db::stable_layer_tag>
template class layer_class<db::object_with_properties<db::Shape::path_ptr_array_type>, db::stable_layer_tag>;
template class layer_class<db::Shape::edge_type, db::stable_layer_tag>;
template class layer_class<db::object_with_properties<db::Shape::edge_type>, db::stable_layer_tag>;
template class layer_class<db::Shape::point_type, db::stable_layer_tag>;
template class layer_class<db::object_with_properties<db::Shape::point_type>, db::stable_layer_tag>;
template class layer_class<db::Shape::edge_pair_type, db::stable_layer_tag>;
template class layer_class<db::object_with_properties<db::Shape::edge_pair_type>, db::stable_layer_tag>;
template class layer_class<db::Shape::text_type, db::stable_layer_tag>;
@ -957,6 +965,8 @@ template class layer_class<db::Shape::edge_type, db::unstable_layer_tag>;
template class layer_class<db::object_with_properties<db::Shape::edge_type>, db::unstable_layer_tag>;
template class layer_class<db::Shape::edge_pair_type, db::unstable_layer_tag>;
template class layer_class<db::object_with_properties<db::Shape::edge_pair_type>, db::unstable_layer_tag>;
template class layer_class<db::Shape::point_type, db::unstable_layer_tag>;
template class layer_class<db::object_with_properties<db::Shape::point_type>, db::unstable_layer_tag>;
template class layer_class<db::Shape::text_type, db::unstable_layer_tag>;
template class layer_class<db::object_with_properties<db::Shape::text_type>, db::unstable_layer_tag>;
template class layer_class<db::Shape::text_ref_type, db::unstable_layer_tag>;

View File

@ -134,6 +134,8 @@ template DB_PUBLIC layer<db::Shape::edge_type, db::stable_layer_tag> &Shapes::ge
template DB_PUBLIC layer<db::object_with_properties<db::Shape::edge_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::edge_type>, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::edge_pair_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::edge_pair_type, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::object_with_properties<db::Shape::edge_pair_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::edge_pair_type>, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::point_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::point_type, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::object_with_properties<db::Shape::point_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::point_type>, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::text_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::text_type, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::object_with_properties<db::Shape::text_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::text_type>, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::text_ref_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::text_ref_type, db::stable_layer_tag> ();
@ -150,6 +152,7 @@ template DB_PUBLIC layer<db::Shape::short_box_array_type, db::stable_layer_tag>
template DB_PUBLIC layer<db::object_with_properties<db::Shape::short_box_array_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::short_box_array_type>, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::user_object_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::user_object_type, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::object_with_properties<db::Shape::user_object_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::user_object_type>, db::stable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::polygon_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::polygon_type, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::object_with_properties<db::Shape::polygon_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::polygon_type>, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::simple_polygon_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::simple_polygon_type, db::unstable_layer_tag> ();
@ -172,6 +175,8 @@ template DB_PUBLIC layer<db::Shape::edge_type, db::unstable_layer_tag> &Shapes::
template DB_PUBLIC layer<db::object_with_properties<db::Shape::edge_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::edge_type>, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::edge_pair_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::edge_pair_type, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::object_with_properties<db::Shape::edge_pair_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::edge_pair_type>, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::point_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::point_type, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::object_with_properties<db::Shape::point_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::point_type>, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::text_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::text_type, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::object_with_properties<db::Shape::text_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::text_type>, db::unstable_layer_tag> ();
template DB_PUBLIC layer<db::Shape::text_ref_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::text_ref_type, db::unstable_layer_tag> ();
@ -211,6 +216,8 @@ template DB_PUBLIC const layer<db::Shape::edge_type, db::stable_layer_tag> &Shap
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::edge_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::edge_type>, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::edge_pair_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::edge_pair_type, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::edge_pair_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::edge_pair_type>, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::point_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::point_type, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::point_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::point_type>, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::text_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::text_type, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::text_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::text_type>, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::text_ref_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::text_ref_type, db::stable_layer_tag> () const;
@ -227,6 +234,7 @@ template DB_PUBLIC const layer<db::Shape::short_box_array_type, db::stable_layer
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::short_box_array_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::short_box_array_type>, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::user_object_type, db::stable_layer_tag> &Shapes::get_layer<db::Shape::user_object_type, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::user_object_type>, db::stable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::user_object_type>, db::stable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::polygon_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::polygon_type, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::polygon_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::polygon_type>, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::simple_polygon_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::simple_polygon_type, db::unstable_layer_tag> () const;
@ -249,6 +257,8 @@ template DB_PUBLIC const layer<db::Shape::edge_type, db::unstable_layer_tag> &Sh
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::edge_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::edge_type>, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::edge_pair_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::edge_pair_type, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::edge_pair_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::edge_pair_type>, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::point_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::point_type, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::point_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::point_type>, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::text_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::text_type, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::object_with_properties<db::Shape::text_type>, db::unstable_layer_tag> &Shapes::get_layer<db::object_with_properties<db::Shape::text_type>, db::unstable_layer_tag> () const;
template DB_PUBLIC const layer<db::Shape::text_ref_type, db::unstable_layer_tag> &Shapes::get_layer<db::Shape::text_ref_type, db::unstable_layer_tag> () const;
@ -315,6 +325,8 @@ Shapes::is_valid (const Shapes::shape_type &shape) const
return is_valid_shape_by_tag (shape_type::edge_type::tag (), shape);
case shape_type::EdgePair:
return is_valid_shape_by_tag (shape_type::edge_pair_type::tag (), shape);
case shape_type::Point:
return is_valid_shape_by_tag (shape_type::point_type::tag (), shape);
case shape_type::Path:
return is_valid_shape_by_tag (shape_type::path_type::tag (), shape);
case shape_type::PathRef:
@ -478,6 +490,9 @@ Shapes::erase_shape (const Shapes::shape_type &shape)
case shape_type::EdgePair:
erase_shape_by_tag (shape_type::edge_pair_type::tag (), shape);
break;
case shape_type::Point:
erase_shape_by_tag (shape_type::point_type::tag (), shape);
break;
case shape_type::Path:
erase_shape_by_tag (shape_type::path_type::tag (), shape);
break;
@ -570,6 +585,9 @@ Shapes::erase_shapes (const std::vector<Shapes::shape_type> &shapes)
case shape_type::Edge:
erase_shapes_by_tag (shape_type::edge_type::tag (), s, snext);
break;
case shape_type::Point:
erase_shapes_by_tag (shape_type::point_type::tag (), s, snext);
break;
case shape_type::EdgePair:
erase_shapes_by_tag (shape_type::edge_pair_type::tag (), s, snext);
break;
@ -625,5 +643,4 @@ Shapes::erase_shapes (const std::vector<Shapes::shape_type> &shapes)
}
}
}

View File

@ -169,6 +169,18 @@ struct edge_pair_defs
method ("bbox", &C::bbox,
"@brief Gets the bounding box of the edge pair\n"
) +
method ("perimeter", &C::perimeter,
"@brief Gets the perimeter of the edge pair\n"
"\n"
"The perimeter is defined as the sum of the lengths of both edges ('active perimeter').\n"
"\n"
"This attribute has been introduced in version 0.28."
) +
method ("area", &C::area,
"@brief Gets the area between the edges of the edge pair\n"
"\n"
"This attribute has been introduced in version 0.28."
) +
method ("<", &C::less, gsi::arg ("box"),
"@brief Less operator\n"
"Returns true, if this edge pair is 'less' with respect to first and second edge\n"

View File

@ -709,6 +709,26 @@ static tl::Variant get_dedge_pair (const db::Shape *s)
}
}
static tl::Variant get_point (const db::Shape *s)
{
db::Shape::point_type p;
if (s->point (p)) {
return tl::Variant (p);
} else {
return tl::Variant ();
}
}
static tl::Variant get_dpoint (const db::Shape *s)
{
db::Shape::point_type p;
if (s->point (p)) {
return tl::Variant (db::CplxTrans (shape_dbu (s)) * p);
} else {
return tl::Variant ();
}
}
static tl::Variant get_text (const db::Shape *s)
{
db::Shape::text_type p;
@ -1108,6 +1128,7 @@ static int t_simplePolygonPtrArray () { return db::Shape::SimplePolygonPtr
static int t_simplePolygonPtrArrayMember () { return db::Shape::SimplePolygonPtrArrayMember; }
static int t_edge () { return db::Shape::Edge; }
static int t_edge_pair () { return db::Shape::EdgePair; }
static int t_point () { return db::Shape::Point; }
static int t_path () { return db::Shape::Path; }
static int t_pathRef () { return db::Shape::PathRef; }
static int t_pathPtrArray () { return db::Shape::PathPtrArray; }
@ -1250,6 +1271,22 @@ Class<db::Shape> decl_Shape ("db", "Shape",
"\n"
"This method has been introduced in version 0.25."
) +
gsi::method_ext ("point=", &set_shape<db::Point>, gsi::arg("point"),
"@brief Replaces the shape by the given point\n"
"This method replaces the shape by the given point. This method can only be called "
"for editable layouts. It does not change the user properties of the shape.\n"
"Calling this method will invalidate any iterators. It should not be called inside a "
"loop iterating over shapes.\n"
"\n"
"This method has been introduced in version 0.28."
) +
gsi::method_ext ("point=|dpoint=", &set_dshape<db::DPoint>, gsi::arg("point"),
"@brief Replaces the shape by the given point (in micrometer units)\n"
"This method replaces the shape by the given point, like \\point= with a \\Point argument does. "
"This version translates the point from micrometer units to database units internally.\n"
"\n"
"This method has been introduced in version 0.28."
) +
gsi::method_ext ("edge_pair=", &set_shape<db::EdgePair>, gsi::arg("edge_pair"),
"@brief Replaces the shape by the given edge pair\n"
"This method replaces the shape by the given edge pair. This method can only be called "
@ -1760,6 +1797,23 @@ Class<db::Shape> decl_Shape ("db", "Shape",
"\n"
"This method has been added in version 0.26.\n"
) +
gsi::method ("is_point?", &db::Shape::is_point,
"@brief Returns true, if the object is an point\n"
"\n"
"This method has been introduced in version 0.28.\n"
) +
gsi::method_ext ("point", &get_point,
"@brief Returns the point object\n"
"\n"
"This method has been introduced in version 0.28.\n"
) +
gsi::method_ext ("dpoint", &get_dpoint,
"@brief Returns the point object as a \\DPoint object in micrometer units\n"
"See \\point for a description of this method. This method returns the point after translation to "
"micrometer units.\n"
"\n"
"This method has been introduced in version 0.28.\n"
) +
gsi::method ("is_text?", &db::Shape::is_text,
"@brief Returns true, if the object is a text\n"
) +
@ -2057,6 +2111,7 @@ Class<db::Shape> decl_Shape ("db", "Shape",
gsi::method ("TSimplePolygonPtrArrayMember|#t_simple_polygon_ptr_array_member", &t_simplePolygonPtrArrayMember) +
gsi::method ("TEdge|#t_edge", &t_edge) +
gsi::method ("TEdgePair|#t_edge_pair", &t_edge_pair) +
gsi::method ("TPoint|#t_point", &t_point) +
gsi::method ("TPath|#t_path", &t_path) +
gsi::method ("TPathRef|#t_path_ref", &t_pathRef) +
gsi::method ("TPathPtrArray|#t_path_ptr_array", &t_pathPtrArray) +

View File

@ -454,6 +454,7 @@ static unsigned int s_regions () { return db::ShapeIterator::Regions
static unsigned int s_boxes () { return db::ShapeIterator::Boxes; }
static unsigned int s_edges () { return db::ShapeIterator::Edges; }
static unsigned int s_edge_pairs () { return db::ShapeIterator::EdgePairs; }
static unsigned int s_points () { return db::ShapeIterator::Points; }
static unsigned int s_paths () { return db::ShapeIterator::Paths; }
static unsigned int s_texts () { return db::ShapeIterator::Texts; }
static unsigned int s_user_objects () { return db::ShapeIterator::UserObjects; }
@ -875,6 +876,25 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"\n"
"This variant has been introduced in version 0.26.\n"
) +
gsi::method_ext ("replace", &replace<db::Point>, gsi::arg ("shape"), gsi::arg ("point"),
"@brief Replaces the given shape with an point object\n"
"\n"
"This method replaces the given shape with the "
"object specified. It does not change the property Id. To change the property Id, "
"use the \\replace_prop_id method. To replace a shape and discard the property Id, erase the "
"shape and insert a new shape."
"\n"
"This variant has been introduced in version 0.28."
) +
gsi::method_ext ("replace", &dreplace<db::DPoint>, gsi::arg ("shape"), gsi::arg ("point"),
"@brief Replaces the given shape with an point given in micrometer units\n"
"@return A reference to the new shape (a \\Shape object)\n"
"\n"
"This method behaves like the \\replace version with an \\Point argument, except that it will "
"internally translate the point from micrometer to database units.\n"
"\n"
"This variant has been introduced in version 0.28."
) +
gsi::method_ext ("replace", &replace<db::Text>, gsi::arg ("shape"), gsi::arg ("text"),
"@brief Replaces the given shape with a text object\n"
"@return A reference to the new shape (a \\Shape object)\n"
@ -989,6 +1009,19 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
"\n"
"This variant has been introduced in version 0.26."
) +
gsi::method_ext ("insert|#insert_point", &insert<db::Point>, gsi::arg ("point"),
"@brief Inserts an point into the shapes list\n"
"\n"
"This variant has been introduced in version 0.28.\n"
) +
gsi::method_ext ("insert", &dinsert<db::DPoint>, gsi::arg ("point"),
"@brief Inserts a micrometer-unit point into the shapes list\n"
"@return A reference to the new shape (a \\Shape object)\n"
"This method behaves like the \\insert version with a \\Point argument, except that it will "
"internally translate the point from micrometer to database units.\n"
"\n"
"This variant has been introduced in version 0.28.\n"
) +
gsi::method_ext ("insert|#insert_text", &insert<db::Text>, gsi::arg ("text"),
"@brief Inserts a text into the shapes list\n"
"@return A reference to the new shape (a \\Shape object)\n"
@ -1285,6 +1318,11 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
gsi::method ("SEdgePairs|#s_edge_pairs", &s_edge_pairs,
"@brief Indicates that edge pairs shall be retrieved"
) +
gsi::method ("SPoints|#s_points", &s_points,
"@brief Indicates that points shall be retrieved"
"\n"
"This constant has been added in version 0.28."
) +
gsi::method ("SPaths|#s_paths", &s_paths,
"@brief Indicates that paths shall be retrieved"
) +

View File

@ -35,11 +35,15 @@ TEST(1)
EXPECT_EQ (ep == db::EdgePair (db::Edge (), db::Edge ()), true);
EXPECT_EQ (ep != db::EdgePair (db::Edge (), db::Edge ()), false);
EXPECT_EQ (ep < db::EdgePair (db::Edge (), db::Edge ()), false);
EXPECT_EQ (ep.area (), db::EdgePair::area_type (0));
EXPECT_EQ (ep.perimeter (), db::EdgePair::perimeter_type (0));
ep = db::EdgePair (db::Edge (db::Point (10, 30), db::Point (15, 30)), db::Edge (db::Point (0, 30), db::Point (0, 40)));
EXPECT_EQ (ep.to_string (), "(10,30;15,30)/(0,30;0,40)");
EXPECT_EQ (ep.normalized ().to_string (), "(15,30;10,30)/(0,30;0,40)");
EXPECT_EQ (ep.normalized ().normalized ().to_string (), "(15,30;10,30)/(0,30;0,40)");
EXPECT_EQ (ep.area (), db::EdgePair::area_type (50)); // weird orientation :(
EXPECT_EQ (ep.perimeter (), db::EdgePair::perimeter_type (15));
ep = db::EdgePair (db::Edge (db::Point (1, 2), db::Point (11, 12)), db::Edge (db::Point (-5, 5), db::Point (5, 15)));
EXPECT_EQ (ep.to_string (), "(1,2;11,12)/(-5,5;5,15)");

View File

@ -565,7 +565,7 @@ TEST(15c)
r.insert (db::Box (db::Point (400, 250), db::Point (500, 300)));
EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)|(500,300;500,200)");
EXPECT_EQ (db::compare (r.space_check (120, db::RegionCheckOptions (false, db::Projection)), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300);(300,200;400,200)|(400,300;300,300)"), true);
EXPECT_EQ (db::compare (r.space_check (120, db::RegionCheckOptions (false, db::Projection)), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300);(300,200;400,200)|(400,300;300,300);(300,300;300,400)|(200,400;200,300);(300,400;300,500)|(200,500;200,400)"), true);
EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)|(400,300;300,300)");
EXPECT_EQ (db::compare (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300)"), true);
}

View File

@ -815,3 +815,136 @@ TEST(8)
}
// Edges, EdgePairs, Points
TEST(9)
{
db::Manager m (true);
db::Shapes s (&m, 0, db::default_editable_mode ());
s.insert (db::Point (100, 200));
s.insert (db::Edge (db::Point (100, 200), db::Point (200, 400)));
s.insert (db::EdgePair (db::Edge (db::Point (100, 200), db::Point (200, 400)), db::Edge (db::Point (0, 300), db::Point (100, 500))));
db::ShapeIterator si;
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), true);
EXPECT_EQ (si->is_edge_pair (), false);
EXPECT_EQ (si->is_point (), false);
EXPECT_EQ (si->to_string (), "edge (100,200;200,400)");
EXPECT_EQ (si->edge ().to_string (), "(100,200;200,400)");
++si;
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), false);
EXPECT_EQ (si->is_edge_pair (), true);
EXPECT_EQ (si->is_point (), false);
EXPECT_EQ (si->to_string (), "edge_pair (100,200;200,400)/(0,300;100,500)");
EXPECT_EQ (si->edge_pair ().to_string (), "(100,200;200,400)/(0,300;100,500)");
++si;
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), false);
EXPECT_EQ (si->is_edge_pair (), false);
EXPECT_EQ (si->is_point (), true);
EXPECT_EQ (si->to_string (), "point 100,200");
EXPECT_EQ (si->point ().to_string (), "100,200");
++si;
EXPECT_EQ (si.at_end (), true);
si = s.begin (db::ShapeIterator::Edges);
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), true);
EXPECT_EQ (si->is_edge_pair (), false);
EXPECT_EQ (si->is_point (), false);
EXPECT_EQ (si->to_string (), "edge (100,200;200,400)");
EXPECT_EQ (si->edge ().to_string (), "(100,200;200,400)");
++si;
EXPECT_EQ (si.at_end (), true);
si = s.begin (db::ShapeIterator::EdgePairs);
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), false);
EXPECT_EQ (si->is_edge_pair (), true);
EXPECT_EQ (si->is_point (), false);
EXPECT_EQ (si->to_string (), "edge_pair (100,200;200,400)/(0,300;100,500)");
EXPECT_EQ (si->edge_pair ().to_string (), "(100,200;200,400)/(0,300;100,500)");
++si;
EXPECT_EQ (si.at_end (), true);
si = s.begin (db::ShapeIterator::Points);
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), false);
EXPECT_EQ (si->is_edge_pair (), false);
EXPECT_EQ (si->is_point (), true);
EXPECT_EQ (si->to_string (), "point 100,200");
EXPECT_EQ (si->point ().to_string (), "100,200");
++si;
EXPECT_EQ (si.at_end (), true);
s.clear ();
s.insert (db::PointWithProperties (db::Point (100, 200), 1));
s.insert (db::EdgeWithProperties (db::Edge (db::Point (100, 200), db::Point (200, 400)), 2));
s.insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (db::Point (100, 200), db::Point (200, 400)), db::Edge (db::Point (0, 300), db::Point (100, 500))), 3));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), true);
EXPECT_EQ (si->prop_id (), db::properties_id_type (2));
EXPECT_EQ (si->is_edge_pair (), false);
EXPECT_EQ (si->is_point (), false);
EXPECT_EQ (si->to_string (), "edge (100,200;200,400) prop_id=2");
EXPECT_EQ (si->edge ().to_string (), "(100,200;200,400)");
++si;
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), false);
EXPECT_EQ (si->is_edge_pair (), true);
EXPECT_EQ (si->prop_id (), db::properties_id_type (3));
EXPECT_EQ (si->is_point (), false);
EXPECT_EQ (si->to_string (), "edge_pair (100,200;200,400)/(0,300;100,500) prop_id=3");
EXPECT_EQ (si->edge_pair ().to_string (), "(100,200;200,400)/(0,300;100,500)");
++si;
EXPECT_EQ (si.at_end (), false);
EXPECT_EQ (si->is_edge (), false);
EXPECT_EQ (si->is_edge_pair (), false);
EXPECT_EQ (si->is_point (), true);
EXPECT_EQ (si->prop_id (), db::properties_id_type (1));
EXPECT_EQ (si->to_string (), "point 100,200 prop_id=1");
EXPECT_EQ (si->point ().to_string (), "100,200");
++si;
EXPECT_EQ (si.at_end (), true);
}

View File

@ -3406,33 +3406,6 @@ TEST(24c)
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
}
// Bug #107
TEST(100)
{
db::Manager m (true);
db::Shapes shapes1 (&m, 0, true);
m.transaction ("y");
shapes1.insert (db::Box (200, -200, 100, -100));
m.commit ();
EXPECT_EQ (shapes_to_string_norm (_this, shapes1),
"box (100,-200;200,-100) #0\n"
);
m.undo ();
EXPECT_EQ (shapes_to_string_norm (_this, shapes1),
""
);
m.redo ();
EXPECT_EQ (shapes_to_string_norm (_this, shapes1),
"box (100,-200;200,-100) #0\n"
);
m.undo ();
EXPECT_EQ (shapes_to_string_norm (_this, shapes1),
""
);
}
// Shape insert and clear and undo/redo - different layouts
TEST(24d)
{
@ -3499,6 +3472,33 @@ TEST(24d)
EXPECT_EQ (shapes_to_string_norm (_this, s1), "");
}
// Bug #107
TEST(100)
{
db::Manager m (true);
db::Shapes shapes1 (&m, 0, true);
m.transaction ("y");
shapes1.insert (db::Box (200, -200, 100, -100));
m.commit ();
EXPECT_EQ (shapes_to_string_norm (_this, shapes1),
"box (100,-200;200,-100) #0\n"
);
m.undo ();
EXPECT_EQ (shapes_to_string_norm (_this, shapes1),
""
);
m.redo ();
EXPECT_EQ (shapes_to_string_norm (_this, shapes1),
"box (100,-200;200,-100) #0\n"
);
m.undo ();
EXPECT_EQ (shapes_to_string_norm (_this, shapes1),
""
);
}
// Bug #835
TEST(101)
{

View File

@ -1386,3 +1386,13 @@ TEST(58d_in_and_out)
{
run_test (_this, "58", true);
}
TEST(60_issue1216)
{
run_test (_this, "60", false);
}
TEST(60d_issue1216)
{
run_test (_this, "60", true);
}

View File

@ -45,6 +45,53 @@
namespace edt
{
// -------------------------------------------------------------------------
static std::string cell_name_from_sel (const edt::Service::obj_iterator &pos, edt::Service *service)
{
if (! pos->is_cell_inst ()) {
return std::string ();
}
const lay::CellView &cv = service->view ()->cellview (pos->cv_index ());
db::Layout *def_layout = &cv->layout ();
db::cell_index_type def_cell_index = pos->back ().inst_ptr.cell_index ();
std::pair<db::Library *, db::cell_index_type> dl = def_layout->defining_library (def_cell_index);
if (dl.first) {
def_layout = &dl.first->layout ();
def_cell_index = dl.second;
}
std::pair<bool, db::pcell_id_type> pci = def_layout->is_pcell_instance (def_cell_index);
if (pci.first && def_layout->pcell_declaration (pci.second)) {
return def_layout->pcell_header (pci.second)->get_name ();
} else {
return def_layout->cell_name (def_cell_index);
}
}
namespace {
struct SelectionPtrSort
{
SelectionPtrSort (edt::Service *service)
: mp_service (service)
{
// .. nothing yet ..
}
bool operator() (const edt::Service::obj_iterator &a, const edt::Service::obj_iterator &b)
{
return cell_name_from_sel (a, mp_service) < cell_name_from_sel (b, mp_service);
}
private:
edt::Service *mp_service;
};
}
// -------------------------------------------------------------------------
// InstPropertiesPage implementation
@ -61,6 +108,9 @@ InstPropertiesPage::InstPropertiesPage (edt::Service *service, db::Manager *mana
for (edt::Service::obj_iterator s = service->selection ().begin (); s != service->selection ().end (); ++s) {
m_selection_ptrs.push_back (s);
}
std::sort (m_selection_ptrs.begin (), m_selection_ptrs.end (), SelectionPtrSort (service));
m_prop_id = 0;
mp_service->clear_highlights ();
@ -249,9 +299,9 @@ InstPropertiesPage::select_entries (const std::vector<size_t> &entries)
std::string
InstPropertiesPage::description (size_t entry) const
{
std::string d;
edt::Service::obj_iterator pos = m_selection_ptrs [entry];
std::string d = cell_name_from_sel (pos, mp_service);
if (! pos->is_cell_inst ()) {
return d;
}
@ -259,21 +309,6 @@ InstPropertiesPage::description (size_t entry) const
const lay::CellView &cv = mp_service->view ()->cellview (pos->cv_index ());
double dbu = cv->layout ().dbu ();
db::Layout *def_layout = &cv->layout ();
db::cell_index_type def_cell_index = pos->back ().inst_ptr.cell_index ();
std::pair<db::Library *, db::cell_index_type> dl = def_layout->defining_library (def_cell_index);
if (dl.first) {
def_layout = &dl.first->layout ();
def_cell_index = dl.second;
}
std::pair<bool, db::pcell_id_type> pci = def_layout->is_pcell_instance (def_cell_index);
if (pci.first && def_layout->pcell_declaration (pci.second)) {
d += def_layout->pcell_header (pci.second)->get_name ();
} else {
d += def_layout->cell_name (def_cell_index);
}
db::ICplxTrans t (pos->back ().inst_ptr.complex_trans ());
db::DCplxTrans dt = db::CplxTrans (dbu) * t * db::CplxTrans (dbu).inverted ();

View File

@ -69,7 +69,7 @@ RecentConfigurationPage::init ()
}
mp_tree_widget->setHeaderLabels (column_labels);
update_list (get_stored_values ());
update_list ();
}
RecentConfigurationPage::~RecentConfigurationPage ()
@ -314,11 +314,17 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
void
RecentConfigurationPage::layers_changed (int)
{
update_list (get_stored_values ());
dm_update_list ();
}
void
RecentConfigurationPage::technology_changed (const std::string &)
{
dm_update_list ();
}
void
RecentConfigurationPage::update_list ()
{
update_list (get_stored_values ());
}

View File

@ -27,6 +27,7 @@
#include "layEditorOptionsPage.h"
#include "tlObject.h"
#include "tlDeferredExecution.h"
#include <list>
#include <QTreeWidget>
@ -79,7 +80,7 @@ public:
template <class Iter>
RecentConfigurationPage (lay::LayoutViewBase *view, lay::Dispatcher *dispatcher, const std::string &recent_cfg_name, Iter begin_cfg, Iter end_cfg)
: EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg)
: EditorOptionsPage (view, dispatcher), m_recent_cfg_name (recent_cfg_name), m_cfg (begin_cfg, end_cfg), dm_update_list (this, &RecentConfigurationPage::update_list)
{
init ();
}
@ -99,9 +100,11 @@ private:
std::string m_recent_cfg_name;
std::list<ConfigurationDescriptor> m_cfg;
QTreeWidget *mp_tree_widget;
tl::DeferredMethod<RecentConfigurationPage> dm_update_list;
void init ();
void update_list (const std::list<std::vector<std::string> > &stored_values);
void update_list ();
std::list<std::vector<std::string> > get_stored_values () const;
void set_stored_values (const std::list<std::vector<std::string> > &values) const;
void render_to (QTreeWidgetItem *item, int column, const std::vector<std::string> &values, RecentConfigurationPage::ConfigurationRendering rendering);

View File

@ -1443,7 +1443,8 @@ ApplicationBase::get_config_names () const
GuiApplication::GuiApplication (int &argc, char **argv)
: QApplication (argc, argv), ApplicationBase (false),
mp_mw (0),
mp_recorder (0)
mp_recorder (0),
m_in_notify (0)
{
// install a special style proxy to overcome the issue of black-on-black tree expanders
setStyle (new lay::BackgroundAwareTreeStyle (0));
@ -1479,14 +1480,28 @@ GuiApplication::initialize ()
bool
GuiApplication::notify (QObject *receiver, QEvent *e)
{
// Note: due to a bug in some Qt versions (i.e. 4.8.3) throwing exceptions across
// signals may not be safe. Hence the local BEGIN_PROTECTED .. END_PROTECTED approach
// is still preferred over the global solution through "notify"
bool in_notify = (m_in_notify > 0);
bool ret = true;
BEGIN_PROTECTED
ret = QApplication::notify (receiver, e);
END_PROTECTED
++m_in_notify;
// Note: due to a bug in some Qt versions (i.e. 4.8.3) throwing exceptions across
// signals may not be safe. Hence the local BEGIN_PROTECTED .. END_PROTECTED approach
// is still preferred over the global solution through "notify".
// Because END_PROTECTED may raise other events (message box) and this may cause other
// exceptions, we use silent mode inside notify to avoid recursion.
if (in_notify) {
BEGIN_PROTECTED_SILENT
ret = QApplication::notify (receiver, e);
END_PROTECTED_SILENT
} else {
BEGIN_PROTECTED
ret = QApplication::notify (receiver, e);
END_PROTECTED
}
--m_in_notify;
return ret;
}

View File

@ -479,6 +479,7 @@ protected:
private:
MainWindow *mp_mw;
gtf::Recorder *mp_recorder;
int m_in_notify;
};
/**

View File

@ -153,6 +153,11 @@ public:
}
}
void emit_data_changed ()
{
emit dataChanged (index (0, 0, QModelIndex ()), index (rowCount (QModelIndex ()) - 1, columnCount (QModelIndex ()) - 1, QModelIndex ()));
}
private:
PropertiesDialog *mp_dialog;
int m_icon_width, m_icon_height;
@ -566,6 +571,9 @@ BEGIN_PROTECTED
m_transaction_id = t.id ();
}
// updates cell names in instances for example
mp_tree_model->emit_data_changed ();
END_PROTECTED
}

View File

@ -545,19 +545,19 @@ via_size (double dbu, const Shape &shape)
void
LEFImporter::read_viadef_by_geometry (GeometryBasedLayoutGenerator *lg, ViaDesc &via_desc, const std::string &n, double dbu)
{
// ignore resistance spec
if (test ("RESISTANCE")) {
get_double ();
test (";");
}
std::string layer_name;
std::set<std::string> seen_layers;
std::vector<std::string> routing_layers;
while (true) {
if (test ("LAYER")) {
// ignore resistance spec
if (test ("RESISTANCE")) {
get_double ();
test (";");
} else if (test ("LAYER")) {
layer_name = get ();

View File

@ -942,3 +942,15 @@ TEST(204_concave_pins)
run_test (_this, "issue-1132", "read:test.lef", "au.oas.gz", lefdef_opt, false);
}
// issue 1214
TEST(205_lef_resistance)
{
db::LEFDEFReaderOptions lefdef_opt = default_options ();
lefdef_opt.set_lef_pins_datatype (12);
lefdef_opt.set_lef_pins_suffix (".LEFPIN");
lefdef_opt.set_lef_labels_datatype (11);
lefdef_opt.set_lef_labels_suffix (".LEFLABEL");
run_test (_this, "issue-1214", "read:merged.nom.lef", "au.oas.gz", lefdef_opt, false);
}

View File

@ -2964,7 +2964,7 @@ OASISWriter::write (const db::Path &path, db::properties_id_type prop_id, const
}
void
OASISWriter::write (const db::Edge &edge, db::properties_id_type prop_id, const db::Repetition & /*rep*/)
OASISWriter::write (const db::Edge &edge, db::properties_id_type prop_id, const db::Repetition &rep)
{
m_progress.set (mp_stream->pos ());
@ -2980,6 +2980,9 @@ OASISWriter::write (const db::Edge &edge, db::properties_id_type prop_id, const
if (mm_datatype != m_datatype) {
info |= 0x02;
}
if (! rep.is_singular ()) {
info |= 0x04;
}
if (mm_geometry_x != edge.p1 ().x ()) {
info |= 0x10;
}
@ -3030,6 +3033,9 @@ OASISWriter::write (const db::Edge &edge, db::properties_id_type prop_id, const
mm_geometry_y = edge.p1 ().y ();
write_coord (edge.p1 ().y ());
}
if (info & 0x04) {
write (rep);
}
if (prop_id != 0) {
write_props (prop_id);

View File

@ -51,6 +51,7 @@ SOURCES = \
tlLongInt.cc \
tlUniqueId.cc \
tlList.cc \
tlSList.cc \
tlEquivalenceClusters.cc \
tlUniqueName.cc \
tlRecipe.cc \
@ -115,6 +116,7 @@ HEADERS = \
tlLongInt.h \
tlUniqueId.h \
tlList.h \
tlSList.h \
tlEquivalenceClusters.h \
tlUniqueName.h \
tlRecipe.h \

View File

@ -263,7 +263,9 @@ InputHttpStreamPrivateData::InputHttpStreamPrivateData (InputHttpStream *stream,
s_auth_handler = new AuthenticationHandler ();
connect (s_network_manager, SIGNAL (authenticationRequired (QNetworkReply *, QAuthenticator *)), s_auth_handler, SLOT (authenticationRequired (QNetworkReply *, QAuthenticator *)));
connect (s_network_manager, SIGNAL (proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *)), s_auth_handler, SLOT (proxyAuthenticationRequired (const QNetworkProxy &, QAuthenticator *)));
#if !defined(QT_NO_SSL)
connect (s_network_manager, SIGNAL (sslErrors (QNetworkReply *, const QList<QSslError> &)), this, SLOT (sslErrors (QNetworkReply *, const QList<QSslError> &)));
#endif
tl::StaticObjects::reg (&s_network_manager);
tl::StaticObjects::reg (&s_auth_handler);
@ -515,6 +517,7 @@ InputHttpStreamPrivateData::read (char *b, size_t n)
return data.size ();
}
#if !defined(QT_NO_SSL)
void
InputHttpStreamPrivateData::sslErrors (QNetworkReply *, const QList<QSslError> &errors)
{
@ -528,6 +531,7 @@ InputHttpStreamPrivateData::sslErrors (QNetworkReply *, const QList<QSslError> &
m_ssl_errors += "\"";
}
}
#endif
void
InputHttpStreamPrivateData::reset ()

View File

@ -108,7 +108,9 @@ public:
private slots:
void finished (QNetworkReply *);
void resend ();
#if !defined(QT_NO_SSL)
void sslErrors (QNetworkReply *reply, const QList<QSslError> &errors);
#endif
private:
std::string m_url;

31
src/tl/tl/tlSList.cc Normal file
View File

@ -0,0 +1,31 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlSList.h"
namespace tl
{
// .. nothing yet ..
}

324
src/tl/tl/tlSList.h Normal file
View File

@ -0,0 +1,324 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_tlSList
#define HDR_tlSList
#include "tlCommon.h"
#include <algorithm>
#include <iterator>
namespace tl
{
/**
* @brief A simple single-linked list implementation
*
* This implementation supports:
* - fast size
* - push_back, push_front
* - forward iterator, const_iterator
* - splice
* - pop_front
* - clear
* - empty
*/
template <class T>
class slist
{
private:
struct node_type
{
node_type (const T &_t) : next (0), t (_t) { }
node_type (T &&_t) : next (0), t (_t) { }
node_type *next;
T t;
};
public:
class const_iterator;
class iterator
{
public:
typedef std::forward_iterator_tag category;
typedef T value_type;
typedef T &reference;
typedef T *pointer;
iterator (node_type *p = 0) : mp_p (p) { }
iterator operator++ () { mp_p = mp_p->next; return *this; }
T *operator-> () const
{
return &mp_p->t;
}
T &operator* () const
{
return mp_p->t;
}
bool operator== (iterator other) const { return mp_p == other.mp_p; }
bool operator!= (iterator other) const { return mp_p != other.mp_p; }
private:
friend class slist<T>::const_iterator;
node_type *mp_p;
};
class const_iterator
{
public:
typedef std::forward_iterator_tag category;
typedef const T value_type;
typedef const T &reference;
typedef const T *pointer;
const_iterator (iterator i) : mp_p (i.mp_p) { }
const_iterator (const node_type *p = 0) : mp_p (p) { }
const_iterator operator++ () { mp_p = mp_p->next; return *this; }
const T *operator-> () const
{
return &mp_p->t;
}
const T &operator* () const
{
return mp_p->t;
}
bool operator== (const_iterator other) const { return mp_p == other.mp_p; }
bool operator!= (const_iterator other) const { return mp_p != other.mp_p; }
private:
const node_type *mp_p;
};
slist ()
: mp_first (0), mp_last (0), m_size (0)
{
// .. nothing yet ..
}
template <class Iter>
slist (Iter from, Iter to)
: mp_first (0), mp_last (0), m_size (0)
{
for (Iter i = from; i != to; ++i) {
push_back (*i);
}
}
slist (const slist<T> &other)
: mp_first (0), mp_last (0), m_size (0)
{
for (auto i = other.begin (); i != other.end (); ++i) {
push_back (*i);
}
}
slist (slist<T> &&other)
: mp_first (0), mp_last (0), m_size (0)
{
std::swap (mp_first, other.mp_first);
std::swap (mp_last, other.mp_last);
std::swap (m_size, other.m_size);
}
slist<T> &operator= (const slist<T> &other)
{
if (this != &other) {
clear ();
for (const_iterator i = other.begin (); i != other.end (); ++i) {
push_back (*i);
}
}
return *this;
}
slist<T> &operator= (slist<T> &&other)
{
clear ();
std::swap (mp_first, other.mp_first);
std::swap (mp_last, other.mp_last);
std::swap (m_size, other.m_size);
return *this;
}
~slist ()
{
clear ();
}
iterator begin ()
{
return iterator (mp_first);
}
iterator end ()
{
return iterator (0);
}
const_iterator begin () const
{
return const_iterator (mp_first);
}
const_iterator end () const
{
return const_iterator (0);
}
size_t size () const
{
return m_size;
}
bool empty () const
{
return mp_first == 0;
}
void clear ()
{
while (! empty ()) {
pop_front ();
}
}
void swap (slist<T> &other)
{
std::swap (mp_first, other.mp_first);
std::swap (mp_last, other.mp_last);
std::swap (m_size, other.m_size);
}
void pop_front ()
{
if (mp_first) {
node_type *n = mp_first;
if (n == mp_last) {
mp_first = mp_last = 0;
} else {
mp_first = mp_first->next;
}
delete n;
--m_size;
}
}
T &front ()
{
return mp_first->t;
}
const T &front () const
{
return mp_first->t;
}
T &back ()
{
return mp_last->t;
}
const T &back () const
{
return mp_last->t;
}
void push_front (const T &t)
{
push_front_impl (new node_type (t));
}
void push_front (T &&t)
{
push_front_impl (new node_type (t));
}
void push_back (const T &t)
{
push_back_impl (new node_type (t));
}
void push_back (T &&t)
{
push_back_impl (new node_type (t));
}
void splice (slist<T> &other)
{
if (! other.mp_first) {
return;
}
if (! mp_first) {
mp_first = other.mp_first;
} else {
mp_last->next = other.mp_first;
}
mp_last = other.mp_last;
m_size += other.m_size;
other.mp_first = other.mp_last = 0;
other.m_size = 0;
}
private:
node_type *mp_first, *mp_last;
size_t m_size;
void push_front_impl (node_type *n)
{
if (mp_first) {
n->next = mp_first;
mp_first = n;
} else {
mp_first = mp_last = n;
}
++m_size;
}
void push_back_impl (node_type *n)
{
if (mp_last) {
mp_last->next = n;
mp_last = n;
} else {
mp_first = mp_last = n;
}
++m_size;
}
};
}
#endif

View File

@ -0,0 +1,192 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2022 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "tlSList.h"
#include "tlUnitTest.h"
#include "tlString.h"
namespace
{
static size_t obj_count = 0;
struct MyClass1
{
MyClass1 (int _n) : n (_n) { ++obj_count; }
MyClass1 (const MyClass1 &other) : n (other.n) { ++obj_count; }
MyClass1 &operator= (const MyClass1 &other) { n = other.n; return *this; }
~MyClass1 () { --obj_count; }
int n;
bool operator== (const MyClass1 &other) const { return n == other.n; }
bool operator< (const MyClass1 &other) const { return n < other.n; }
};
}
template <class C>
static std::string l2s (const tl::slist<C> &l)
{
std::string x;
for (typename tl::slist<C>::const_iterator i = l.begin (); i != l.end (); ++i) {
if (!x.empty ()) {
x += ",";
}
x += tl::to_string (i->n);
}
return x;
}
template <class C>
static std::string l2s_nc (tl::slist<C> &l)
{
std::string x;
for (typename tl::slist<C>::iterator i = l.begin (); i != l.end (); ++i) {
if (!x.empty ()) {
x += ",";
}
x += tl::to_string (i->n);
}
return x;
}
TEST(1_Basic)
{
obj_count = 0;
{
MyClass1 c1 (-1);
tl::slist<MyClass1> l1, l2;
EXPECT_EQ (l1.empty (), true);
EXPECT_EQ (l1.size (), size_t (0));
EXPECT_EQ (l2s (l1), "");
l1.push_back (MyClass1 (17));
EXPECT_EQ (l1.empty (), false);
EXPECT_EQ (l1.size (), size_t (1));
EXPECT_EQ (l2s (l1), "17");
l1.push_back (MyClass1 (42));
l2 = l1;
tl::slist<MyClass1> l3 (l2);
EXPECT_EQ (l1.empty (), false);
EXPECT_EQ (l1.size (), size_t (2));
EXPECT_EQ (l2s (l1), "17,42");
l1.pop_front ();
EXPECT_EQ (l1.empty (), false);
EXPECT_EQ (l1.size (), size_t (1));
EXPECT_EQ (l2s (l1), "42");
l1.clear ();
EXPECT_EQ (l1.empty (), true);
EXPECT_EQ (l1.size (), size_t (0));
EXPECT_EQ (l2s (l1), "");
EXPECT_EQ (l2s (l2), "17,42");
l2.pop_front ();
EXPECT_EQ (l2s (l2), "42");
l3.push_back (MyClass1 (2));
l3.push_front (MyClass1 (1));
EXPECT_EQ (l2s (l3), "1,17,42,2");
EXPECT_EQ (l2s_nc (l3), "1,17,42,2");
EXPECT_EQ (l3.size (), size_t (4));
l3.pop_front ();
EXPECT_EQ (l2s (l3), "17,42,2");
EXPECT_EQ (l3.size (), size_t (3));
c1 = l3.front ();
EXPECT_EQ (c1.n, 17);
c1 = l3.back ();
EXPECT_EQ (c1.n, 2);
l3.pop_front ();
EXPECT_EQ (l2s (l3), "42,2");
EXPECT_EQ (l3.size (), size_t (2));
l3.push_back (MyClass1 (1));
EXPECT_EQ (l2s (l3), "42,2,1");
EXPECT_EQ (l3.size (), size_t (3));
l3.swap (l2);
EXPECT_EQ (l2s (l2), "42,2,1");
EXPECT_EQ (l2s (l3), "42");
l1.clear ();
l2.swap (l1);
EXPECT_EQ (l2s (l1), "42,2,1");
EXPECT_EQ (l2s (l2), "");
l1.clear ();
l3.clear ();
l2.swap (l1);
EXPECT_EQ (l2s (l1), "");
EXPECT_EQ (l2s (l2), "");
}
EXPECT_EQ (obj_count, size_t (0));
}
TEST(2_SpliceAndMove)
{
obj_count = 0;
{
tl::slist<MyClass1> l1, l2;
l1.splice (l2);
EXPECT_EQ (l2s (l1), "");
l1.push_back (MyClass1 (17));
l1.push_back (MyClass1 (42));
l1.splice (l2);
EXPECT_EQ (l2s (l1), "17,42");
EXPECT_EQ (l2s (l2), "");
l2.splice (l1);
EXPECT_EQ (l2s (l2), "17,42");
EXPECT_EQ (l2s (l1), "");
l1.swap (l2);
l2.push_back (MyClass1 (2));
l2.push_back (MyClass1 (1));
l1.splice (l2);
EXPECT_EQ (l2s (l1), "17,42,2,1");
EXPECT_EQ (l2s (l2), "");
l2 = std::move (l1);
EXPECT_EQ (l2s (l2), "17,42,2,1");
EXPECT_EQ (l2s (l1), "");
l1 = tl::slist<MyClass1> (std::move (l2));
EXPECT_EQ (l2s (l1), "17,42,2,1");
EXPECT_EQ (l2s (l2), "");
}
EXPECT_EQ (obj_count, size_t (0));
}

View File

@ -39,6 +39,7 @@ SOURCES = \
tlThreadsTests.cc \
tlUniqueIdTests.cc \
tlListTests.cc \
tlSListTests.cc \
tlEquivalenceClustersTests.cc \
tlUniqueNameTests.cc \
tlGlobPatternTests.cc \

30
testdata/drc/drcSimpleTests_60.drc vendored Normal file
View File

@ -0,0 +1,30 @@
# Moved implementation
source($drc_test_source)
target($drc_test_target)
if $drc_test_deep
deep
end
l8 = input(8, 0)
l9 = input(9, 0)
l8.output(8, 0)
l9.output(9, 0)
# NOTE: "sized" tests issue #1216
l8.sized(0.1, 0).moved(-0.1, 0).sized(0, 0.1).moved(0, -0.1).output(108, 0)
l9.sized(0.1, 0).moved(-0.1, 0).sized(0, 0.1).moved(0, -0.1).output(109, 0)
l8.edges.moved(-0.1, -0.1).extended_out(0.05).output(118, 0)
l9.edges.moved(-0.1, -0.1).extended_out(0.05).output(119, 0)
# NOTE: "sized" tests issue #1216
l8.rotated(90.0).sized(0, 0.1).output(208, 0)
l9.rotated(90.0).sized(0, 0.1).output(209, 0)
l8.edges.rotated(90.0).extended_out(0.05).output(218, 0)
l9.edges.rotated(90.0).extended_out(0.05).output(219, 0)

BIN
testdata/drc/drcSimpleTests_60.gds vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au60.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au60d.gds vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
testdata/lefdef/issue-1214/au.oas.gz vendored Normal file

Binary file not shown.

27023
testdata/lefdef/issue-1214/merged.nom.lef vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,8 @@ class DBEdgePair_TestClass < TestBase
ep = RBA::EdgePair::new
assert_equal(ep.to_s, "(0,0;0,0)/(0,0;0,0)")
assert_equal(ep.to_s, "(0,0;0,0)/(0,0;0,0)")
ep.first = RBA::Edge::new(0, 0, 10, 20)
assert_equal(ep.to_s, "(0,0;10,20)/(0,0;0,0)")
@ -57,6 +59,18 @@ class DBEdgePair_TestClass < TestBase
assert_equal(ep.simple_polygon(0).to_s, "(-10,0;-10,30;0,0;10,20)")
assert_equal(ep.simple_polygon(0).class.to_s, "RBA::SimplePolygon")
ep = RBA::EdgePair::new(RBA::Edge::new(0, 0, 10, 0), RBA::Edge::new(0, 20, 0, 0))
assert_equal(ep.perimeter, 30)
assert_equal(ep.area, 100)
assert_equal(ep.simple_polygon(0).area, 100)
ep = RBA::EdgePair::new(RBA::Edge::new(0, 0, 10, 0), RBA::Edge::new(0, 0, 0, 20))
assert_equal(ep.perimeter, 30)
assert_equal(ep.area, 0)
assert_equal(ep.simple_polygon(0).area, 0)
end
# Basics
@ -92,6 +106,18 @@ class DBEdgePair_TestClass < TestBase
assert_equal(ep.simple_polygon(0).to_s, "(-10,0;-10,30;0,0;10,20)")
assert_equal(ep.simple_polygon(0).class.to_s, "RBA::DSimplePolygon")
ep = RBA::DEdgePair::new(RBA::DEdge::new(0, 0, 10, 0), RBA::DEdge::new(0, 20, 0, 0))
assert_equal(ep.perimeter, 30)
assert_equal(ep.area, 100)
assert_equal(ep.simple_polygon(0).area, 100)
ep = RBA::DEdgePair::new(RBA::DEdge::new(0, 0, 10, 0), RBA::DEdge::new(0, 0, 0, 20))
assert_equal(ep.perimeter, 30)
assert_equal(ep.area, 0)
assert_equal(ep.simple_polygon(0).area, 0)
end
# Fuzzy compare

View File

@ -158,6 +158,9 @@ class DBShapes_TestClass < TestBase
shapes.each( RBA::Shapes::SEdges ) { |s| arr.push( s ) }
assert_equal( arr.size, 0 )
arr = []
shapes.each( RBA::Shapes::SPoints ) { |s| arr.push( s ) }
assert_equal( arr.size, 0 )
arr = []
shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].prop_id, 0 )
@ -166,6 +169,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].type, RBA::Shape::t_box )
assert_equal( arr[0].polygon.to_s, "(10,-10;10,40;50,40;50,-10)" )
assert_equal( arr[0].simple_polygon.to_s, "(10,-10;10,40;50,40;50,-10)" )
assert_equal( arr[0].point.inspect, "nil" )
assert_equal( arr[0].edge.inspect, "nil" )
assert_equal( arr[0].edge_pair.inspect, "nil" )
assert_equal( arr[0].box.to_s, "(10,-10;50,40)" )
@ -190,6 +194,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].is_edge?, true )
assert_equal( arr[0].polygon.inspect, "nil" )
assert_equal( arr[0].simple_polygon.inspect, "nil" )
assert_equal( arr[0].point.inspect, "nil" )
assert_equal( arr[0].edge.to_s, "(-1,2;5,2)" )
assert_equal( arr[0].edge_pair.inspect, "nil" )
assert_equal( arr[0].box.inspect, "nil" )
@ -217,6 +222,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].polygon.inspect, "nil" )
assert_equal( arr[0].simple_polygon.inspect, "nil" )
assert_equal( arr[0].edge_pair.to_s, "(-1,2;5,2)/(-1,5;5,5)" )
assert_equal( arr[0].point.inspect, "nil" )
assert_equal( arr[0].edge.inspect, "nil" )
assert_equal( arr[0].box.inspect, "nil" )
assert_equal( arr[0].path.inspect, "nil" )
@ -228,6 +234,33 @@ class DBShapes_TestClass < TestBase
assert_equal( arr.size, 1 )
assert_equal( arr[0].is_box?, true )
# points
a = RBA::Point::new( -1, 2 )
c1.shapes( lindex ).insert( a )
arr = []
shapes.each( RBA::Shapes::SPoints ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].prop_id, 0 )
assert_equal( arr[0].has_prop_id?, false )
assert_equal( arr[0].is_null?, false )
assert_equal( arr[0].type, RBA::Shape::t_point )
assert_equal( arr[0].is_point?, true )
assert_equal( arr[0].polygon.inspect, "nil" )
assert_equal( arr[0].simple_polygon.inspect, "nil" )
assert_equal( arr[0].point.to_s, "-1,2" )
assert_equal( arr[0].edge.inspect, "nil" )
assert_equal( arr[0].edge_pair.inspect, "nil" )
assert_equal( arr[0].box.inspect, "nil" )
assert_equal( arr[0].path.inspect, "nil" )
assert_equal( arr[0].text.inspect, "nil" )
assert_equal( arr[0].point == a, true )
assert_equal( arr[0].bbox == RBA::Box::new(a, a), true )
arr = []
shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].is_box?, true )
# paths
a = RBA::Path::new( [ RBA::Point::new( 0, 10 ), RBA::Point::new( 10, 50 ) ], 25 )
@ -486,6 +519,9 @@ class DBShapes_TestClass < TestBase
shapes.each( RBA::Shapes::SEdges ) { |s| arr.push( s ) }
assert_equal( arr.size, 0 )
arr = []
shapes.each( RBA::Shapes::SPoints ) { |s| arr.push( s ) }
assert_equal( arr.size, 0 )
arr = []
shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].prop_id, 0 )
@ -543,6 +579,7 @@ class DBShapes_TestClass < TestBase
assert_equal( arr[0].is_edge_pair?, true )
assert_equal( arr[0].dpolygon.inspect, "nil" )
assert_equal( arr[0].dsimple_polygon.inspect, "nil" )
assert_equal( arr[0].dpoint.inspect, "nil" )
assert_equal( arr[0].dedge_pair.to_s, "(-0.001,0.002;0.005,0.002)/(-0.001,0.005;0.005,0.005)" )
assert_equal( arr[0].dedge.inspect, "nil" )
assert_equal( arr[0].dbox.inspect, "nil" )
@ -554,6 +591,32 @@ class DBShapes_TestClass < TestBase
assert_equal( arr.size, 1 )
assert_equal( arr[0].is_box?, true )
# points
a = RBA::DPoint::new( -1, 2 )
c1.shapes( lindex ).insert( a )
arr = []
shapes.each( RBA::Shapes::SPoints ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].prop_id, 0 )
assert_equal( arr[0].has_prop_id?, false )
assert_equal( arr[0].is_null?, false )
assert_equal( arr[0].type, RBA::Shape::t_point )
assert_equal( arr[0].is_point?, true )
assert_equal( arr[0].dpolygon.inspect, "nil" )
assert_equal( arr[0].dsimple_polygon.inspect, "nil" )
assert_equal( arr[0].dpoint.to_s, "-1,2" )
assert_equal( arr[0].dedge.inspect, "nil" )
assert_equal( arr[0].dedge_pair.inspect, "nil" )
assert_equal( arr[0].dbox.inspect, "nil" )
assert_equal( arr[0].dpath.inspect, "nil" )
assert_equal( arr[0].dtext.inspect, "nil" )
assert_equal( arr[0].dbbox.to_s, "(-1,2;-1,2)" )
arr = []
shapes.each( RBA::Shapes::SBoxes ) { |s| arr.push( s ) }
assert_equal( arr.size, 1 )
assert_equal( arr[0].is_box?, true )
# paths
a = RBA::DPath::new( [ RBA::DPoint::new( 0, 0.010 ), RBA::DPoint::new( 0.010, 0.050 ) ], 0.025 )