mirror of https://github.com/KLayout/klayout.git
Merge remote-tracking branch 'origin/master' into feature/issue-2337
This commit is contained in:
commit
4afe2e5e8a
|
|
@ -66,7 +66,7 @@ jobs:
|
||||||
mkdir -p $HOST_CCACHE_DIR
|
mkdir -p $HOST_CCACHE_DIR
|
||||||
- name: Build wheels (ARM)
|
- name: Build wheels (ARM)
|
||||||
if: matrix.os == 'ubuntu-24.04-arm'
|
if: matrix.os == 'ubuntu-24.04-arm'
|
||||||
uses: pypa/cibuildwheel@v3.4.0
|
uses: pypa/cibuildwheel@v3.4.1
|
||||||
env:
|
env:
|
||||||
# override the default CentOS “yum install … ccache” and drop ccache
|
# override the default CentOS “yum install … ccache” and drop ccache
|
||||||
CIBW_BEFORE_ALL_LINUX: |
|
CIBW_BEFORE_ALL_LINUX: |
|
||||||
|
|
@ -81,7 +81,7 @@ jobs:
|
||||||
|
|
||||||
- name: Build wheels (all other platforms)
|
- name: Build wheels (all other platforms)
|
||||||
if: matrix.os != 'ubuntu-24.04-arm'
|
if: matrix.os != 'ubuntu-24.04-arm'
|
||||||
uses: pypa/cibuildwheel@v3.4.0
|
uses: pypa/cibuildwheel@v3.4.1
|
||||||
env:
|
env:
|
||||||
CIBW_BUILD: ${{ matrix.cibuild }}
|
CIBW_BUILD: ${{ matrix.cibuild }}
|
||||||
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
|
CIBW_ARCHS_MACOS: ${{ matrix.macos-arch }}
|
||||||
|
|
@ -127,7 +127,7 @@ jobs:
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
- uses: pypa/gh-action-pypi-publish@v1.13.0
|
- uses: pypa/gh-action-pypi-publish@v1.14.0
|
||||||
continue-on-error: true # might fail if we don't bump the version
|
continue-on-error: true # might fail if we don't bump the version
|
||||||
with:
|
with:
|
||||||
user: __token__
|
user: __token__
|
||||||
|
|
@ -144,7 +144,7 @@ jobs:
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
- uses: pypa/gh-action-pypi-publish@v1.13.0
|
- uses: pypa/gh-action-pypi-publish@v1.14.0
|
||||||
with:
|
with:
|
||||||
user: __token__
|
user: __token__
|
||||||
password: ${{ secrets.pypi_password }}
|
password: ${{ secrets.pypi_password }}
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,7 @@ RubyTahoe = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions
|
||||||
# install with 'sudo port install ruby34'
|
# install with 'sudo port install ruby34'
|
||||||
# [Key Type Name] = 'MP34'
|
# [Key Type Name] = 'MP34'
|
||||||
Ruby34MacPorts = { 'exe': '/opt/local/bin/ruby3.4',
|
Ruby34MacPorts = { 'exe': '/opt/local/bin/ruby3.4',
|
||||||
'inc': '/opt/local/include/ruby-3.4.8',
|
'inc': '/opt/local/include/ruby-3.4.9',
|
||||||
'lib': '/opt/local/lib/libruby.3.4.dylib'
|
'lib': '/opt/local/lib/libruby.3.4.dylib'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -567,8 +567,8 @@ if _have_Homebrew_Python:
|
||||||
# [4] KLayout executables including buddy tools
|
# [4] KLayout executables including buddy tools
|
||||||
#-----------------------------------------------------
|
#-----------------------------------------------------
|
||||||
KLayoutExecs = [ 'klayout' ]
|
KLayoutExecs = [ 'klayout' ]
|
||||||
KLayoutExecs += [ 'strm2cif', 'strm2dxf', 'strm2gds', 'strm2gdstxt', 'strm2mag', 'strm2oas' ]
|
KLayoutExecs += [ 'strm2cif', 'strm2dxf', 'strm2gds', 'strm2gdstxt', 'strm2lstr', 'strm2mag' ]
|
||||||
KLayoutExecs += [ 'strm2txt', 'strmclip', 'strmcmp', 'strmrun', 'strmxor' ]
|
KLayoutExecs += [ 'strm2oas', 'strm2txt', 'strmclip', 'strmcmp', 'strmrun', 'strmxor' ]
|
||||||
|
|
||||||
#----------------
|
#----------------
|
||||||
# End of File
|
# End of File
|
||||||
|
|
|
||||||
|
|
@ -1541,6 +1541,19 @@ Service::begin_move (lay::Editable::MoveMode mode, const db::DPoint &p, lay::ang
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int snap_prio (lay::PointSnapToObjectResult::ObjectSnap os)
|
||||||
|
{
|
||||||
|
if (os == lay::PointSnapToObjectResult::ObjectVertex) {
|
||||||
|
return 3;
|
||||||
|
} else if (os == lay::PointSnapToObjectResult::ObjectEdge) {
|
||||||
|
return 2;
|
||||||
|
} else if (os == lay::PointSnapToObjectResult::ObjectUnspecific) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Service::snap_rulers (lay::angle_constraint_type ac)
|
Service::snap_rulers (lay::angle_constraint_type ac)
|
||||||
{
|
{
|
||||||
|
|
@ -1566,7 +1579,7 @@ Service::snap_rulers (lay::angle_constraint_type ac)
|
||||||
auto snp = snap2_details (org1, p1, ruler, ac);
|
auto snp = snap2_details (org1, p1, ruler, ac);
|
||||||
double dist = p1.distance (snp.snapped_point);
|
double dist = p1.distance (snp.snapped_point);
|
||||||
|
|
||||||
if (min_dist < 0 || dist < min_dist) {
|
if (min_dist < 0 || snap_prio (snp.object_snap) > snap_prio (min_snp.object_snap) || (snap_prio (snp.object_snap) == snap_prio (min_snp.object_snap) && dist < min_dist)) {
|
||||||
min_snp = snp;
|
min_snp = snp;
|
||||||
min_dist = dist;
|
min_dist = dist;
|
||||||
min_delta = snp.snapped_point - p1;
|
min_delta = snp.snapped_point - p1;
|
||||||
|
|
@ -1575,7 +1588,7 @@ Service::snap_rulers (lay::angle_constraint_type ac)
|
||||||
snp = snap2_details (org2, p2, ruler, ac);
|
snp = snap2_details (org2, p2, ruler, ac);
|
||||||
dist = p2.distance (snp.snapped_point);
|
dist = p2.distance (snp.snapped_point);
|
||||||
|
|
||||||
if (min_dist < 0 || dist < min_dist) {
|
if (min_dist < 0 || snap_prio (snp.object_snap) > snap_prio (min_snp.object_snap) || (snap_prio (snp.object_snap) == snap_prio (min_snp.object_snap) && dist < min_dist)) {
|
||||||
min_snp = snp;
|
min_snp = snp;
|
||||||
min_dist = dist;
|
min_dist = dist;
|
||||||
min_delta = snp.snapped_point - p2;
|
min_delta = snp.snapped_point - p2;
|
||||||
|
|
@ -1631,10 +1644,10 @@ Service::move (const db::DPoint &p, lay::angle_constraint_type ac)
|
||||||
|
|
||||||
m_trans = db::DTrans (dp + (m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1);
|
m_trans = db::DTrans (dp + (m_p1 - db::DPoint ()) - m_trans.disp ()) * m_trans * db::DTrans (db::DPoint () - m_p1);
|
||||||
|
|
||||||
propose_move_transformation (m_trans, 1);
|
|
||||||
|
|
||||||
snap_rulers (ac_eff);
|
snap_rulers (ac_eff);
|
||||||
|
|
||||||
|
propose_move_transformation (m_trans, 1);
|
||||||
|
|
||||||
for (std::vector<ant::View *>::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
|
for (std::vector<ant::View *>::iterator r = m_rulers.begin (); r != m_rulers.end (); ++r) {
|
||||||
(*r)->transform_by (db::DCplxTrans (m_trans));
|
(*r)->transform_by (db::DCplxTrans (m_trans));
|
||||||
}
|
}
|
||||||
|
|
@ -1834,6 +1847,7 @@ Service::edit_cancel ()
|
||||||
m_move_mode = MoveNone;
|
m_move_mode = MoveNone;
|
||||||
m_selected.clear ();
|
m_selected.clear ();
|
||||||
selection_to_view ();
|
selection_to_view ();
|
||||||
|
clear_mouse_cursors ();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,13 @@ EdgePairs::EdgePairs (DeepShapeStore &dss)
|
||||||
mp_delegate = new DeepEdgePairs (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
mp_delegate = new DeepEdgePairs (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EdgePairs::convert_to_deep (const db::DeepLayer &layer)
|
||||||
|
{
|
||||||
|
tl_assert (mp_delegate->deep () == 0);
|
||||||
|
set_delegate (copy_data_id (new db::DeepEdgePairs (layer)));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EdgePairs::write (const std::string &fn) const
|
EdgePairs::write (const std::string &fn) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,11 @@ public:
|
||||||
*/
|
*/
|
||||||
explicit EdgePairs (DeepShapeStore &dss);
|
explicit EdgePairs (DeepShapeStore &dss);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts the shape collection to a deep one using the specified layer
|
||||||
|
*/
|
||||||
|
virtual void convert_to_deep (const db::DeepLayer &layer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Writes the edge pair collection to a file
|
* @brief Writes the edge pair collection to a file
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,13 @@ Edges::Edges (DeepShapeStore &dss)
|
||||||
mp_delegate = new DeepEdges (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
mp_delegate = new DeepEdges (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Edges::convert_to_deep (const db::DeepLayer &layer)
|
||||||
|
{
|
||||||
|
tl_assert (mp_delegate->deep () == 0);
|
||||||
|
set_delegate (copy_data_id (new db::DeepEdges (layer)));
|
||||||
|
}
|
||||||
|
|
||||||
const db::RecursiveShapeIterator &
|
const db::RecursiveShapeIterator &
|
||||||
Edges::iter () const
|
Edges::iter () const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,11 @@ public:
|
||||||
*/
|
*/
|
||||||
explicit Edges (DeepShapeStore &dss);
|
explicit Edges (DeepShapeStore &dss);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts the shape collection to a deep one using the specified layer
|
||||||
|
*/
|
||||||
|
virtual void convert_to_deep (const db::DeepLayer &layer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the ShapeCollection interface
|
* @brief Implementation of the ShapeCollection interface
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,7 @@ copy_or_propagate_shapes (db::Layout &target,
|
||||||
|
|
||||||
db::Cell &target_cell = target.cell (cm->second);
|
db::Cell &target_cell = target.cell (cm->second);
|
||||||
transformer->insert_transformed (target_cell.shapes (target_layer), source_cell.shapes (source_layer), trans * propagate_trans);
|
transformer->insert_transformed (target_cell.shapes (target_layer), source_cell.shapes (source_layer), trans * propagate_trans);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,11 @@ LibraryProxy::update (db::ImportLayerMapping *layer_mapping)
|
||||||
|
|
||||||
inst.transform_into (db::ICplxTrans (lib->layout ().dbu () / layout ()->dbu ()));
|
inst.transform_into (db::ICplxTrans (lib->layout ().dbu () / layout ()->dbu ()));
|
||||||
|
|
||||||
insert (inst);
|
if (i->has_prop_id ()) {
|
||||||
|
insert (db::CellInstArrayWithProperties (inst, i->prop_id ()));
|
||||||
|
} else {
|
||||||
|
insert (inst);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,10 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo
|
||||||
|
|
||||||
std::pair<bool, db::DeepLayer> alias = dss.layer_for_flat (tl::id_of (l->second->get_delegate ()));
|
std::pair<bool, db::DeepLayer> alias = dss.layer_for_flat (tl::id_of (l->second->get_delegate ()));
|
||||||
if (alias.first) {
|
if (alias.first) {
|
||||||
// use deep layer alias for a given flat one (if found)
|
// use deep layer alias for a given flat one (if found) and convert layer to a deep one
|
||||||
layers.push_back (alias.second.layer ());
|
db::DeepLayer dl = alias.second;
|
||||||
|
l->second->convert_to_deep (dl);
|
||||||
|
layers.push_back (dl.layer ());
|
||||||
} else {
|
} else {
|
||||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction (device %s): must be of deep region kind")), ld->name, name ()));
|
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction (device %s): must be of deep region kind")), ld->name, name ()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1581,7 +1581,7 @@ public:
|
||||||
void translate (const polygon<C> &d, const T &t, db::generic_repository<C> &, db::ArrayRepository &)
|
void translate (const polygon<C> &d, const T &t, db::generic_repository<C> &, db::ArrayRepository &)
|
||||||
{
|
{
|
||||||
*this = d;
|
*this = d;
|
||||||
transform (t);
|
transform (t, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,13 @@ Region::Region (DeepShapeStore &dss)
|
||||||
mp_delegate = new db::DeepRegion (db::DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
mp_delegate = new db::DeepRegion (db::DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Region::convert_to_deep (const db::DeepLayer &layer)
|
||||||
|
{
|
||||||
|
tl_assert (mp_delegate->deep () == 0);
|
||||||
|
set_delegate (copy_data_id (new db::DeepRegion (layer)));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Region::write (const std::string &fn) const
|
Region::write (const std::string &fn) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void write (const std::string &fn) const;
|
void write (const std::string &fn) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts the shape collection to a deep one using the specified layer
|
||||||
|
*/
|
||||||
|
virtual void convert_to_deep (const db::DeepLayer &layer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the ShapeCollection interface
|
* @brief Implementation of the ShapeCollection interface
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,12 @@ class DB_PUBLIC ShapeCollectionDelegateBase
|
||||||
: public tl::UniqueId
|
: public tl::UniqueId
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ShapeCollectionDelegateBase () { }
|
ShapeCollectionDelegateBase ()
|
||||||
|
: m_data_id (tl::id_of (this))
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~ShapeCollectionDelegateBase () { }
|
virtual ~ShapeCollectionDelegateBase () { }
|
||||||
|
|
||||||
virtual DeepShapeCollectionDelegateBase *deep () { return 0; }
|
virtual DeepShapeCollectionDelegateBase *deep () { return 0; }
|
||||||
|
|
@ -88,6 +93,22 @@ public:
|
||||||
apply_property_translator (db::PropertiesTranslator::make_remove_all ());
|
apply_property_translator (db::PropertiesTranslator::make_remove_all ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tl::id_type data_id () const
|
||||||
|
{
|
||||||
|
return m_data_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ShapeCollection;
|
||||||
|
|
||||||
|
tl::id_type m_data_id;
|
||||||
|
|
||||||
|
// used for conversion to deep
|
||||||
|
void set_data_id (tl::id_type data_id)
|
||||||
|
{
|
||||||
|
m_data_id = data_id;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -102,6 +123,11 @@ public:
|
||||||
|
|
||||||
virtual ShapeCollectionDelegateBase *get_delegate () const = 0;
|
virtual ShapeCollectionDelegateBase *get_delegate () const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts the shape collection to a deep one using the specified layer
|
||||||
|
*/
|
||||||
|
virtual void convert_to_deep (const db::DeepLayer &layer) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Applies a PropertyTranslator
|
* @brief Applies a PropertyTranslator
|
||||||
*
|
*
|
||||||
|
|
@ -111,6 +137,14 @@ public:
|
||||||
* delivered by "properties_repository".
|
* delivered by "properties_repository".
|
||||||
*/
|
*/
|
||||||
void apply_property_translator (const db::PropertiesTranslator &pt);
|
void apply_property_translator (const db::PropertiesTranslator &pt);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <class Delegate>
|
||||||
|
Delegate *copy_data_id (Delegate *dlg)
|
||||||
|
{
|
||||||
|
dlg->set_data_id (get_delegate ()->data_id ());
|
||||||
|
return dlg;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,13 @@ Texts::Texts (DeepShapeStore &dss)
|
||||||
mp_delegate = new DeepTexts (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
mp_delegate = new DeepTexts (DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Texts::convert_to_deep (const db::DeepLayer &layer)
|
||||||
|
{
|
||||||
|
tl_assert (mp_delegate->deep () == 0);
|
||||||
|
set_delegate (copy_data_id (new db::DeepTexts (layer)));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Texts::write (const std::string &fn) const
|
Texts::write (const std::string &fn) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void write (const std::string &fn) const;
|
void write (const std::string &fn) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts the shape collection to a deep one using the specified layer
|
||||||
|
*/
|
||||||
|
virtual void convert_to_deep (const db::DeepLayer &layer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Implementation of the ShapeCollection interface
|
* @brief Implementation of the ShapeCollection interface
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -630,9 +630,9 @@ static bool is_deep (const db::EdgePairs *ep)
|
||||||
return dynamic_cast<const db::DeepEdgePairs *> (ep->delegate ()) != 0;
|
return dynamic_cast<const db::DeepEdgePairs *> (ep->delegate ()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t id (const db::EdgePairs *ep)
|
static size_t data_id (const db::EdgePairs *ep)
|
||||||
{
|
{
|
||||||
return tl::id_of (ep->delegate ());
|
return ep->delegate ()->data_id ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::EdgePairs filtered (const db::EdgePairs *r, const gsi::EdgePairFilterBase *f)
|
static db::EdgePairs filtered (const db::EdgePairs *r, const gsi::EdgePairFilterBase *f)
|
||||||
|
|
@ -1114,7 +1114,7 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.26."
|
"This method has been added in version 0.26."
|
||||||
) +
|
) +
|
||||||
method_ext ("data_id", &id,
|
method_ext ("data_id", &data_id,
|
||||||
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.26."
|
"This method has been added in version 0.26."
|
||||||
|
|
|
||||||
|
|
@ -892,9 +892,9 @@ static db::Edges *new_texts_as_dots2 (const db::RecursiveShapeIterator &si, db::
|
||||||
return new db::Edges (db::Region (si).texts_as_dots (pat, pattern, dss));
|
return new db::Edges (db::Region (si).texts_as_dots (pat, pattern, dss));
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t id (const db::Edges *e)
|
static size_t data_id (const db::Edges *e)
|
||||||
{
|
{
|
||||||
return tl::id_of (e->delegate ());
|
return e->delegate ()->data_id ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<db::Edges> andnot_with_edges (const db::Edges *r, const db::Edges &other)
|
static std::vector<db::Edges> andnot_with_edges (const db::Edges *r, const db::Edges &other)
|
||||||
|
|
@ -2572,7 +2572,7 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.26."
|
"This method has been added in version 0.26."
|
||||||
) +
|
) +
|
||||||
method_ext ("data_id", &id,
|
method_ext ("data_id", &data_id,
|
||||||
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.26."
|
"This method has been added in version 0.26."
|
||||||
|
|
|
||||||
|
|
@ -1288,9 +1288,9 @@ static bool is_deep (const db::Region *region)
|
||||||
return dynamic_cast<const db::DeepRegion *> (region->delegate ()) != 0;
|
return dynamic_cast<const db::DeepRegion *> (region->delegate ()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t id (const db::Region *r)
|
static size_t data_id (const db::Region *r)
|
||||||
{
|
{
|
||||||
return tl::id_of (r->delegate ());
|
return r->delegate ()->data_id ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -4214,7 +4214,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.26."
|
"This method has been added in version 0.26."
|
||||||
) +
|
) +
|
||||||
method_ext ("data_id", &id,
|
method_ext ("data_id", &data_id,
|
||||||
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.26."
|
"This method has been added in version 0.26."
|
||||||
|
|
|
||||||
|
|
@ -477,9 +477,9 @@ static bool is_deep (const db::Texts *t)
|
||||||
return dynamic_cast<const db::DeepTexts *> (t->delegate ()) != 0;
|
return dynamic_cast<const db::DeepTexts *> (t->delegate ()) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t id (const db::Texts *t)
|
static size_t data_id (const db::Texts *t)
|
||||||
{
|
{
|
||||||
return tl::id_of (t->delegate ());
|
return t->delegate ()->data_id ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static db::Texts filtered (const db::Texts *r, const gsi::TextFilterBase *f)
|
static db::Texts filtered (const db::Texts *r, const gsi::TextFilterBase *f)
|
||||||
|
|
@ -686,7 +686,7 @@ Class<db::Texts> decl_Texts (decl_dbShapeCollection, "db", "Texts",
|
||||||
method_ext ("is_deep?", &is_deep,
|
method_ext ("is_deep?", &is_deep,
|
||||||
"@brief Returns true if the edge pair collection is a deep (hierarchical) one\n"
|
"@brief Returns true if the edge pair collection is a deep (hierarchical) one\n"
|
||||||
) +
|
) +
|
||||||
method_ext ("data_id", &id,
|
method_ext ("data_id", &data_id,
|
||||||
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
||||||
) +
|
) +
|
||||||
method ("+|join", &db::Texts::operator+, gsi::arg ("other"),
|
method ("+|join", &db::Texts::operator+, gsi::arg ("other"),
|
||||||
|
|
|
||||||
|
|
@ -1009,3 +1009,34 @@ TEST(100_UndoOfDeleteLayer)
|
||||||
EXPECT_EQ (l.get_properties (li).to_string (), "1/0");
|
EXPECT_EQ (l.get_properties (li).to_string (), "1/0");
|
||||||
EXPECT_EQ (l.get_properties (li2).to_string (), "2/0");
|
EXPECT_EQ (l.get_properties (li2).to_string (), "2/0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// issue #2343
|
||||||
|
TEST(101_CopyTreeDoesNotModifyPolygons)
|
||||||
|
{
|
||||||
|
db::Manager m;
|
||||||
|
db::Layout l (&m);
|
||||||
|
db::Cell &top = l.cell (l.add_cell ("TOP"));
|
||||||
|
l.insert_layer (db::LayerProperties (1, 0));
|
||||||
|
|
||||||
|
std::unique_ptr<db::Layout> t (new db::Layout ());
|
||||||
|
db::Cell &ttop = t->cell (t->add_cell ("TOP"));
|
||||||
|
unsigned int tl1 = t->insert_layer (db::LayerProperties (1, 0));
|
||||||
|
|
||||||
|
std::vector<db::Point> pts = {
|
||||||
|
{ 0, 0 }, { 0, 1000 }, { 500, 1000 }, { 1500, 1000 }, { 1000, 1000 }, { 1000, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
db::Polygon poly;
|
||||||
|
poly.assign_hull (pts.begin (), pts.end (), false /*don't compress*/, false /*don't remove reflected*/);
|
||||||
|
ttop.shapes (tl1).insert (poly);
|
||||||
|
|
||||||
|
EXPECT_EQ (l2s (*t), "begin_lib 0.001\nbegin_cell {TOP}\nboundary 1 0 {0 0} {0 1000} {500 1000} {1500 1000} {1000 1000} {1000 0} {0 0}\nend_cell\nend_lib\n");
|
||||||
|
|
||||||
|
db::CellMapping cm;
|
||||||
|
cm.create_single_mapping (l, top.cell_index (), *t, ttop.cell_index ());
|
||||||
|
l.copy_tree_shapes (*t, cm);
|
||||||
|
|
||||||
|
// polygon is still not normalized
|
||||||
|
EXPECT_EQ (l2s (l), "begin_lib 0.001\nbegin_cell {TOP}\nboundary 1 0 {0 0} {0 1000} {500 1000} {1500 1000} {1000 1000} {1000 0} {0 0}\nend_cell\nend_lib\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
#include "dbTestSupport.h"
|
#include "dbTestSupport.h"
|
||||||
#include "dbFileBasedLibrary.h"
|
#include "dbFileBasedLibrary.h"
|
||||||
#include "dbColdProxy.h"
|
#include "dbColdProxy.h"
|
||||||
|
#include "dbTextWriter.h"
|
||||||
#include "tlStream.h"
|
#include "tlStream.h"
|
||||||
#include "tlStaticObjects.h"
|
#include "tlStaticObjects.h"
|
||||||
#include "tlUnitTest.h"
|
#include "tlUnitTest.h"
|
||||||
|
|
@ -861,3 +862,64 @@ TEST(7_monsterlib)
|
||||||
// but the layout did not change
|
// but the layout did not change
|
||||||
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/libman/design_au5.gds", db::NormalizationMode (db::NoNormalization | db::WithoutCellNames | db::AsPolygons));
|
db::compare_layouts (_this, layout, tl::testsrc () + "/testdata/libman/design_au5.gds", db::NormalizationMode (db::NoNormalization | db::WithoutCellNames | db::AsPolygons));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class PCellWithChildDeclaration :
|
||||||
|
public db::PCellDeclaration
|
||||||
|
{
|
||||||
|
void produce (const db::Layout &layout, const std::vector<unsigned int> & /*layer_ids*/, const db::pcell_parameters_type & /*parameters*/, db::Cell &cell) const
|
||||||
|
{
|
||||||
|
auto cid = const_cast<db::Layout &> (layout).add_cell ("CHILD");
|
||||||
|
|
||||||
|
db::PropertiesSet ps;
|
||||||
|
ps.insert ("id", tl::Variant ("my_id"));
|
||||||
|
|
||||||
|
auto ps_id = db::properties_id (ps);
|
||||||
|
cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (cid, db::Trans ()), ps_id));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string l2s (const db::Layout &layout)
|
||||||
|
{
|
||||||
|
tl::OutputStringStream os;
|
||||||
|
tl::OutputStream ostream (os);
|
||||||
|
db::TextWriter writer (ostream);
|
||||||
|
writer.write (layout);
|
||||||
|
return os.string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// PCells with subcells with properties
|
||||||
|
TEST(8_issue2344)
|
||||||
|
{
|
||||||
|
std::unique_ptr<db::Library> lib (new db::Library ());
|
||||||
|
lib->set_name ("__PCellLibrary");
|
||||||
|
lib->layout ().register_pcell ("PCell1", new PCellWithChildDeclaration ());
|
||||||
|
db::LibraryManager::instance ().register_lib (lib.get ());
|
||||||
|
|
||||||
|
db::Layout ly;
|
||||||
|
std::pair<bool, db::pcell_id_type> pc = lib->layout ().pcell_by_name ("PCell1");
|
||||||
|
tl_assert (pc.first);
|
||||||
|
|
||||||
|
db::cell_index_type lib_cell = lib->layout ().get_pcell_variant_dict (pc.second, std::map<std::string, tl::Variant> ());
|
||||||
|
ly.get_lib_proxy (lib.get (), lib_cell);
|
||||||
|
|
||||||
|
EXPECT_EQ (l2s (ly),
|
||||||
|
"begin_lib 0.001\n"
|
||||||
|
"begin_cell {CHILD}\n"
|
||||||
|
"end_cell\n"
|
||||||
|
"begin_cell {PCell1}\n"
|
||||||
|
"set props {\n"
|
||||||
|
" {{id} {my_id}}\n"
|
||||||
|
"}\n"
|
||||||
|
"srefp $props {CHILD} 0 0 1 {0 0}\n"
|
||||||
|
"end_cell\n"
|
||||||
|
"end_lib\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
db::LibraryManager::instance ().delete_lib (lib.release ());
|
||||||
|
EXPECT (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -323,7 +323,9 @@ module DRC
|
||||||
#
|
#
|
||||||
# If layers are not named, they will be given a name made from the
|
# If layers are not named, they will be given a name made from the
|
||||||
# \name_prefix and an incremental number when the layer is used for the
|
# \name_prefix and an incremental number when the layer is used for the
|
||||||
# first time.
|
# first time. As the default name prefix is "l", you may can name conflicts
|
||||||
|
# with auto-named layers, if you register explicit layer names like "l5".
|
||||||
|
# Consider changing the name prefix in that case to some prefix you are not using.
|
||||||
#
|
#
|
||||||
# \name can only be used once on a layer and the layer names must be
|
# \name can only be used once on a layer and the layer names must be
|
||||||
# unique (not taken by another layer).
|
# unique (not taken by another layer).
|
||||||
|
|
|
||||||
|
|
@ -1009,6 +1009,7 @@ Object::operator= (const img::Object &d)
|
||||||
|
|
||||||
m_trans = d.m_trans;
|
m_trans = d.m_trans;
|
||||||
m_filename = d.m_filename;
|
m_filename = d.m_filename;
|
||||||
|
m_tag = d.m_tag;
|
||||||
|
|
||||||
mp_data = d.mp_data;
|
mp_data = d.mp_data;
|
||||||
if (mp_data) {
|
if (mp_data) {
|
||||||
|
|
@ -1963,6 +1964,7 @@ void
|
||||||
Object::swap (Object &other)
|
Object::swap (Object &other)
|
||||||
{
|
{
|
||||||
m_filename.swap (other.m_filename);
|
m_filename.swap (other.m_filename);
|
||||||
|
m_tag.swap (other.m_tag);
|
||||||
std::swap (m_trans, other.m_trans);
|
std::swap (m_trans, other.m_trans);
|
||||||
std::swap (mp_data, other.mp_data);
|
std::swap (mp_data, other.mp_data);
|
||||||
std::swap (m_id, other.m_id);
|
std::swap (m_id, other.m_id);
|
||||||
|
|
@ -1979,6 +1981,12 @@ Object::swap (Object &other)
|
||||||
std::swap (m_updates_enabled, other.m_updates_enabled);
|
std::swap (m_updates_enabled, other.m_updates_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Object::set_tag (const std::string &tag)
|
||||||
|
{
|
||||||
|
m_tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
Object::width () const
|
Object::width () const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -581,6 +581,22 @@ public:
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the tag string
|
||||||
|
*
|
||||||
|
* The tag string is an arbitrary string that can be used to identify
|
||||||
|
* the image. It is not persisted and it not considered for equality or sorting.
|
||||||
|
*/
|
||||||
|
void set_tag (const std::string &tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the tag string
|
||||||
|
*/
|
||||||
|
const std::string tag () const
|
||||||
|
{
|
||||||
|
return m_tag;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Accessor to the width property
|
* @brief Accessor to the width property
|
||||||
*/
|
*/
|
||||||
|
|
@ -1036,6 +1052,7 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_filename;
|
std::string m_filename;
|
||||||
|
std::string m_tag;
|
||||||
db::Matrix3d m_trans;
|
db::Matrix3d m_trans;
|
||||||
DataHeader *mp_data;
|
DataHeader *mp_data;
|
||||||
size_t m_id;
|
size_t m_id;
|
||||||
|
|
|
||||||
|
|
@ -314,46 +314,48 @@ PropertiesPage::min_max_value_changed ()
|
||||||
emit edited ();
|
emit edited ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PropertiesPage::update_controls ()
|
||||||
|
{
|
||||||
|
bool has_error = false;
|
||||||
|
|
||||||
|
value_le->setText (QString ());
|
||||||
|
value_le->setEnabled (false);
|
||||||
|
|
||||||
|
colors->setEnabled (false_color_control->has_selection ());
|
||||||
|
colors->set_single_mode (false);
|
||||||
|
|
||||||
|
if (false_color_control->has_selection () && false_color_control->selected_node () > 0 && false_color_control->selected_node () < int (false_color_control->nodes ().size ()) - 1) {
|
||||||
|
|
||||||
|
double xmin, xmax;
|
||||||
|
get_xmin_xmax (xmin, xmax, has_error);
|
||||||
|
|
||||||
|
if (! has_error) {
|
||||||
|
|
||||||
|
double x = false_color_control->nodes () [false_color_control->selected_node ()].first;
|
||||||
|
double xx = x * (xmax - xmin) + xmin;
|
||||||
|
|
||||||
|
value_le->setText (tl::to_qstring (tl::sprintf ("%.4g", xx)));
|
||||||
|
value_le->setEnabled (true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (false_color_control->has_selection ()) {
|
||||||
|
|
||||||
|
colors->set_single_mode (true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return has_error;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PropertiesPage::color_mapping_changed ()
|
PropertiesPage::color_mapping_changed ()
|
||||||
{
|
{
|
||||||
if (! m_no_signals) {
|
if (! m_no_signals && ! update_controls ()) {
|
||||||
|
m_in_color_mapping_signal = true;
|
||||||
bool has_error = false;
|
emit edited ();
|
||||||
|
m_in_color_mapping_signal = false;
|
||||||
value_le->setText (QString ());
|
|
||||||
value_le->setEnabled (false);
|
|
||||||
|
|
||||||
colors->setEnabled (false_color_control->has_selection ());
|
|
||||||
colors->set_single_mode (false);
|
|
||||||
|
|
||||||
if (false_color_control->has_selection () && false_color_control->selected_node () > 0 && false_color_control->selected_node () < int (false_color_control->nodes ().size ()) - 1) {
|
|
||||||
|
|
||||||
double xmin, xmax;
|
|
||||||
get_xmin_xmax (xmin, xmax, has_error);
|
|
||||||
|
|
||||||
if (! has_error) {
|
|
||||||
|
|
||||||
double x = false_color_control->nodes () [false_color_control->selected_node ()].first;
|
|
||||||
double xx = x * (xmax - xmin) + xmin;
|
|
||||||
|
|
||||||
value_le->setText (tl::to_qstring (tl::sprintf ("%.4g", xx)));
|
|
||||||
value_le->setEnabled (true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (false_color_control->has_selection ()) {
|
|
||||||
|
|
||||||
colors->set_single_mode (true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! has_error) {
|
|
||||||
m_in_color_mapping_signal = true;
|
|
||||||
emit edited ();
|
|
||||||
m_in_color_mapping_signal = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -509,6 +511,7 @@ PropertiesPage::update ()
|
||||||
|
|
||||||
m_no_signals = false;
|
m_no_signals = false;
|
||||||
|
|
||||||
|
update_controls ();
|
||||||
recompute_histogram ();
|
recompute_histogram ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ private:
|
||||||
void invalidate ();
|
void invalidate ();
|
||||||
void init ();
|
void init ();
|
||||||
void get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out);
|
void get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out);
|
||||||
|
bool update_controls ();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1658,6 +1658,12 @@ GuiApplication::event (QEvent *event)
|
||||||
return QApplication::event(event);
|
return QApplication::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void atexit_handler ()
|
||||||
|
{
|
||||||
|
if (lay::ApplicationBase::instance ()) {
|
||||||
|
lay::ApplicationBase::instance ()->shutdown ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
GuiApplication::exec ()
|
GuiApplication::exec ()
|
||||||
|
|
@ -1693,6 +1699,10 @@ GuiApplication::exec ()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register an exit handler to shutdown cleanly in case of an explicit exit
|
||||||
|
// inside the code
|
||||||
|
::atexit (&atexit_handler);
|
||||||
|
|
||||||
return QApplication::exec ();
|
return QApplication::exec ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,15 @@ public:
|
||||||
*/
|
*/
|
||||||
void exit (int result);
|
void exit (int result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Shut down the application
|
||||||
|
*
|
||||||
|
* Calling this function will close the main window and
|
||||||
|
* prepare for exit. Unlike "exit", it dows not actually exit
|
||||||
|
* the process.
|
||||||
|
*/
|
||||||
|
virtual void shutdown ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return the program's version
|
* @brief Return the program's version
|
||||||
*/
|
*/
|
||||||
|
|
@ -330,7 +339,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void setup () = 0;
|
virtual void setup () = 0;
|
||||||
virtual void shutdown ();
|
|
||||||
virtual void prepare_recording (const std::string >f_record, bool gtf_record_incremental);
|
virtual void prepare_recording (const std::string >f_record, bool gtf_record_incremental);
|
||||||
virtual void start_recording ();
|
virtual void start_recording ();
|
||||||
virtual lay::Dispatcher *dispatcher () const = 0;
|
virtual lay::Dispatcher *dispatcher () const = 0;
|
||||||
|
|
|
||||||
|
|
@ -168,12 +168,14 @@ BEGIN_PROTECTED
|
||||||
|
|
||||||
} else if (rb_shapes->isChecked ()) {
|
} else if (rb_shapes->isChecked ()) {
|
||||||
|
|
||||||
|
lay::CellView ccv = view ()->cellview (cb_layer->cv_index ());
|
||||||
int sel_layer = cb_layer->current_layer ();
|
int sel_layer = cb_layer->current_layer ();
|
||||||
if (sel_layer < 0 || ! cv->layout ().is_valid_layer (sel_layer)) {
|
|
||||||
|
if (! ccv.is_valid () || sel_layer < 0 || ! ccv->layout ().is_valid_layer (sel_layer)) {
|
||||||
throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get clip boxes from")));
|
throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get clip boxes from")));
|
||||||
}
|
}
|
||||||
|
|
||||||
db::collect_clip_boxes (cv->layout (), cv.cell_index (), (unsigned int) sel_layer, clip_boxes);
|
db::collect_clip_boxes (ccv->layout (), ccv.cell_index (), (unsigned int) sel_layer, clip_boxes);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,6 @@ show_dock_widget (QDockWidget *dock_widget, bool visible)
|
||||||
|
|
||||||
MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
|
MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
|
||||||
: QMainWindow (0),
|
: QMainWindow (0),
|
||||||
tl::Object (),
|
|
||||||
lay::DispatcherDelegate (),
|
lay::DispatcherDelegate (),
|
||||||
m_dispatcher (this),
|
m_dispatcher (this),
|
||||||
m_text_progress (this, 10 /*verbosity threshold*/),
|
m_text_progress (this, 10 /*verbosity threshold*/),
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,6 @@ class ProgressWidget;
|
||||||
*/
|
*/
|
||||||
class LAY_PUBLIC MainWindow
|
class LAY_PUBLIC MainWindow
|
||||||
: public QMainWindow,
|
: public QMainWindow,
|
||||||
public tl::Object,
|
|
||||||
public gsi::ObjectBase,
|
public gsi::ObjectBase,
|
||||||
public lay::DispatcherDelegate
|
public lay::DispatcherDelegate
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ class ConfigureAction;
|
||||||
* @brief A delegate by which the dispatcher can submit notification events
|
* @brief A delegate by which the dispatcher can submit notification events
|
||||||
*/
|
*/
|
||||||
class LAYBASIC_PUBLIC DispatcherDelegate
|
class LAYBASIC_PUBLIC DispatcherDelegate
|
||||||
|
: public tl::Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
@ -271,7 +272,7 @@ private:
|
||||||
#if defined(HAVE_QT)
|
#if defined(HAVE_QT)
|
||||||
QWidget *mp_menu_parent_widget;
|
QWidget *mp_menu_parent_widget;
|
||||||
#endif
|
#endif
|
||||||
DispatcherDelegate *mp_delegate;
|
tl::weak_ptr<DispatcherDelegate> mp_delegate;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief Gets a value indicating whether the page is for that specific plugin (given by a declaration object)
|
* @brief Gets a value indicating whether the page is for that specific plugin (given by a declaration object)
|
||||||
*/
|
*/
|
||||||
bool for_plugin_declaration (const lay::PluginDeclaration *pd)
|
bool for_plugin_declaration (const lay::PluginDeclaration *pd) const
|
||||||
{
|
{
|
||||||
return m_plugin_declarations.find (pd) != m_plugin_declarations.end ();
|
return m_plugin_declarations.find (pd) != m_plugin_declarations.end ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -947,8 +947,10 @@ LayoutCanvas::screenshot ()
|
||||||
void
|
void
|
||||||
LayoutCanvas::resize_event (unsigned int width, unsigned int height)
|
LayoutCanvas::resize_event (unsigned int width, unsigned int height)
|
||||||
{
|
{
|
||||||
unsigned int w = width * dpr () + 0.5, h = height * dpr () + 0.5;
|
unsigned int w = (unsigned int) ceil (width * dpr () - db::epsilon);
|
||||||
unsigned int wl = width * m_oversampling * dpr () + 0.5, hl = height * m_oversampling * dpr () + 0.5;
|
unsigned int h = (unsigned int) ceil (height * dpr () - db::epsilon);
|
||||||
|
unsigned int wl = w * m_oversampling;
|
||||||
|
unsigned int hl = h * m_oversampling;
|
||||||
|
|
||||||
if (m_viewport.width () != w || m_viewport.height () != h ||
|
if (m_viewport.width () != w || m_viewport.height () != h ||
|
||||||
m_viewport_l.width () != wl || m_viewport_l.height () != hl) {
|
m_viewport_l.width () != wl || m_viewport_l.height () != hl) {
|
||||||
|
|
@ -957,8 +959,8 @@ LayoutCanvas::resize_event (unsigned int width, unsigned int height)
|
||||||
m_image_cache.clear ();
|
m_image_cache.clear ();
|
||||||
|
|
||||||
// set the viewport to the new size
|
// set the viewport to the new size
|
||||||
m_viewport.set_size (width * dpr () + 0.5, height * dpr () + 0.5);
|
m_viewport.set_size (w, h);
|
||||||
m_viewport_l.set_size (width * m_oversampling * dpr () + 0.5, height * m_oversampling * dpr () + 0.5);
|
m_viewport_l.set_size (wl, hl);
|
||||||
|
|
||||||
mouse_event_trans (db::DCplxTrans (1.0 / dpr ()) * m_viewport.trans ());
|
mouse_event_trans (db::DCplxTrans (1.0 / dpr ()) * m_viewport.trans ());
|
||||||
do_redraw_all (true);
|
do_redraw_all (true);
|
||||||
|
|
|
||||||
|
|
@ -2225,6 +2225,14 @@ public:
|
||||||
return pi;
|
return pi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the active plugin
|
||||||
|
*/
|
||||||
|
lay::Plugin *active_plugin () const
|
||||||
|
{
|
||||||
|
return mp_active_plugin;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a plugin of the given type
|
* @brief Create a plugin of the given type
|
||||||
*
|
*
|
||||||
|
|
@ -3214,11 +3222,6 @@ protected:
|
||||||
|
|
||||||
void init (db::Manager *mgr);
|
void init (db::Manager *mgr);
|
||||||
|
|
||||||
lay::Plugin *active_plugin () const
|
|
||||||
{
|
|
||||||
return mp_active_plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual LayoutView *get_ui ();
|
virtual LayoutView *get_ui ();
|
||||||
|
|
||||||
bool configure (const std::string &name, const std::string &value);
|
bool configure (const std::string &name, const std::string &value);
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,12 @@ public:
|
||||||
options.push_back (std::pair<std::string, std::string> (cfg_layers_always_show_ld, "true"));
|
options.push_back (std::pair<std::string, std::string> (cfg_layers_always_show_ld, "true"));
|
||||||
options.push_back (std::pair<std::string, std::string> (cfg_layers_always_show_layout_index, "false"));
|
options.push_back (std::pair<std::string, std::string> (cfg_layers_always_show_layout_index, "false"));
|
||||||
options.push_back (std::pair<std::string, std::string> (cfg_test_shapes_in_view, "false"));
|
options.push_back (std::pair<std::string, std::string> (cfg_test_shapes_in_view, "false"));
|
||||||
|
options.push_back (std::pair<std::string, std::string> (cfg_layer_search_as_expressions, "true"));
|
||||||
|
options.push_back (std::pair<std::string, std::string> (cfg_layer_search_as_filter, "false"));
|
||||||
|
options.push_back (std::pair<std::string, std::string> (cfg_layer_search_case_sensitive, "true"));
|
||||||
|
options.push_back (std::pair<std::string, std::string> (cfg_cell_search_as_expressions, "true"));
|
||||||
|
options.push_back (std::pair<std::string, std::string> (cfg_cell_search_as_filter, "false"));
|
||||||
|
options.push_back (std::pair<std::string, std::string> (cfg_cell_search_case_sensitive, "true"));
|
||||||
options.push_back (std::pair<std::string, std::string> (cfg_flat_cell_list, "false"));
|
options.push_back (std::pair<std::string, std::string> (cfg_flat_cell_list, "false"));
|
||||||
options.push_back (std::pair<std::string, std::string> (cfg_split_cell_list, "false"));
|
options.push_back (std::pair<std::string, std::string> (cfg_split_cell_list, "false"));
|
||||||
options.push_back (std::pair<std::string, std::string> (cfg_cell_list_sorting, "by-name"));
|
options.push_back (std::pair<std::string, std::string> (cfg_cell_list_sorting, "by-name"));
|
||||||
|
|
|
||||||
|
|
@ -437,9 +437,12 @@ MoveService::drag_cancel ()
|
||||||
{
|
{
|
||||||
m_shift = db::DPoint ();
|
m_shift = db::DPoint ();
|
||||||
if (m_dragging) {
|
if (m_dragging) {
|
||||||
|
|
||||||
show_toolbox (false);
|
show_toolbox (false);
|
||||||
ui ()->ungrab_mouse (this);
|
ui ()->ungrab_mouse (this);
|
||||||
|
|
||||||
m_dragging = false;
|
m_dragging = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -332,6 +332,14 @@ public:
|
||||||
{
|
{
|
||||||
return new SelectionService (view);
|
return new SelectionService (view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual std::vector<std::string> additional_editor_options_pages () const
|
||||||
|
{
|
||||||
|
std::vector<std::string> names;
|
||||||
|
// TODO: provide in a central place instead of borrowing from the edt module
|
||||||
|
names.push_back ("GenericEditorOptions");
|
||||||
|
return names;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static tl::RegisteredClass<lay::PluginDeclaration> selection_service_decl (new SelectionServiceDeclaration (), -980, "laybasic::SelectionServicePlugin");
|
static tl::RegisteredClass<lay::PluginDeclaration> selection_service_decl (new SelectionServiceDeclaration (), -980, "laybasic::SelectionServicePlugin");
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,13 @@ static const std::string cfg_layers_always_show_layout_index ("layers-always-sho
|
||||||
static const std::string cfg_reader_options_show_always ("reader-options-show-always");
|
static const std::string cfg_reader_options_show_always ("reader-options-show-always");
|
||||||
static const std::string cfg_tip_window_hidden ("tip-window-hidden");
|
static const std::string cfg_tip_window_hidden ("tip-window-hidden");
|
||||||
|
|
||||||
|
static const std::string cfg_layer_search_as_expressions ("layer-search-as-expressions");
|
||||||
|
static const std::string cfg_layer_search_as_filter ("layer-search-as-filter");
|
||||||
|
static const std::string cfg_layer_search_case_sensitive ("layer-search-case-sensitive");
|
||||||
|
static const std::string cfg_cell_search_as_expressions ("cell-search-as-expressions");
|
||||||
|
static const std::string cfg_cell_search_as_filter ("cell-search-as-filter");
|
||||||
|
static const std::string cfg_cell_search_case_sensitive ("cell-search-case-sensitive");
|
||||||
|
|
||||||
static const std::string cfg_bitmap_oversampling ("bitmap-oversampling");
|
static const std::string cfg_bitmap_oversampling ("bitmap-oversampling");
|
||||||
static const std::string cfg_highres_mode ("highres-mode");
|
static const std::string cfg_highres_mode ("highres-mode");
|
||||||
static const std::string cfg_subres_mode ("subres-mode");
|
static const std::string cfg_subres_mode ("subres-mode");
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ HierarchyControlPanel::HierarchyControlPanel (lay::LayoutViewBase *view, QWidget
|
||||||
mp_search_edit_box->set_escape_signal_enabled (true);
|
mp_search_edit_box->set_escape_signal_enabled (true);
|
||||||
mp_search_edit_box->set_tab_signal_enabled (true);
|
mp_search_edit_box->set_tab_signal_enabled (true);
|
||||||
connect (mp_search_edit_box, SIGNAL (returnPressed ()), this, SLOT (search_editing_finished ()));
|
connect (mp_search_edit_box, SIGNAL (returnPressed ()), this, SLOT (search_editing_finished ()));
|
||||||
connect (mp_search_edit_box, SIGNAL (textEdited (const QString &)), this, SLOT (search_edited ()));
|
connect (mp_search_edit_box, SIGNAL (textEdited (const QString &)), this, SLOT (search_edited_no_signal ()));
|
||||||
connect (mp_search_edit_box, SIGNAL (esc_pressed ()), this, SLOT (search_editing_finished ()));
|
connect (mp_search_edit_box, SIGNAL (esc_pressed ()), this, SLOT (search_editing_finished ()));
|
||||||
connect (mp_search_edit_box, SIGNAL (tab_pressed ()), this, SLOT (search_next ()));
|
connect (mp_search_edit_box, SIGNAL (tab_pressed ()), this, SLOT (search_next ()));
|
||||||
connect (mp_search_edit_box, SIGNAL (backtab_pressed ()), this, SLOT (search_prev ()));
|
connect (mp_search_edit_box, SIGNAL (backtab_pressed ()), this, SLOT (search_prev ()));
|
||||||
|
|
@ -452,8 +452,42 @@ HierarchyControlPanel::search_triggered (const QString &t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HierarchyControlPanel::set_search_as_filter (bool f)
|
||||||
|
{
|
||||||
|
if (f != search_as_filter ()) {
|
||||||
|
mp_filter->setChecked (f);
|
||||||
|
search_edited_no_signal ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HierarchyControlPanel::set_search_case_sensitive (bool f)
|
||||||
|
{
|
||||||
|
if (f != search_case_sensitive ()) {
|
||||||
|
mp_case_sensitive->setChecked (f);
|
||||||
|
search_edited_no_signal ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HierarchyControlPanel::set_search_as_expression (bool f)
|
||||||
|
{
|
||||||
|
if (f != search_as_expression ()) {
|
||||||
|
mp_use_regular_expressions->setChecked (f);
|
||||||
|
search_edited_no_signal ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
HierarchyControlPanel::search_edited ()
|
HierarchyControlPanel::search_edited ()
|
||||||
|
{
|
||||||
|
search_edited_no_signal ();
|
||||||
|
emit search_options_changed ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
HierarchyControlPanel::search_edited_no_signal ()
|
||||||
{
|
{
|
||||||
bool filter_invalid = false;
|
bool filter_invalid = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,52 @@ public:
|
||||||
return m_active_index;
|
return m_active_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the "as_filter" flag for the search feature
|
||||||
|
*
|
||||||
|
* If this flag is set, search expressions are applied as filter
|
||||||
|
*/
|
||||||
|
void set_search_as_filter (bool f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the "search_as_filter" flag
|
||||||
|
*/
|
||||||
|
bool search_as_filter ()
|
||||||
|
{
|
||||||
|
return mp_filter->isChecked ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the "case_sensitive" flag for the search feature
|
||||||
|
*
|
||||||
|
* If this flag is set, search expressions are case sensitive
|
||||||
|
*/
|
||||||
|
void set_search_case_sensitive (bool f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the "case_sensitive" flag for the search feature
|
||||||
|
*/
|
||||||
|
bool search_case_sensitive ()
|
||||||
|
{
|
||||||
|
return mp_case_sensitive->isChecked ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the "as_expression" flag for the search feature
|
||||||
|
*
|
||||||
|
* If this flag is set, search expressions are handled as glob expressions
|
||||||
|
*/
|
||||||
|
void set_search_as_expression (bool f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the "as_expression" flag for the search feature
|
||||||
|
*/
|
||||||
|
bool search_as_expression ()
|
||||||
|
{
|
||||||
|
return mp_use_regular_expressions->isChecked ();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the paths of the selected cells
|
* @brief Returns the paths of the selected cells
|
||||||
*/
|
*/
|
||||||
|
|
@ -273,6 +319,7 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void cell_selected (cell_path_type path, int cellview_index);
|
void cell_selected (cell_path_type path, int cellview_index);
|
||||||
void active_cellview_changed (int cellview_index);
|
void active_cellview_changed (int cellview_index);
|
||||||
|
void search_options_changed ();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clicked (const QModelIndex &index);
|
void clicked (const QModelIndex &index);
|
||||||
|
|
@ -283,6 +330,7 @@ public slots:
|
||||||
void context_menu (const QPoint &pt);
|
void context_menu (const QPoint &pt);
|
||||||
void search_triggered (const QString &t);
|
void search_triggered (const QString &t);
|
||||||
void search_edited ();
|
void search_edited ();
|
||||||
|
void search_edited_no_signal ();
|
||||||
void search_editing_finished ();
|
void search_editing_finished ();
|
||||||
void search_next ();
|
void search_next ();
|
||||||
void search_prev ();
|
void search_prev ();
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ LayerControlPanel::LayerControlPanel (lay::LayoutViewBase *view, db::Manager *ma
|
||||||
mp_search_edit_box->set_escape_signal_enabled (true);
|
mp_search_edit_box->set_escape_signal_enabled (true);
|
||||||
mp_search_edit_box->set_tab_signal_enabled (true);
|
mp_search_edit_box->set_tab_signal_enabled (true);
|
||||||
connect (mp_search_edit_box, SIGNAL (returnPressed ()), this, SLOT (search_editing_finished ()));
|
connect (mp_search_edit_box, SIGNAL (returnPressed ()), this, SLOT (search_editing_finished ()));
|
||||||
connect (mp_search_edit_box, SIGNAL (textEdited (const QString &)), this, SLOT (search_edited ()));
|
connect (mp_search_edit_box, SIGNAL (textEdited (const QString &)), this, SLOT (search_edited_no_signal ()));
|
||||||
connect (mp_search_edit_box, SIGNAL (esc_pressed ()), this, SLOT (search_editing_finished ()));
|
connect (mp_search_edit_box, SIGNAL (esc_pressed ()), this, SLOT (search_editing_finished ()));
|
||||||
connect (mp_search_edit_box, SIGNAL (tab_pressed ()), this, SLOT (search_next ()));
|
connect (mp_search_edit_box, SIGNAL (tab_pressed ()), this, SLOT (search_next ()));
|
||||||
connect (mp_search_edit_box, SIGNAL (backtab_pressed ()), this, SLOT (search_prev ()));
|
connect (mp_search_edit_box, SIGNAL (backtab_pressed ()), this, SLOT (search_prev ()));
|
||||||
|
|
@ -1160,12 +1160,46 @@ LayerControlPanel::search_triggered (const QString &t)
|
||||||
mp_search_frame->show ();
|
mp_search_frame->show ();
|
||||||
mp_search_edit_box->setText (t);
|
mp_search_edit_box->setText (t);
|
||||||
mp_search_edit_box->setFocus ();
|
mp_search_edit_box->setFocus ();
|
||||||
search_edited ();
|
search_edited_no_signal ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerControlPanel::set_search_as_filter (bool f)
|
||||||
|
{
|
||||||
|
if (f != search_as_filter ()) {
|
||||||
|
mp_filter->setChecked (f);
|
||||||
|
search_edited_no_signal ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerControlPanel::set_search_case_sensitive (bool f)
|
||||||
|
{
|
||||||
|
if (f != search_case_sensitive ()) {
|
||||||
|
mp_case_sensitive->setChecked (f);
|
||||||
|
search_edited_no_signal ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerControlPanel::set_search_as_expression (bool f)
|
||||||
|
{
|
||||||
|
if (f != search_as_expression ()) {
|
||||||
|
mp_use_regular_expressions->setChecked (f);
|
||||||
|
search_edited_no_signal ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerControlPanel::search_edited ()
|
LayerControlPanel::search_edited ()
|
||||||
|
{
|
||||||
|
search_edited_no_signal ();
|
||||||
|
emit search_options_changed ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayerControlPanel::search_edited_no_signal ()
|
||||||
{
|
{
|
||||||
if (! mp_model) {
|
if (! mp_model) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,51 @@ public:
|
||||||
return mp_model->get_test_shapes_in_view ();
|
return mp_model->get_test_shapes_in_view ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the "as_filter" flag for the search feature
|
||||||
|
*
|
||||||
|
* If this flag is set, search expressions are applied as filter
|
||||||
|
*/
|
||||||
|
void set_search_as_filter (bool f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the "search_as_filter" flag
|
||||||
|
*/
|
||||||
|
bool search_as_filter ()
|
||||||
|
{
|
||||||
|
return mp_filter->isChecked ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the "case_sensitive" flag for the search feature
|
||||||
|
*
|
||||||
|
* If this flag is set, search expressions are case sensitive
|
||||||
|
*/
|
||||||
|
void set_search_case_sensitive (bool f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the "case_sensitive" flag for the search feature
|
||||||
|
*/
|
||||||
|
bool search_case_sensitive ()
|
||||||
|
{
|
||||||
|
return mp_case_sensitive->isChecked ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the "as_expression" flag for the search feature
|
||||||
|
*
|
||||||
|
* If this flag is set, search expressions are handled as glob expressions
|
||||||
|
*/
|
||||||
|
void set_search_as_expression (bool f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the "as_expression" flag for the search feature
|
||||||
|
*/
|
||||||
|
bool search_as_expression ()
|
||||||
|
{
|
||||||
|
return mp_use_regular_expressions->isChecked ();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the animation phase
|
* @brief Set the animation phase
|
||||||
*/
|
*/
|
||||||
|
|
@ -297,6 +342,7 @@ signals:
|
||||||
void tab_changed ();
|
void tab_changed ();
|
||||||
void current_layer_changed (const lay::LayerPropertiesConstIterator &iter);
|
void current_layer_changed (const lay::LayerPropertiesConstIterator &iter);
|
||||||
void selected_layers_changed ();
|
void selected_layers_changed ();
|
||||||
|
void search_options_changed ();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void cm_new_tab ();
|
void cm_new_tab ();
|
||||||
|
|
@ -344,6 +390,7 @@ public slots:
|
||||||
void downdown_clicked ();
|
void downdown_clicked ();
|
||||||
void search_triggered (const QString &t);
|
void search_triggered (const QString &t);
|
||||||
void search_edited ();
|
void search_edited ();
|
||||||
|
void search_edited_no_signal ();
|
||||||
void search_editing_finished ();
|
void search_editing_finished ();
|
||||||
void search_next ();
|
void search_next ();
|
||||||
void search_prev ();
|
void search_prev ();
|
||||||
|
|
|
||||||
|
|
@ -848,6 +848,12 @@ LayerSelectionComboBox::is_no_layer_selected () const
|
||||||
return currentIndex () < 0;
|
return currentIndex () < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
LayerSelectionComboBox::cv_index () const
|
||||||
|
{
|
||||||
|
return mp_private->cv_index;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
LayerSelectionComboBox::current_layer () const
|
LayerSelectionComboBox::current_layer () const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,14 @@ public:
|
||||||
*/
|
*/
|
||||||
bool is_no_layer_selected () const;
|
bool is_no_layer_selected () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the cellview index
|
||||||
|
*
|
||||||
|
* NOTE: this methods returns -1 if the widget is not
|
||||||
|
* associated with a cellview index.
|
||||||
|
*/
|
||||||
|
int cv_index () const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the current layer (index)
|
* @brief Get the current layer (index)
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -120,8 +120,13 @@ EditorOptionsPages::editor_options_pages ()
|
||||||
bool
|
bool
|
||||||
EditorOptionsPages::has_content () const
|
EditorOptionsPages::has_content () const
|
||||||
{
|
{
|
||||||
|
lay::Plugin *plugin = mp_view->active_plugin ();
|
||||||
|
if (! plugin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
|
for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||||
if (p->active () && ! p->is_modal_page () && ! p->is_toolbox_widget ()) {
|
if (! p->is_modal_page () && ! p->is_toolbox_widget () && p->for_plugin_declaration (plugin->plugin_declaration ())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,8 +136,13 @@ EditorOptionsPages::has_content () const
|
||||||
bool
|
bool
|
||||||
EditorOptionsPages::has_modal_content () const
|
EditorOptionsPages::has_modal_content () const
|
||||||
{
|
{
|
||||||
|
lay::Plugin *plugin = mp_view->active_plugin ();
|
||||||
|
if (! plugin) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
|
for (auto p = m_pages.begin (); p != m_pages.end (); ++p) {
|
||||||
if (p->active () && p->is_modal_page () && ! p->is_toolbox_widget ()) {
|
if (p->is_modal_page () && ! p->is_toolbox_widget () && p->for_plugin_declaration (plugin->plugin_declaration ())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +183,7 @@ EditorOptionsPages::activate (const lay::Plugin *plugin)
|
||||||
bool is_active = plugin && op->for_plugin_declaration (plugin->plugin_declaration ());
|
bool is_active = plugin && op->for_plugin_declaration (plugin->plugin_declaration ());
|
||||||
|
|
||||||
// The zero order page is picked as the initial one
|
// The zero order page is picked as the initial one
|
||||||
if (is_active && ! op->active () && op->order () == 0 && page == 0) {
|
if (is_active && ! op->active () && (op->order () == 0 || page == 0)) {
|
||||||
page = op.operator-> ();
|
page = op.operator-> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,16 @@ void LayoutViewSignalConnector::layer_order_changed ()
|
||||||
mp_view->layer_order_changed ();
|
mp_view->layer_order_changed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LayoutViewSignalConnector::layer_search_options_edited ()
|
||||||
|
{
|
||||||
|
mp_view->layer_search_options_edited ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutViewSignalConnector::cell_search_options_edited ()
|
||||||
|
{
|
||||||
|
mp_view->cell_search_options_edited ();
|
||||||
|
}
|
||||||
|
|
||||||
void LayoutViewSignalConnector::min_hier_changed (int i)
|
void LayoutViewSignalConnector::min_hier_changed (int i)
|
||||||
{
|
{
|
||||||
mp_view->min_hier_changed (i);
|
mp_view->min_hier_changed (i);
|
||||||
|
|
@ -573,6 +583,7 @@ LayoutView::init_ui (db::Manager *mgr)
|
||||||
mp_hierarchy_panel = new lay::HierarchyControlPanel (this, hierarchy_frame, "hcp");
|
mp_hierarchy_panel = new lay::HierarchyControlPanel (this, hierarchy_frame, "hcp");
|
||||||
left_frame_ly->addWidget (mp_hierarchy_panel, 1 /*stretch*/);
|
left_frame_ly->addWidget (mp_hierarchy_panel, 1 /*stretch*/);
|
||||||
|
|
||||||
|
QObject::connect (mp_hierarchy_panel, SIGNAL (search_options_changed ()), mp_connector, SLOT (cell_search_options_edited ()));
|
||||||
QObject::connect (mp_hierarchy_panel, SIGNAL (cell_selected (cell_path_type, int)), mp_connector, SLOT (select_cell_dispatch (cell_path_type, int)));
|
QObject::connect (mp_hierarchy_panel, SIGNAL (cell_selected (cell_path_type, int)), mp_connector, SLOT (select_cell_dispatch (cell_path_type, int)));
|
||||||
QObject::connect (mp_hierarchy_panel, SIGNAL (active_cellview_changed (int)), mp_connector, SLOT (active_cellview_changed (int)));
|
QObject::connect (mp_hierarchy_panel, SIGNAL (active_cellview_changed (int)), mp_connector, SLOT (active_cellview_changed (int)));
|
||||||
QObject::connect (mp_hierarchy_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ()));
|
QObject::connect (mp_hierarchy_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ()));
|
||||||
|
|
@ -655,6 +666,7 @@ LayoutView::init_ui (db::Manager *mgr)
|
||||||
mp_control_frame = mp_control_panel;
|
mp_control_frame = mp_control_panel;
|
||||||
|
|
||||||
QObject::connect (mp_control_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ()));
|
QObject::connect (mp_control_frame, SIGNAL (destroyed ()), mp_connector, SLOT (side_panel_destroyed ()));
|
||||||
|
QObject::connect (mp_control_frame, SIGNAL (search_options_changed ()), mp_connector, SLOT (layer_search_options_edited ()));
|
||||||
QObject::connect (mp_control_panel, SIGNAL (tab_changed ()), mp_connector, SLOT (layer_tab_changed ()));
|
QObject::connect (mp_control_panel, SIGNAL (tab_changed ()), mp_connector, SLOT (layer_tab_changed ()));
|
||||||
QObject::connect (mp_control_panel, SIGNAL (order_changed ()), mp_connector, SLOT (layer_order_changed ()));
|
QObject::connect (mp_control_panel, SIGNAL (order_changed ()), mp_connector, SLOT (layer_order_changed ()));
|
||||||
QObject::connect (mp_control_panel, SIGNAL (current_layer_changed (const lay::LayerPropertiesConstIterator &)), mp_connector, SLOT (current_layer_changed_slot (const lay::LayerPropertiesConstIterator &)));
|
QObject::connect (mp_control_panel, SIGNAL (current_layer_changed (const lay::LayerPropertiesConstIterator &)), mp_connector, SLOT (current_layer_changed_slot (const lay::LayerPropertiesConstIterator &)));
|
||||||
|
|
@ -1041,6 +1053,60 @@ LayoutView::configure (const std::string &name, const std::string &value)
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_layer_search_as_expressions) {
|
||||||
|
|
||||||
|
bool f;
|
||||||
|
tl::from_string (value, f);
|
||||||
|
if (mp_control_panel) {
|
||||||
|
mp_control_panel->set_search_as_expression (f);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_layer_search_as_filter) {
|
||||||
|
|
||||||
|
bool f;
|
||||||
|
tl::from_string (value, f);
|
||||||
|
if (mp_control_panel) {
|
||||||
|
mp_control_panel->set_search_as_filter (f);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_layer_search_case_sensitive) {
|
||||||
|
|
||||||
|
bool f;
|
||||||
|
tl::from_string (value, f);
|
||||||
|
if (mp_control_panel) {
|
||||||
|
mp_control_panel->set_search_case_sensitive (f);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_cell_search_as_expressions) {
|
||||||
|
|
||||||
|
bool f;
|
||||||
|
tl::from_string (value, f);
|
||||||
|
if (mp_hierarchy_panel) {
|
||||||
|
mp_hierarchy_panel->set_search_as_expression (f);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_cell_search_as_filter) {
|
||||||
|
|
||||||
|
bool f;
|
||||||
|
tl::from_string (value, f);
|
||||||
|
if (mp_hierarchy_panel) {
|
||||||
|
mp_hierarchy_panel->set_search_as_filter (f);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_cell_search_case_sensitive) {
|
||||||
|
|
||||||
|
bool f;
|
||||||
|
tl::from_string (value, f);
|
||||||
|
if (mp_hierarchy_panel) {
|
||||||
|
mp_hierarchy_panel->set_search_case_sensitive (f);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
} else if (name == cfg_layers_always_show_source) {
|
} else if (name == cfg_layers_always_show_source) {
|
||||||
|
|
||||||
bool a = false;
|
bool a = false;
|
||||||
|
|
@ -1299,6 +1365,26 @@ LayoutView::max_hier_changed (int i)
|
||||||
set_hier_levels (std::make_pair (get_hier_levels ().first, i));
|
set_hier_levels (std::make_pair (get_hier_levels ().first, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayoutView::layer_search_options_edited ()
|
||||||
|
{
|
||||||
|
if (mp_control_panel) {
|
||||||
|
dispatcher ()->config_set (cfg_layer_search_as_expressions, mp_control_panel->search_as_expression ());
|
||||||
|
dispatcher ()->config_set (cfg_layer_search_case_sensitive, mp_control_panel->search_case_sensitive ());
|
||||||
|
dispatcher ()->config_set (cfg_layer_search_as_filter, mp_control_panel->search_as_filter ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LayoutView::cell_search_options_edited ()
|
||||||
|
{
|
||||||
|
if (mp_hierarchy_panel) {
|
||||||
|
dispatcher ()->config_set (cfg_cell_search_as_expressions, mp_hierarchy_panel->search_as_expression ());
|
||||||
|
dispatcher ()->config_set (cfg_cell_search_case_sensitive, mp_hierarchy_panel->search_case_sensitive ());
|
||||||
|
dispatcher ()->config_set (cfg_cell_search_as_filter, mp_hierarchy_panel->search_as_filter ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tl::Color
|
tl::Color
|
||||||
LayoutView::default_background_color ()
|
LayoutView::default_background_color ()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,8 @@ public slots:
|
||||||
void layer_tab_changed ();
|
void layer_tab_changed ();
|
||||||
void layer_order_changed ();
|
void layer_order_changed ();
|
||||||
void select_cell_dispatch (const cell_path_type &path, int cellview_index);
|
void select_cell_dispatch (const cell_path_type &path, int cellview_index);
|
||||||
|
void layer_search_options_edited ();
|
||||||
|
void cell_search_options_edited ();
|
||||||
void min_hier_changed (int i);
|
void min_hier_changed (int i);
|
||||||
void max_hier_changed (int i);
|
void max_hier_changed (int i);
|
||||||
void app_terminated ();
|
void app_terminated ();
|
||||||
|
|
@ -654,6 +656,8 @@ private:
|
||||||
void layer_order_changed ();
|
void layer_order_changed ();
|
||||||
void min_hier_changed (int i);
|
void min_hier_changed (int i);
|
||||||
void max_hier_changed (int i);
|
void max_hier_changed (int i);
|
||||||
|
void layer_search_options_edited ();
|
||||||
|
void cell_search_options_edited ();
|
||||||
|
|
||||||
bool event_filter (QObject *obj, QEvent *ev, bool &taken);
|
bool event_filter (QObject *obj, QEvent *ev, bool &taken);
|
||||||
QSize size_hint () const;
|
QSize size_hint () const;
|
||||||
|
|
|
||||||
|
|
@ -362,3 +362,9 @@ TEST(63_FlagMissingPorts)
|
||||||
run_test (_this, "flag_missing_ports", "flag_missing_ports.gds", false, true, "TOP");
|
run_test (_this, "flag_missing_ports", "flag_missing_ports.gds", false, true, "TOP");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split substrate - marker and global connection (issue #2345)
|
||||||
|
TEST(64_SplitSubstrate)
|
||||||
|
{
|
||||||
|
run_test (_this, "split_substrate", "split_substrate.gds", true, false /*no LVS*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
|
!equals(HAVE_QT, "0") {
|
||||||
|
SUBDIRS = lay_plugin
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,600 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>DensityMapDialog</class>
|
||||||
|
<widget class="QDialog" name="DensityMapDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>657</width>
|
||||||
|
<height>480</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Density Map</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin" stdset="0">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_3">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin" stdset="0">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>Density map parameters</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="le_pixel_size">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>100</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pixel size</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="le_window_size">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>µm</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QSpinBox" name="sb_threads">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>Averaging window size</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Threads</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>353</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>µm (a multiple of the pixel size or empty)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_12">
|
||||||
|
<property name="text">
|
||||||
|
<string>Boundary mode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1" colspan="3">
|
||||||
|
<widget class="QComboBox" name="cb_boundary_mode">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Periodic (repeat region seamlessly)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use zero density outside</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use 100% density outside</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use average density outside</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Compute density of shapes on</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="2" colspan="2">
|
||||||
|
<widget class="QStackedWidget" name="layer_stack">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="page_3">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="lay::LayerSelectionComboBox" name="cb_source_layer">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>385</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="page_4">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3"/>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QComboBox" name="layer_cb">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Layer</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Visible layers</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Selected layers</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>8</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Compute density map of region</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QFrame" name="frame_2">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin" stdset="0">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::NoFrame</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin" stdset="0">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2" rowspan="2" colspan="2">
|
||||||
|
<widget class="QStackedWidget" name="region_stack">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="page">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="lay::LayerSelectionComboBox" name="cb_box_layer">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToContents</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>351</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="page_2">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="region_box_group">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Box Boundaries (all values in µm)</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="_2">
|
||||||
|
<property name="margin" stdset="0">
|
||||||
|
<number>9</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>6</number>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>y =</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>2nd corner</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>x =</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>1st corner</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>x =</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>y =</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="4">
|
||||||
|
<widget class="QLineEdit" name="le_y2"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QLineEdit" name="le_x2"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="4">
|
||||||
|
<widget class="QLineEdit" name="le_y1"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLineEdit" name="le_x1"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="page_5"/>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QComboBox" name="region_cb">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Global bounding box</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Bounding box of layer ...</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Single box with ..</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Visible region</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Defined by rulers</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>8</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="button_box">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>lay::LayerSelectionComboBox</class>
|
||||||
|
<extends>QComboBox</extends>
|
||||||
|
<header>layWidgets.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>le_pixel_size</tabstop>
|
||||||
|
<tabstop>sb_threads</tabstop>
|
||||||
|
<tabstop>layer_cb</tabstop>
|
||||||
|
<tabstop>cb_source_layer</tabstop>
|
||||||
|
<tabstop>region_cb</tabstop>
|
||||||
|
<tabstop>cb_box_layer</tabstop>
|
||||||
|
<tabstop>le_x1</tabstop>
|
||||||
|
<tabstop>le_y1</tabstop>
|
||||||
|
<tabstop>le_x2</tabstop>
|
||||||
|
<tabstop>le_y2</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>button_box</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>DensityMapDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>button_box</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>DensityMapDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
|
|
@ -0,0 +1,765 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2026 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 "layDensityMapDialog.h"
|
||||||
|
|
||||||
|
#include "dbClip.h"
|
||||||
|
#include "dbTilingProcessor.h"
|
||||||
|
#include "antService.h"
|
||||||
|
#include "tlException.h"
|
||||||
|
#include "tlString.h"
|
||||||
|
#include "tlExceptions.h"
|
||||||
|
#include "layUtils.h"
|
||||||
|
#include "imgObject.h"
|
||||||
|
#include "imgService.h"
|
||||||
|
|
||||||
|
namespace lay
|
||||||
|
{
|
||||||
|
|
||||||
|
static const std::string layer_mode_specific ("layer-mode-specific");
|
||||||
|
static const std::string layer_mode_visible ("layer-mode-visible");
|
||||||
|
static const std::string layer_mode_selected ("layer-mode-selected");
|
||||||
|
|
||||||
|
// items in layer_cb
|
||||||
|
static const std::vector<std::string> layer_modes = { layer_mode_specific, layer_mode_visible, layer_mode_selected };
|
||||||
|
|
||||||
|
static const std::string region_mode_global_bbox ("region-mode-global-bbox");
|
||||||
|
static const std::string region_mode_layer_bbox ("region-mode-layer-bbox");
|
||||||
|
static const std::string region_mode_single_box ("region-mode-single-box");
|
||||||
|
static const std::string region_mode_visible_region ("region-mode-visible-region");
|
||||||
|
static const std::string region_mode_by_rulers ("region-mode-by-rulers");
|
||||||
|
|
||||||
|
// items in region_cb
|
||||||
|
static const std::vector<std::string> region_modes = {
|
||||||
|
region_mode_global_bbox,
|
||||||
|
region_mode_layer_bbox,
|
||||||
|
region_mode_single_box,
|
||||||
|
region_mode_visible_region,
|
||||||
|
region_mode_by_rulers
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::string boundary_mode_periodic ("boundary-mode-periodic");
|
||||||
|
static const std::string boundary_mode_zero ("boundary-mode-zero");
|
||||||
|
static const std::string boundary_mode_one ("boundary-mode-one");
|
||||||
|
static const std::string boundary_mode_average ("boundary-mode-average");
|
||||||
|
|
||||||
|
// items in boundary_mode_cb
|
||||||
|
static const std::vector<std::string> boundary_modes = { boundary_mode_periodic, boundary_mode_zero, boundary_mode_one, boundary_mode_average };
|
||||||
|
|
||||||
|
static const std::string cfg_density_map_region_mode ("density-map-region-mode");
|
||||||
|
static const std::string cfg_density_map_layer_mode ("density-map-layer-mode");
|
||||||
|
static const std::string cfg_density_map_pixel_size ("density-map-pixel-size");
|
||||||
|
static const std::string cfg_density_map_window_size ("density-map-window-size");
|
||||||
|
static const std::string cfg_density_map_boundary_mode ("density-map-boundary-mode");
|
||||||
|
static const std::string cfg_density_map_threads ("density-map-threads");
|
||||||
|
static const std::string cfg_density_map_source_layer ("density-map-source-layer");
|
||||||
|
static const std::string cfg_density_map_box_layer ("density-map-box-layer");
|
||||||
|
static const std::string cfg_density_map_single_box ("density-map-single-box");
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Declaration of the configuration options
|
||||||
|
|
||||||
|
class DensityMapDialogPluginDeclaration
|
||||||
|
: public lay::PluginDeclaration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void get_options (std::vector < std::pair<std::string, std::string> > &options) const
|
||||||
|
{
|
||||||
|
options.push_back (std::make_pair (cfg_density_map_layer_mode, layer_mode_specific));
|
||||||
|
options.push_back (std::make_pair (cfg_density_map_region_mode, region_mode_global_bbox));
|
||||||
|
options.push_back (std::make_pair (cfg_density_map_pixel_size, "100"));
|
||||||
|
options.push_back (std::make_pair (cfg_density_map_window_size, "0"));
|
||||||
|
options.push_back (std::make_pair (cfg_density_map_boundary_mode, boundary_mode_periodic));
|
||||||
|
options.push_back (std::make_pair (cfg_density_map_threads, "1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual lay::ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const
|
||||||
|
{
|
||||||
|
return 0; // .. no config page yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
|
||||||
|
{
|
||||||
|
lay::PluginDeclaration::get_menu_entries (menu_entries);
|
||||||
|
menu_entries.push_back (lay::menu_item ("density_map::show", "density_map_tool:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("Density Map"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const
|
||||||
|
{
|
||||||
|
if (lay::has_gui ()) {
|
||||||
|
return new DensityMapDialog (root, view);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new DensityMapDialogPluginDeclaration (), 3002, "lay::DensityMapPlugin");
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
|
DensityMapDialog::DensityMapDialog (lay::Dispatcher *root, LayoutViewBase *vw)
|
||||||
|
: lay::Browser (root, vw),
|
||||||
|
Ui::DensityMapDialog ()
|
||||||
|
{
|
||||||
|
Ui::DensityMapDialog::setupUi (this);
|
||||||
|
|
||||||
|
connect (layer_cb, SIGNAL (activated (int)), SLOT (layer_mode_changed (int)));
|
||||||
|
connect (region_cb, SIGNAL (activated (int)), SLOT (region_mode_changed (int)));
|
||||||
|
|
||||||
|
connect (button_box->button (QDialogButtonBox::Apply), SIGNAL (clicked ()), this, SLOT (apply ()));
|
||||||
|
|
||||||
|
region_mode_changed (region_cb->currentIndex ());
|
||||||
|
layer_mode_changed (layer_cb->currentIndex ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DensityMapDialog::region_mode_changed (int mode)
|
||||||
|
{
|
||||||
|
if (mode < 0 || mode >= int (region_modes.size ())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &rm = region_modes [mode];
|
||||||
|
if (rm == region_mode_layer_bbox) {
|
||||||
|
region_stack->setCurrentIndex (0);
|
||||||
|
} else if (rm == region_mode_single_box) {
|
||||||
|
region_stack->setCurrentIndex (1);
|
||||||
|
} else {
|
||||||
|
region_stack->setCurrentIndex (2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DensityMapDialog::layer_mode_changed (int mode)
|
||||||
|
{
|
||||||
|
if (mode < 0 || mode >= int (layer_modes.size ())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &lm = layer_modes [mode];
|
||||||
|
if (lm == layer_mode_specific) {
|
||||||
|
layer_stack->setCurrentIndex (0);
|
||||||
|
} else {
|
||||||
|
layer_stack->setCurrentIndex (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DensityMapDialog::menu_activated (const std::string &symbol)
|
||||||
|
{
|
||||||
|
if (symbol == "density_map::show") {
|
||||||
|
|
||||||
|
int cv_index = view ()->active_cellview_index ();
|
||||||
|
|
||||||
|
lay::CellView cv = view ()->cellview (cv_index);
|
||||||
|
if (cv.is_valid ()) {
|
||||||
|
cb_box_layer->set_view (view (), cv_index);
|
||||||
|
cb_source_layer->set_view (view (), cv_index);
|
||||||
|
show ();
|
||||||
|
activate ();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
lay::Browser::menu_activated (symbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DensityMapDialog::~DensityMapDialog ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
class DensityMapTileReceiver
|
||||||
|
: public db::TileOutputReceiver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DensityMapTileReceiver (img::Object *img)
|
||||||
|
: mp_img (img)
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void put (size_t ix, size_t iy, const db::Box &tile, size_t /*id*/, const tl::Variant &obj, double /*dbu*/, const db::ICplxTrans & /*trans*/, bool /*clip*/)
|
||||||
|
{
|
||||||
|
if (tl::verbosity () >= 30) {
|
||||||
|
tl::info << "Density map value: " << ix << "," << iy << " " << tile.to_string () << " -> " << obj.to_string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_img->set_pixel (ix, iy, obj.to_double ());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
img::Object *mp_img;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DensityMapDialog::apply ()
|
||||||
|
{
|
||||||
|
BEGIN_PROTECTED
|
||||||
|
|
||||||
|
make_density_map ();
|
||||||
|
|
||||||
|
END_PROTECTED
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DensityMapDialog::accept ()
|
||||||
|
{
|
||||||
|
BEGIN_PROTECTED
|
||||||
|
|
||||||
|
make_density_map ();
|
||||||
|
|
||||||
|
// close this dialog
|
||||||
|
QDialog::accept ();
|
||||||
|
|
||||||
|
END_PROTECTED
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DensityMapDialog::configure (const std::string &name, const std::string &value)
|
||||||
|
{
|
||||||
|
if (name == cfg_density_map_layer_mode) {
|
||||||
|
|
||||||
|
int mode = 0;
|
||||||
|
for (size_t i = 0; i < layer_modes.size (); ++i) {
|
||||||
|
if (layer_modes[i] == value) {
|
||||||
|
mode = int (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layer_cb->setCurrentIndex (mode);
|
||||||
|
layer_mode_changed (mode);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_density_map_region_mode) {
|
||||||
|
|
||||||
|
int mode = 0;
|
||||||
|
for (size_t i = 0; i < region_modes.size (); ++i) {
|
||||||
|
if (region_modes[i] == value) {
|
||||||
|
mode = int (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
region_cb->setCurrentIndex (mode);
|
||||||
|
region_mode_changed (mode);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_density_map_pixel_size) {
|
||||||
|
|
||||||
|
double px = 100.0;
|
||||||
|
try {
|
||||||
|
tl::from_string (value, px);
|
||||||
|
le_pixel_size->setText (tl::to_qstring (tl::to_string (px)));
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_density_map_window_size) {
|
||||||
|
|
||||||
|
double ws = 0.0;
|
||||||
|
try {
|
||||||
|
tl::from_string (value, ws);
|
||||||
|
if (ws > 0) {
|
||||||
|
le_window_size->setText (tl::to_qstring (tl::to_string (ws)));
|
||||||
|
} else {
|
||||||
|
le_window_size->setText (QString ());
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_density_map_boundary_mode) {
|
||||||
|
|
||||||
|
int mode = 0;
|
||||||
|
for (size_t i = 0; i < boundary_modes.size (); ++i) {
|
||||||
|
if (boundary_modes[i] == value) {
|
||||||
|
mode = int (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cb_boundary_mode->setCurrentIndex (mode);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_density_map_threads) {
|
||||||
|
|
||||||
|
int thr = 1;
|
||||||
|
try {
|
||||||
|
tl::from_string (value, thr);
|
||||||
|
sb_threads->setValue (thr);
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_density_map_source_layer) {
|
||||||
|
|
||||||
|
db::LayerProperties lp;
|
||||||
|
try {
|
||||||
|
tl::from_string (value, lp);
|
||||||
|
cb_source_layer->set_current_layer (lp);
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_density_map_box_layer) {
|
||||||
|
|
||||||
|
db::LayerProperties lp;
|
||||||
|
try {
|
||||||
|
tl::from_string (value, lp);
|
||||||
|
cb_box_layer->set_current_layer (lp);
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (name == cfg_density_map_single_box) {
|
||||||
|
|
||||||
|
db::DBox bx;
|
||||||
|
try {
|
||||||
|
tl::from_string (value, bx);
|
||||||
|
if (bx.empty ()) {
|
||||||
|
le_x1->setText (QString ());
|
||||||
|
le_y1->setText (QString ());
|
||||||
|
le_x2->setText (QString ());
|
||||||
|
le_y2->setText (QString ());
|
||||||
|
} else {
|
||||||
|
le_x1->setText (tl::to_qstring (tl::to_string (bx.left ())));
|
||||||
|
le_y1->setText (tl::to_qstring (tl::to_string (bx.bottom ())));
|
||||||
|
le_x2->setText (tl::to_qstring (tl::to_string (bx.right ())));
|
||||||
|
le_y2->setText (tl::to_qstring (tl::to_string (bx.top ())));
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DensityMapDialog::make_density_map ()
|
||||||
|
{
|
||||||
|
DensityMapParameters par;
|
||||||
|
|
||||||
|
par.threads = std::max (1, sb_threads->value ());
|
||||||
|
|
||||||
|
par.pixel_size = 0.0;
|
||||||
|
tl::from_string_ext (tl::to_string (le_pixel_size->text ()), par.pixel_size);
|
||||||
|
|
||||||
|
if (par.pixel_size < 1e-6) {
|
||||||
|
throw tl::Exception (tl::to_string (QObject::tr ("The pixel size must be positive and not zero")));
|
||||||
|
}
|
||||||
|
|
||||||
|
par.window_size = 0.0;
|
||||||
|
if (! le_window_size->text ().simplified ().isEmpty ()) {
|
||||||
|
tl::from_string_ext (tl::to_string (le_window_size->text ()), par.window_size);
|
||||||
|
if (par.window_size < 1e-6) {
|
||||||
|
throw tl::Exception (tl::to_string (QObject::tr ("The window size must be positive and not zero or empty")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int boundary_mode = cb_boundary_mode->currentIndex ();
|
||||||
|
if (boundary_mode < 0 || boundary_mode >= int (boundary_modes.size ())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
par.boundary_mode = boundary_modes [boundary_mode];
|
||||||
|
|
||||||
|
int region_mode = region_cb->currentIndex ();
|
||||||
|
if (region_mode < 0 || region_mode >= int (region_modes.size ())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto &rm = region_modes [region_mode];
|
||||||
|
|
||||||
|
int layer_mode = layer_cb->currentIndex ();
|
||||||
|
if (layer_mode < 0 || layer_mode >= int (layer_modes.size ())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto &lm = layer_modes [layer_mode];
|
||||||
|
|
||||||
|
db::LayerProperties region_layer;
|
||||||
|
db::LayerProperties source_layer;
|
||||||
|
|
||||||
|
if (rm == region_mode_single_box) {
|
||||||
|
|
||||||
|
if (le_x1->text ().isEmpty () || le_x2->text ().isEmpty () ||
|
||||||
|
le_y1->text ().isEmpty () || le_y2->text ().isEmpty ()) {
|
||||||
|
throw tl::Exception (tl::to_string (QObject::tr ("All four coordinates of the clip box must be given")));
|
||||||
|
}
|
||||||
|
|
||||||
|
double x1 = 0.0, y1 = 0.0;
|
||||||
|
double x2 = 0.0, y2 = 0.0;
|
||||||
|
tl::from_string_ext (tl::to_string (le_x1->text ()), x1);
|
||||||
|
tl::from_string_ext (tl::to_string (le_x2->text ()), x2);
|
||||||
|
tl::from_string_ext (tl::to_string (le_y1->text ()), y1);
|
||||||
|
tl::from_string_ext (tl::to_string (le_y2->text ()), y2);
|
||||||
|
|
||||||
|
par.region = db::DBox (db::DPoint (x1, y1), db::DPoint (x2, y2));
|
||||||
|
|
||||||
|
} else if (rm == region_mode_by_rulers) {
|
||||||
|
|
||||||
|
ant::Service *ant_service = view ()->get_plugin <ant::Service> ();
|
||||||
|
if (ant_service) {
|
||||||
|
ant::AnnotationIterator ant = ant_service->begin_annotations ();
|
||||||
|
while (! ant.at_end ()) {
|
||||||
|
par.region += db::DBox (ant->p1 (), ant->p2 ());
|
||||||
|
++ant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (rm == region_mode_layer_bbox) {
|
||||||
|
|
||||||
|
lay::CellView ccv = view ()->cellview (cb_box_layer->cv_index ());
|
||||||
|
int sel_layer = cb_box_layer->current_layer ();
|
||||||
|
|
||||||
|
region_layer = cb_box_layer->current_layer_props ();
|
||||||
|
|
||||||
|
if (! ccv.is_valid () || sel_layer < 0 || ! ccv->layout ().is_valid_layer (sel_layer)) {
|
||||||
|
throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get clip boxes from")));
|
||||||
|
}
|
||||||
|
|
||||||
|
par.region = db::CplxTrans (ccv->layout ().dbu ()) * ccv->layout ().cell (ccv.cell_index ()).bbox (sel_layer);
|
||||||
|
|
||||||
|
} else if (rm == region_mode_visible_region) {
|
||||||
|
|
||||||
|
par.region = view ()->box ();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
lay::CellView cv = view ()->cellview (view ()->active_cellview_index ());
|
||||||
|
par.region = db::CplxTrans (cv->layout ().dbu ()) * cv->layout ().cell (cv.cell_index ()).bbox ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lm == layer_mode_specific) {
|
||||||
|
|
||||||
|
int cvi = cb_source_layer->cv_index ();
|
||||||
|
lay::CellView ccv = view ()->cellview (cvi);
|
||||||
|
int sel_layer = cb_source_layer->current_layer ();
|
||||||
|
|
||||||
|
source_layer = cb_source_layer->current_layer_props ();
|
||||||
|
|
||||||
|
if (! ccv.is_valid () || sel_layer < 0 || ! ccv->layout ().is_valid_layer (sel_layer)) {
|
||||||
|
throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get clip boxes from")));
|
||||||
|
}
|
||||||
|
|
||||||
|
par.input_layers.push_back (std::make_pair (cvi, sel_layer));
|
||||||
|
|
||||||
|
} else if (lm == layer_mode_visible) {
|
||||||
|
|
||||||
|
for (auto l = view ()->begin_layers (); !l.at_end (); ++l) {
|
||||||
|
|
||||||
|
if (! l->has_children () && l->visible (true)) {
|
||||||
|
|
||||||
|
int cvi = (l->cellview_index () >= 0) ? l->cellview_index () : 0;
|
||||||
|
lay::CellView ccv = view ()->cellview (cvi);
|
||||||
|
int li = l->layer_index ();
|
||||||
|
|
||||||
|
if (ccv.is_valid () || li >= 0 || ! ccv->layout ().is_valid_layer (li)) {
|
||||||
|
par.input_layers.push_back (std::make_pair (cvi, li));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (lm == layer_mode_selected) {
|
||||||
|
|
||||||
|
auto sel = view ()->selected_layers ();
|
||||||
|
for (auto s = sel.begin (); s != sel.end (); ++s) {
|
||||||
|
|
||||||
|
auto l = *s;
|
||||||
|
if (! l->has_children ()) {
|
||||||
|
|
||||||
|
int cvi = (l->cellview_index () >= 0) ? l->cellview_index () : 0;
|
||||||
|
lay::CellView ccv = view ()->cellview (cvi);
|
||||||
|
int li = l->layer_index ();
|
||||||
|
|
||||||
|
if (ccv.is_valid () || li >= 0 || ! ccv->layout ().is_valid_layer (li)) {
|
||||||
|
par.input_layers.push_back (std::make_pair (cvi, li));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit the parameters
|
||||||
|
dispatcher ()->config_set (cfg_density_map_layer_mode, lm);
|
||||||
|
dispatcher ()->config_set (cfg_density_map_region_mode, rm);
|
||||||
|
dispatcher ()->config_set (cfg_density_map_boundary_mode, par.boundary_mode);
|
||||||
|
dispatcher ()->config_set (cfg_density_map_threads, tl::to_string (par.threads));
|
||||||
|
dispatcher ()->config_set (cfg_density_map_pixel_size, tl::to_string (par.pixel_size));
|
||||||
|
dispatcher ()->config_set (cfg_density_map_window_size, tl::to_string (par.window_size));
|
||||||
|
|
||||||
|
if (lm == layer_mode_specific) {
|
||||||
|
dispatcher ()->config_set (cfg_density_map_source_layer, source_layer.to_string ());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rm == region_mode_layer_bbox) {
|
||||||
|
dispatcher ()->config_set (cfg_density_map_box_layer, region_layer.to_string ());
|
||||||
|
} else if (rm == region_mode_single_box) {
|
||||||
|
dispatcher ()->config_set (cfg_density_map_single_box, par.region.to_string ());
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatcher ()->config_setup ();
|
||||||
|
|
||||||
|
compute_density_map (par);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DensityMapDialog::compute_density_map (const DensityMapParameters &par)
|
||||||
|
{
|
||||||
|
if (par.region.empty ()) {
|
||||||
|
throw tl::Exception (tl::to_string (QObject::tr ("Density map region is empty")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (par.input_layers.empty ()) {
|
||||||
|
throw tl::Exception (tl::to_string (QObject::tr ("No input layers given")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the tile origins
|
||||||
|
|
||||||
|
const double max_wh = 100000.0;
|
||||||
|
const int max_pixels = 100000000;
|
||||||
|
|
||||||
|
double dnx = std::max (1.0, ceil (par.region.width () / par.pixel_size - db::epsilon));
|
||||||
|
double dny = std::max (1.0, ceil (par.region.height () / par.pixel_size - db::epsilon));
|
||||||
|
if (dnx > max_wh || dny > max_wh) {
|
||||||
|
throw tl::Exception (tl::sprintf (tl::to_string (QObject::tr ("Density map dimensions exceed maximum limit of %g pixels in one direction"))), max_wh);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nx = int (dnx);
|
||||||
|
int ny = int (dny);
|
||||||
|
if (dnx * dny > max_pixels) {
|
||||||
|
throw tl::Exception (tl::sprintf (tl::to_string (QObject::tr ("Density map array exceed maximum limit of %d pixels in total"))), max_pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
double x0 = par.region.center ().x () - nx * 0.5 * par.pixel_size;
|
||||||
|
double y0 = par.region.center ().y () - ny * 0.5 * par.pixel_size;
|
||||||
|
|
||||||
|
double dbu = view ()->cellview (par.input_layers.front ().first)->layout ().dbu ();
|
||||||
|
|
||||||
|
// Set up the tiling processor
|
||||||
|
|
||||||
|
db::TilingProcessor tp;
|
||||||
|
|
||||||
|
tp.tiles (nx, ny);
|
||||||
|
tp.tile_origin (x0, y0);
|
||||||
|
tp.tile_size (par.pixel_size, par.pixel_size);
|
||||||
|
|
||||||
|
tp.set_threads (par.threads);
|
||||||
|
tp.set_dbu (dbu);
|
||||||
|
|
||||||
|
int ninput = 1;
|
||||||
|
std::string in_expr;
|
||||||
|
|
||||||
|
for (auto i = par.input_layers.begin (); i != par.input_layers.end (); ++i, ++ninput) {
|
||||||
|
|
||||||
|
const lay::CellView &cv = view ()->cellview (i->first);
|
||||||
|
const db::Layout &ly = cv->layout ();
|
||||||
|
const db::Cell &cell = ly.cell (cv.cell_index ());
|
||||||
|
|
||||||
|
std::string in_name = "in" + tl::to_string (ninput);
|
||||||
|
tp.input (in_name, db::RecursiveShapeIterator (ly, cell, i->second, true), db::ICplxTrans (ly.dbu () / dbu), db::TilingProcessor::TypeRegion, true);
|
||||||
|
|
||||||
|
if (! in_expr.empty ()) {
|
||||||
|
in_expr += "+";
|
||||||
|
}
|
||||||
|
in_expr += in_name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tp.queue (std::string ("var inp = ") + in_expr + "; _tile && _output(dens, to_f(inp.area(_tile.bbox)) / to_f(_tile.bbox.area))");
|
||||||
|
|
||||||
|
// Prepare the Image for receiving
|
||||||
|
|
||||||
|
img::Object *img_object = 0;
|
||||||
|
|
||||||
|
img::Service *img_service = view ()->get_plugin <img::Service> ();
|
||||||
|
if (img_service) {
|
||||||
|
|
||||||
|
const std::string img_tag = "density-map-image";
|
||||||
|
|
||||||
|
img::DataMapping dm;
|
||||||
|
dm.false_color_nodes.clear ();
|
||||||
|
|
||||||
|
// default mapping blue -> red
|
||||||
|
// TODO: we could use that from a previous image ...
|
||||||
|
dm.false_color_nodes.push_back (std::make_pair (0.0, std::make_pair (0x0000ff, 0x0000ff)));
|
||||||
|
dm.false_color_nodes.push_back (std::make_pair (1.0, std::make_pair (0xff0000, 0xff0000)));
|
||||||
|
|
||||||
|
for (auto i = img_service->begin_images (); ! i.at_end (); ++i) {
|
||||||
|
if (i->tag () == img_tag) {
|
||||||
|
// inherit data mapping from previous image
|
||||||
|
dm = i->data_mapping ();
|
||||||
|
img_service->erase_image_by_id (i->id ());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img::Object img (nx, ny, db::DCplxTrans (par.pixel_size, 0.0, false, par.region.center () - db::DPoint ()), false, false);
|
||||||
|
img.set_data_mapping (dm);
|
||||||
|
img.set_tag (img_tag);
|
||||||
|
|
||||||
|
img_object = img_service->insert_image (img);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tl_assert (img_object);
|
||||||
|
tp.output ("dens", 0, new DensityMapTileReceiver (img_object), db::ICplxTrans ());
|
||||||
|
|
||||||
|
// Execute the tiling processor
|
||||||
|
|
||||||
|
tp.execute (tl::to_string (tr ("Computing density map")));
|
||||||
|
|
||||||
|
// Do the averaging if requested
|
||||||
|
|
||||||
|
unsigned int nw = (unsigned int) (std::max (0.0, std::min (1000.0, floor (par.window_size / par.pixel_size + 0.5))));
|
||||||
|
|
||||||
|
if (nw > 1) {
|
||||||
|
average_window (*img_object, par.boundary_mode, nw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int safe_mod (int a, int b)
|
||||||
|
{
|
||||||
|
if (a < 0) {
|
||||||
|
return b - (-a % b);
|
||||||
|
} else {
|
||||||
|
return a % b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DensityMapDialog::average_window (img::Object &img_object, const std::string boundary_mode, int nw)
|
||||||
|
{
|
||||||
|
bool periodic = (boundary_mode == boundary_mode_periodic);
|
||||||
|
|
||||||
|
int nx = img_object.width ();
|
||||||
|
int ny = img_object.height ();
|
||||||
|
|
||||||
|
// compute the outside value if not periodic
|
||||||
|
double outside = 0.0;
|
||||||
|
if (boundary_mode == boundary_mode_one) {
|
||||||
|
|
||||||
|
outside = 1.0;
|
||||||
|
|
||||||
|
} else if (boundary_mode == boundary_mode_average) {
|
||||||
|
|
||||||
|
double outside = 0.0;
|
||||||
|
const float *d = img_object.float_data ();
|
||||||
|
for (size_t i = size_t (nx) * size_t (ny); i > 0; --i) {
|
||||||
|
outside += *d++;
|
||||||
|
}
|
||||||
|
outside /= double (nx) * double (ny);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<double> vavg_data;
|
||||||
|
vavg_data.resize (size_t (nx) * size_t (ny), 0.0);
|
||||||
|
|
||||||
|
// vertical sum
|
||||||
|
|
||||||
|
for (int y = 0; y < ny; ++y) {
|
||||||
|
|
||||||
|
int wh = nw / 2;
|
||||||
|
double fb = (nw % 2 == 0) ? 0.5 : 1.0;
|
||||||
|
|
||||||
|
for (int dy = -wh; dy <= wh; ++dy) {
|
||||||
|
|
||||||
|
// top and bottom row count half in case of even nw
|
||||||
|
double f = (dy == -wh || dy == wh) ? fb : 1.0;
|
||||||
|
|
||||||
|
std::vector<double>::iterator d = vavg_data.begin () + y * nx;
|
||||||
|
if (periodic || (y + dy >= 0 && y + dy < ny)) {
|
||||||
|
const float *s = img_object.float_data () + safe_mod (y + dy, ny) * nx;
|
||||||
|
for (int ix = 0; ix < nx; ++ix) {
|
||||||
|
*d++ += f * *s++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int ix = 0; ix < nx; ++ix) {
|
||||||
|
*d++ += f * outside;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// horizontal sum
|
||||||
|
|
||||||
|
outside *= nw; // because we do normalization later
|
||||||
|
|
||||||
|
// TODO: transposing the image would make things more efficient
|
||||||
|
|
||||||
|
std::vector<double> havg_data;
|
||||||
|
havg_data.resize (size_t (nx) * size_t (ny), 0.0);
|
||||||
|
|
||||||
|
for (int x = 0; x < nx; ++x) {
|
||||||
|
|
||||||
|
int wh = nw / 2;
|
||||||
|
double fb = (nw % 2 == 0) ? 0.5 : 1.0;
|
||||||
|
|
||||||
|
for (int dx = -wh; dx <= wh; ++dx) {
|
||||||
|
|
||||||
|
// top and bottom row count half in case of even nw
|
||||||
|
double f = (dx == -wh || dx == wh) ? fb : 1.0;
|
||||||
|
|
||||||
|
std::vector<double>::iterator d = havg_data.begin () + x;
|
||||||
|
|
||||||
|
if (periodic || (x + dx >= 0 && x + dx < nx)) {
|
||||||
|
std::vector<double>::const_iterator s = vavg_data.begin () + safe_mod (x + dx, nx);
|
||||||
|
for (int iy = 0; iy < ny; ++iy) {
|
||||||
|
*d += f * *s;
|
||||||
|
d += nx;
|
||||||
|
s += nx;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int iy = 0; iy < ny; ++iy) {
|
||||||
|
*d += f * outside;
|
||||||
|
d += nx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// take the average
|
||||||
|
double s = 1.0 / (double (nw) * double (nw));
|
||||||
|
for (auto i = havg_data.begin (); i != havg_data.end (); ++i) {
|
||||||
|
*i *= s;
|
||||||
|
}
|
||||||
|
|
||||||
|
img_object.set_data (nx, ny, havg_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2026 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_layDensityMapDialog
|
||||||
|
#define HDR_layDensityMapDialog
|
||||||
|
|
||||||
|
#include "ui_DensityMapDialog.h"
|
||||||
|
|
||||||
|
#include "layLayoutView.h"
|
||||||
|
#include "layBrowser.h"
|
||||||
|
#include "layMarker.h"
|
||||||
|
|
||||||
|
namespace img
|
||||||
|
{
|
||||||
|
class Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace lay
|
||||||
|
{
|
||||||
|
|
||||||
|
class DensityMapDialog
|
||||||
|
: public lay::Browser,
|
||||||
|
private Ui::DensityMapDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DensityMapDialog (lay::Dispatcher *root, lay::LayoutViewBase *view);
|
||||||
|
~DensityMapDialog ();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void layer_mode_changed (int);
|
||||||
|
void region_mode_changed (int);
|
||||||
|
void accept ();
|
||||||
|
void apply ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct DensityMapParameters
|
||||||
|
{
|
||||||
|
DensityMapParameters ()
|
||||||
|
: pixel_size (100.0), threads (1)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Collects all cv_index/layer index pairs used for input
|
||||||
|
std::vector<std::pair<unsigned int, unsigned int> > input_layers;
|
||||||
|
|
||||||
|
// The region to compute the density map from
|
||||||
|
db::DBox region;
|
||||||
|
|
||||||
|
// The pixel size
|
||||||
|
double pixel_size;
|
||||||
|
|
||||||
|
// The window size or zero for "no window"
|
||||||
|
double window_size;
|
||||||
|
|
||||||
|
// The boundary mode
|
||||||
|
std::string boundary_mode;
|
||||||
|
|
||||||
|
// The number of threads to use
|
||||||
|
int threads;
|
||||||
|
};
|
||||||
|
|
||||||
|
// implementation of the lay::Plugin interface
|
||||||
|
virtual bool configure (const std::string &name, const std::string &value);
|
||||||
|
|
||||||
|
// implementation of the lay::Plugin interface
|
||||||
|
void menu_activated (const std::string &symbol);
|
||||||
|
|
||||||
|
void make_density_map ();
|
||||||
|
void compute_density_map (const DensityMapParameters &par);
|
||||||
|
void average_window (img::Object &img_object, const std::string boundary_mode, int nw);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
|
||||||
|
TARGET = density_map_ui
|
||||||
|
DESTDIR = $$OUT_PWD/../../../../lay_plugins
|
||||||
|
|
||||||
|
include($$PWD/../../../lay_plugin.pri)
|
||||||
|
|
||||||
|
INCLUDEPATH += $$IMG_INC $$ANT_INC
|
||||||
|
DEPENDPATH += $$IMG_INC $$ANT_INC
|
||||||
|
LIBS += -L$$DESTDIR/.. -lklayout_img -lklayout_ant
|
||||||
|
|
||||||
|
HEADERS = \
|
||||||
|
layDensityMapDialog.h \
|
||||||
|
|
||||||
|
SOURCES = \
|
||||||
|
layDensityMapDialog.cc \
|
||||||
|
|
||||||
|
FORMS = \
|
||||||
|
DensityMapDialog.ui \
|
||||||
|
|
@ -1920,13 +1920,15 @@ static void map_databases (rdb::Database &self, const rdb::Database &other,
|
||||||
std::map<id_type, id_type> &rev_tag2tag,
|
std::map<id_type, id_type> &rev_tag2tag,
|
||||||
bool create_missing)
|
bool create_missing)
|
||||||
{
|
{
|
||||||
|
std::list<std::pair<rdb::Cell *, const rdb::Cell *> > new_cells;
|
||||||
|
|
||||||
for (auto c = other.cells ().begin (); c != other.cells ().end (); ++c) {
|
for (auto c = other.cells ().begin (); c != other.cells ().end (); ++c) {
|
||||||
// TODO: do we have a consistent scheme of naming variants? What requirements
|
// TODO: do we have a consistent scheme of naming variants? What requirements
|
||||||
// exist towards detecting variant specific waivers
|
// exist towards detecting variant specific waivers
|
||||||
rdb::Cell *this_cell = self.cell_by_qname_non_const (c->qname ());
|
rdb::Cell *this_cell = self.cell_by_qname_non_const (c->qname ());
|
||||||
if (! this_cell && create_missing) {
|
if (! this_cell && create_missing) {
|
||||||
this_cell = self.create_cell (c->name (), c->variant (), c->layout_name ());
|
this_cell = self.create_cell (c->name (), c->variant (), c->layout_name ());
|
||||||
this_cell->import_references (c->references ());
|
new_cells.push_back (std::make_pair (this_cell, c.operator-> ()));
|
||||||
}
|
}
|
||||||
if (this_cell) {
|
if (this_cell) {
|
||||||
cell2cell.insert (std::make_pair (this_cell->id (), c->id ()));
|
cell2cell.insert (std::make_pair (this_cell->id (), c->id ()));
|
||||||
|
|
@ -1934,6 +1936,19 @@ static void map_databases (rdb::Database &self, const rdb::Database &other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// import and map references for new cells
|
||||||
|
for (auto cp = new_cells.begin (); cp != new_cells.end (); ++cp) {
|
||||||
|
auto &new_refs = cp->first->references ();
|
||||||
|
for (auto r = cp->second->references ().begin (); r != cp->second->references ().end (); ++r) {
|
||||||
|
rdb::Reference rnew = *r;
|
||||||
|
auto cid = rev_cell2cell.find (rnew.parent_cell_id ());
|
||||||
|
if (cid != rev_cell2cell.end ()) {
|
||||||
|
rnew.set_parent_cell_id (cid->second);
|
||||||
|
new_refs.insert (rnew);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto c = other.categories ().begin (); c != other.categories ().end (); ++c) {
|
for (auto c = other.categories ().begin (); c != other.categories ().end (); ++c) {
|
||||||
map_category (*c, self, cat2cat, rev_cat2cat, create_missing, 0);
|
map_category (*c, self, cat2cat, rev_cat2cat, create_missing, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -979,16 +979,18 @@ TEST(22_MergeCells)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
rdb::Cell *cell1, *cell2, *cell3;
|
||||||
|
cell1 = db2.create_cell ("B");
|
||||||
|
cell2 = db2.create_cell ("A");
|
||||||
|
cell3 = db2.create_cell ("A", "VAR2", "ALAY");
|
||||||
|
|
||||||
|
// NOTE: db2 parent is at a different position (issue #2339)
|
||||||
rdb::Cell *parent;
|
rdb::Cell *parent;
|
||||||
parent = db2.create_cell ("TOP");
|
parent = db2.create_cell ("TOP");
|
||||||
|
|
||||||
rdb::Cell *cell;
|
cell1->references ().insert (rdb::Reference (db::DCplxTrans (db::DVector (1.0, 0.0)), parent->id ()));
|
||||||
cell = db2.create_cell ("B");
|
cell2->references ().insert (rdb::Reference (db::DCplxTrans (db::DVector (1.0, 2.5)), parent->id ())); // reference not taken as cell will be taken from db1
|
||||||
cell->references ().insert (rdb::Reference (db::DCplxTrans (db::DVector (1.0, 0.0)), parent->id ()));
|
cell3->references ().insert (rdb::Reference (db::DCplxTrans (db::DVector (1.0, -1.0)), parent->id ()));
|
||||||
cell = db2.create_cell ("A");
|
|
||||||
cell->references ().insert (rdb::Reference (db::DCplxTrans (db::DVector (1.0, 2.5)), parent->id ())); // reference not taken!
|
|
||||||
cell = db2.create_cell ("A", "VAR2", "ALAY");
|
|
||||||
cell->references ().insert (rdb::Reference (db::DCplxTrans (db::DVector (1.0, -1.0)), parent->id ()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db1.merge (db2);
|
db1.merge (db2);
|
||||||
|
|
@ -996,13 +998,13 @@ TEST(22_MergeCells)
|
||||||
std::set<std::string> cells;
|
std::set<std::string> cells;
|
||||||
for (auto c = db1.cells ().begin (); c != db1.cells ().end (); ++c) {
|
for (auto c = db1.cells ().begin (); c != db1.cells ().end (); ++c) {
|
||||||
if (c->references ().begin () != c->references ().end ()) {
|
if (c->references ().begin () != c->references ().end ()) {
|
||||||
cells.insert (c->qname () + "[" + c->references ().begin ()->trans_str () + "]");
|
cells.insert (c->qname () + "[" + c->references ().begin ()->trans_str () + ":" + db1.cell_by_id (c->references ().begin ()->parent_cell_id ())->qname () + "]");
|
||||||
} else {
|
} else {
|
||||||
cells.insert (c->qname ());
|
cells.insert (c->qname ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_EQ (tl::join (cells.begin (), cells.end (), ";"), "A:1[r0 *1 1,2];A:VAR1[r0 *1 1,-2];A:VAR2[r0 *1 1,-1];B[r0 *1 1,0];TOP");
|
EXPECT_EQ (tl::join (cells.begin (), cells.end (), ";"), "A:1[r0 *1 1,2:TOP];A:VAR1[r0 *1 1,-2:TOP];A:VAR2[r0 *1 1,-1:TOP];B[r0 *1 1,0:TOP];TOP");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(23_MergeTags)
|
TEST(23_MergeTags)
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,13 @@
|
||||||
|
* Extracted by KLayout
|
||||||
|
|
||||||
|
.SUBCKT TOP A Q IOSUB SUBSTRATE
|
||||||
|
X$1 \$7 \$1 Q IOSUB IOSUB INV
|
||||||
|
X$2 \$7 A \$1 SUBSTRATE SUBSTRATE INV
|
||||||
|
.ENDS TOP
|
||||||
|
|
||||||
|
.SUBCKT INV \$2 \$4 \$5 \$1 \$I11
|
||||||
|
M$1 \$2 \$4 \$5 \$2 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||||
|
+ PD=3.45U
|
||||||
|
M$2 \$1 \$4 \$5 \$I11 NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U
|
||||||
|
+ PD=3.45U
|
||||||
|
.ENDS INV
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,215 @@
|
||||||
|
#%l2n-klayout
|
||||||
|
W(TOP)
|
||||||
|
U(0.001)
|
||||||
|
L(l3 '1/0')
|
||||||
|
L(l4 '3/0')
|
||||||
|
L(l15 '3/1')
|
||||||
|
L(l8 '4/0')
|
||||||
|
L(l11 '5/0')
|
||||||
|
L(l12 '6/0')
|
||||||
|
L(l16 '6/1')
|
||||||
|
L(l13 '7/0')
|
||||||
|
L(l14 '8/0')
|
||||||
|
L(l17)
|
||||||
|
L(l22 '10/0')
|
||||||
|
L(l7)
|
||||||
|
L(l10)
|
||||||
|
L(l2)
|
||||||
|
L(l9)
|
||||||
|
L(l6)
|
||||||
|
L(l21)
|
||||||
|
L(l18)
|
||||||
|
L(l20)
|
||||||
|
L(l19)
|
||||||
|
C(l3 l3 l10)
|
||||||
|
C(l4 l4 l15 l11)
|
||||||
|
C(l15 l4 l15)
|
||||||
|
C(l8 l8 l12 l10 l2 l9 l6)
|
||||||
|
CS(l8 l10 l2 l9 l6)
|
||||||
|
C(l11 l4 l11 l12)
|
||||||
|
CS(l11 l4)
|
||||||
|
C(l12 l8 l11 l12 l16 l13)
|
||||||
|
C(l16 l12 l16)
|
||||||
|
C(l13 l12 l13 l14)
|
||||||
|
C(l14 l13 l14 l17)
|
||||||
|
C(l17 l14 l17)
|
||||||
|
C(l22 l22 l21 l20)
|
||||||
|
C(l7 l7 l18 l20)
|
||||||
|
C(l10 l3 l8 l10)
|
||||||
|
CS(l10 l3)
|
||||||
|
C(l2 l8 l2)
|
||||||
|
C(l9 l8 l9 l21 l19)
|
||||||
|
C(l6 l8 l6)
|
||||||
|
C(l21 l22 l9 l21)
|
||||||
|
CS(l21 l22)
|
||||||
|
C(l18 l7 l18)
|
||||||
|
C(l20 l22 l7 l20)
|
||||||
|
C(l19 l9 l19)
|
||||||
|
G(l22 IOSUB)
|
||||||
|
G(l18 SUBSTRATE)
|
||||||
|
G(l19 SUBSTRATE)
|
||||||
|
GS(l19 SUBSTRATE)
|
||||||
|
H(W B('Net with incomplete wiring (soft-connected partial nets)') C(TOP) X('soft-connection-check'))
|
||||||
|
H(B('\tPartial net #1: TOP/INV[r0 3,1.6]:$1 - $2') C(TOP) Q('(1.5,3.95;1.5,4.85;5.3,4.85;5.3,3.95)'))
|
||||||
|
H(B('\tPartial net #2: TOP/INV[r0 7.7,1.6]:$2 - $2') C(TOP) Q('(6.2,3.95;6.2,4.85;10,4.85;10,3.95)'))
|
||||||
|
K(PMOS MOS4)
|
||||||
|
K(NMOS MOS4)
|
||||||
|
D(D$PMOS PMOS
|
||||||
|
T(S
|
||||||
|
R(l2 (-900 -475) (775 950))
|
||||||
|
)
|
||||||
|
T(G
|
||||||
|
R(l4 (-125 -475) (250 950))
|
||||||
|
)
|
||||||
|
T(D
|
||||||
|
R(l2 (125 -475) (775 950))
|
||||||
|
)
|
||||||
|
T(B
|
||||||
|
R(l3 (-125 -475) (250 950))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
D(D$NMOS NMOS
|
||||||
|
T(S
|
||||||
|
R(l6 (-900 -475) (775 950))
|
||||||
|
)
|
||||||
|
T(G
|
||||||
|
R(l4 (-125 -475) (250 950))
|
||||||
|
)
|
||||||
|
T(D
|
||||||
|
R(l6 (125 -475) (775 950))
|
||||||
|
)
|
||||||
|
T(B
|
||||||
|
R(l7 (-125 -475) (250 950))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(INV
|
||||||
|
R((-1500 -800) (3800 4600))
|
||||||
|
N(1 I($1)
|
||||||
|
R(l8 (1700 100) (200 200))
|
||||||
|
R(l8 (-200 -600) (200 200))
|
||||||
|
R(l8 (-1610 -210) (220 220))
|
||||||
|
R(l8 (-220 180) (220 220))
|
||||||
|
R(l12 (890 -760) (800 900))
|
||||||
|
R(l12 (-1980 -830) (360 760))
|
||||||
|
R(l13 (-305 -705) (250 250))
|
||||||
|
R(l13 (-250 150) (250 250))
|
||||||
|
R(l13 (1175 -225) (200 200))
|
||||||
|
R(l13 (-200 -600) (200 200))
|
||||||
|
R(l14 (-3400 -350) (3000 900))
|
||||||
|
R(l14 (-200 -900) (1000 900))
|
||||||
|
R(l9 (-700 -950) (400 1000))
|
||||||
|
R(l6 (-1875 -975) (775 950))
|
||||||
|
)
|
||||||
|
N(2 I($2)
|
||||||
|
R(l3 (-1500 1800) (3000 2000))
|
||||||
|
R(l3 (-200 -2000) (1000 2000))
|
||||||
|
R(l8 (-2010 -1310) (220 220))
|
||||||
|
R(l8 (-220 180) (220 220))
|
||||||
|
R(l8 (1190 -210) (200 200))
|
||||||
|
R(l8 (-200 -600) (200 200))
|
||||||
|
R(l12 (-1680 -280) (360 760))
|
||||||
|
R(l12 (820 -830) (800 900))
|
||||||
|
R(l13 (-1925 -775) (250 250))
|
||||||
|
R(l13 (-250 150) (250 250))
|
||||||
|
R(l13 (1175 -225) (200 200))
|
||||||
|
R(l13 (-200 -600) (200 200))
|
||||||
|
R(l14 (-3400 -350) (3000 900))
|
||||||
|
R(l14 (-200 -900) (1000 900))
|
||||||
|
R(l10 (-700 -950) (400 1000))
|
||||||
|
R(l2 (-1875 -975) (775 950))
|
||||||
|
)
|
||||||
|
N(3 I($4)
|
||||||
|
R(l4 (-125 -250) (250 2500))
|
||||||
|
R(l4 (-250 -3050) (250 1600))
|
||||||
|
R(l4 (-250 1200) (250 1600))
|
||||||
|
)
|
||||||
|
N(4 I($5)
|
||||||
|
R(l8 (-510 -310) (220 220))
|
||||||
|
R(l8 (-220 180) (220 220))
|
||||||
|
R(l8 (-220 2180) (220 220))
|
||||||
|
R(l8 (-220 180) (220 220))
|
||||||
|
R(l12 (-290 -3530) (360 2840))
|
||||||
|
R(l12 (-360 -2800) (360 760))
|
||||||
|
R(l12 (-360 2040) (360 760))
|
||||||
|
R(l2 (-680 -855) (775 950))
|
||||||
|
R(l6 (-775 -3750) (775 950))
|
||||||
|
)
|
||||||
|
N(5 I($I11))
|
||||||
|
P(2)
|
||||||
|
P(3)
|
||||||
|
P(4)
|
||||||
|
P(1)
|
||||||
|
P(5)
|
||||||
|
D(1 D$PMOS
|
||||||
|
Y(0 2800)
|
||||||
|
E(L 0.25)
|
||||||
|
E(W 0.95)
|
||||||
|
E(AS 0.73625)
|
||||||
|
E(AD 0.73625)
|
||||||
|
E(PS 3.45)
|
||||||
|
E(PD 3.45)
|
||||||
|
T(S 4)
|
||||||
|
T(G 3)
|
||||||
|
T(D 2)
|
||||||
|
T(B 2)
|
||||||
|
)
|
||||||
|
D(2 D$NMOS
|
||||||
|
Y(0 0)
|
||||||
|
E(L 0.25)
|
||||||
|
E(W 0.95)
|
||||||
|
E(AS 0.73625)
|
||||||
|
E(AD 0.73625)
|
||||||
|
E(PS 3.45)
|
||||||
|
E(PD 3.45)
|
||||||
|
T(S 4)
|
||||||
|
T(G 3)
|
||||||
|
T(D 1)
|
||||||
|
T(B 5)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
X(TOP
|
||||||
|
R((1334 621) (9246 5073))
|
||||||
|
N(1 I($1)
|
||||||
|
R(l4 (2920 2600) (3980 400))
|
||||||
|
R(l11 (-300 -300) (200 200))
|
||||||
|
R(l12 (-300 -300) (690 400))
|
||||||
|
)
|
||||||
|
N(2 I(A)
|
||||||
|
R(l4 (7700 2600) (2880 400))
|
||||||
|
R(l15 (-2380 -200) (0 0))
|
||||||
|
)
|
||||||
|
N(3 I(Q)
|
||||||
|
R(l12 (1810 2600) (690 400))
|
||||||
|
R(l16 (-400 -200) (0 0))
|
||||||
|
)
|
||||||
|
N(4 I(IOSUB)
|
||||||
|
R(l22 (1334 621) (4230 5073))
|
||||||
|
R(l21 (-964 -4594) (400 1000))
|
||||||
|
R(l20 (-2125 -975) (250 950))
|
||||||
|
)
|
||||||
|
N(5 I($7)
|
||||||
|
R(l3 (4000 3400) (2700 2000))
|
||||||
|
)
|
||||||
|
N(6 I(SUBSTRATE)
|
||||||
|
R(l18 (7575 1125) (250 950))
|
||||||
|
R(l19 (1475 -975) (400 1000))
|
||||||
|
)
|
||||||
|
P(2 I(A))
|
||||||
|
P(3 I(Q))
|
||||||
|
P(4 I(IOSUB))
|
||||||
|
P(6 I(SUBSTRATE))
|
||||||
|
X(1 INV Y(3000 1600)
|
||||||
|
P(0 5)
|
||||||
|
P(1 1)
|
||||||
|
P(2 3)
|
||||||
|
P(3 4)
|
||||||
|
P(4 4)
|
||||||
|
)
|
||||||
|
X(2 INV Y(7700 1600)
|
||||||
|
P(0 5)
|
||||||
|
P(1 2)
|
||||||
|
P(2 1)
|
||||||
|
P(3 6)
|
||||||
|
P(4 6)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
|
||||||
|
$lvs_test_source && source($lvs_test_source)
|
||||||
|
|
||||||
|
if $lvs_test_target_l2n
|
||||||
|
report_netlist($lvs_test_target_l2n)
|
||||||
|
else
|
||||||
|
report_netlist
|
||||||
|
end
|
||||||
|
|
||||||
|
writer = write_spice(true, false)
|
||||||
|
$lvs_test_target_cir && target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout")
|
||||||
|
|
||||||
|
deep
|
||||||
|
|
||||||
|
# Drawing layers
|
||||||
|
|
||||||
|
nwell = input(1, 0)
|
||||||
|
active = input(2, 0)
|
||||||
|
nplus = input(2, 1)
|
||||||
|
pplus = input(2, 2)
|
||||||
|
poly = input(3, 0)
|
||||||
|
poly_lbl = input(3, 1)
|
||||||
|
diff_cont = input(4, 0)
|
||||||
|
poly_cont = input(5, 0)
|
||||||
|
metal1 = input(6, 0)
|
||||||
|
metal1_lbl = input(6, 1)
|
||||||
|
via1 = input(7, 0)
|
||||||
|
metal2 = input(8, 0)
|
||||||
|
metal2_lbl = input(8, 1)
|
||||||
|
iosub = input(10, 0)
|
||||||
|
|
||||||
|
# Bulk layer for terminal provisioning
|
||||||
|
|
||||||
|
bulk = polygon_layer
|
||||||
|
|
||||||
|
psd = nil
|
||||||
|
nsd = nil
|
||||||
|
|
||||||
|
# Computed layers
|
||||||
|
|
||||||
|
active_in_nwell = active & nwell
|
||||||
|
pactive = active_in_nwell & pplus
|
||||||
|
ntie = active_in_nwell & nplus
|
||||||
|
pgate = pactive & poly
|
||||||
|
psd = pactive - pgate
|
||||||
|
|
||||||
|
active_outside_nwell = active - nwell
|
||||||
|
nactive = active_outside_nwell & nplus
|
||||||
|
ptie = active_outside_nwell & pplus
|
||||||
|
ngate = nactive & poly
|
||||||
|
nsd = nactive - ngate
|
||||||
|
|
||||||
|
# Device extraction
|
||||||
|
|
||||||
|
# PMOS transistor device extraction
|
||||||
|
extract_devices(mos4("PMOS"), { "SD" => psd, "G" => pgate, "W" => nwell,
|
||||||
|
"tS" => psd, "tD" => psd, "tG" => poly })
|
||||||
|
|
||||||
|
# NMOS transistor device extraction
|
||||||
|
extract_devices(mos4("NMOS"), { "SD" => nsd, "G" => ngate, "W" => bulk,
|
||||||
|
"tS" => nsd, "tD" => nsd, "tG" => poly })
|
||||||
|
|
||||||
|
# Define connectivity for netlist extraction
|
||||||
|
|
||||||
|
# Inter-layer
|
||||||
|
|
||||||
|
soft_connect(diff_cont, psd)
|
||||||
|
soft_connect(diff_cont, nsd)
|
||||||
|
soft_connect(diff_cont, ptie)
|
||||||
|
soft_connect(diff_cont, ntie)
|
||||||
|
soft_connect(ntie, nwell)
|
||||||
|
soft_connect(poly_cont, poly)
|
||||||
|
|
||||||
|
connect(diff_cont, metal1)
|
||||||
|
connect(poly_cont, metal1)
|
||||||
|
connect(metal1, via1)
|
||||||
|
connect(via1, metal2)
|
||||||
|
|
||||||
|
# attach labels
|
||||||
|
connect(poly, poly_lbl)
|
||||||
|
connect(metal1, metal1_lbl)
|
||||||
|
connect(metal2, metal2_lbl)
|
||||||
|
|
||||||
|
# Split bulk and ptie into inside and outside iosub
|
||||||
|
(bulk_io, bulk_reg) = bulk.andnot(iosub)
|
||||||
|
(ptie_io, ptie_reg) = ptie.andnot(iosub)
|
||||||
|
|
||||||
|
# connect outside to "SUBSTRATE" globally
|
||||||
|
connect(bulk, bulk_reg)
|
||||||
|
connect(ptie, ptie_reg)
|
||||||
|
connect_global(bulk_reg, "SUBSTRATE")
|
||||||
|
soft_connect_global(ptie_reg, "SUBSTRATE")
|
||||||
|
|
||||||
|
# connect inside to "IOSUB" via polygons
|
||||||
|
connect(bulk, bulk_io)
|
||||||
|
connect(ptie, ptie_io)
|
||||||
|
connect(bulk_io, iosub)
|
||||||
|
soft_connect(ptie_io, iosub)
|
||||||
|
connect_global(iosub, "IOSUB")
|
||||||
|
|
||||||
|
# Netlist section (NOTE: we only check log here)
|
||||||
|
# for debugging: _make_soft_connection_diodes(true)
|
||||||
|
netlist
|
||||||
|
|
||||||
|
netlist.simplify
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue