diff --git a/scripts/deploy-win-mingw.sh b/scripts/deploy-win-mingw.sh
index 746815a56..94a73fb1f 100644
--- a/scripts/deploy-win-mingw.sh
+++ b/scripts/deploy-win-mingw.sh
@@ -134,6 +134,13 @@ if ! [ -e $target/klayout.exe ]; then
exit 1
fi
+# ----------------------------------------------------------
+# cert.pem
+
+echo "Installing cert.pem .."
+
+cp $mingw_inst/etc/ssl/cert.pem $target
+
# ----------------------------------------------------------
# Plugins
diff --git a/scripts/klayout-inst.nsis b/scripts/klayout-inst.nsis
index a4d4a655e..cbf3cefd7 100644
--- a/scripts/klayout-inst.nsis
+++ b/scripts/klayout-inst.nsis
@@ -40,7 +40,7 @@ InstallDirRegKey HKLM \
"UninstallString"
# The text to prompt the user to enter a directory
-DirText "Please select your ${NAME} installation path below:"
+DirText "Please select your ${NAME} installation path below (CAUTION: THE GIVEN FOLDER WILL BE DELETED ENTIRELY ON UNINSTALLATION - DO NOT USE A GENERAL PURPOSE FOLDER OR A DRIVE ONLY):"
# automatically close the installer when done.
AutoCloseWindow true
@@ -68,6 +68,7 @@ section
file *.dll
file strm*.exe
file .*-paths.txt
+ file cert.pem
file /r db_plugins
file /r lay_plugins
file /r audio
@@ -154,7 +155,7 @@ section "Uninstall"
# now delete installed files
rmDir /r "$INSTDIR"
- # create a shortcut
+ # remove shortcut
rmDir /r "$SMPROGRAMS\${NAME}"
DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}"
diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc
index 12b9a1774..d81032b0b 100644
--- a/src/db/db/dbDeepEdges.cc
+++ b/src/db/db/dbDeepEdges.cc
@@ -176,6 +176,7 @@ DeepEdges::~DeepEdges ()
DeepEdges::DeepEdges (const DeepEdges &other)
: MutableEdges (other), DeepShapeCollectionDelegateBase (other),
m_merged_edges_valid (other.m_merged_edges_valid),
+ m_merged_edges_boc_hash (other.m_merged_edges_boc_hash),
m_is_merged (other.m_is_merged)
{
if (m_merged_edges_valid) {
@@ -192,6 +193,7 @@ DeepEdges::operator= (const DeepEdges &other)
DeepShapeCollectionDelegateBase::operator= (other);
m_merged_edges_valid = other.m_merged_edges_valid;
+ m_merged_edges_boc_hash = other.m_merged_edges_boc_hash;
m_is_merged = other.m_is_merged;
if (m_merged_edges_valid) {
m_merged_edges = other.m_merged_edges.copy ();
@@ -205,6 +207,7 @@ DeepEdges::operator= (const DeepEdges &other)
void DeepEdges::init ()
{
m_merged_edges_valid = false;
+ m_merged_edges_boc_hash = 0;
m_merged_edges = db::DeepLayer ();
m_is_merged = false;
}
@@ -458,6 +461,7 @@ void DeepEdges::apply_property_translator (const db::PropertiesTranslator &pt)
DeepShapeCollectionDelegateBase::apply_property_translator (pt);
m_merged_edges_valid = false;
+ m_merged_edges_boc_hash = 0;
m_merged_edges = db::DeepLayer ();
}
@@ -637,10 +641,16 @@ DeepEdges::merged_deep_layer () const
}
}
+bool
+DeepEdges::merged_edges_available () const
+{
+ return m_is_merged || (m_merged_edges_valid && m_merged_edges_boc_hash == deep_layer ().breakout_cells_hash ());
+}
+
void
DeepEdges::ensure_merged_edges_valid () const
{
- if (! m_merged_edges_valid) {
+ if (! m_merged_edges_valid || (! m_is_merged && m_merged_edges_boc_hash != deep_layer ().breakout_cells_hash ())) {
if (m_is_merged) {
@@ -659,7 +669,7 @@ DeepEdges::ensure_merged_edges_valid () const
db::Connectivity conn;
conn.connect (deep_layer ());
hc.set_base_verbosity (base_verbosity() + 10);
- hc.build (layout, deep_layer ().initial_cell (), conn);
+ hc.build (layout, deep_layer ().initial_cell (), conn, 0, deep_layer ().breakout_cells ());
// collect the clusters and merge them into larger edges
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
@@ -683,6 +693,7 @@ DeepEdges::ensure_merged_edges_valid () const
}
m_merged_edges_valid = true;
+ m_merged_edges_boc_hash = deep_layer ().breakout_cells_hash ();
}
}
@@ -692,6 +703,7 @@ DeepEdges::set_is_merged (bool f)
{
m_is_merged = f;
m_merged_edges_valid = false;
+ m_merged_edges_boc_hash = 0;
m_merged_edges = db::DeepLayer ();
}
@@ -909,7 +921,7 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
db::EdgeBoolAndOrNotLocalOperation local_op (op);
- db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
+ db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
@@ -936,7 +948,7 @@ DeepEdges::edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t mode,
db::EdgeToPolygonLocalOperation op (mode, include_borders);
- db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
+ db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (deep_layer ().store ()->threads ());
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
@@ -1253,7 +1265,6 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t
std::unique_ptr res (new db::DeepRegion (edges.derived ()));
db::Layout &layout = const_cast (edges.layout ());
- db::Cell &top_cell = const_cast (edges.initial_cell ());
// TODO: there is a special case when we'd need a MagnificationAndOrientationReducer:
// dots formally don't have an orientation, hence the interpretation is x and y.
@@ -1271,7 +1282,7 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t
db::Connectivity conn (db::Connectivity::EdgesConnectByPoints);
conn.connect (edges);
hc.set_base_verbosity (base_verbosity () + 10);
- hc.build (layout, edges.initial_cell (), conn);
+ hc.build (layout, edges.initial_cell (), conn, 0, edges.breakout_cells ());
// TODO: iterate only over the called cells?
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
@@ -1714,7 +1725,7 @@ DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMod
db::Edge2PolygonInteractingLocalOperation op (mode, inverse ? db::Edge2PolygonInteractingLocalOperation::Inverse : db::Edge2PolygonInteractingLocalOperation::Normal);
- db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
@@ -1746,7 +1757,7 @@ DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteracti
db::Edge2PolygonInteractingLocalOperation op (mode, db::Edge2PolygonInteractingLocalOperation::Both);
- db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
@@ -1772,7 +1783,7 @@ DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal);
- db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
@@ -1804,7 +1815,7 @@ DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractio
db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both);
- db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
@@ -1830,7 +1841,7 @@ RegionDelegate *DeepEdges::pull_generic (const Region &other) const
db::Edge2PolygonPullLocalOperation op;
- db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell ());
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), edges.breakout_cells (), other_polygons.breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
@@ -1856,7 +1867,7 @@ EdgesDelegate *DeepEdges::pull_generic (const Edges &other) const
db::Edge2EdgePullLocalOperation op;
- db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_edges.layout (), &other_edges.initial_cell ());
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_edges.layout (), &other_edges.initial_cell (), edges.breakout_cells (), other_edges.breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
@@ -1885,7 +1896,7 @@ EdgesDelegate *DeepEdges::in (const Edges &other, bool invert) const
db::ContainedEdgesLocalOperation op (invert ? Negative : Positive);
- db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
@@ -1916,7 +1927,7 @@ std::pair DeepEdges::in_and_out (const Edges &
db::ContainedEdgesLocalOperation op (PositiveAndNegative);
- db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
+ db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
@@ -2049,7 +2060,9 @@ DeepEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Coord
db::local_processor proc (const_cast (&edges.layout ()),
const_cast (&edges.initial_cell ()),
other_deep ? &other_deep->deep_layer ().layout () : const_cast (&edges.layout ()),
- other_deep ? &other_deep->deep_layer ().initial_cell () : const_cast (&edges.initial_cell ()));
+ other_deep ? &other_deep->deep_layer ().initial_cell () : const_cast (&edges.initial_cell ()),
+ edges.breakout_cells (),
+ other_deep ? other_deep->deep_layer ().breakout_cells () : 0);
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h
index 78fb04935..bdd7ea947 100644
--- a/src/db/db/dbDeepEdges.h
+++ b/src/db/db/dbDeepEdges.h
@@ -170,6 +170,9 @@ public:
void set_is_merged (bool f);
+ bool merged_edges_available () const;
+ const DeepLayer &merged_deep_layer () const;
+
protected:
virtual void merged_semantics_changed ();
@@ -180,11 +183,11 @@ private:
mutable DeepLayer m_merged_edges;
mutable bool m_merged_edges_valid;
+ mutable size_t m_merged_edges_boc_hash;
bool m_is_merged;
void init ();
void ensure_merged_edges_valid () const;
- const DeepLayer &merged_deep_layer () const;
DeepLayer and_or_not_with(const DeepEdges *other, EdgeBoolOp op) const;
std::pair edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t op, bool include_borders) const;
EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const db::EdgesCheckOptions &options) const;
diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc
index b6e04023a..11780bfd6 100644
--- a/src/db/db/dbDeepRegion.cc
+++ b/src/db/db/dbDeepRegion.cc
@@ -179,6 +179,7 @@ DeepRegion::~DeepRegion ()
DeepRegion::DeepRegion (const DeepRegion &other)
: MutableRegion (other), DeepShapeCollectionDelegateBase (other),
m_merged_polygons_valid (other.m_merged_polygons_valid),
+ m_merged_polygons_boc_hash (other.m_merged_polygons_boc_hash),
m_is_merged (other.m_is_merged)
{
if (m_merged_polygons_valid) {
@@ -195,6 +196,7 @@ DeepRegion::operator= (const DeepRegion &other)
DeepShapeCollectionDelegateBase::operator= (other);
m_merged_polygons_valid = other.m_merged_polygons_valid;
+ m_merged_polygons_boc_hash = other.m_merged_polygons_boc_hash;
m_is_merged = other.m_is_merged;
if (m_merged_polygons_valid) {
m_merged_polygons = other.m_merged_polygons.copy ();
@@ -208,6 +210,7 @@ DeepRegion::operator= (const DeepRegion &other)
void DeepRegion::init ()
{
m_merged_polygons_valid = false;
+ m_merged_polygons_boc_hash = 0;
m_merged_polygons = db::DeepLayer ();
m_is_merged = false;
}
@@ -484,6 +487,7 @@ void DeepRegion::apply_property_translator (const db::PropertiesTranslator &pt)
DeepShapeCollectionDelegateBase::apply_property_translator (pt);
m_merged_polygons_valid = false;
+ m_merged_polygons_boc_hash = 0;
m_merged_polygons = db::DeepLayer ();
}
@@ -683,13 +687,13 @@ DeepRegion::merged_deep_layer () const
bool
DeepRegion::merged_polygons_available () const
{
- return m_is_merged || m_merged_polygons_valid;
+ return m_is_merged || (m_merged_polygons_valid && m_merged_polygons_boc_hash == deep_layer ().breakout_cells_hash ());
}
void
DeepRegion::ensure_merged_polygons_valid () const
{
- if (! m_merged_polygons_valid) {
+ if (! m_merged_polygons_valid || (! m_is_merged && m_merged_polygons_boc_hash != deep_layer ().breakout_cells_hash ())) {
if (m_is_merged) {
@@ -708,7 +712,7 @@ DeepRegion::ensure_merged_polygons_valid () const
db::Connectivity conn;
conn.connect (deep_layer ());
hc.set_base_verbosity (base_verbosity () + 10);
- hc.build (layout, deep_layer ().initial_cell (), conn, 0, 0, true /*separate_attributes*/);
+ hc.build (layout, deep_layer ().initial_cell (), conn, 0, deep_layer ().breakout_cells (), true /*separate_attributes*/);
// collect the clusters and merge them into big polygons
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
@@ -732,6 +736,7 @@ DeepRegion::ensure_merged_polygons_valid () const
}
m_merged_polygons_valid = true;
+ m_merged_polygons_boc_hash = deep_layer ().breakout_cells_hash ();
}
}
@@ -741,6 +746,7 @@ DeepRegion::set_is_merged (bool f)
{
m_is_merged = f;
m_merged_polygons_valid = false;
+ m_merged_polygons_boc_hash = 0;
m_merged_polygons = db::DeepLayer ();
}
diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h
index df40fec49..cc05259b7 100644
--- a/src/db/db/dbDeepRegion.h
+++ b/src/db/db/dbDeepRegion.h
@@ -173,6 +173,7 @@ private:
mutable DeepLayer m_merged_polygons;
mutable bool m_merged_polygons_valid;
+ mutable size_t m_merged_polygons_boc_hash;
bool m_is_merged;
void init ();
diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc
index 81ff9c327..70005e136 100644
--- a/src/db/db/dbDeepShapeStore.cc
+++ b/src/db/db/dbDeepShapeStore.cc
@@ -184,6 +184,12 @@ DeepLayer::breakout_cells () const
return store ()->breakout_cells (layout_index ());
}
+size_t
+DeepLayer::breakout_cells_hash () const
+{
+ return store ()->breakout_cells_hash (layout_index ());
+}
+
void
DeepLayer::insert_into (db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer) const
{
@@ -409,36 +415,51 @@ DeepShapeStoreState::text_property_name () const
const std::set *
DeepShapeStoreState::breakout_cells (unsigned int layout_index) const
{
- const std::set &boc = (const_cast (this))->ensure_breakout_cells (layout_index);
- if (boc.empty ()) {
+ const std::pair, size_t> &boc = (const_cast (this))->ensure_breakout_cells (layout_index);
+ if (boc.first.empty ()) {
return 0;
} else {
- return &boc;
+ return &boc.first;
}
}
+size_t
+DeepShapeStoreState::breakout_cells_hash (unsigned int layout_index) const
+{
+ const std::pair, size_t> &boc = (const_cast (this))->ensure_breakout_cells (layout_index);
+ return boc.second;
+}
+
void
DeepShapeStoreState::clear_breakout_cells (unsigned int layout_index)
{
- ensure_breakout_cells (layout_index).clear ();
+ std::pair, size_t> &boc = ensure_breakout_cells (layout_index);
+ boc.first.clear ();
+ boc.second = std::hash >() (boc.first);
}
void
-DeepShapeStoreState::set_breakout_cells (unsigned int layout_index, const std::set &boc)
+DeepShapeStoreState::set_breakout_cells (unsigned int layout_index, const std::set &boc_in)
{
- ensure_breakout_cells (layout_index) = boc;
+ std::pair, size_t> &boc = ensure_breakout_cells (layout_index);
+ boc.first = boc_in;
+ boc.second = std::hash >() (boc.first);
}
void
DeepShapeStoreState::add_breakout_cell (unsigned int layout_index, db::cell_index_type ci)
{
- ensure_breakout_cells (layout_index).insert (ci);
+ std::pair, size_t> &boc = ensure_breakout_cells (layout_index);
+ boc.first.insert (ci);
+ boc.second = std::hash >() (boc.first);
}
void
DeepShapeStoreState::add_breakout_cells (unsigned int layout_index, const std::set &cc)
{
- ensure_breakout_cells (layout_index).insert (cc.begin (), cc.end ());
+ std::pair, size_t> &boc = ensure_breakout_cells (layout_index);
+ boc.first.insert (cc.begin (), cc.end ());
+ boc.second = std::hash >() (boc.first);
}
void
@@ -726,6 +747,12 @@ DeepShapeStore::breakout_cells (unsigned int layout_index) const
return m_state.breakout_cells (layout_index);
}
+size_t
+DeepShapeStore::breakout_cells_hash (unsigned int layout_index) const
+{
+ return m_state.breakout_cells_hash (layout_index);
+}
+
void
DeepShapeStore::clear_breakout_cells (unsigned int layout_index)
{
diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h
index 1e6e0aaaa..ab2f2336b 100644
--- a/src/db/db/dbDeepShapeStore.h
+++ b/src/db/db/dbDeepShapeStore.h
@@ -165,6 +165,11 @@ public:
*/
const std::set *breakout_cells () const;
+ /**
+ * @brief Gets a hash value representing the breakout cells
+ */
+ size_t breakout_cells_hash () const;
+
/**
* @brief Inserts the layer into the given layout, starting from the given cell and into the given layer
*/
@@ -251,6 +256,7 @@ public:
bool reject_odd_polygons () const;
const std::set *breakout_cells (unsigned int layout_index) const;
+ size_t breakout_cells_hash (unsigned int layout_index) const;
void clear_breakout_cells (unsigned int layout_index);
void set_breakout_cells (unsigned int layout_index, const std::set &boc);
void add_breakout_cell (unsigned int layout_index, db::cell_index_type ci);
@@ -265,14 +271,14 @@ private:
size_t m_max_vertex_count;
bool m_reject_odd_polygons;
tl::Variant m_text_property_name;
- std::vector > m_breakout_cells;
+ std::vector, size_t> > m_breakout_cells;
int m_text_enlargement;
bool m_subcircuit_hierarchy_for_nets;
- std::set &ensure_breakout_cells (unsigned int layout_index)
+ std::pair, size_t> &ensure_breakout_cells (unsigned int layout_index)
{
if (m_breakout_cells.size () <= size_t (layout_index)) {
- m_breakout_cells.resize (layout_index + 1, std::set ());
+ m_breakout_cells.resize (layout_index + 1, std::pair, size_t> ());
}
return m_breakout_cells [layout_index];
}
@@ -782,6 +788,11 @@ public:
*/
const std::set *breakout_cells (unsigned int layout_index) const;
+ /**
+ * @brief Gets a hash value representing the breakout cells
+ */
+ size_t breakout_cells_hash (unsigned int layout_index) const;
+
/**
* @brief Clears the breakout cell list for a given layout
*/
diff --git a/src/db/db/dbTechnology.cc b/src/db/db/dbTechnology.cc
index 2ed47818d..ad4eb63cf 100644
--- a/src/db/db/dbTechnology.cc
+++ b/src/db/db/dbTechnology.cc
@@ -80,7 +80,7 @@ Technologies::instance ()
static tl::XMLElementList xml_elements ()
{
- return make_element ((Technologies::const_iterator (Technologies::*) () const) &Technologies::begin, (Technologies::const_iterator (Technologies::*) () const) &Technologies::end, &Technologies::add, "technology",
+ return make_element ((Technologies::const_iterator (Technologies::*) () const) &Technologies::begin, (Technologies::const_iterator (Technologies::*) () const) &Technologies::end, &Technologies::add_void, "technology",
Technology::xml_elements ()
);
}
@@ -92,7 +92,7 @@ Technologies::to_xml () const
db::Technologies copy;
for (const_iterator t = begin (); t != end (); ++t) {
if (t->is_persisted ()) {
- copy.add (new Technology (*t));
+ copy.add (*t);
}
}
@@ -110,7 +110,7 @@ Technologies::load_from_xml (const std::string &s)
db::Technologies copy;
for (const_iterator t = begin (); t != end (); ++t) {
if (! t->is_persisted ()) {
- copy.add (new Technology (*t));
+ copy.add (*t);
}
}
@@ -121,34 +121,31 @@ Technologies::load_from_xml (const std::string &s)
*this = copy;
}
-void
-Technologies::add_tech (Technology *tech, bool replace_same)
+db::Technology *
+Technologies::add_tech (const Technology &tech, bool replace_same)
{
- if (! tech) {
- return;
- }
-
- std::unique_ptr tech_ptr (tech);
-
Technology *t = 0;
for (tl::stable_vector::iterator i = m_technologies.begin (); !t && i != m_technologies.end (); ++i) {
- if (i->name () == tech->name ()) {
+ if (i->name () == tech.name ()) {
t = i.operator-> ();
}
}
if (t) {
if (replace_same) {
- *t = *tech;
+ *t = tech;
} else {
- throw tl::Exception (tl::to_string (tr ("A technology with this name already exists: ")) + tech->name ());
+ throw tl::Exception (tl::to_string (tr ("A technology with this name already exists: ")) + tech.name ());
}
} else {
- m_technologies.push_back (tech_ptr.release ());
- tech->technology_changed_with_sender_event.add (this, &Technologies::technology_changed);
+ t = new Technology (tech);
+ m_technologies.push_back (t);
+ t->technology_changed_with_sender_event.add (this, &Technologies::technology_changed);
}
technologies_changed ();
+
+ return t;
}
void
diff --git a/src/db/db/dbTechnology.h b/src/db/db/dbTechnology.h
index 9d68d93cf..9327b6d2d 100644
--- a/src/db/db/dbTechnology.h
+++ b/src/db/db/dbTechnology.h
@@ -121,24 +121,34 @@ public:
/**
* @brief Adds a technology to the setup
*
- * The container becomes owner of the technology object.
- * Replaces a technology with the name of the given technology.
+ * @return A reference to the new Technology object
+ *
+ * If a technology with the given name already exists, it is replaced.
*/
- void add (Technology *technology)
+ db::Technology *add (const Technology &technology)
{
- add_tech (technology, true /*replace*/);
+ return add_tech (technology, true /*replace*/);
}
/**
* @brief Adds a technology with a new name
*
+ * @return A reference to the new Technology object
+ *
* Like \add, but throws an exception if a technology with this name
- * already exists. Takes over ownership over the technology object.
- * The technology object is discarded if an exception is thrown.
+ * already exists.
*/
- void add_new (Technology *technology)
+ db::Technology *add_new (const Technology &technology)
{
- add_tech (technology, false /*throws exception on same name*/);
+ return add_tech (technology, false /*throws exception on same name*/);
+ }
+
+ /**
+ * @brief Same as add, but no return value (for XML binding)
+ */
+ void add_void (const Technology &technology)
+ {
+ add (technology);
}
/**
@@ -244,7 +254,7 @@ private:
bool m_changed;
bool m_in_update;
- void add_tech (Technology *technology, bool replace_same);
+ Technology *add_tech(const Technology &technology, bool replace_same);
};
/**
diff --git a/src/db/db/gsiDeclDbEdge.cc b/src/db/db/gsiDeclDbEdge.cc
index 8d1f0d94b..405b38f2c 100644
--- a/src/db/db/gsiDeclDbEdge.cc
+++ b/src/db/db/gsiDeclDbEdge.cc
@@ -555,7 +555,7 @@ struct edge_defs
"This method has been introduced in version 0.26.2.\n"
) +
method ("distance", &C::distance, gsi::arg ("p"),
- "@brief Distance between the edge and a point.\n"
+ "@brief Gets the distance of the point from the line through the edge.\n"
"\n"
"Returns the distance between the edge and the point. The \n"
"distance is signed which is negative if the point is to the\n"
@@ -564,6 +564,11 @@ struct edge_defs
"line through the edge. If the edge is degenerated, the distance\n"
"is not defined.\n"
"\n"
+ "This method considers the edge to define an infinite line running through it.\n"
+ "\\distance returns the distance of 'p' to this line.\n"
+ "A similar method is \\euclidian_distance, but the latter regards\n"
+ "the edge a finite set of points between the endpoints.\n"
+ "\n"
"@param p The point to test.\n"
"\n"
"@return The distance\n"
@@ -578,6 +583,19 @@ struct edge_defs
"\n"
"@return The side value\n"
) +
+ method ("euclidian_distance", &C::euclidian_distance, gsi::arg ("p"),
+ "@brief Gets the distance of the point from the the edge.\n"
+ "\n"
+ "Returns the minimum distance of the point to any point on the edge.\n"
+ "Unlike \\distance, the edge is considered a finite set of points between\n"
+ "the endpoints. The result is also not signed like it is the case for \\distance.\n"
+ "\n"
+ "This method has been introduced in version 0.28.14.\n"
+ "\n"
+ "@param p The point to test.\n"
+ "\n"
+ "@return The distance\n"
+ ) +
method ("distance_abs", &C::distance_abs, gsi::arg ("p"),
"@brief Absolute distance between the edge and a point.\n"
"\n"
diff --git a/src/db/db/gsiDeclDbEdgePair.cc b/src/db/db/gsiDeclDbEdgePair.cc
index 3d90abefe..4fb90d763 100644
--- a/src/db/db/gsiDeclDbEdgePair.cc
+++ b/src/db/db/gsiDeclDbEdgePair.cc
@@ -169,6 +169,14 @@ struct edge_pair_defs
method ("bbox", &C::bbox,
"@brief Gets the bounding box of the edge pair\n"
) +
+ method ("distance", &C::distance,
+ "@brief Gets the distance of the edges in the edge pair\n"
+ "\n"
+ "The distance between the two edges is defined as the minimum distance between any "
+ "two points on the two edges.\n"
+ "\n"
+ "This attribute has been introduced in version 0.28.14."
+ ) +
method ("perimeter", &C::perimeter,
"@brief Gets the perimeter of the edge pair\n"
"\n"
diff --git a/src/db/db/gsiDeclDbTechnologies.cc b/src/db/db/gsiDeclDbTechnologies.cc
index 7b442971f..81bc2ca48 100644
--- a/src/db/db/gsiDeclDbTechnologies.cc
+++ b/src/db/db/gsiDeclDbTechnologies.cc
@@ -45,10 +45,14 @@ static db::Technology *technology_by_name (const std::string &name)
static db::Technology *create_technology (const std::string &name)
{
- db::Technology *tech = new db::Technology ();
- tech->set_name (name);
- db::Technologies::instance ()->add_new (tech);
- return tech;
+ db::Technology tech;
+ tech.set_name (name);
+ return db::Technologies::instance ()->add_new (tech);
+}
+
+static db::Technology *register_technology (const db::Technology &tech)
+{
+ return db::Technologies::instance ()->add_new (tech);
}
static void remove_technology (const std::string &name)
@@ -291,10 +295,24 @@ gsi::Class technology_decl ("db", "Technology",
gsi::method ("create_technology", &create_technology, gsi::arg ("name"),
"@brief Creates a new (empty) technology with the given name\n"
"\n"
+ "The new technology is already registered in the system.\n"
+ "\n"
"This method returns a reference to the new technology."
) +
+ gsi::method ("register_technology", ®ister_technology, gsi::arg ("tech"),
+ "@brief Registers a technology in the system\n"
+ "\n"
+ "Only after a technology is registered, it can be used in the system, e.g. by "
+ "specifying its name in \\Layout#technology_name. While \\create_technology already registers "
+ "the technology, this method allows registering a Technology object that has created in other ways.\n"
+ "\n"
+ "This method returns a reference to the new technology object, which is a copy of the argument. "
+ "\\remove_technology can be used to remove a technology registered by this method.\n"
+ "\n"
+ "This method has been introduced in version 0.28.14."
+ ) +
gsi::method ("remove_technology", &remove_technology, gsi::arg ("name"),
- "@brief Removes the technology with the given name\n"
+ "@brief Removes the technology with the given name from the system\n"
) +
gsi::method ("technologies_to_xml", &technologies_to_xml,
"@brief Returns a XML representation of all technologies registered in the system\n"
@@ -317,12 +335,13 @@ gsi::Class technology_decl ("db", "Technology",
gsi::method ("technologies_from_xml", &technologies_from_xml, gsi::arg ("xml"),
"@brief Loads the technologies from a XML representation\n"
"\n"
- "See \\technologies_to_xml for details. This method is the corresponding setter."
+ "See \\technologies_to_xml for details."
) +
gsi::method ("technology_from_xml", &technology_from_xml, gsi::arg ("xml"),
"@brief Loads the technology from a XML representation\n"
"\n"
- "See \\technology_to_xml for details."
+ "See \\technology_to_xml for details. Note that this function will create "
+ "a new Technology object which is not registered in the system. See \\Technology#register for details."
) +
gsi::method_ext ("component_names", &get_component_names,
"@brief Gets the names of all components available for \\component"
@@ -338,6 +357,21 @@ gsi::Class technology_decl ("db", "Technology",
"definitions are returned with \\technology_by_name. Use \\create_technology to register "
"new technologies and \\remove_technology to delete technologies.\n"
"\n"
+ "Note that a Technology object needs to be registered in the system, before its name "
+ "can be used to specify a technology, for example in \\Layout#technology_name. "
+ "Technology objects created by \\create_technology are automatically registered. "
+ "If you create a Technology object directly, you need to register it explicitly:"
+ "\n"
+ "@code\n"
+ "tech = RBA::Technology::new\n"
+ "tech.load(\"mytech.lyt\")\n"
+ "RBA::Technology::register_technology(tech)\n"
+ "@/code\n"
+ "\n"
+ "Note that in the latter example, an exception will be thrown if a technology with the same "
+ "name already exists. Also note, that \\Technology#register will register a copy of the "
+ "object, so modifying it after registration will not have any effect.\n"
+ "\n"
"The Technology class has been introduced in version 0.25.\n"
);
diff --git a/src/db/unit_tests/dbDeepEdgesTests.cc b/src/db/unit_tests/dbDeepEdgesTests.cc
index fae54490e..783ceb326 100644
--- a/src/db/unit_tests/dbDeepEdgesTests.cc
+++ b/src/db/unit_tests/dbDeepEdgesTests.cc
@@ -29,6 +29,7 @@
#include "dbEdgesUtils.h"
#include "dbDeepShapeStore.h"
#include "dbCellGraphUtils.h"
+#include "dbDeepEdges.h"
#include "tlUnitTest.h"
#include "tlStream.h"
@@ -1292,3 +1293,140 @@ TEST(20_in_and_out)
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au20.gds");
}
+TEST(deep_edges_and_cheats)
+{
+ db::Layout ly;
+ {
+ std::string fn (tl::testdata ());
+ fn += "/algo/cheats.gds";
+ tl::InputStream stream (fn);
+ db::Reader reader (stream);
+ reader.read (ly);
+ }
+
+ db::cell_index_type top_cell_index = *ly.begin_top_down ();
+ db::Cell &top_cell = ly.cell (top_cell_index);
+
+ unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
+ unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
+ unsigned int l10 = ly.get_layer (db::LayerProperties (10, 0));
+ unsigned int l11 = ly.get_layer (db::LayerProperties (11, 0));
+ unsigned int l12 = ly.get_layer (db::LayerProperties (12, 0));
+ unsigned int l13 = ly.get_layer (db::LayerProperties (13, 0));
+ unsigned int l14 = ly.get_layer (db::LayerProperties (14, 0));
+ unsigned int l19 = ly.get_layer (db::LayerProperties (19, 0));
+ unsigned int l20 = ly.get_layer (db::LayerProperties (20, 0));
+ unsigned int l21 = ly.get_layer (db::LayerProperties (21, 0));
+ unsigned int l22 = ly.get_layer (db::LayerProperties (22, 0));
+ unsigned int l23 = ly.get_layer (db::LayerProperties (23, 0));
+ unsigned int l24 = ly.get_layer (db::LayerProperties (24, 0));
+ unsigned int l29 = ly.get_layer (db::LayerProperties (29, 0));
+ unsigned int l30 = ly.get_layer (db::LayerProperties (30, 0));
+ unsigned int l31 = ly.get_layer (db::LayerProperties (31, 0));
+ unsigned int l32 = ly.get_layer (db::LayerProperties (32, 0));
+ unsigned int l33 = ly.get_layer (db::LayerProperties (33, 0));
+ unsigned int l34 = ly.get_layer (db::LayerProperties (34, 0));
+ unsigned int l39 = ly.get_layer (db::LayerProperties (39, 0));
+
+ db::DeepShapeStore dss;
+
+ db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
+ db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
+
+ (r1.edges () - r2).insert_into (&ly, top_cell_index, l10);
+
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second);
+
+ (r1.edges () - r2).insert_into (&ly, top_cell_index, l11);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second);
+
+ (r1.edges () - r2).insert_into (&ly, top_cell_index, l12);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second);
+
+ (r1.edges () - r2).insert_into (&ly, top_cell_index, l13);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second);
+
+ (r1.edges () - r2).insert_into (&ly, top_cell_index, l14);
+
+ dss.clear_breakout_cells (0);
+ (r1.edges () - r2).insert_into (&ly, top_cell_index, l19);
+
+ (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l20);
+
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second);
+
+ (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l21);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second);
+
+ (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l22);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second);
+
+ (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l23);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second);
+
+ (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l24);
+
+ dss.clear_breakout_cells (0);
+ (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l29);
+
+ db::Region eo;
+ db::Edges e1;
+
+ e1 = r2.edges ();
+ e1.extended (eo, 0, 0, 500, 0);
+ eo.insert_into (&ly, top_cell_index, l30);
+ EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true);
+
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second);
+
+ e1 = r2.edges ();
+ e1.extended (eo, 0, 0, 500, 0);
+ eo.insert_into (&ly, top_cell_index, l31);
+ EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second);
+
+ e1 = r2.edges ();
+ e1.extended (eo, 0, 0, 500, 0);
+ eo.insert_into (&ly, top_cell_index, l32);
+ EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second);
+
+ e1 = r2.edges ();
+ e1.extended (eo, 0, 0, 500, 0);
+ eo.insert_into (&ly, top_cell_index, l33);
+ EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second);
+
+ e1 = r2.edges ();
+ e1.extended (eo, 0, 0, 500, 0);
+ eo.insert_into (&ly, top_cell_index, l34);
+ EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true);
+
+ dss.clear_breakout_cells (0);
+
+ e1 = r2.edges ();
+ e1.extended (eo, 0, 0, 500, 0);
+ eo.insert_into (&ly, top_cell_index, l39);
+ EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true);
+
+ CHECKPOINT();
+ db::compare_layouts (_this, ly, tl::testdata () + "/algo/cheats_edges_au.gds");
+}
diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc
index 5bdeaadd3..3583dc279 100644
--- a/src/db/unit_tests/dbDeepRegionTests.cc
+++ b/src/db/unit_tests/dbDeepRegionTests.cc
@@ -30,6 +30,7 @@
#include "dbRegionProcessors.h"
#include "dbEdgesUtils.h"
#include "dbDeepShapeStore.h"
+#include "dbDeepRegion.h"
#include "dbOriginalLayerRegion.h"
#include "dbCellGraphUtils.h"
#include "dbTestSupport.h"
@@ -2846,3 +2847,97 @@ TEST(issue_663_separation_from_inside)
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testdata () + "/algo/deep_region_au663.gds");
}
+
+TEST(deep_region_and_cheats)
+{
+ db::Layout ly;
+ {
+ std::string fn (tl::testdata ());
+ fn += "/algo/cheats.gds";
+ tl::InputStream stream (fn);
+ db::Reader reader (stream);
+ reader.read (ly);
+ }
+
+ db::cell_index_type top_cell_index = *ly.begin_top_down ();
+ db::Cell &top_cell = ly.cell (top_cell_index);
+
+ unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
+ unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
+ unsigned int l10 = ly.get_layer (db::LayerProperties (10, 0));
+ unsigned int l11 = ly.get_layer (db::LayerProperties (11, 0));
+ unsigned int l12 = ly.get_layer (db::LayerProperties (12, 0));
+ unsigned int l13 = ly.get_layer (db::LayerProperties (13, 0));
+ unsigned int l14 = ly.get_layer (db::LayerProperties (14, 0));
+ unsigned int l19 = ly.get_layer (db::LayerProperties (19, 0));
+ unsigned int l20 = ly.get_layer (db::LayerProperties (20, 0));
+ unsigned int l21 = ly.get_layer (db::LayerProperties (21, 0));
+ unsigned int l22 = ly.get_layer (db::LayerProperties (22, 0));
+ unsigned int l23 = ly.get_layer (db::LayerProperties (23, 0));
+ unsigned int l24 = ly.get_layer (db::LayerProperties (24, 0));
+ unsigned int l29 = ly.get_layer (db::LayerProperties (29, 0));
+
+ db::DeepShapeStore dss;
+
+ db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
+ db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
+
+ (r1 - r2).insert_into (&ly, top_cell_index, l10);
+
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second);
+
+ (r1 - r2).insert_into (&ly, top_cell_index, l11);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second);
+
+ (r1 - r2).insert_into (&ly, top_cell_index, l12);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second);
+
+ (r1 - r2).insert_into (&ly, top_cell_index, l13);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second);
+
+ (r1 - r2).insert_into (&ly, top_cell_index, l14);
+
+ dss.clear_breakout_cells (0);
+ (r1 - r2).insert_into (&ly, top_cell_index, l19);
+
+ EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), false);
+
+ r1.sized (-1000).insert_into (&ly, top_cell_index, l20);
+ EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true);
+
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second);
+
+ r1.sized (-1000).insert_into (&ly, top_cell_index, l21);
+ EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second);
+
+ r1.sized (-1000).insert_into (&ly, top_cell_index, l22);
+ EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second);
+
+ r1.sized (-1000).insert_into (&ly, top_cell_index, l23);
+ EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true);
+
+ dss.clear_breakout_cells (0);
+ dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second);
+
+ r1.sized (-1000).insert_into (&ly, top_cell_index, l24);
+ EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true);
+
+ dss.clear_breakout_cells (0);
+ r1.sized (-1000).insert_into (&ly, top_cell_index, l29);
+ EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true);
+
+ CHECKPOINT();
+ db::compare_layouts (_this, ly, tl::testdata () + "/algo/cheats_au.gds");
+}
diff --git a/src/doc/doc/programming/ruby_binding.xml b/src/doc/doc/programming/ruby_binding.xml
index 6ff93b20c..655f395de 100644
--- a/src/doc/doc/programming/ruby_binding.xml
+++ b/src/doc/doc/programming/ruby_binding.xml
@@ -408,6 +408,61 @@ A::new.f(x)
omitted, the default value is used instead.
+ Implicit conversions
+
+ String arguments
+
+
+ If a method expects a string argument, other types are converted to strings
+ using the "to_s" method. In Python, the equivalent is "str(...)".
+
+
+
+ Example:
+
+
+ # Also accepts a float value for the first string argument -
+# it is converted to "2.5"
+t = RBA::Text::new(2.5, RBA::Trans::new)
+
+ Conversion constructors
+
+ Conversion constructors are constructors that take an object of a
+different class and convert it to the target class.
+Conversion constructors are used implicitly in applicable cases
+to convert one type to the type requested by the argument.
+
+
+ For example, in the following code, the Region object's "+" operator
+ is used. This expects a Region object as the second parameter, but as
+ there is conversion constructor available which converts a Box to
+ a Region, it is possible to use a Box directly:
+
+
+ r = RBA::Region::new(RBA::Box::new(0, 0, 1000, 2000))
+r += RBA::Box::new(3000, 0, 4000, 2000)
+
+ Implicit constructor from lists
+
+
+ When an object is expected for an argument and a list is given,
+ the object constructor is called with the arguments from the list.
+ This specifically allows using size-2 lists instead of Point or
+ Vector arguments. In Python, a "list" can also be a tuple.
+
+
+
+ In the following example, this mechanism is used for
+ the polygon point list which is expected to be an array
+ of Point objects, but can use size-2 arrays instead.
+ Also, the "moved" method expects a Vector, but here
+ as well, size-2 arrays can be used instead:
+
+
+ pts = [ [ 0, 0 ], [ 0, 1000 ], [ 1000, 0 ] ]
+poly = RBA::Polygon::new(pts)
+poly = poly.moved([ 100, 200 ])
+
Constness
diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc
index 5d415b9b5..3d022b244 100644
--- a/src/edt/edt/edtService.cc
+++ b/src/edt/edt/edtService.cc
@@ -261,7 +261,7 @@ Service::snap_marker_to_grid (const db::DVector &v, bool &snapped) const
if (snapped) {
vr += vv;
- return db::DVector (vr.x () * snapped_to.x (), vr.y () * snapped_to.y ());
+ return db::DVector (vr.x () * fabs (snapped_to.x ()), vr.y () * fabs (snapped_to.y ()));
} else {
return db::DVector ();
}
diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc
index 89433d867..930801c5f 100644
--- a/src/lay/lay/layApplication.cc
+++ b/src/lay/lay/layApplication.cc
@@ -64,6 +64,7 @@
#include "tlHttpStream.h"
#include "tlArch.h"
#include "tlFileUtils.h"
+#include "tlEnv.h"
#include
#include
@@ -568,6 +569,19 @@ ApplicationBase::init_app ()
}
std::string short_arch_string = tl::join (as, "-");
+#if defined(_WIN32)
+ // Set SSL_CERT_FILE for Windows installation and libcrypto.
+
+ std::string cert_file = "cert.pem";
+ std::string cert_env_var = "SSL_CERT_FILE";
+ if (! tl::has_env (cert_env_var)) {
+ std::string cert_path = tl::combine_path (m_inst_path, cert_file);
+ if (tl::file_exists (cert_path)) {
+ tl::set_env (cert_env_var, cert_path);
+ }
+ }
+#endif
+
std::vector klp_paths;
for (std::vector ::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) {
diff --git a/src/lay/lay/layMacroController.cc b/src/lay/lay/layMacroController.cc
index 2eb517e76..7c78016fe 100644
--- a/src/lay/lay/layMacroController.cc
+++ b/src/lay/lay/layMacroController.cc
@@ -379,9 +379,11 @@ MacroController::sync_package_paths ()
void
MacroController::sync_implicit_macros (bool ask_before_autorun)
{
+ // gets the external paths (tech, packages) into m_external_paths
+ sync_macro_sources ();
+
if (m_no_implicit_macros) {
- sync_macro_sources ();
sync_package_paths ();
} else {
@@ -392,9 +394,6 @@ MacroController::sync_implicit_macros (bool ask_before_autorun)
prev_folders_by_path.insert (std::make_pair (p->path, *p));
}
- // gets the external paths (tech, packages) into m_external_paths
- sync_macro_sources ();
-
// delete macro collections which are no longer required or update description
std::vector folders_to_delete;
diff --git a/src/lay/lay/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc
index 193de09cd..788a7a8e3 100644
--- a/src/lay/lay/layMacroEditorDialog.cc
+++ b/src/lay/lay/layMacroEditorDialog.cc
@@ -2092,7 +2092,6 @@ MacroEditorDialog::search_editing ()
}
apply_search ();
- page->find_reset (); // search from the initial position
if (! page->has_multi_block_selection ()) {
page->find_next ();
}
@@ -2119,7 +2118,6 @@ MacroEditorDialog::search_edited ()
}
apply_search ();
- page->find_reset (); // search from the initial position
if (! page->has_multi_block_selection ()) {
page->find_next ();
}
diff --git a/src/lay/lay/laySaltDownloadManager.cc b/src/lay/lay/laySaltDownloadManager.cc
index 559b59333..3dd9f3727 100644
--- a/src/lay/lay/laySaltDownloadManager.cc
+++ b/src/lay/lay/laySaltDownloadManager.cc
@@ -523,6 +523,9 @@ SaltDownloadManager::execute (lay::SaltManagerDialog *parent, lay::Salt &salt)
dialog->start ();
+ // Stop other events to interfere with the download, specifically not macro controller updates
+ tl::NoDeferredMethods silent_section;
+
std::sort (m_registry.begin (), m_registry.end ());
for (std::vector::const_iterator p = m_registry.begin (); p != m_registry.end (); ++p) {
diff --git a/src/lay/lay/laySaltManagerDialog.cc b/src/lay/lay/laySaltManagerDialog.cc
index 4e86323bd..dd58ed13e 100644
--- a/src/lay/lay/laySaltManagerDialog.cc
+++ b/src/lay/lay/laySaltManagerDialog.cc
@@ -1213,13 +1213,13 @@ private:
void
SaltManagerDialog::get_remote_grain_info (lay::SaltGrain *g, SaltGrainDetailsTextWidget *details)
{
- if (! g) {
+ // NOTE: we don't want to interfere with download here, so refuse to do update
+ // the info while a package is downloaded.
+ if (! g || m_downloaded_grain.get ()) {
details->setHtml (QString ());
return;
}
- tl_assert (m_downloaded_grain.get () == 0);
-
m_downloaded_grain.reset (0);
if (m_downloaded_grain_reader.get ()) {
diff --git a/src/lay/lay/layTechSetupDialog.cc b/src/lay/lay/layTechSetupDialog.cc
index ae62c3ab4..8700a9416 100644
--- a/src/lay/lay/layTechSetupDialog.cc
+++ b/src/lay/lay/layTechSetupDialog.cc
@@ -775,13 +775,13 @@ BEGIN_PROTECTED
}
}
- db::Technology *nt = new db::Technology (*t);
+ db::Technology nt (*t);
- nt->set_tech_file_path (tl::to_string (tech_dir.absoluteFilePath (tn + QString::fromUtf8 (".lyt"))));
- nt->set_default_base_path (tl::to_string (tech_dir.absolutePath ()));
- nt->set_persisted (false);
- nt->set_name (tl::to_string (tn));
- nt->set_description (std::string ());
+ nt.set_tech_file_path (tl::to_string (tech_dir.absoluteFilePath (tn + QString::fromUtf8 (".lyt"))));
+ nt.set_default_base_path (tl::to_string (tech_dir.absolutePath ()));
+ nt.set_persisted (false);
+ nt.set_name (tl::to_string (tn));
+ nt.set_description (std::string ());
m_technologies.add (nt);
update_tech_tree ();
@@ -900,12 +900,7 @@ BEGIN_PROTECTED
db::Technology t;
t.load (fn);
-
- if (m_technologies.has_technology (t.name ())) {
- *m_technologies.technology_by_name (t.name ()) = t;
- } else {
- m_technologies.add (new db::Technology (t));
- }
+ m_technologies.add (t);
update_tech_tree ();
select_tech (*m_technologies.technology_by_name (t.name ()));
diff --git a/src/lay/lay/layTechnologyController.cc b/src/lay/lay/layTechnologyController.cc
index 212e2a7df..7fcfb0f85 100644
--- a/src/lay/lay/layTechnologyController.cc
+++ b/src/lay/lay/layTechnologyController.cc
@@ -536,7 +536,7 @@ TechnologyController::rescan (db::Technologies &technologies)
technologies.clear ();
for (db::Technologies::const_iterator t = current.begin (); t != current.end (); ++t) {
if (t->is_persisted ()) {
- technologies.add (new db::Technology (*t));
+ technologies.add (*t);
}
}
@@ -596,7 +596,7 @@ TechnologyController::rescan (db::Technologies &technologies)
t.set_persisted (false); // don't save that one in the configuration
t.set_readonly (readonly || ! QFileInfo (dir.filePath (*lf)).isWritable ());
t.set_grain_name (grain_name);
- technologies.add (new db::Technology (t));
+ technologies.add (t);
} catch (tl::Exception &ex) {
tl::warn << tl::to_string (QObject::tr ("Unable to auto-import technology file ")) << tl::to_string (*lf) << ": " << ex.msg ();
@@ -608,14 +608,14 @@ TechnologyController::rescan (db::Technologies &technologies)
for (std::vector::const_iterator t = m_temp_tech.begin (); t != m_temp_tech.end (); ++t) {
- db::Technology *tech = new db::Technology (*t);
if (tl::verbosity () >= 20) {
- tl::info << "Registering special technology from " << tech->tech_file_path () << " as " << tech->name ();
+ tl::info << "Registering special technology from " << t->tech_file_path () << " as " << t->name ();
}
+
+ db::Technology *tech = technologies.add (*t);
tech->set_persisted (false); // don't save that one in the configuration
tech->set_tech_file_path (std::string ()); // don't save to a file either
tech->set_readonly (true); // don't edit
- technologies.add (tech);
}
}
diff --git a/src/layui/layui/layNetlistBrowserDialog.cc b/src/layui/layui/layNetlistBrowserDialog.cc
index 9f393573a..10c798adb 100644
--- a/src/layui/layui/layNetlistBrowserDialog.cc
+++ b/src/layui/layui/layNetlistBrowserDialog.cc
@@ -677,7 +677,13 @@ NetlistBrowserDialog::l2ndbs_changed ()
for (unsigned int i = 0; i < view ()->num_l2ndbs (); ++i) {
const db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (i);
- mp_ui->l2ndb_cb->addItem (tl::to_qstring (l2ndb->name ()));
+ std::string text = l2ndb->name ();
+ if (! l2ndb->description ().empty ()) {
+ text += " (";
+ text += l2ndb->description ();
+ text += ")";
+ }
+ mp_ui->l2ndb_cb->addItem (tl::to_qstring (text));
if (l2ndb->name () == m_l2ndb_name) {
l2n_index = i;
}
diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc
index e8c3947ed..3c24089ae 100644
--- a/src/layui/layui/layNetlistBrowserPage.cc
+++ b/src/layui/layui/layNetlistBrowserPage.cc
@@ -1345,7 +1345,7 @@ bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit)
void
NetlistBrowserPage::adjust_view ()
{
- if (! mp_database.get () || ! mp_view) {
+ if (! mp_database.get () || ! mp_database->netlist () || ! mp_view) {
return;
}
@@ -1666,7 +1666,7 @@ NetlistBrowserPage::update_highlights ()
}
clear_markers ();
- if (! mp_database.get () || ! mp_view) {
+ if (! mp_database.get () || ! mp_database->netlist () || ! mp_view) {
return;
}
diff --git a/src/layui/layui/rdbMarkerBrowserDialog.cc b/src/layui/layui/rdbMarkerBrowserDialog.cc
index ed0dd5c45..ccfa15386 100644
--- a/src/layui/layui/rdbMarkerBrowserDialog.cc
+++ b/src/layui/layui/rdbMarkerBrowserDialog.cc
@@ -582,7 +582,13 @@ MarkerBrowserDialog::rdbs_changed ()
for (unsigned int i = 0; i < view ()->num_rdbs (); ++i) {
const rdb::Database *rdb = view ()->get_rdb (i);
- mp_ui->rdb_cb->addItem (tl::to_qstring (rdb->name ()));
+ std::string text = rdb->name ();
+ if (! rdb->description ().empty ()) {
+ text += " (";
+ text += rdb->description ();
+ text += ")";
+ }
+ mp_ui->rdb_cb->addItem (tl::to_qstring (text));
if (rdb->name () == m_rdb_name) {
rdb_index = i;
}
@@ -761,23 +767,35 @@ MarkerBrowserDialog::scan_layer ()
std::string desc;
for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) {
- if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) {
+ if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
if (! desc.empty ()) {
desc += ", ";
}
desc += layout.get_properties ((*l)->layer_index ()).to_string ();
}
}
- rdb->set_description ("Shapes of layer(s) " + desc);
+ desc = tl::to_string (tr ("Hierarchical shapes of layer(s) ")) + desc;
+ desc += " ";
+ desc += tl::to_string (tr ("from cell "));
+ desc += cv->layout ().cell_name (cv.cell_index ());
+ rdb->set_description (desc);
+
+ std::set called_cells;
+ called_cells.insert (cv.cell_index ());
+ cv->layout ().cell (cv.cell_index ()).collect_called_cells (called_cells);
for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) {
- if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) {
+ if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
- rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ());
+ rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ());
for (db::Layout::const_iterator cid = layout.begin (); cid != layout.end (); ++cid) {
+ if (called_cells.find (cid->cell_index ()) == called_cells.end ()) {
+ continue;
+ }
+
const db::Cell &cell = *cid;
if (cell.shapes ((*l)->layer_index ()).size () > 0) {
@@ -855,18 +873,22 @@ MarkerBrowserDialog::scan_layer_flat ()
std::string desc;
for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) {
- if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) {
+ if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
if (! desc.empty ()) {
desc += ", ";
}
desc += layout.get_properties ((*l)->layer_index ()).to_string ();
}
}
- rdb->set_description ("Shapes of layer(s) " + desc);
+ desc = tl::to_string (tr ("Flat shapes of layer(s) ")) + desc;
+ desc += " ";
+ desc += tl::to_string (tr ("from cell "));
+ desc += cv->layout ().cell_name (cv.cell_index ());
+ rdb->set_description (desc);
for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) {
- if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) {
+ if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) {
rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ());
diff --git a/src/layui/layui/rdbMarkerBrowserPage.cc b/src/layui/layui/rdbMarkerBrowserPage.cc
index 0b795ccab..0aff85df3 100644
--- a/src/layui/layui/rdbMarkerBrowserPage.cc
+++ b/src/layui/layui/rdbMarkerBrowserPage.cc
@@ -2148,7 +2148,7 @@ MarkerBrowserPage::do_update_markers ()
lay::CellView cv = mp_view->cellview (m_cv_index);
if (! current_cell && cv.is_valid ()) {
- current_cell = mp_database->cell_by_qname (cv->layout ().cell_name (cv.cell_index ()));
+ current_cell = mp_database->cell_by_qname (cv->layout ().cell_name (cv.ctx_cell_index ()));
}
std::vector tv = mp_view->cv_transform_variants (m_cv_index);
@@ -2182,7 +2182,7 @@ MarkerBrowserPage::do_update_markers ()
// If we could not find a transformation in the RDB, try to find one in the layout DB:
std::pair cc = cv->layout ().cell_by_name (c->name ().c_str ());
if (cc.first) {
- std::pair ic = db::find_layout_context (cv->layout (), cc.second, cv.cell_index ());
+ std::pair ic = db::find_layout_context (cv->layout (), cc.second, cv.ctx_cell_index ());
if (ic.first) {
context.first = true;
context.second = db::DCplxTrans (cv->layout ().dbu ()) * db::DCplxTrans (ic.second) * db::DCplxTrans (1.0 / cv->layout ().dbu ());
@@ -2197,7 +2197,7 @@ MarkerBrowserPage::do_update_markers ()
context = std::pair (true, db::DCplxTrans ());
} else if (! current_cell) {
m_error_text = tl::sprintf (tl::to_string (QObject::tr ("Current layout cell '%s' not found in marker database and no path found from marker's cell '%s' to current cell in the layout database.")),
- cv->layout ().cell_name (cv.cell_index ()), c->name ());
+ cv->layout ().cell_name (cv.ctx_cell_index ()), c->name ());
} else {
m_error_text = tl::sprintf (tl::to_string (QObject::tr ("No example instantiation given in marker database for marker's cell '%s' to current cell '%s' and no such path in the layout database either.")),
c->name (), current_cell->name ());
diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc b/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc
index 84738ddd8..776f6c07d 100644
--- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc
+++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc
@@ -378,8 +378,10 @@ NetTracerData::configure_l2n (db::LayoutToNetlist &l2n)
// make all connections (intra and inter-layer)
for (std::map >::const_iterator r = m_l2n_regions.begin (); r != m_l2n_regions.end (); ++r) {
- l2n.connect (*r->second->get ());
const std::set &connections_to = log_connections (r->first);
+ if (! connections_to.empty ()) {
+ l2n.connect (*r->second->get ());
+ }
for (std::set::const_iterator c = connections_to.begin (); c != connections_to.end (); ++c) {
std::map >::const_iterator rc = m_l2n_regions.find (*c);
if (rc != m_l2n_regions.end ()) {
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
index 42c5c86b4..a3fba85bc 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc
@@ -348,10 +348,10 @@ END_PROTECTED
}
bool
-NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerData &data)
+NetTracerDialog::get_net_tracer_setup_from_tech (const std::string &tech_name, const std::string &stack_name, const db::Layout &layout, db::NetTracerData &data)
{
// fetch the net tracer data from the technology and apply to the current layout
- const db::Technology *tech = cv->technology ();
+ const db::Technology *tech = db::Technologies::instance ()->technology_by_name (tech_name);
if (! tech) {
return false;
}
@@ -361,8 +361,6 @@ NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerDat
return false;
}
- std::string stack_name = tl::to_string (stack_selector->itemData (stack_selector->currentIndex ()).toString ());
-
const db::NetTracerConnectivity *connectivity = 0;
for (auto d = tech_component->begin (); d != tech_component->end () && ! connectivity; ++d) {
if (d->name () == stack_name) {
@@ -375,10 +373,25 @@ NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerDat
}
// Set up the net tracer environment
- data = connectivity->get_tracer_data (cv->layout ());
+ data = connectivity->get_tracer_data (layout);
return true;
}
+bool
+NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerData &data)
+{
+ // fetch the net tracer data from the technology and apply to the current layout
+ const db::Technology *tech = cv->technology ();
+ if (! tech) {
+ return false;
+ }
+
+ const std::string &tech_name = tech->name ();
+ std::string stack_name = tl::to_string (stack_selector->itemData (stack_selector->currentIndex ()).toString ());
+
+ return get_net_tracer_setup_from_tech (tech_name, stack_name, cv->layout (), data);
+}
+
db::NetTracerNet *
NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path)
{
@@ -652,11 +665,16 @@ NetTracerDialog::menu_activated (const std::string &symbol)
const lay::CellView &cv = view ()->cellview (view ()->active_cellview_index ());
if (cv.is_valid ()) {
+
db::RecursiveShapeIterator si (cv->layout (), *cv.cell (), std::vector ());
std::unique_ptr l2ndb (new db::LayoutToNetlist (si));
trace_all_nets (l2ndb.get (), cv, flat);
- unsigned int l2ndb_index = view ()->add_l2ndb (l2ndb.release ());
- view ()->open_l2ndb_browser (l2ndb_index, view ()->index_of_cellview (&cv));
+
+ if (l2ndb->netlist ()) {
+ unsigned int l2ndb_index = view ()->add_l2ndb (l2ndb.release ());
+ view ()->open_l2ndb_browser (l2ndb_index, view ()->index_of_cellview (&cv));
+ }
+
}
} else {
@@ -1319,7 +1337,7 @@ BEGIN_PROTECTED
db::Technology tech = *db::Technologies::instance ()->technology_by_name (tech_name);
// call the dialog and if successful, install the new technology
- lay::TechComponentSetupDialog dialog (this, &tech, db::net_tracer_component_name ());
+ lay::TechComponentSetupDialog dialog (isVisible () ? this : parentWidget (), &tech, db::net_tracer_component_name ());
if (dialog.exec ()) {
*db::Technologies::instance ()->technology_by_name (tech.name ()) = tech;
update_list_of_stacks ();
@@ -1781,13 +1799,79 @@ NetTracerDialog::clear_markers ()
void
NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView &cv, bool flat)
{
+ const db::Technology *tech = cv->technology ();
+ if (! tech) {
+ return;
+ }
+
+ static std::string current_stack;
+
+ QStringList stacks;
+ std::vector raw_stacks;
+ int current = 0;
+
+ const db::NetTracerTechnologyComponent *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ()));
+ if (tech_component) {
+ for (auto d = tech_component->begin (); d != tech_component->end (); ++d) {
+ raw_stacks.push_back (d->name ());
+ if (d->name () == current_stack) {
+ current = stacks.size ();
+ }
+ if (d->name ().empty ()) {
+ stacks.push_back (tr ("(default)"));
+ } else {
+ stacks.push_back (tl::to_qstring (d->name ()));
+ }
+ }
+ }
+
+ if (raw_stacks.empty ()) {
+ return;
+ }
+
+ current_stack = raw_stacks.front ();
+
+ if (stacks.size () >= 2) {
+ bool ok = true;
+ QString sel = QInputDialog::getItem (parentWidget (), tr ("Select Stack for Net Tracing (All Nets)"), tr ("Stack"), stacks, current, false, &ok);
+ if (! ok) {
+ return;
+ }
+ current = stacks.indexOf (sel);
+ if (current < 0) {
+ return;
+ }
+ current_stack = raw_stacks [current];
+ }
+
db::NetTracerData tracer_data;
- if (! get_net_tracer_setup (cv, tracer_data)) {
+ if (! get_net_tracer_setup_from_tech (tech->name (), current_stack, cv->layout (), tracer_data)) {
return;
}
tracer_data.configure_l2n (*l2ndb);
+ std::string description = flat ? tl::to_string (tr ("Flat nets")) : tl::to_string (tr ("Hierarchical nets"));
+ std::string name = flat ? "Flat_Nets" : "Hierarchical_Nets";
+ if (! tech->name ().empty ()) {
+ description += ", ";
+ description += tl::to_string (tr ("Technology"));
+ description += ": ";
+ description += tech->name ();
+ name += "_";
+ name += tech->name ();
+ }
+ if (! current_stack.empty ()) {
+ description += ", ";
+ description += tl::to_string (tr ("Stack"));
+ description += ": ";
+ description += current_stack;
+ name += "_";
+ name += current_stack;
+ }
+ l2ndb->set_description (description);
+ l2ndb->set_name (name);
+
l2ndb->clear_join_nets ();
l2ndb->clear_join_net_names ();
diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h
index 8d304c0ba..61306de66 100644
--- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h
+++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h
@@ -127,6 +127,7 @@ private:
void release_mouse ();
db::NetTracerNet *do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path);
bool get_net_tracer_setup (const lay::CellView &cv, db::NetTracerData &data);
+ static bool get_net_tracer_setup_from_tech (const std::string &tech_name, const std::string &stack_name, const db::Layout &layout, db::NetTracerData &data);
void trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView &cv, bool flat);
lay::LayoutViewBase *view ()
diff --git a/src/pymod/unit_tests/pymod_tests.cc b/src/pymod/unit_tests/pymod_tests.cc
index d523dd344..7ec39f7af 100644
--- a/src/pymod/unit_tests/pymod_tests.cc
+++ b/src/pymod/unit_tests/pymod_tests.cc
@@ -32,19 +32,12 @@
#include "tlUnitTest.h"
#include "tlStream.h"
+#include "tlEnv.h"
int run_pymodtest (tl::TestBase *_this, const std::string &fn)
{
- static std::string pypath;
- if (pypath.empty ()) {
- pypath = "PYTHONPATH=";
- pypath += STRINGIFY (PYTHONPATH);
- }
-#if defined(_WIN32)
- _putenv (const_cast (pypath.c_str ()));
-#else
- putenv (const_cast (pypath.c_str ()));
-#endif
+ std::string pypath = STRINGIFY (PYTHONPATH);
+ tl::set_env ("PYTHONPATH", pypath);
tl::info << pypath;
std::string fp (tl::testdata ());
diff --git a/src/rba/unit_tests/rbaTests.cc b/src/rba/unit_tests/rbaTests.cc
index ec0fcb24a..b5c5f4162 100644
--- a/src/rba/unit_tests/rbaTests.cc
+++ b/src/rba/unit_tests/rbaTests.cc
@@ -137,6 +137,7 @@ RUBYTEST (dbTilingProcessorTest, "dbTilingProcessorTest.rb")
RUBYTEST (dbTransTest, "dbTransTest.rb")
RUBYTEST (dbVectorTest, "dbVectorTest.rb")
RUBYTEST (dbUtilsTests, "dbUtilsTests.rb")
+RUBYTEST (dbTechnologies, "dbTechnologies.rb")
RUBYTEST (edtTest, "edtTest.rb")
RUBYTEST (extNetTracer, "extNetTracer.rb")
RUBYTEST (imgObject, "imgObject.rb")
@@ -147,7 +148,6 @@ RUBYTEST (layMacro, "layMacro.rb")
RUBYTEST (layMenuTest, "layMenuTest.rb")
RUBYTEST (layPixelBuffer, "layPixelBuffer.rb")
RUBYTEST (laySession, "laySession.rb")
-RUBYTEST (layTechnologies, "layTechnologies.rb")
RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb")
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
RUBYTEST (qtbinding, "qtbinding.rb")
diff --git a/src/tl/tl/tlEnv.cc b/src/tl/tl/tlEnv.cc
index ffd779ddd..b5aa647bb 100644
--- a/src/tl/tl/tlEnv.cc
+++ b/src/tl/tl/tlEnv.cc
@@ -23,6 +23,7 @@
#include "tlEnv.h"
#include "tlString.h"
+#include "tlThreads.h"
#include
@@ -38,8 +39,17 @@
namespace tl
{
+static tl::Mutex *s_env_lock = 0;
+static std::map s_env_map;
+
std::string get_env (const std::string &name, const std::string &def_value)
{
+ if (! s_env_lock) {
+ s_env_lock = new tl::Mutex ();
+ }
+
+ tl::MutexLocker env_locker (s_env_lock);
+
#ifdef _WIN32
std::wstring wname = tl::to_wstring (name);
wchar_t *env = _wgetenv (wname.c_str ());
@@ -58,8 +68,54 @@ std::string get_env (const std::string &name, const std::string &def_value)
#endif
}
+void set_env (const std::string &name, const std::string &value)
+{
+ if (! s_env_lock) {
+ s_env_lock = new tl::Mutex ();
+ }
+
+ tl::MutexLocker env_locker (s_env_lock);
+
+ s_env_map [name] = name + "=" + value;
+ const std::string &s = s_env_map [name];
+
+#if defined(_WIN32)
+ _putenv (const_cast (s.c_str ()));
+#else
+ putenv (const_cast (s.c_str ()));
+#endif
+}
+
+void unset_env (const std::string &name)
+{
+ if (! s_env_lock) {
+ s_env_lock = new tl::Mutex ();
+ }
+
+ tl::MutexLocker env_locker (s_env_lock);
+
+#if defined(_WIN32)
+ s_env_map [name] = name + "=";
+#else
+ s_env_map [name] = name;
+#endif
+ const std::string &s = s_env_map [name];
+
+#if defined(_WIN32)
+ _putenv (const_cast (s.c_str ()));
+#else
+ putenv (const_cast (s.c_str ()));
+#endif
+}
+
bool has_env (const std::string &name)
{
+ if (! s_env_lock) {
+ s_env_lock = new tl::Mutex ();
+ }
+
+ tl::MutexLocker env_locker (s_env_lock);
+
#ifdef _WIN32
std::wstring wname = tl::to_wstring (name);
wchar_t *env = _wgetenv (wname.c_str ());
diff --git a/src/tl/tl/tlEnv.h b/src/tl/tl/tlEnv.h
index 454b68bd8..ca17fdd30 100644
--- a/src/tl/tl/tlEnv.h
+++ b/src/tl/tl/tlEnv.h
@@ -38,6 +38,16 @@ namespace tl
*/
std::string TL_PUBLIC get_env (const std::string &name, const std::string &def_value = std::string ());
+/**
+ * @brief Sets the value for the given environment variable
+ */
+void TL_PUBLIC set_env (const std::string &name, const std::string &value);
+
+/**
+ * @brief Removes the given environment variable
+ */
+void TL_PUBLIC unset_env (const std::string &name);
+
/**
* @brief Gets the value if the given environment variable is set
*/
diff --git a/src/tl/tl/tlGit.cc b/src/tl/tl/tlGit.cc
index 851e8fcd1..118b1d188 100644
--- a/src/tl/tl/tlGit.cc
+++ b/src/tl/tl/tlGit.cc
@@ -27,6 +27,7 @@
#include "tlProgress.h"
#include "tlStaticObjects.h"
#include "tlLog.h"
+#include "tlEnv.h"
#include
#include
@@ -314,6 +315,16 @@ GitObject::read (const std::string &org_url, const std::string &org_filter, cons
fetch_opts.callbacks.credentials = &credentials_cb;
fetch_opts.callbacks.payload = (void *) &progress;
+ // get proxy configuration from environment variable if available
+ // (see https://www.klayout.de/forum/discussion/2404)
+
+ std::string http_proxy = tl::get_env ("KLAYOUT_GIT_HTTP_PROXY");
+
+ if (! http_proxy.empty ()) {
+ fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED;
+ fetch_opts.proxy_opts.url = http_proxy.c_str ();
+ }
+
// build refspecs in case they are needed
char *refs[] = { (char *) branch.c_str () };
diff --git a/src/tl/unit_tests/tlEnvTests.cc b/src/tl/unit_tests/tlEnvTests.cc
new file mode 100644
index 000000000..46a0f0364
--- /dev/null
+++ b/src/tl/unit_tests/tlEnvTests.cc
@@ -0,0 +1,45 @@
+
+/*
+
+ KLayout Layout Viewer
+ Copyright (C) 2006-2023 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 "tlEnv.h"
+#include "tlUnitTest.h"
+
+const char *dne_name = "__DOES_NOT_EXIST__";
+
+TEST(1)
+{
+ EXPECT_EQ (tl::has_env (dne_name), false);
+
+ tl::set_env (dne_name, "123");
+ EXPECT_EQ (tl::has_env (dne_name), true);
+
+ EXPECT_EQ (tl::get_env (dne_name), "123");
+
+ tl::set_env (dne_name, "42");
+ EXPECT_EQ (tl::has_env (dne_name), true);
+
+ EXPECT_EQ (tl::get_env (dne_name), "42");
+
+ tl::unset_env (dne_name);
+ EXPECT_EQ (tl::get_env (dne_name, "bla"), "bla");
+ EXPECT_EQ (tl::has_env (dne_name), false);
+}
diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro
index 2e0bab909..0e4bcc449 100644
--- a/src/tl/unit_tests/unit_tests.pro
+++ b/src/tl/unit_tests/unit_tests.pro
@@ -16,6 +16,7 @@ SOURCES = \
tlDataMappingTests.cc \
tlDeferredExecutionTests.cc \
tlDeflateTests.cc \
+ tlEnvTests.cc \
tlEventsTests.cc \
tlExpressionTests.cc \
tlFileSystemWatcherTests.cc \
diff --git a/testdata/algo/cheats.gds b/testdata/algo/cheats.gds
new file mode 100644
index 000000000..4563489f9
Binary files /dev/null and b/testdata/algo/cheats.gds differ
diff --git a/testdata/algo/cheats_au.gds b/testdata/algo/cheats_au.gds
new file mode 100644
index 000000000..a55ec86c5
Binary files /dev/null and b/testdata/algo/cheats_au.gds differ
diff --git a/testdata/algo/cheats_edges_au.gds b/testdata/algo/cheats_edges_au.gds
new file mode 100644
index 000000000..cf9f6e068
Binary files /dev/null and b/testdata/algo/cheats_edges_au.gds differ
diff --git a/testdata/drc/cheats.gds b/testdata/drc/cheats.gds
new file mode 100644
index 000000000..4563489f9
Binary files /dev/null and b/testdata/drc/cheats.gds differ
diff --git a/testdata/ruby/dbEdgePairTest.rb b/testdata/ruby/dbEdgePairTest.rb
index 7e6502495..3fa8c757f 100644
--- a/testdata/ruby/dbEdgePairTest.rb
+++ b/testdata/ruby/dbEdgePairTest.rb
@@ -61,6 +61,7 @@ class DBEdgePair_TestClass < TestBase
ep = RBA::EdgePair::new(RBA::Edge::new(0, 0, 10, 0), RBA::Edge::new(0, 20, 0, 0))
+ assert_equal(ep.distance, 0)
assert_equal(ep.perimeter, 30)
assert_equal(ep.area, 100)
assert_equal(ep.simple_polygon(0).area, 100)
@@ -71,6 +72,10 @@ class DBEdgePair_TestClass < TestBase
assert_equal(ep.area, 0)
assert_equal(ep.simple_polygon(0).area, 0)
+ ep = RBA::EdgePair::new(RBA::Edge::new(0, 0, 10, 0), RBA::Edge::new(-10, 10, 20, 10))
+
+ assert_equal(ep.distance, 10)
+
end
# Basics
@@ -108,6 +113,7 @@ class DBEdgePair_TestClass < TestBase
ep = RBA::DEdgePair::new(RBA::DEdge::new(0, 0, 10, 0), RBA::DEdge::new(0, 20, 0, 0))
+ assert_equal(ep.distance, 0)
assert_equal(ep.perimeter, 30)
assert_equal(ep.area, 100)
assert_equal(ep.simple_polygon(0).area, 100)
@@ -118,6 +124,10 @@ class DBEdgePair_TestClass < TestBase
assert_equal(ep.area, 0)
assert_equal(ep.simple_polygon(0).area, 0)
+ ep = RBA::DEdgePair::new(RBA::DEdge::new(0, 0, 10, 0), RBA::DEdge::new(-10, 10, 20, 10))
+
+ assert_equal(ep.distance, 10)
+
end
# Fuzzy compare
diff --git a/testdata/ruby/dbEdgeTest.rb b/testdata/ruby/dbEdgeTest.rb
index c6edc7fe8..ee0c81a5e 100644
--- a/testdata/ruby/dbEdgeTest.rb
+++ b/testdata/ruby/dbEdgeTest.rb
@@ -111,6 +111,9 @@ class DBEdge_TestClass < TestBase
assert_equal( a.intersect?( RBA::DEdge::new( -1, 11, 1, 15 ) ), false )
assert_equal( a.distance( RBA::DPoint::new( 3, 3 ) ), 1.0 )
assert_equal( a.distance( RBA::DPoint::new( 3, 1 ) ), -1.0 )
+ assert_equal( a.euclidian_distance( RBA::DPoint::new( 3, 3 ) ), 1.0 )
+ assert_equal( a.euclidian_distance( RBA::DPoint::new( 3, 1 ) ), 1.0 )
+ assert_equal( a.euclidian_distance( RBA::DPoint::new( -3, 2 ) ), 1.0 )
assert_equal( a.distance_abs( RBA::DPoint::new( 3, 3 ) ), 1.0 )
assert_equal( a.distance_abs( RBA::DPoint::new( 3, 1 ) ), 1.0 )
assert_equal( a.side_of( RBA::DPoint::new( 3, 3 ) ), 1 )
@@ -224,10 +227,13 @@ class DBEdge_TestClass < TestBase
assert_equal( a.intersection_point( RBA::Edge::new( RBA::Point::new( -1, -1 ), RBA::Point::new( 1, 5 ) ) ).to_s, "0,2" )
assert_equal( a.intersection_point( RBA::Edge::new( RBA::Point::new( -1, 3 ), RBA::Point::new( 1, 5 ) ) ) == nil, true )
assert_equal( a.intersect?( RBA::Edge::new( RBA::Point::new( -1, 11 ), RBA::Point::new( 1, 15 ) ) ), false )
- assert_equal( a.distance( RBA::Point::new( 3, 3 ) ), 1.0 )
- assert_equal( a.distance( RBA::Point::new( 3, 1 ) ), -1.0 )
- assert_equal( a.distance_abs( RBA::Point::new( 3, 3 ) ), 1.0 )
- assert_equal( a.distance_abs( RBA::Point::new( 3, 1 ) ), 1.0 )
+ assert_equal( a.distance( RBA::Point::new( 3, 3 ) ), 1 )
+ assert_equal( a.distance( RBA::Point::new( 3, 1 ) ), -1 )
+ assert_equal( a.euclidian_distance( RBA::Point::new( 3, 4 ) ), 2 )
+ assert_equal( a.euclidian_distance( RBA::Point::new( 3, 0 ) ), 2 )
+ assert_equal( a.euclidian_distance( RBA::Point::new( -4, 2 ) ), 2 )
+ assert_equal( a.distance_abs( RBA::Point::new( 3, 3 ) ), 1 )
+ assert_equal( a.distance_abs( RBA::Point::new( 3, 1 ) ), 1 )
assert_equal( a.side_of( RBA::Point::new( 3, 3 ) ), 1 )
assert_equal( a.side_of( RBA::Point::new( 3, 1 ) ), -1 )
diff --git a/testdata/ruby/layTechnologies.rb b/testdata/ruby/dbTechnologies.rb
similarity index 95%
rename from testdata/ruby/layTechnologies.rb
rename to testdata/ruby/dbTechnologies.rb
index 29ab17734..d4f6e9a66 100644
--- a/testdata/ruby/layTechnologies.rb
+++ b/testdata/ruby/dbTechnologies.rb
@@ -73,6 +73,16 @@ END
RBA::Technology::remove_technology("MINE2")
assert_equal(RBA::Technology::technology_names.inspect, '[""]')
+ # registration
+ tech = RBA::Technology::new
+ tech.name = "NEW"
+ tech.dbu = 0.5
+ tech_new = RBA::Technology::register_technology(tech)
+ tech._destroy
+ assert_equal(RBA::Technology::technology_names.inspect, '["", "NEW"]')
+ assert_equal(tech_new.dbu, 0.5)
+ assert_equal(tech_new.name, "NEW")
+
end
def test_2