Merge branch 'drc-enhancements' into fill-enhancements

This commit is contained in:
Matthias Koefferlein 2021-03-29 15:07:47 +02:00
commit 8fda92a9c4
137 changed files with 3864 additions and 1304 deletions

View File

@ -34,7 +34,7 @@ def Get_Default_Config():
Usage = "\n"
Usage += "---------------------------------------------------------------------------------------------------------\n"
Usage += "<< Usage of 'build4mac.py' >>\n"
Usage += " for building KLayout 0.26.1 or later on different Apple Mac OSX platforms.\n"
Usage += " for building KLayout 0.26.11 or later on different Apple Mac OSX platforms.\n"
Usage += "\n"
Usage += "$ [python] ./build4mac.py \n"
Usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value\n"
@ -58,6 +58,7 @@ def Get_Default_Config():
Usage += " : Ana3: use Python 3.7 from Anaconda3 | \n"
Usage += " : HBAuto: use the latest Python 3.x auto-detected from Homebrew | \n"
Usage += " [-n|--noqtbinding] : don't create Qt bindings for ruby scripts | disabled \n"
Usage += " [-u|--noqtuitools] : don't include uitools in Qt binding | disabled \n"
Usage += " [-m|--make <option>] : option passed to 'make' | '-j4' \n"
Usage += " [-d|--debug] : enable debug mode build | disabled \n"
Usage += " [-c|--checkcom] : check command-line and exit without building | disabled \n"
@ -137,6 +138,7 @@ def Get_Default_Config():
NonOSStdLang = False
NoQtBindings = False
NoQtUiTools = False
MakeOptions = "-j4"
DebugMode = False
CheckComOnly = False
@ -157,6 +159,7 @@ def Get_Default_Config():
config['ModulePython'] = ModulePython # Python module to be used
config['NonOSStdLang'] = NonOSStdLang # True if non-OS-standard language is chosen
config['NoQtBindings'] = NoQtBindings # True if not creating Qt bindings for Ruby scripts
config['NoQtUiTools'] = NoQtUiTools # True if not to include QtUiTools in Qt binding
config['MakeOptions'] = MakeOptions # options passed to `make`
config['DebugMode'] = DebugMode # True if debug mode build
config['CheckComOnly'] = CheckComOnly # True if only for checking the command line parameters to "build.sh"
@ -195,6 +198,7 @@ def Parse_CLI_Args(config):
ModulePython = config['ModulePython']
NonOSStdLang = config['NonOSStdLang']
NoQtBindings = config['NoQtBindings']
NoQtUiTools = config['NoQtUiTools']
MakeOptions = config['MakeOptions']
DebugMode = config['DebugMode']
CheckComOnly = config['CheckComOnly']
@ -226,6 +230,12 @@ def Parse_CLI_Args(config):
default=False,
help="do not create Qt bindings for Ruby scripts" )
p.add_option( '-u', '--noqtuitools',
action='store_true',
dest='no_qt_uitools',
default=False,
help="don't include uitools in Qt binding" )
p.add_option( '-m', '--make',
dest='make_option',
help="options passed to `make`" )
@ -268,6 +278,7 @@ def Parse_CLI_Args(config):
type_ruby = "sys",
type_python = "sys",
no_qt_binding = False,
no_qt_uitools = False,
make_option = "-j4",
debug_build = False,
check_command = False,
@ -406,6 +417,7 @@ def Parse_CLI_Args(config):
ModuleSet = ( choiceQt5, choiceRuby, choicePython )
NoQtBindings = opt.no_qt_binding
NoQtUiTools = opt.no_qt_uitools
MakeOptions = opt.make_option
DebugMode = opt.debug_build
CheckComOnly = opt.check_command
@ -462,6 +474,7 @@ def Parse_CLI_Args(config):
config['ModulePython'] = ModulePython
config['NonOSStdLang'] = NonOSStdLang
config['NoQtBindings'] = NoQtBindings
config['NoQtUiTools'] = NoQtUiTools
config['MakeOptions'] = MakeOptions
config['DebugMode'] = DebugMode
config['CheckComOnly'] = CheckComOnly
@ -491,6 +504,7 @@ def Get_Build_Parameters(config):
ModulePython = config['ModulePython']
ModuleSet = config['ModuleSet']
NoQtBindings = config['NoQtBindings']
NoQtUiTools = config['NoQtUiTools']
MakeOptions = config['MakeOptions']
DebugMode = config['DebugMode']
CheckComOnly = config['CheckComOnly']
@ -542,11 +556,14 @@ def Get_Build_Parameters(config):
# (E) want Qt bindings with Ruby scripts?
parameters['no_qt_bindings'] = NoQtBindings
# (F) options to `make` tool
# (F) want QtUiTools?
parameters['no_qt_uitools'] = NoQtUiTools
# (G) options to `make` tool
if not MakeOptions == "":
parameters['make_options'] = MakeOptions
# (G) about Ruby
# (H) about Ruby
if ModuleRuby != "nil":
parameters['ruby'] = RubyDictionary[ModuleRuby]['exe']
parameters['rbinc'] = RubyDictionary[ModuleRuby]['inc']
@ -554,7 +571,7 @@ def Get_Build_Parameters(config):
if 'inc2' in RubyDictionary[ModuleRuby]:
parameters['rbinc2'] = RubyDictionary[ModuleRuby]['inc2']
# (H) about Python
# (I) about Python
if ModulePython != "nil":
parameters['python'] = PythonDictionary[ModulePython]['exe']
parameters['pyinc'] = PythonDictionary[ModulePython]['inc']
@ -566,7 +583,7 @@ def Get_Build_Parameters(config):
config['MacBuildDirQAT'] = MacBuildDirQAT # relative path to build directory for QATest
config['MacBuildLog'] = MacBuildLog # relative path to build log file
# (I) Extra parameteres needed for deployment
# (J) Extra parameters needed for deployment
parameters['project_dir'] = ProjectDir
return parameters
@ -607,11 +624,15 @@ def Run_Build_Command(parameters):
else:
cmd_args += " \\\n -with-qtbinding"
# (F) options to `make` tool
# (F) want QtUiTools?
if parameters['no_qt_uitools']:
cmd_args += " \\\n -without-qt-uitools"
# (G) options to `make` tool
if 'make_options' in parameters:
cmd_args += " \\\n -option %s" % parameters['make_options']
# (G) about Ruby
# (H) about Ruby
if 'ruby' in parameters:
cmd_args += " \\\n -ruby %s" % parameters['ruby']
cmd_args += " \\\n -rbinc %s" % parameters['rbinc']
@ -621,7 +642,7 @@ def Run_Build_Command(parameters):
else:
cmd_args += " \\\n -noruby"
# (H) about Python
# (I) about Python
if 'python' in parameters:
cmd_args += " \\\n -python %s" % parameters['python']
cmd_args += " \\\n -pyinc %s" % parameters['pyinc']

View File

@ -378,28 +378,77 @@ AsIfFlatRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &f
return new_edge_pairs.release ();
}
RegionDelegate *
AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const
namespace {
class OutputPairHolder
{
public:
OutputPairHolder (InteractingOutputMode output_mode, bool merged_semantics)
{
if (output_mode == None) {
return;
}
if (output_mode == Positive || output_mode == Negative || output_mode == PositiveAndNegative) {
m_positive.reset (new FlatRegion (merged_semantics));
m_results.push_back (& m_positive->raw_polygons ());
} else {
m_results.push_back ((db::Shapes *) 0);
}
if (output_mode == PositiveAndNegative) {
m_negative.reset (new FlatRegion (merged_semantics));
m_results.push_back (& m_negative->raw_polygons ());
}
}
std::pair<RegionDelegate *, RegionDelegate *> region_pair ()
{
return std::make_pair (m_positive.release (), m_negative.release ());
}
const std::vector<db::Shapes *> &results () { return m_results; }
private:
std::unique_ptr<FlatRegion> m_positive, m_negative;
std::vector<db::Shapes *> m_results;
};
}
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
OutputPairHolder oph (output_mode, merged_semantics ());
if (output_mode == None) {
return oph.region_pair ();
}
min_count = std::max (size_t (1), min_count);
if (max_count < min_count || other.empty ()) {
if (! inverse) {
return new EmptyRegion ();
// shortcut
if (empty ()) {
if (output_mode == Positive || output_mode == Negative) {
return std::make_pair (clone (), (RegionDelegate *) 0);
} else {
return clone ();
return std::make_pair (clone (), clone ());
}
} else if (max_count < min_count || other.empty ()) {
if (output_mode == Positive) {
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
} else if (output_mode == Negative) {
return std::make_pair (clone (), (RegionDelegate *) 0);
} else {
return std::make_pair (new EmptyRegion (), clone ());
}
} else if (empty ()) {
return clone ();
}
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
#if defined(USE_LOCAL_PROCESSOR)
db::RegionIterator polygons (begin_merged ());
db::interacting_with_edge_local_operation<db::Polygon, db::Edge, db::Polygon> op (inverse, min_count, max_count, true);
db::interacting_with_edge_local_operation<db::Polygon, db::Edge, db::Polygon> op (output_mode, min_count, max_count, true);
db::local_processor<db::Polygon, db::Edge, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());
@ -413,71 +462,42 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse,
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
return output.release ();
#else
std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > counted_results;
ResultCountingInserter inserter (counted_results);
db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve1 (count ());
scanner.reserve2 (other.count ());
std::unique_ptr<FlatRegion> output (new FlatRegion (false));
region_to_edge_interaction_filter<db::Polygon, db::Edge, ResultCountingInserter> filter (inserter, false, counting /*get all in counting mode*/);
AddressablePolygonDelivery p (begin_merged ());
for ( ; ! p.at_end (); ++p) {
scanner.insert1 (p.operator-> (), 0);
if (inverse) {
inserter.init (p.operator-> ());
}
}
AddressableEdgeDelivery e (counting ? other.addressable_merged_edges () : other.addressable_edges ());
for ( ; ! e.at_end (); ++e) {
scanner.insert2 (e.operator-> (), 0);
}
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Edge> ());
// select hits based on their count
for (std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> >::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
bool hit = r->second >= min_count && r->second <= max_count;
if (hit != inverse) {
output->insert (*r->first);
}
}
return output.release ();
#endif
return oph.region_pair ();
}
RegionDelegate *
AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
OutputPairHolder oph (output_mode, merged_semantics ());
if (max_count < min_count || other.empty ()) {
if (! inverse) {
return new EmptyRegion ();
} else {
return clone ();
}
} else if (empty ()) {
return clone ();
if (output_mode == None) {
return oph.region_pair ();
}
#if defined(USE_LOCAL_PROCESSOR)
min_count = std::max (size_t (1), min_count);
// shortcut
if (empty ()) {
if (output_mode == Positive || output_mode == Negative) {
return std::make_pair (clone (), (RegionDelegate *) 0);
} else {
return std::make_pair (clone (), clone ());
}
} else if (max_count < min_count || other.empty ()) {
if (output_mode == Positive) {
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
} else if (output_mode == Negative) {
return std::make_pair (clone (), (RegionDelegate *) 0);
} else {
return std::make_pair (new EmptyRegion (), clone ());
}
}
db::RegionIterator polygons (begin_merged ());
db::interacting_with_text_local_operation<db::Polygon, db::Text, db::Polygon> op (inverse, min_count, max_count);
db::interacting_with_text_local_operation<db::Polygon, db::Text, db::Polygon> op (output_mode, min_count, max_count);
db::local_processor<db::Polygon, db::Text, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());
@ -487,84 +507,58 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse,
std::vector<generic_shape_iterator<db::Text> > others;
others.push_back (other.begin ());
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ()));
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();
#else
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > counted_results;
ResultCountingInserter inserter (counted_results);
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner (report_progress (), progress_desc ());
scanner.reserve1 (count ());
scanner.reserve2 (other.count ());
region_to_text_interaction_filter<db::Polygon, db::Text, ResultCountingInserter> filter (inserter, false, counting /*get all in counting mode*/);
AddressablePolygonDelivery p (begin_merged ());
for ( ; ! p.at_end (); ++p) {
scanner.insert1 (p.operator-> (), 0);
if (inverse) {
inserter.init (p.operator-> ());
}
}
AddressableTextDelivery e (other.addressable_texts ());
for ( ; ! e.at_end (); ++e) {
scanner.insert2 (e.operator-> (), 0);
}
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
// select hits based on their count
std::unique_ptr<FlatRegion> output (new FlatRegion (true));
for (std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> >::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
bool hit = r->second >= min_count && r->second <= max_count;
if (hit != inverse) {
output->insert (*r->first);
}
}
return output.release ();
#endif
return oph.region_pair ();
}
RegionDelegate *
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const
std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
OutputPairHolder oph (output_mode, merged_semantics ());
if (output_mode == None) {
return oph.region_pair ();
}
min_count = std::max (size_t (1), min_count);
// shortcut
if (empty ()) {
return clone ();
if (output_mode == Positive || output_mode == Negative) {
return std::make_pair (clone (), (RegionDelegate *) 0);
} else {
return std::make_pair (clone (), clone ());
}
} else if (max_count < min_count || other.empty ()) {
// clear, if b is empty and
// * mode is inside, enclosing or interacting and inverse is false ("inside" or "interacting")
// * mode is outside and inverse is true ("not outside")
if ((mode <= 0) != inverse) {
return new EmptyRegion ();
if ((mode <= 0)) {
if (output_mode == Positive) {
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
} else if (output_mode == Negative) {
return std::make_pair (clone (), (RegionDelegate *) 0);
} else {
return std::make_pair (new EmptyRegion (), clone ());
}
} else {
return clone ();
if (output_mode == Positive) {
return std::make_pair (clone(), (RegionDelegate *) 0);
} else if (output_mode == Negative) {
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
} else {
return std::make_pair (clone (), new EmptyRegion ());
}
}
}
#if defined(USE_LOCAL_PROCESSOR)
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
db::RegionIterator polygons (begin_merged ());
db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> op (mode, touching, inverse, min_count, max_count, true);
db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> op (mode, touching, output_mode, min_count, max_count, true);
db::local_processor<db::Polygon, db::Polygon, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ());
@ -574,121 +568,9 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
std::vector<generic_shape_iterator<db::Polygon> > others;
others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ());
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ()));
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();
#else
db::EdgeProcessor ep (report_progress (), progress_desc ());
ep.set_base_verbosity (base_verbosity ());
size_t n = 0;
size_t nstart = 0;
if (mode < -1) {
// in enclosing mode self must be primary and other the secondary. For other
// modes it's the other way round
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
if (mode > 0 || p->box ().touches (other.bbox ())) {
ep.insert (*p, n);
}
}
nstart = n;
}
if (min_count == size_t (1) && max_count == std::numeric_limits<size_t>::max ()) {
if (mode < 0) {
// NOTE: on "inside" or "enclosing", the other region must be merged
for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, n);
}
}
} else {
for (RegionIterator p = other.begin (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, n);
}
}
}
++n;
} else {
// with counting we need to separate the other polygons by different properties
// cannot only have min_count/max_count in outside mode
tl_assert (mode <= 0);
for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, n);
}
++n;
}
}
if (mode >= -1) {
nstart = n;
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
if (mode > 0 || p->box ().touches (other.bbox ())) {
ep.insert (*p, n);
}
}
}
// there should be at least one element to look at for primary
tl_assert (nstart > 0);
db::InteractionDetector id (mode, nstart - 1);
id.set_include_touching (touching);
db::EdgeSink es;
ep.process (es, id);
id.finish ();
std::unique_ptr<FlatRegion> output (new FlatRegion (false));
std::map <size_t, size_t> interaction_counts;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () ; ++i) {
if (i->first < nstart && i->second >= nstart) {
interaction_counts [mode < -1 ? i->first : i->second] += 1;
}
}
output->reserve (n);
n = (mode < -1 ? 0 : nstart);
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
size_t count = 0;
std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n);
if (c != interaction_counts.end ()) {
count = c->second;
}
if ((count >= min_count && count <= max_count) != inverse) {
output->insert (*p);
}
}
return output.release ();
#endif
return oph.region_pair ();
}
EdgesDelegate *

View File

@ -139,72 +139,107 @@ public:
virtual RegionDelegate *selected_outside (const Region &other) const
{
return selected_interacting_generic (other, 1, false, false);
return selected_interacting_generic (other, 1, false, Positive, size_t (0), std::numeric_limits<size_t>::max ()).first;
}
virtual RegionDelegate *selected_not_outside (const Region &other) const
{
return selected_interacting_generic (other, 1, false, true);
return selected_interacting_generic (other, 1, false, Negative, size_t (0), std::numeric_limits<size_t>::max ()).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &other) const
{
return selected_interacting_generic (other, 1, false, PositiveAndNegative, size_t (0), std::numeric_limits<size_t>::max ());
}
virtual RegionDelegate *selected_inside (const Region &other) const
{
return selected_interacting_generic (other, -1, true, false);
return selected_interacting_generic (other, -1, true, Positive, size_t (0), std::numeric_limits<size_t>::max ()).first;
}
virtual RegionDelegate *selected_not_inside (const Region &other) const
{
return selected_interacting_generic (other, -1, true, true);
return selected_interacting_generic (other, -1, true, Negative, size_t (0), std::numeric_limits<size_t>::max ()).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_inside_pair (const Region &other) const
{
return selected_interacting_generic (other, -1, true, PositiveAndNegative, size_t (0), std::numeric_limits<size_t>::max ());
}
virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, -2, false, false, min_count, max_count);
return selected_interacting_generic (other, -2, false, Positive, min_count, max_count).first;
}
virtual RegionDelegate *selected_not_enclosing (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, -2, false, true, min_count, max_count);
return selected_interacting_generic (other, -2, false, Negative, min_count, max_count).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_enclosing_pair (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, -2, false, PositiveAndNegative, min_count, max_count);
}
virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, 0, true, false, min_count, max_count);
return selected_interacting_generic (other, 0, true, Positive, min_count, max_count).first;
}
virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, 0, true, true, min_count, max_count);
return selected_interacting_generic (other, 0, true, Negative, min_count, max_count).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, 0, true, PositiveAndNegative, min_count, max_count);
}
virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, false, min_count, max_count);
return selected_interacting_generic (other, Positive, min_count, max_count).first;
}
virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, true, min_count, max_count);
return selected_interacting_generic (other, Negative, min_count, max_count).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, PositiveAndNegative, min_count, max_count);
}
virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, false, min_count, max_count);
return selected_interacting_generic (other, Positive, min_count, max_count).first;
}
virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, true, min_count, max_count);
return selected_interacting_generic (other, Negative, min_count, max_count).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Texts &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, PositiveAndNegative, min_count, max_count);
}
virtual RegionDelegate *selected_overlapping (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, 0, false, false, min_count, max_count);
return selected_interacting_generic (other, 0, false, Positive, min_count, max_count).first;
}
virtual RegionDelegate *selected_not_overlapping (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, 0, false, true, min_count, max_count);
return selected_interacting_generic (other, 0, false, Negative, min_count, max_count).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_overlapping_pair (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, 0, false, PositiveAndNegative, min_count, max_count);
}
virtual RegionDelegate *pull_inside (const Region &other) const
@ -245,9 +280,9 @@ protected:
virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const;
virtual EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const;
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
virtual EdgesDelegate *pull_generic (const Edges &other) const;
virtual TextsDelegate *pull_generic (const Texts &other) const;

View File

@ -1060,13 +1060,13 @@ template void CompoundRegionLogicalCaseSelectOperationNode::implement_compute_lo
// ---------------------------------------------------------------------------------------------
CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count)
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count, b->is_merged ())
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse ? Negative : Positive, min_count, max_count, b->is_merged ())
{
// .. nothing yet ..
}
CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (db::Region *a, db::Region *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count)
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count, b->is_merged ())
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse ? Negative : Positive, min_count, max_count, b->is_merged ())
{
// .. nothing yet ..
}
@ -1080,7 +1080,7 @@ CompoundRegionInteractOperationNode::generated_description () const
// ---------------------------------------------------------------------------------------------
CompoundRegionInteractWithEdgeOperationNode::CompoundRegionInteractWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, bool inverse, size_t min_count, size_t max_count)
: compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon> (&m_op, a, b), m_op (inverse, min_count, max_count, b->is_merged ())
: compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon> (&m_op, a, b), m_op (inverse ? Negative : Positive, min_count, max_count, b->is_merged ())
{
// .. nothing yet ..
}

View File

@ -753,7 +753,8 @@ public:
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::PolygonRef, db::PolygonRef> & /*interactions*/, std::vector<std::unordered_set<db::EdgePair> > & /*results*/, size_t /*max_vertex_count*/, double /*area_ratio*/) const { }
private:
db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> m_op;
typedef db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> op_type;
op_type m_op;
};
class DB_PUBLIC CompoundRegionInteractWithEdgeOperationNode

View File

@ -1519,9 +1519,67 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, c
return res.release ();
}
RegionDelegate *
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const
namespace
{
class InteractingResultHolder
{
public:
InteractingResultHolder (InteractingOutputMode output_mode, bool is_merged, const db::DeepLayer &polygons)
: m_output_mode (output_mode), m_is_merged (is_merged)
{
if (m_output_mode == Positive || m_output_mode == Negative) {
m_dl1 = db::DeepLayer (polygons.derived ());
} else if (m_output_mode == PositiveAndNegative) {
m_dl1 = db::DeepLayer (polygons.derived ());
m_dl2 = db::DeepLayer (polygons.derived ());
}
}
std::vector<unsigned int> layers () const
{
std::vector<unsigned int> l;
if (m_output_mode == Positive || m_output_mode == Negative) {
l.push_back (m_dl1.layer ());
} else if (m_output_mode == PositiveAndNegative) {
l.push_back (m_dl1.layer ());
l.push_back (m_dl2.layer ());
}
return l;
}
std::pair<RegionDelegate *, RegionDelegate *> result_pair ()
{
if (m_output_mode == Positive || m_output_mode == Negative) {
db::DeepRegion *res = new db::DeepRegion (m_dl1);
res->set_is_merged (m_is_merged);
return std::pair<RegionDelegate *, RegionDelegate *> (res, 0);
} else if (m_output_mode == PositiveAndNegative) {
db::DeepRegion *res1 = new db::DeepRegion (m_dl1);
res1->set_is_merged (m_is_merged);
db::DeepRegion *res2 = new db::DeepRegion (m_dl2);
res2->set_is_merged (m_is_merged);
return std::pair<RegionDelegate *, RegionDelegate *> (res1, res2);
} else {
return std::pair<RegionDelegate *, RegionDelegate *> (0, 0);
}
}
private:
InteractingOutputMode m_output_mode;
bool m_is_merged;
DeepLayer m_dl1, m_dl2;
};
}
std::pair<RegionDelegate *, RegionDelegate *>
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
if (output_mode == None) {
return std::pair<RegionDelegate *, RegionDelegate *> (0, 0);
}
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
// with these flag set to true, the resulting polygons are broken again.
@ -1539,9 +1597,7 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
// NOTE: on "inside" or with counting, the other polygons must be merged
const db::DeepLayer &other_polygons = (mode < 0 || counting) ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
DeepLayer dl_out (polygons.derived ());
db::InteractingLocalOperation op (mode, touching, inverse, min_count, max_count, true);
db::InteractingLocalOperation op (mode, touching, output_mode, min_count, max_count, true);
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ());
proc.set_description (progress_desc ());
@ -1553,17 +1609,16 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
}
proc.run (&op, polygons.layer (), other_polygons.layer (), dl_out.layer ());
bool result_is_merged = (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ()));
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
db::DeepRegion *res = new db::DeepRegion (dl_out);
if (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ())) {
res->set_is_merged (true);
}
return res;
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
return orh.result_pair ();
}
RegionDelegate *
DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const
std::pair<RegionDelegate *, RegionDelegate *>
DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
@ -1580,9 +1635,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size
const db::DeepLayer &polygons = merged_deep_layer ();
DeepLayer dl_out (polygons.derived ());
db::InteractingWithEdgeLocalOperation op (inverse, min_count, max_count, true);
db::InteractingWithEdgeLocalOperation op (output_mode, min_count, max_count, true);
db::local_processor<db::PolygonRef, db::Edge, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_description (progress_desc ());
@ -1594,13 +1647,12 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
}
proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), dl_out.layer ());
bool result_is_merged = (! split_after && other.is_merged () && (merged_semantics () || is_merged ()));
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
db::DeepRegion *res = new db::DeepRegion (dl_out);
if (! split_after) {
res->set_is_merged (other.is_merged () && (merged_semantics () || is_merged ()));
}
return res;
proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), orh.layers ());
return orh.result_pair ();
}
RegionDelegate *
@ -1706,8 +1758,9 @@ DeepRegion::pull_generic (const Texts &other) const
return res;
}
RegionDelegate *
DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const
std::pair<RegionDelegate *, RegionDelegate *>
DeepRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
{
// with these flag set to true, the resulting polygons are broken again.
bool split_after = false;
@ -1722,9 +1775,7 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size
const db::DeepLayer &polygons = merged_deep_layer ();
DeepLayer dl_out (polygons.derived ());
db::InteractingWithTextLocalOperation op (inverse, min_count, max_count);
db::InteractingWithTextLocalOperation op (output_mode, min_count, max_count);
db::local_processor<db::PolygonRef, db::TextRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_description (progress_desc ());
@ -1736,13 +1787,12 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
}
proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
bool result_is_merged = (! split_after && (merged_semantics () || is_merged ()));
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
db::DeepRegion *res = new db::DeepRegion (dl_out);
if (! split_after) {
res->set_is_merged (merged_semantics () || is_merged ());
}
return res;
proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), orh.layers ());
return orh.result_pair ();
}
}

View File

@ -140,9 +140,9 @@ protected:
virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const;
virtual EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const;
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const;
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const;
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
virtual EdgesDelegate *pull_generic (const Edges &other) const;
virtual TextsDelegate *pull_generic (const Texts &other) const;

View File

@ -953,7 +953,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
// collects the cell mappings we skip because they are variants (variant building or box variants)
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) {
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell () && original_builder.source ().global_trans ().is_unity ()) {
// This is the case of mapping back to the original. In this case we can use the information
// provided inside the original hierarchy builders. They list the source cells and the target cells

View File

@ -252,6 +252,7 @@ public:
DeviceParameterCompareDelegate () { }
virtual ~DeviceParameterCompareDelegate () { }
virtual DeviceParameterCompareDelegate *clone () const = 0;
virtual bool less (const db::Device &a, const db::Device &b) const = 0;
virtual bool equal (const db::Device &a, const db::Device &b) const = 0;
};
@ -273,6 +274,11 @@ public:
virtual bool less (const db::Device &a, const db::Device &b) const;
virtual bool equal (const db::Device &a, const db::Device &b) const;
virtual DeviceParameterCompareDelegate *clone () const
{
return new EqualDeviceParameters (*this);
}
EqualDeviceParameters &operator+= (const EqualDeviceParameters &other);
EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const
@ -298,6 +304,11 @@ public:
virtual bool less (const db::Device &a, const db::Device &b) const;
virtual bool equal (const db::Device &a, const db::Device &b) const;
virtual DeviceParameterCompareDelegate *clone () const
{
return new AllDeviceParametersAreEqual (*this);
}
private:
double m_relative;
};
@ -574,6 +585,14 @@ public:
/**
* @brief Gets the parameter compare delegate or null if no such delegate is registered
*/
const db::DeviceParameterCompareDelegate *parameter_compare_delegate () const
{
return mp_pc_delegate.get ();
}
/**
* @brief Gets the parameter compare delegate or null if no such delegate is registered (non-const version)
*/
db::DeviceParameterCompareDelegate *parameter_compare_delegate ()
{
return mp_pc_delegate.get ();

View File

@ -108,18 +108,25 @@ public:
virtual RegionDelegate *selected_outside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *selected_inside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_inside (const Region &) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_inside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *selected_enclosing (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_enclosing (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_enclosing_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *selected_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *selected_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Edges &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *selected_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Texts &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *selected_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); }
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_overlapping_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); }
virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); }

View File

@ -1280,6 +1280,14 @@ void local_processor<TS, TI, TR>::run (local_operation<TS, TI, TR> *op, unsigned
run (op, subject_layer, il, ol);
}
template <class TS, class TI, class TR>
void local_processor<TS, TI, TR>::run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, unsigned int intruder_layer, const std::vector<unsigned int> &output_layers)
{
std::vector<unsigned int> ol, il;
il.push_back (intruder_layer);
run (op, subject_layer, il, output_layers);
}
template <class TS, class TI, class TR>
void local_processor<TS, TI, TR>::run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers, unsigned int output_layer)
{

View File

@ -419,6 +419,7 @@ public:
local_processor (db::Layout *layout = 0, db::Cell *top = 0, const std::set<db::cell_index_type> *breakout_cells = 0);
local_processor (db::Layout *subject_layout, db::Cell *subject_top, const db::Layout *intruder_layout, const db::Cell *intruder_cell, const std::set<db::cell_index_type> *subject_breakout_cells = 0, const std::set<db::cell_index_type> *intruder_breakout_cells = 0);
void run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, unsigned int intruder_layer, unsigned int output_layers);
void run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, unsigned int intruder_layer, const std::vector<unsigned int> &output_layers);
void run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers, const std::vector<unsigned int> &output_layers);
void run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers, unsigned int output_layer);
void compute_contexts (local_processor_contexts<TS, TI, TR> &contexts, const local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers) const;

View File

@ -40,10 +40,10 @@ int
compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2)
{
if ((iter1.layout () == 0) != (iter2.layout () == 0)) {
return (iter1.layout () == 0) < (iter2.layout () == 0);
return (iter1.layout () == 0) < (iter2.layout () == 0) ? -1 : 1;
}
if ((iter1.top_cell () == 0) != (iter2.top_cell () == 0)) {
return (iter1.top_cell () == 0) < (iter2.top_cell () == 0);
return (iter1.top_cell () == 0) < (iter2.top_cell () == 0) ? -1 : 1;
}
// basic source (layout, top_cell) needs to be the same of course
@ -70,6 +70,11 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
return iter1.enables () < iter2.enables () ? -1 : 1;
}
// compare global transformations
if (! iter1.global_trans ().equal (iter2.global_trans ())) {
return iter1.global_trans ().less (iter2.global_trans ()) ? -1 : 1;
}
// if a region is set, the hierarchical appearance is the same only if the layers and
// complex region are identical
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) {
@ -338,7 +343,7 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
}
HierarchyBuilder::new_inst_mode
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
if (all) {
@ -349,6 +354,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
new_inst.object () = db::CellInst (new_cell);
new_inst.transform (always_apply);
new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst);
@ -367,7 +373,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
}
bool
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
{
if (all) {
@ -386,7 +392,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
// for a new cell, create this instance
if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (db::CellInst (new_cell), trans);
db::CellInstArray new_inst (db::CellInst (new_cell), always_apply * trans);
new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst);
@ -399,11 +405,11 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
}
void
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box &region, const box_tree_type *complex_region)
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &apply_always, const db::ICplxTrans & /*trans*/, const db::Box &region, const box_tree_type *complex_region)
{
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
db::Shapes &shapes = (*c)->shapes (m_target_layer);
mp_pipe->push (shape, m_trans, region, complex_region, &shapes);
mp_pipe->push (shape, m_trans * apply_always, region, complex_region, &shapes);
}
}
@ -528,9 +534,12 @@ ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Box &box, const
if (complex_region) {
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (bb, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
mp_pipe->push (*cr & bb, trans, world, 0, target);
db::Box bc = *cr & bb;
if (! bc.empty ()) {
mp_pipe->push (bc, trans, world, 0, target);
}
}
} else {
} else if (! bb.empty ()) {
mp_pipe->push (bb, trans, world, 0, target);
}
}

View File

@ -273,9 +273,9 @@ public:
virtual void end (const RecursiveShapeIterator *iter);
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box &region, const box_tree_type *complex_region);
virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell);
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region);
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region);
/**
* @brief Sets the target layer - shapes will be put there

View File

@ -1671,7 +1671,9 @@ Layout::do_update ()
// HINT: because of some gcc bug, automatic destruction of the tl::Progress
// object does not work. We overcome this problem by creating the object with new
// and catching exceptions.
tl::RelativeProgress *pr = new tl::RelativeProgress (tl::to_string (tr ("Sorting layout")), m_cells_size, 1000);
// As this operation is critical we don't want to have it cancelled. Plus: do_update is called during ~LayoutLocker and
// if we throw exceptions then, we'll get a runtime assertion.
tl::RelativeProgress *pr = new tl::RelativeProgress (tl::to_string (tr ("Sorting layout")), m_cells_size, 0, false /*can't cancel*/);
pr->set_desc ("");
try {

View File

@ -632,6 +632,9 @@ LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutTo
}
size_t pin_id = circuit->add_pin (pin).id ();
// NOTE: because we identify pins by their order and not by ID we need to ensure the pin IDs are
// generated sequentially.
tl_assert (circuit->pin_count () == pin_id + 1);
if (net) {
circuit->connect_pin (pin_id, net);
}

View File

@ -561,7 +561,8 @@ void std_writer_impl<Keys>::write (const db::SubCircuit &subcircuit, std::map<co
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
}
for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p) {
unsigned int pin_id = 0;
for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p, ++pin_id) {
const db::Net *net = subcircuit.net_for_pin (p->id ());
if (net) {
if (separate_lines) {
@ -569,7 +570,7 @@ void std_writer_impl<Keys>::write (const db::SubCircuit &subcircuit, std::map<co
} else {
*mp_stream << " ";
}
*mp_stream << Keys::pin_key << "(" << tl::to_string (p->id ()) << " " << net2id [net] << ")";
*mp_stream << Keys::pin_key << "(" << tl::to_string (pin_id) << " " << net2id [net] << ")";
if (separate_lines) {
*mp_stream << endl;
}

View File

@ -88,19 +88,19 @@ namespace db
*
* [xref-def]:
*
* circuit([non] [non] [status]? [circuit-xrefs])
* circuit([non] [non] [status]? [message]? [circuit-xrefs])
* - circuit pair [short key: X]
*
* [circuit-xrefs]:
*
* xref([pair]*)
* xref([pair]*) - circuit cross-reference part [short key: Z]
*
* [pair]
*
* pin([ion] [ion] [status]?) - a pin pair [short key: P]
* device([ion] [ion] [status]?) - a device pair [short key: D]
* circuit([ion] [ion] [status]?) - a subcircuit pair [short key: X]
* net([ion] [ion] [status]?) - a net pair [short key: N]
* pin([ion] [ion] [status]? [message]?) - a pin pair [short key: P]
* device([ion] [ion] [status]? [message]?) - a device pair [short key: D]
* circuit([ion] [ion] [status]? [message]?) - a subcircuit pair [short key: X]
* net([ion] [ion] [status]? [message]?) - a net pair [short key: N]
*
* [non]
*
@ -110,6 +110,10 @@ namespace db
*
* <id> | ()
*
* [message]
*
* description(<name>) - error description [short key: B]
*
* [status]
*
* mismatch | - [short key: 0]

View File

@ -112,6 +112,18 @@ void LayoutVsSchematicStandardReader::read_netlist (db::LayoutVsSchematic *lvs)
}
}
bool LayoutVsSchematicStandardReader::read_message (std::string &msg)
{
if (test (skeys::description_key) || test (lkeys::description_key)) {
Brace br (this);
read_word_or_quoted (msg);
br.done ();
return true;
} else {
return false;
}
}
bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::Status &status)
{
if (test (skeys::match_key) || test (lkeys::match_key)) {
@ -189,11 +201,14 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref
xref->gen_begin_circuit (circuit_a, circuit_b);
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
while (br) {
if (read_status (status)) {
// continue
} else if (read_message (msg)) {
// continue
} else if (test (skeys::xref_key) || test (lkeys::xref_key)) {
read_xrefs_for_circuits (xref, circuit_a, circuit_b);
} else if (at_end ()) {
@ -204,7 +219,7 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref
}
xref->gen_end_circuit (circuit_a, circuit_b, status);
xref->gen_end_circuit (circuit_a, circuit_b, status, msg);
br.done ();
@ -325,11 +340,13 @@ void LayoutVsSchematicStandardReader::read_net_pair (db::NetlistCrossReference *
ion_b = read_ion ();
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
read_status (status);
read_message (msg);
br.done ();
xref->gen_nets (net_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), net_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status);
xref->gen_nets (net_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), net_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg);
}
void LayoutVsSchematicStandardReader::read_pin_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b)
@ -341,11 +358,13 @@ void LayoutVsSchematicStandardReader::read_pin_pair (db::NetlistCrossReference *
ion_b = read_ion ();
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
read_status (status);
read_message (msg);
br.done ();
xref->gen_pins (pin_by_numerical_id (circuit_a, ion_a), pin_by_numerical_id (circuit_b, ion_b), status);
xref->gen_pins (pin_by_numerical_id (circuit_a, ion_a), pin_by_numerical_id (circuit_b, ion_b), status, msg);
}
void LayoutVsSchematicStandardReader::read_device_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b)
@ -357,11 +376,13 @@ void LayoutVsSchematicStandardReader::read_device_pair (db::NetlistCrossReferenc
ion_b = read_ion ();
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
read_status (status);
read_message (msg);
br.done ();
xref->gen_devices (device_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), device_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status);
xref->gen_devices (device_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), device_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg);
}
void LayoutVsSchematicStandardReader::read_subcircuit_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b)
@ -373,11 +394,13 @@ void LayoutVsSchematicStandardReader::read_subcircuit_pair (db::NetlistCrossRefe
ion_b = read_ion ();
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
read_status (status);
read_message (msg);
br.done ();
xref->gen_subcircuits (subcircuit_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), subcircuit_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status);
xref->gen_subcircuits (subcircuit_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), subcircuit_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg);
}
}

View File

@ -78,6 +78,7 @@ private:
void read_netlist (db::LayoutVsSchematic *lvs);
bool read_status (db::NetlistCrossReference::Status &status);
bool read_message (std::string &msg);
void read_xref (db::NetlistCrossReference *xref);
void read_xrefs_for_circuits (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b);
void read_net_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b);

View File

@ -70,6 +70,7 @@ private:
}
std::string status_to_s (const db::NetlistCrossReference::Status status);
std::string message_to_s (const std::string &msg);
void write (const db::NetlistCrossReference *xref);
std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > m_net2id_per_circuit_a, m_net2id_per_circuit_b;
@ -145,7 +146,7 @@ std::string ion_to_s (const Obj *obj)
}
}
std::string net_id_to_s (const db::Net *net, const std::map<const db::Net *, unsigned int> &net2id)
static std::string net_id_to_s (const db::Net *net, const std::map<const db::Net *, unsigned int> &net2id)
{
if (net) {
std::map<const db::Net *, unsigned int>::const_iterator i = net2id.find (net);
@ -156,6 +157,37 @@ std::string net_id_to_s (const db::Net *net, const std::map<const db::Net *, uns
}
}
static void build_pin_index_map (const db::Circuit *c, std::map<const db::Pin *, unsigned int> &pin2index)
{
if (c) {
size_t pi = 0;
for (db::Circuit::const_pin_iterator p = c->begin_pins (); p != c->end_pins (); ++p, ++pi) {
pin2index.insert (std::make_pair (p.operator-> (), pi));
}
}
}
static std::string pin_id_to_s (const db::Pin *pin, const std::map<const db::Pin *, unsigned int> &pin2index)
{
if (pin) {
std::map<const db::Pin *, unsigned int>::const_iterator i = pin2index.find (pin);
tl_assert (i != pin2index.end ());
return tl::to_string (i->second);
} else {
return "()";
}
}
template <class Keys>
std::string std_writer_impl<Keys>::message_to_s (const std::string &msg)
{
if (msg.empty ()) {
return std::string ();
} else {
return " " + Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")";
}
}
template <class Keys>
std::string std_writer_impl<Keys>::status_to_s (const db::NetlistCrossReference::Status status)
{
@ -182,23 +214,27 @@ void std_writer_impl<Keys>::write (const db::NetlistCrossReference *xref)
const db::NetlistCrossReference::PerCircuitData *pcd = xref->per_circuit_data_for (*c);
tl_assert (pcd != 0);
stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << endl;
stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << message_to_s (pcd->msg) << endl;
stream () << indent2 << Keys::xref_key << "(" << endl;
for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) {
stream () << indent1 << indent2 << Keys::net_key << "(" << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << " " << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << ")" << endl;
stream () << indent1 << indent2 << Keys::net_key << "(" << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << " " << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
}
std::map<const db::Pin *, unsigned int> pin2index_a, pin2index_b;
build_pin_index_map (c->first, pin2index_a);
build_pin_index_map (c->second, pin2index_b);
for (db::NetlistCrossReference::PerCircuitData::pin_pairs_const_iterator n = pcd->pins.begin (); n != pcd->pins.end (); ++n) {
stream () << indent1 << indent2 << Keys::pin_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
stream () << indent1 << indent2 << Keys::pin_key << "(" << pin_id_to_s (n->pair.first, pin2index_a) << " " << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
}
for (db::NetlistCrossReference::PerCircuitData::device_pairs_const_iterator n = pcd->devices.begin (); n != pcd->devices.end (); ++n) {
stream () << indent1 << indent2 << Keys::device_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
stream () << indent1 << indent2 << Keys::device_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
}
for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_const_iterator n = pcd->subcircuits.begin (); n != pcd->subcircuits.end (); ++n) {
stream () << indent1 << indent2 << Keys::circuit_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
stream () << indent1 << indent2 << Keys::circuit_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
}
stream () << indent2 << ")" << endl;

View File

@ -54,6 +54,11 @@ enum OnEmptyIntruderHint {
*/
Copy,
/**
* @brief Copy the subject shape to the second result
*/
CopyToSecond,
/**
* @brief Drop the subject shape
*/

View File

@ -397,7 +397,7 @@ public:
* @brief A generic categorizer
*
* The objective of this class is to supply a category ID for a given object.
* The category ID also identities equivalent objects from netlist A and B.
* The category ID also identifies equivalent objects from netlist A and B.
*/
template <class Obj>
class generic_categorizer
@ -2991,6 +2991,23 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
}
}
// impose the compare tolerances of the layout (first netlist) on the schematic (second netlist)
// TODO: this is kind of clumsy. But it's very important to use the same device sorting for both netlists, so we play this trick.
// A better solution was to have a common compare framework for both netlists.
for (std::map<size_t, std::pair<const db::DeviceClass *, const db::DeviceClass *> >::const_iterator i = cat2dc.begin (); i != cat2dc.end (); ++i) {
if (i->second.first && i->second.second) {
const db::DeviceClass *da = i->second.first;
db::DeviceClass *db = const_cast<db::DeviceClass *> (i->second.second);
const db::DeviceParameterCompareDelegate *cmp = da->parameter_compare_delegate ();
db->set_parameter_compare_delegate (cmp ? cmp->clone () : 0);
}
}
// device whether to use a device category in strict mode
device_categorizer.clear_strict_device_categories ();
@ -3083,7 +3100,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
} else {
if (mp_logger) {
mp_logger->circuit_skipped (ca, cb);
mp_logger->circuit_skipped (ca, cb, generate_subcircuits_not_verified_warning (ca, verified_circuits_a, cb, verified_circuits_b));
good = false;
}
@ -3130,24 +3147,61 @@ NetlistComparer::derive_pin_equivalence (const db::Circuit *ca, const db::Circui
circuit_pin_mapper->map_pins (cb, pb);
}
static bool is_valid_circuit (const db::Circuit *c)
{
// typical via subcircuits attach through one pin. We can safely ignore such subcircuits because they don't
// contribute graph edges.
return c->pin_count () > 1;
}
bool
NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const
{
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
const db::Circuit *cr = sc->circuit_ref ();
// typical via subcircuits attach through one pin. We can safely ignore such subcircuits because they don't
// contribute graph edges.
if (cr->pin_count () > 1 && verified_circuits.find (cr) == verified_circuits.end ()) {
if (is_valid_circuit (cr) && verified_circuits.find (cr) == verified_circuits.end ()) {
return false;
}
}
return true;
}
static std::vector<std::string> unverified_names (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits)
{
std::vector<std::string> names;
std::set<const db::Circuit *> seen;
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
const db::Circuit *cr = sc->circuit_ref ();
if (is_valid_circuit (cr) && seen.find (cr) == seen.end () && verified_circuits.find (cr) == verified_circuits.end ()) {
seen.insert (cr);
names.push_back (cr->name ());
}
}
std::sort (names.begin (), names.end ());
return names;
}
std::string
NetlistComparer::generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set<const db::Circuit *> &verified_circuits_a, const db::Circuit *cb, const std::set<const db::Circuit *> &verified_circuits_b) const
{
std::string msg = tl::sprintf (tl::to_string (tr ("Circuits %s and %s could not be compared because the following subcircuits failed to compare:")), ca->name (), cb->name ());
std::vector<std::string> names_a = unverified_names (ca, verified_circuits_a);
if (! names_a.empty ()) {
msg += "\n A: " + tl::join (names_a, ",");
}
std::vector<std::string> names_b = unverified_names (cb, verified_circuits_b);
if (! names_b.empty ()) {
msg += "\n B: " + tl::join (names_b, ",");
}
return msg;
}
static std::vector<std::pair<size_t, size_t> >
compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict)
{

View File

@ -64,7 +64,7 @@ public:
* @brief There is a device class mismatch
* "a" is null if there is no match for b and vice versa.
*/
virtual void device_class_mismatch (const db::DeviceClass * /*a*/, const db::DeviceClass * /*b*/) { }
virtual void device_class_mismatch (const db::DeviceClass * /*a*/, const db::DeviceClass * /*b*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief Begin logging for circuit a and b
@ -74,19 +74,19 @@ public:
/**
* @brief End logging for circuit a and b
*/
virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/) { }
virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief Circuits are skipped
* Circuits are skipped if their subcircuits could not be matched.
*/
virtual void circuit_skipped (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
virtual void circuit_skipped (const db::Circuit * /*a*/, const db::Circuit * /*b*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief There is a circuit mismatch
* "a" is null if there is no match for b and vice versa.
*/
virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief Nets a and b match exactly
@ -98,7 +98,7 @@ public:
* Other nets might also match with a and also with b. Matching this a and b is
* an arbitrary decision.
*/
virtual void match_ambiguous_nets (const db::Net * /*a*/, const db::Net * /*b*/) { }
virtual void match_ambiguous_nets (const db::Net * /*a*/, const db::Net * /*b*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief Net a or b doesn't match
@ -107,7 +107,7 @@ public:
* nets are known not to match. Still the compare algorithm will proceed as
* if these nets were equivalent to derive further matches.
*/
virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/) { }
virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief Devices a and b match exactly
@ -128,7 +128,7 @@ public:
* @brief Device a or b doesn't match
* "a" is null if there is no match for b and vice versa.
*/
virtual void device_mismatch (const db::Device * /*a*/, const db::Device * /*b*/) { }
virtual void device_mismatch (const db::Device * /*a*/, const db::Device * /*b*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief Pins a and b of the current circuit are matched
@ -139,7 +139,7 @@ public:
* @brief Pin a or b doesn't match
* "a" is null if there is no match for b and vice versa.
*/
virtual void pin_mismatch (const db::Pin * /*a*/, const db::Pin * /*b*/) { }
virtual void pin_mismatch (const db::Pin * /*a*/, const db::Pin * /*b*/, const std::string & /*msg*/ = std::string ()) { }
/**
* @brief Subcircuits a and b match exactly
@ -150,7 +150,7 @@ public:
* @brief SubCircuit a or b doesn't match
* "a" is null if there is no match for b and vice versa.
*/
virtual void subcircuit_mismatch (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/) { }
virtual void subcircuit_mismatch (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/, const std::string & /*msg*/ = std::string ()) { }
private:
// No copying
@ -346,6 +346,7 @@ private:
protected:
bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping) const;
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const;
std::string generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set<const db::Circuit *> &verified_circuits_a, const db::Circuit *cb, const std::set<const db::Circuit *> &verified_circuits_b) const;
static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper);
void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const;
void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const;

View File

@ -338,9 +338,9 @@ NetlistCrossReference::establish_pair (const db::Circuit *a, const db::Circuit *
}
void
NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Status status)
NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Status status, const std::string &msg)
{
mp_per_circuit_data->nets.push_back (NetPairData (a, b, status));
mp_per_circuit_data->nets.push_back (NetPairData (a, b, status, msg));
if (a) {
m_other_net [a] = b;
}
@ -350,9 +350,9 @@ NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Statu
}
void
NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b, Status status)
NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b, Status status, const std::string &msg)
{
mp_per_circuit_data->devices.push_back (DevicePairData (a, b, status));
mp_per_circuit_data->devices.push_back (DevicePairData (a, b, status, msg));
if (a) {
m_other_device [a] = b;
}
@ -362,9 +362,9 @@ NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b,
}
void
NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Status status)
NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg)
{
mp_per_circuit_data->pins.push_back (PinPairData (a, b, status));
mp_per_circuit_data->pins.push_back (PinPairData (a, b, status, msg));
if (a) {
m_other_pin [a] = b;
}
@ -374,9 +374,9 @@ NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Statu
}
void
NetlistCrossReference::establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status)
NetlistCrossReference::establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg)
{
mp_per_circuit_data->subcircuits.push_back (SubCircuitPairData (a, b, status));
mp_per_circuit_data->subcircuits.push_back (SubCircuitPairData (a, b, status, msg));
if (a) {
m_other_subcircuit [a] = b;
}
@ -403,36 +403,37 @@ NetlistCrossReference::sort_circuit ()
}
void
NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit *, Status status)
NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit *, Status status, const std::string &msg)
{
mp_per_circuit_data->status = status;
mp_per_circuit_data->msg = msg;
m_current_circuits = std::make_pair((const db::Circuit *)0, (const db::Circuit *)0);
mp_per_circuit_data = 0;
}
void
NetlistCrossReference::gen_nets (const db::Net *a, const db::Net *b, Status status)
NetlistCrossReference::gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg)
{
establish_pair (a, b, status);
establish_pair (a, b, status, msg);
}
void
NetlistCrossReference::gen_devices (const db::Device *a, const db::Device *b, Status status)
NetlistCrossReference::gen_devices (const db::Device *a, const db::Device *b, Status status, const std::string &msg)
{
establish_pair (a, b, status);
establish_pair (a, b, status, msg);
}
void
NetlistCrossReference::gen_pins (const db::Pin *a, const db::Pin *b, Status status)
NetlistCrossReference::gen_pins (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg)
{
establish_pair (a, b, status);
establish_pair (a, b, status, msg);
}
void
NetlistCrossReference::gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status)
NetlistCrossReference::gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg)
{
establish_pair (a, b, status);
establish_pair (a, b, status, msg);
}
static void init_data_from_single (const db::Net *net, NetlistCrossReference::PerNetData &data, bool first)

View File

@ -61,44 +61,48 @@ public:
{
typedef db::Net object_type;
NetPairData (const db::Net *a, const db::Net *b, Status s) : pair (a, b), status (s) { }
NetPairData (const db::Net *a, const db::Net *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { }
NetPairData () : pair ((const db::Net *)0, (const db::Net *)0), status (None) { }
std::pair<const db::Net *, const db::Net *> pair;
Status status;
std::string msg;
};
struct DevicePairData
{
typedef db::Device object_type;
DevicePairData (const db::Device *a, const db::Device *b, Status s) : pair (a, b), status (s) { }
DevicePairData (const db::Device *a, const db::Device *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { }
DevicePairData () : pair ((const db::Device *)0, (const db::Device *)0), status (None) { }
std::pair<const db::Device *, const db::Device *> pair;
Status status;
std::string msg;
};
struct PinPairData
{
typedef db::Pin object_type;
PinPairData (const db::Pin *a, const db::Pin *b, Status s) : pair (a, b), status (s) { }
PinPairData (const db::Pin *a, const db::Pin *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { }
PinPairData () : pair ((const db::Pin *)0, (const db::Pin *)0), status (None) { }
std::pair<const db::Pin *, const db::Pin *> pair;
Status status;
std::string msg;
};
struct SubCircuitPairData
{
typedef db::SubCircuit object_type;
SubCircuitPairData (const db::SubCircuit *a, const db::SubCircuit *b, Status s) : pair (a, b), status (s) { }
SubCircuitPairData (const db::SubCircuit *a, const db::SubCircuit *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { }
SubCircuitPairData () : pair ((const db::SubCircuit *)0, (const db::SubCircuit *)0), status (None) { }
std::pair<const db::SubCircuit *, const db::SubCircuit *> pair;
Status status;
std::string msg;
};
struct PerCircuitData
@ -115,6 +119,7 @@ public:
typedef subcircuit_pairs_type::const_iterator subcircuit_pairs_const_iterator;
Status status;
std::string msg;
net_pairs_type nets;
device_pairs_type devices;
pin_pairs_type pins;
@ -139,11 +144,11 @@ public:
void gen_begin_netlist (const db::Netlist *a, const db::Netlist *b);
void gen_end_netlist (const db::Netlist *a, const db::Netlist *b);
void gen_begin_circuit (const db::Circuit *a, const db::Circuit *b);
void gen_end_circuit (const db::Circuit *a, const db::Circuit *b, Status status);
void gen_nets (const db::Net *a, const db::Net *b, Status status);
void gen_devices (const db::Device *a, const db::Device *b, Status status);
void gen_pins (const db::Pin *a, const db::Pin *b, Status status);
void gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status);
void gen_end_circuit (const db::Circuit *a, const db::Circuit *b, Status status, const std::string &msg);
void gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg);
void gen_devices (const db::Device *a, const db::Device *b, Status status, const std::string &msg);
void gen_pins (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg);
void gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg);
// db::NetlistCompareLogger interface
virtual void begin_netlist (const db::Netlist *a, const db::Netlist *b)
@ -162,77 +167,77 @@ public:
gen_begin_circuit (a, b);
}
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching)
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg)
{
sort_circuit ();
gen_end_circuit (a, b, matching ? Match : NoMatch);
gen_end_circuit (a, b, matching ? Match : NoMatch, msg);
}
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
{
gen_begin_circuit (a, b);
gen_end_circuit (a, b, Skipped);
gen_end_circuit (a, b, Skipped, msg);
}
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
{
gen_begin_circuit (a, b);
gen_end_circuit (a, b, Mismatch);
gen_end_circuit (a, b, Mismatch, msg);
}
virtual void match_nets (const db::Net *a, const db::Net *b)
{
gen_nets (a, b, Match);
gen_nets (a, b, Match, std::string ());
}
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string &msg)
{
gen_nets (a, b, MatchWithWarning);
gen_nets (a, b, MatchWithWarning, msg);
}
virtual void net_mismatch (const db::Net *a, const db::Net *b)
virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string &msg)
{
gen_nets (a, b, Mismatch);
gen_nets (a, b, Mismatch, msg);
}
virtual void match_devices (const db::Device *a, const db::Device *b)
{
gen_devices (a, b, Match);
gen_devices (a, b, Match, std::string ());
}
virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b)
{
gen_devices (a, b, MatchWithWarning);
gen_devices (a, b, MatchWithWarning, std::string ());
}
virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b)
{
gen_devices (a, b, MatchWithWarning);
gen_devices (a, b, MatchWithWarning, std::string ());
}
virtual void device_mismatch (const db::Device *a, const db::Device *b)
virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string &msg)
{
gen_devices (a, b, Mismatch);
gen_devices (a, b, Mismatch, msg);
}
virtual void match_pins (const db::Pin *a, const db::Pin *b)
{
gen_pins (a, b, Match);
gen_pins (a, b, Match, std::string ());
}
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string &msg)
{
gen_pins (a, b, Mismatch);
gen_pins (a, b, Mismatch, msg);
}
virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
{
gen_subcircuits (a, b, Match);
gen_subcircuits (a, b, Match, std::string ());
}
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg)
{
gen_subcircuits (a, b, Mismatch);
gen_subcircuits (a, b, Mismatch, msg);
}
void clear ();
@ -292,10 +297,10 @@ private:
PerCircuitData *mp_per_circuit_data;
void establish_pair (const db::Circuit *a, const db::Circuit *b);
void establish_pair (const db::Net *a, const db::Net *b, Status status);
void establish_pair (const db::Device *a, const db::Device *b, Status status);
void establish_pair (const db::Pin *a, const db::Pin *b, Status status);
void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status);
void establish_pair (const db::Net *a, const db::Net *b, Status status, const std::string &msg);
void establish_pair (const db::Device *a, const db::Device *b, Status status, const std::string &msg);
void establish_pair (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg);
void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg);
void sort_circuit ();
void sort_netlist ();

View File

@ -35,6 +35,8 @@ static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_ind (new db::device_
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_diode (new db::device_class_template<db::DeviceClassDiode> ("DIODE"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_mos3 (new db::device_class_template<db::DeviceClassMOS3Transistor> ("MOS3"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_mos4 (new db::device_class_template<db::DeviceClassMOS4Transistor> ("MOS4"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_bjt3 (new db::device_class_template<db::DeviceClassBJT3Transistor> ("BJT3"));
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_bjt4 (new db::device_class_template<db::DeviceClassBJT4Transistor> ("BJT4"));
// ------------------------------------------------------------------------------------
// DeviceClassTwoTerminalDevice implementation

View File

@ -725,7 +725,7 @@ template DB_PUBLIC void split_polygon<> (const db::DSimplePolygon &polygon, std:
// Smoothing tools
void
smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &points, db::Coord d)
smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &points, db::Coord d, bool keep_hv)
{
points.clear ();
points.reserve (std::distance (from, to));
@ -781,7 +781,9 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon
bool can_drop = false;
if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) {
if (keep_hv && (p1.x () == p0.x () || p1.y () == p0.y () || p2.x () == p1.x () || p2.y () == p1.y ())) {
// keep points which participate in either a vertical or horizontal edge
} else if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) {
// jog configurations with small edges are candidates
can_drop = true;
} else if (db::vprod_sign (p2 - p1, p1 - p0) < 0) {
@ -839,19 +841,19 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon
}
db::Polygon
smooth (const db::Polygon &polygon, db::Coord d)
smooth (const db::Polygon &polygon, db::Coord d, bool keep_hv)
{
db::Polygon new_poly;
std::vector <db::Point> new_pts;
smooth_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, d);
smooth_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, d, keep_hv);
if (new_pts.size () >= 3) {
new_poly.assign_hull (new_pts.begin (), new_pts.end (), false /*don't compress*/);
for (unsigned int h = 0; h < polygon.holes (); ++h) {
new_pts.clear ();
smooth_contour (polygon.begin_hole (h), polygon.end_hole (h), new_pts, d);
smooth_contour (polygon.begin_hole (h), polygon.end_hole (h), new_pts, d, keep_hv);
if (new_pts.size () >= 3) {
new_poly.insert_hole (new_pts.begin (), new_pts.end (), false /*don't compress*/);
}

View File

@ -449,6 +449,8 @@ db::Polygon DB_PUBLIC compute_rounded (const db::Polygon &poly, double rinner, d
*/
db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner, double router, unsigned int n);
#define KLAYOUT_SMOOTH_HAS_KEEP_HV 1
/**
* @brief Smooth a contour
*
@ -458,13 +460,14 @@ db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner,
* @param to The end of the contour
* @param new_pts The points that make up the new contour
* @param d The distance that determines the smoothing "roughness"
* @param keep_hv If true, vertical and horizontal edges are maintained
*/
void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, db::Coord d);
void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, db::Coord d, bool keep_hv);
/**
* @brief Smooth a polygon (apply smoothing to the whole polygon)
*/
db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d);
db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d, bool keep_hv);
/**
* @brief Returns a value indicating whether the polygon is an "strange polygon"

View File

@ -72,6 +72,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
m_current_layer = d.m_current_layer;
m_shape = d.m_shape;
m_trans = d.m_trans;
m_global_trans = d.m_global_trans;
m_trans_stack = d.m_trans_stack;
m_inst_iterators = d.m_inst_iterators;
m_inst_array_iterators = d.m_inst_array_iterators;
@ -286,6 +287,7 @@ RecursiveShapeIterator::init ()
m_shape_quad_id = 0;
mp_cell = 0;
m_current_layer = 0;
m_global_trans = cplx_trans_type ();
}
void
@ -318,6 +320,26 @@ RecursiveShapeIterator::init_region (const RecursiveShapeIterator::region_type &
}
}
void
RecursiveShapeIterator::set_global_trans (const cplx_trans_type &tr)
{
if (m_global_trans != tr) {
m_global_trans = tr;
m_needs_reinit = true;
}
}
const db::RecursiveShapeIterator::cplx_trans_type &
RecursiveShapeIterator::always_apply () const
{
if (m_trans_stack.empty ()) {
return m_global_trans;
} else {
static cplx_trans_type unity;
return unity;
}
}
void
RecursiveShapeIterator::set_region (const box_type &region)
{
@ -420,13 +442,13 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
m_inst_quad_id_stack.clear ();
m_inst_array_iterators.clear ();
m_cells.clear ();
m_trans = cplx_trans_type ();
m_trans = m_global_trans;
m_current_layer = 0;
m_shape = shape_iterator ();
m_shape_quad_id = 0;
m_local_region_stack.clear ();
m_local_region_stack.push_back (m_region);
m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
m_local_complex_region_stack.clear ();
if (mp_complex_region.get ()) {
@ -571,6 +593,8 @@ RecursiveShapeIterator::bbox () const
}
}
box = box.transformed (m_global_trans);
if (m_region != box_type::world ()) {
box &= m_region;
}
@ -749,8 +773,8 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
box_type new_region = box_type::world ();
// compute the region inside the new cell
if (new_region != m_local_region_stack.front ()) {
new_region = m_trans.inverted () * m_local_region_stack.front ();
if (new_region != m_region) {
new_region = m_trans.inverted () * m_region;
new_region &= cell ()->bbox ();
}
m_local_region_stack.push_back (new_region);
@ -911,7 +935,7 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all;
if (receiver) {
ni = receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
ni = receiver->new_inst (this, m_inst->cell_inst (), always_apply (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
}
if (ni == RecursiveShapeReceiver::NI_skip) {
@ -956,7 +980,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
}
while (! m_inst_array.at_end () && receiver) {
if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
if (receiver->new_inst_member (this, m_inst->cell_inst (), always_apply (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
break;
} else {
++m_inst_array;
@ -999,7 +1023,7 @@ RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
validate (receiver);
while (! at_end ()) {
receiver->shape (this, *m_shape, m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
receiver->shape (this, *m_shape, always_apply (), m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
next (receiver);
}

View File

@ -391,6 +391,30 @@ public:
}
}
/**
* @brief Sets a global transformation
*
* The global transformation will be applied to all shapes delivered by biasing the "trans" attribute
*/
void set_global_trans (const cplx_trans_type &tr);
/**
* @brief Gets the global transformation
*/
cplx_trans_type global_trans () const
{
return m_global_trans;
}
/**
* @brief Gets the transformation which is to be applied always in push mode
*
* The reasoning behind this method is that in push mode and with the presence of a global transformation we need to
* somehow reflect the fact that the top-level is transformed. Instead of transforming every shape and instance we use
* this attribute. It is unity for all cells below top level and equal to the global transformation for the top cell.
*/
const cplx_trans_type &always_apply () const;
/**
* @brief Reset the iterator
*/
@ -727,6 +751,7 @@ private:
bool m_shape_inv_prop_sel;
bool m_overlapping;
std::set<db::cell_index_type> m_start, m_stop;
cplx_trans_type m_global_trans;
const layout_type *mp_layout;
const cell_type *mp_top_cell;
@ -881,7 +906,7 @@ public:
* - NI_single: iterate a single member (the first one)
* - NI_skip: skips the whole array (not a single instance is iterated)
*/
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
/**
* @brief Enters a new array member of the instance
@ -894,14 +919,14 @@ public:
*
* If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered.
*/
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
/**
* @brief Delivers a shape
*
* @param trans The transformation which maps the shape to the top cell.
*/
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
};
} // namespace db

View File

@ -265,15 +265,15 @@ Region::rounded_corners (double rinner, double router, unsigned int n) const
}
void
Region::smooth (coord_type d)
Region::smooth (coord_type d, bool keep_hv)
{
process (SmoothingProcessor (d));
process (SmoothingProcessor (d, keep_hv));
}
Region
Region::smoothed (coord_type d) const
Region::smoothed (coord_type d, bool keep_hv) const
{
return processed (SmoothingProcessor (d));
return processed (SmoothingProcessor (d, keep_hv));
}
void

View File

@ -267,6 +267,16 @@ public:
return mp_delegate;
}
/**
* @brief Takes the underlying delegate object
*/
RegionDelegate *take_delegate ()
{
RegionDelegate *delegate = mp_delegate;
mp_delegate = 0;
return delegate;
}
/**
* @brief Sets the base verbosity
*
@ -1132,6 +1142,19 @@ public:
return Region (mp_delegate->selected_not_outside (other));
}
/**
* @brief Returns all polygons of this which are completly outside polygons from the other region and the opposite ones at the same time
*
* This method is equivalent to calling selected_outside and selected_not_outside, but faster.
*
* Merged semantics applies.
*/
std::pair<Region, Region> selected_outside_differential (const Region &other) const
{
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_outside_pair (other);
return std::pair<Region, Region> (Region (p.first), Region (p.second));
}
/**
* @brief Selects all polygons of this region which are completly inside polygons from the other region
*
@ -1178,6 +1201,19 @@ public:
return Region (mp_delegate->selected_not_inside (other));
}
/**
* @brief Returns all polygons of this which are completly inside polygons from the other region and the opposite ones at the same time
*
* This method is equivalent to calling selected_inside and selected_not_inside, but faster.
*
* Merged semantics applies.
*/
std::pair<Region, Region> selected_inside_differential (const Region &other) const
{
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_inside_pair (other);
return std::pair<Region, Region> (Region (p.first), Region (p.second));
}
/**
* @brief Returns all polygons of this which are enclosing polygons from the other region
*
@ -1224,6 +1260,19 @@ public:
return Region (mp_delegate->selected_not_enclosing (other, min_count, max_count));
}
/**
* @brief Returns all polygons of this which are completly enclosing polygons from the other region and the opposite ones at the same time
*
* This method is equivalent to calling selected_enclosing and selected_not_enclosing, but faster.
*
* Merged semantics applies.
*/
std::pair<Region, Region> selected_enclosing_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_enclosing_pair (other, min_count, max_count);
return std::pair<Region, Region> (Region (p.first), Region (p.second));
}
/**
* @brief Selects all polygons of this region which overlap or touch polygons from the other region
*
@ -1278,6 +1327,19 @@ public:
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**
* @brief Returns all polygons of this which are interacting with polygons from the other region and the opposite ones at the same time
*
* This method is equivalent to calling selected_interacting and selected_not_interacting, but faster.
*
* Merged semantics applies.
*/
std::pair<Region, Region> selected_interacting_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
return std::pair<Region, Region> (Region (p.first), Region (p.second));
}
/**
* @brief Selects all polygons of this region which overlap or touch edges from the given edge collection
*
@ -1324,6 +1386,19 @@ public:
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**
* @brief Returns all polygons of this which are interacting with edges from the other region and the opposite ones at the same time
*
* This method is equivalent to calling selected_interacting and selected_not_interacting, but faster.
*
* Merged semantics applies.
*/
std::pair<Region, Region> selected_interacting_differential (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
return std::pair<Region, Region> (Region (p.first), Region (p.second));
}
/**
* @brief Selects all polygons of this region which overlap or touch texts from the text collection
*
@ -1370,6 +1445,19 @@ public:
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**
* @brief Returns all polygons of this which are interacting with texts from the other region and the opposite ones at the same time
*
* This method is equivalent to calling selected_interacting and selected_not_interacting, but faster.
*
* Merged semantics applies.
*/
std::pair<Region, Region> selected_interacting_differential (const Texts &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
return std::pair<Region, Region> (Region (p.first), Region (p.second));
}
/**
* @brief Selects all polygons of this region which overlap polygons from the other region
*
@ -1416,6 +1504,19 @@ public:
return Region (mp_delegate->selected_not_overlapping (other, min_count, max_count));
}
/**
* @brief Returns all polygons of this which are overlapping polygons from the other region and the opposite ones at the same time
*
* This method is equivalent to calling selected_overlapping and selected_not_overlapping, but faster.
*
* Merged semantics applies.
*/
std::pair<Region, Region> selected_overlapping_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_overlapping_pair (other, min_count, max_count);
return std::pair<Region, Region> (Region (p.first), Region (p.second));
}
/**
* @brief Returns all polygons of "other" which are inside polygons of this region
*
@ -1518,14 +1619,14 @@ public:
/**
* @brief Smoothes the region (in-place)
*/
void smooth (coord_type d);
void smooth (coord_type d, bool keep_hv);
/**
* @brief Returns the smoothed region
*
* @param d The smoothing accuracy
*/
Region smoothed (coord_type d) const;
Region smoothed (coord_type d, bool keep_hv) const;
/**
* @brief Returns the nth polygon

View File

@ -281,18 +281,25 @@ public:
virtual RegionDelegate *selected_outside (const Region &other) const = 0;
virtual RegionDelegate *selected_not_outside (const Region &other) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &other) const = 0;
virtual RegionDelegate *selected_inside (const Region &other) const = 0;
virtual RegionDelegate *selected_not_inside (const Region &other) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_inside_pair (const Region &other) const = 0;
virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_enclosing (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_enclosing_pair (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Texts &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *selected_not_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_overlapping_pair (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual RegionDelegate *pull_inside (const Region &other) const = 0;
virtual RegionDelegate *pull_interacting (const Region &other) const = 0;
virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0;

View File

@ -537,8 +537,8 @@ private:
}
template <class TS, class TI, class TR>
interacting_local_operation<TS, TI, TR>::interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count, bool other_is_merged)
: m_mode (mode), m_touching (touching), m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
interacting_local_operation<TS, TI, TR>::interacting_local_operation (int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged)
: m_mode (mode), m_touching (touching), m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
{
// .. nothing yet ..
}
@ -552,8 +552,13 @@ db::Coord interacting_local_operation<TS, TI, TR>::dist () const
template <class TS, class TI, class TR>
void interacting_local_operation<TS, TI, TR>::do_compute_local (db::Layout * /*layout*/, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<TR> &result = results.front ();
if (m_output_mode == None) {
return;
} else if (m_output_mode == Positive || m_output_mode == Negative) {
tl_assert (results.size () == 1);
} else {
tl_assert (results.size () == 2);
}
db::EdgeProcessor ep;
@ -652,9 +657,21 @@ void interacting_local_operation<TS, TI, TR>::do_compute_local (db::Layout * /*l
if (c != interaction_counts.end ()) {
count = c->second;
}
if ((count >= m_min_count && count <= m_max_count) != m_inverse) {
const TS &subject = interactions.subject_shape (i->first);
result.insert (subject);
bool good = (count >= m_min_count && count <= m_max_count);
if (good) {
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
const TS &subject = interactions.subject_shape (i->first);
results [0].insert (subject);
}
} else {
if (m_output_mode == Negative) {
const TS &subject = interactions.subject_shape (i->first);
// Yes, it's "positive_result" as this is the first one.
results [0].insert (subject);
} else if (m_output_mode == PositiveAndNegative) {
const TS &subject = interactions.subject_shape (i->first);
results [1].insert (subject);
}
}
}
}
@ -663,11 +680,22 @@ template <class TS, class TI, class TR>
OnEmptyIntruderHint
interacting_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
{
if ((m_mode <= 0) != m_inverse) {
return OnEmptyIntruderHint::Drop;
if ((m_mode <= 0)) {
if (m_output_mode == Positive) {
return OnEmptyIntruderHint::Drop;
} else if (m_output_mode == Negative) {
return OnEmptyIntruderHint::Copy;
} else if (m_output_mode == PositiveAndNegative) {
return OnEmptyIntruderHint::CopyToSecond;
}
} else {
return OnEmptyIntruderHint::Copy;
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
return OnEmptyIntruderHint::Copy;
} else if (m_output_mode == Negative) {
return OnEmptyIntruderHint::Drop;
}
}
return OnEmptyIntruderHint::Ignore;
}
template <class TS, class TI, class TR>
@ -761,8 +789,8 @@ template class DB_PUBLIC pull_local_operation<db::Polygon, db::Polygon, db::Poly
// ---------------------------------------------------------------------------------------------------------------
template <class TS, class TI, class TR>
interacting_with_edge_local_operation<TS, TI, TR>::interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count, bool other_is_merged)
: m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
interacting_with_edge_local_operation<TS, TI, TR>::interacting_with_edge_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged)
: m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
{
// .. nothing yet ..
}
@ -777,6 +805,14 @@ db::Coord interacting_with_edge_local_operation<TS, TI, TR>::dist () const
template <class TS, class TI, class TR>
void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
if (m_output_mode == None) {
return;
} else if (m_output_mode == Positive || m_output_mode == Negative) {
tl_assert (results.size () == 1);
} else {
tl_assert (results.size () == 2);
}
std::unordered_map<TR, size_t> counted_results;
bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits<size_t>::max ());
@ -829,7 +865,7 @@ void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::La
const TR *addressable = push_polygon_to_heap (layout, subject, heap);
scanner.insert1 (addressable, 0);
if (m_inverse) {
if (m_output_mode == Negative || m_output_mode == PositiveAndNegative) {
inserter.init (*addressable);
}
@ -839,13 +875,18 @@ void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::La
// select hits based on their count
tl_assert (results.size () == 1);
std::unordered_set<TR> &result = results.front ();
for (typename std::unordered_map<TR, size_t>::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
bool hit = r->second >= m_min_count && r->second <= m_max_count;
if (hit != m_inverse) {
result.insert (r->first);
if (hit) {
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
results [0].insert (r->first);
}
} else {
if (m_output_mode == Negative) {
results [0].insert (r->first);
} else if (m_output_mode == PositiveAndNegative) {
results [1].insert (r->first);
}
}
}
}
@ -853,10 +894,14 @@ void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::La
template <class TS, class TI, class TR>
OnEmptyIntruderHint interacting_with_edge_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
{
if (!m_inverse) {
if (m_output_mode == Positive) {
return OnEmptyIntruderHint::Drop;
} else {
} else if (m_output_mode == Negative) {
return OnEmptyIntruderHint::Copy;
} else if (m_output_mode == PositiveAndNegative) {
return OnEmptyIntruderHint::CopyToSecond;
} else {
return OnEmptyIntruderHint::Ignore;
}
}
@ -1000,8 +1045,8 @@ template class DB_PUBLIC pull_with_text_local_operation<db::Polygon, db::Text, d
// ---------------------------------------------------------------------------------------------------------------
template <class TS, class TI, class TR>
interacting_with_text_local_operation<TS, TI, TR>::interacting_with_text_local_operation (bool inverse, size_t min_count, size_t max_count)
: m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
interacting_with_text_local_operation<TS, TI, TR>::interacting_with_text_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count)
: m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
{
// .. nothing yet ..
}
@ -1017,6 +1062,14 @@ db::Coord interacting_with_text_local_operation<TS, TI, TR>::dist () const
template <class TS, class TI, class TR>
void interacting_with_text_local_operation<TS, TI, TR>::do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
if (m_output_mode == None) {
return;
} else if (m_output_mode == Positive || m_output_mode == Negative) {
tl_assert (results.size () == 1);
} else {
tl_assert (results.size () == 2);
}
std::unordered_map<TR, size_t> counted_results;
bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits<size_t>::max ());
@ -1042,7 +1095,7 @@ void interacting_with_text_local_operation<TS, TI, TR>::do_compute_local (db::La
const TR *addressable = push_polygon_to_heap (layout, interactions.subject_shape (i->first), heap);
scanner.insert1 (addressable, 0);
if (m_inverse) {
if (m_output_mode == Negative || m_output_mode == PositiveAndNegative) {
inserter.init (*addressable);
}
@ -1052,13 +1105,19 @@ void interacting_with_text_local_operation<TS, TI, TR>::do_compute_local (db::La
// select hits based on their count
tl_assert (results.size () == 1);
std::unordered_set<TR> &result = results.front ();
for (typename std::unordered_map<TR, size_t>::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
bool hit = r->second >= m_min_count && r->second <= m_max_count;
if (hit != m_inverse) {
result.insert (r->first);
if (hit) {
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
results [0].insert (r->first);
}
} else {
if (m_output_mode == Negative) {
// Yes. It's "positive"! This is the first output.
results [0].insert (r->first);
} else if (m_output_mode == PositiveAndNegative) {
results [1].insert (r->first);
}
}
}
}
@ -1066,10 +1125,14 @@ void interacting_with_text_local_operation<TS, TI, TR>::do_compute_local (db::La
template <class TS, class TI, class TR>
OnEmptyIntruderHint interacting_with_text_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
{
if (!m_inverse) {
if (m_output_mode == Positive) {
return OnEmptyIntruderHint::Drop;
} else {
} else if (m_output_mode == Negative) {
return OnEmptyIntruderHint::Copy;
} else if (m_output_mode == PositiveAndNegative) {
return OnEmptyIntruderHint::CopyToSecond;
} else {
return OnEmptyIntruderHint::Ignore;
}
}

View File

@ -222,12 +222,16 @@ private:
typedef check_local_operation<db::PolygonRef, db::PolygonRef> CheckLocalOperation;
enum InteractingOutputMode {
None = 0, Positive = 1, Negative = 2, PositiveAndNegative = 3
};
template <class TS, class TI, class TR>
class interacting_local_operation
: public local_operation<TS, TI, TR>
{
public:
interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count, bool other_is_merged);
interacting_local_operation (int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
@ -237,7 +241,7 @@ public:
private:
int m_mode;
bool m_touching;
bool m_inverse;
InteractingOutputMode m_output_mode;
size_t m_min_count, m_max_count;
bool m_other_is_merged;
};
@ -268,7 +272,7 @@ class interacting_with_edge_local_operation
: public local_operation<TS, TI, TR>
{
public:
interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count, bool other_is_merged);
interacting_with_edge_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
@ -276,7 +280,7 @@ public:
virtual std::string description () const;
private:
bool m_inverse;
InteractingOutputMode m_output_mode;
size_t m_min_count, m_max_count;
bool m_other_is_merged;
};
@ -303,7 +307,7 @@ class interacting_with_text_local_operation
: public local_operation<TS, TI, TR>
{
public:
interacting_with_text_local_operation (bool inverse, size_t min_count, size_t max_count);
interacting_with_text_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
@ -311,7 +315,7 @@ public:
virtual std::string description () const;
private:
bool m_inverse;
InteractingOutputMode m_output_mode;
size_t m_min_count, m_max_count;
};

View File

@ -868,14 +868,14 @@ StrangePolygonCheckProcessor::process (const db::Polygon &poly, std::vector<db::
// -------------------------------------------------------------------------------------------------------------
// Smoothing processor
SmoothingProcessor::SmoothingProcessor (db::Coord d) : m_d (d) { }
SmoothingProcessor::SmoothingProcessor (db::Coord d, bool keep_hv) : m_d (d), m_keep_hv (keep_hv) { }
SmoothingProcessor::~SmoothingProcessor () { }
void
SmoothingProcessor::process (const db::Polygon &poly, std::vector<db::Polygon> &res) const
{
res.push_back (db::smooth (poly, m_d));
res.push_back (db::smooth (poly, m_d, m_keep_hv));
}
// -------------------------------------------------------------------------------------------------------------

View File

@ -504,7 +504,7 @@ class DB_PUBLIC SmoothingProcessor
: public PolygonProcessorBase
{
public:
SmoothingProcessor (db::Coord d);
SmoothingProcessor (db::Coord d, bool keep_hv);
~SmoothingProcessor ();
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const;
@ -517,6 +517,7 @@ public:
private:
db::Coord m_d;
bool m_keep_hv;
db::MagnificationReducer m_vars;
};

View File

@ -190,17 +190,17 @@ public:
m_circuit = circuit2str (a) + " vs. " + circuit2str (b);
}
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string & /*msg*/)
{
out ("device_class_mismatch " + device_class2str (a) + " " + device_class2str (b));
}
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/)
{
out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b));
}
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/)
{
out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
}
@ -210,12 +210,12 @@ public:
out ("match_nets " + net2str (a) + " " + net2str (b));
}
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string & /*msg*/)
{
out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b));
}
virtual void net_mismatch (const db::Net *a, const db::Net *b)
virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string & /*msg*/)
{
out ("net_mismatch " + net2str (a) + " " + net2str (b));
}
@ -225,7 +225,7 @@ public:
out ("match_devices " + device2str (a) + " " + device2str (b));
}
virtual void device_mismatch (const db::Device *a, const db::Device *b)
virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string & /*msg*/)
{
out ("device_mismatch " + device2str (a) + " " + device2str (b));
}
@ -245,7 +245,7 @@ public:
out ("match_pins " + pin2str (a) + " " + pin2str (b));
}
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string & /*msg*/)
{
out ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
}
@ -255,7 +255,7 @@ public:
out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b));
}
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string & /*msg*/)
{
out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b));
}

View File

@ -185,10 +185,10 @@ static db::CompoundRegionOperationNode *new_strange_polygons_filter (db::Compoun
return new db::CompoundRegionProcessingOperationNode (new db::StrangePolygonCheckProcessor (), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d)
static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d, bool keep_hv)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d), input, true /*processor is owned*/, d);
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d, keep_hv), input, true /*processor is owned*/, d);
}
static db::CompoundRegionOperationNode *new_rounded_corners (db::CompoundRegionOperationNode *input, double rinner, double router, unsigned int n)
@ -572,9 +572,10 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
"@brief Creates a node extracting strange polygons.\n"
"'strange polygons' are ones which cannot be oriented - e.g. '8' shape polygons."
) +
gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"),
gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("keep_hv", false),
"@brief Creates a node smoothing the polygons.\n"
"@param d The tolerance to be applied for the smoothing."
"@param d The tolerance to be applied for the smoothing.\n"
"@param keep_hv If true, horizontal and vertical edges are maintained.\n"
) +
gsi::constructor ("new_rounded_corners", &new_rounded_corners, gsi::arg ("input"), gsi::arg ("rinner"), gsi::arg ("router"), gsi::arg ("n"),
"@brief Creates a node generating rounded corners.\n"

View File

@ -66,18 +66,18 @@ public:
db::NetlistCompareLogger::end_netlist (a, b);
}
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string &msg)
{
if (cb_device_class_mismatch.can_issue ()) {
cb_device_class_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::device_class_mismatch_fb, a, b);
cb_device_class_mismatch.issue<GenericNetlistCompareLogger, const db::DeviceClass *, const db::DeviceClass *, const std::string &> (&GenericNetlistCompareLogger::device_class_mismatch_fb, a, b, msg);
} else {
db::NetlistCompareLogger::device_class_mismatch (a, b);
}
}
void device_class_mismatch_fb (const db::DeviceClass *a, const db::DeviceClass *b)
void device_class_mismatch_fb (const db::DeviceClass *a, const db::DeviceClass *b, const std::string &msg)
{
db::NetlistCompareLogger::device_class_mismatch (a, b);
db::NetlistCompareLogger::device_class_mismatch (a, b, msg);
}
virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b)
@ -94,46 +94,46 @@ public:
db::NetlistCompareLogger::begin_circuit (a, b);
}
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching)
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg)
{
if (cb_end_circuit.can_issue ()) {
cb_end_circuit.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::end_circuit_fb, a, b, matching);
cb_end_circuit.issue<GenericNetlistCompareLogger, const db::Circuit *, const db::Circuit *, bool, const std::string &> (&GenericNetlistCompareLogger::end_circuit_fb, a, b, matching, msg);
} else {
db::NetlistCompareLogger::end_circuit (a, b, matching);
}
}
void end_circuit_fb (const db::Circuit *a, const db::Circuit *b, bool matching)
void end_circuit_fb (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg)
{
db::NetlistCompareLogger::end_circuit (a, b, matching);
db::NetlistCompareLogger::end_circuit (a, b, matching, msg);
}
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
{
if (cb_circuit_skipped.can_issue ()) {
cb_circuit_skipped.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::circuit_skipped_fb, a, b);
cb_circuit_skipped.issue<GenericNetlistCompareLogger, const db::Circuit *, const db::Circuit *, const std::string &> (&GenericNetlistCompareLogger::circuit_skipped_fb, a, b, msg);
} else {
db::NetlistCompareLogger::circuit_skipped (a, b);
}
}
void circuit_skipped_fb (const db::Circuit *a, const db::Circuit *b)
void circuit_skipped_fb (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
{
db::NetlistCompareLogger::circuit_skipped (a, b);
db::NetlistCompareLogger::circuit_skipped (a, b, msg);
}
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
{
if (cb_circuit_mismatch.can_issue ()) {
cb_circuit_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::circuit_mismatch_fb, a, b);
cb_circuit_mismatch.issue<GenericNetlistCompareLogger, const db::Circuit *, const db::Circuit *, const std::string &> (&GenericNetlistCompareLogger::circuit_mismatch_fb, a, b, msg);
} else {
db::NetlistCompareLogger::circuit_mismatch (a, b);
}
}
void circuit_mismatch_fb (const db::Circuit *a, const db::Circuit *b)
void circuit_mismatch_fb (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
{
db::NetlistCompareLogger::circuit_mismatch (a, b);
db::NetlistCompareLogger::circuit_mismatch (a, b, msg);
}
virtual void match_nets (const db::Net *a, const db::Net *b)
@ -150,32 +150,32 @@ public:
db::NetlistCompareLogger::match_nets (a, b);
}
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string &msg)
{
if (cb_match_ambiguous_nets.can_issue ()) {
cb_match_ambiguous_nets.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_ambiguous_nets_fb, a, b);
cb_match_ambiguous_nets.issue<GenericNetlistCompareLogger, const db::Net *, const db::Net *, const std::string &> (&GenericNetlistCompareLogger::match_ambiguous_nets_fb, a, b, msg);
} else {
db::NetlistCompareLogger::match_ambiguous_nets (a, b);
}
}
void match_ambiguous_nets_fb (const db::Net *a, const db::Net *b)
void match_ambiguous_nets_fb (const db::Net *a, const db::Net *b, const std::string &msg)
{
db::NetlistCompareLogger::match_ambiguous_nets (a, b);
db::NetlistCompareLogger::match_ambiguous_nets (a, b, msg);
}
virtual void net_mismatch (const db::Net *a, const db::Net *b)
virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string &msg)
{
if (cb_net_mismatch.can_issue ()) {
cb_net_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::net_mismatch_fb, a, b);
cb_net_mismatch.issue<GenericNetlistCompareLogger, const db::Net *, const db::Net *, const std::string &> (&GenericNetlistCompareLogger::net_mismatch_fb, a, b, msg);
} else {
db::NetlistCompareLogger::net_mismatch (a, b);
}
}
void net_mismatch_fb (const db::Net *a, const db::Net *b)
void net_mismatch_fb (const db::Net *a, const db::Net *b, const std::string &msg)
{
db::NetlistCompareLogger::net_mismatch (a, b);
db::NetlistCompareLogger::net_mismatch (a, b, msg);
}
virtual void match_devices (const db::Device *a, const db::Device *b)
@ -220,18 +220,18 @@ public:
db::NetlistCompareLogger::match_devices_with_different_device_classes (a, b);
}
virtual void device_mismatch (const db::Device *a, const db::Device *b)
virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string &msg)
{
if (cb_device_mismatch.can_issue ()) {
cb_device_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::device_mismatch_fb, a, b);
cb_device_mismatch.issue<GenericNetlistCompareLogger, const db::Device *, const db::Device *, const std::string &> (&GenericNetlistCompareLogger::device_mismatch_fb, a, b, msg);
} else {
db::NetlistCompareLogger::device_mismatch (a, b);
}
}
void device_mismatch_fb (const db::Device *a, const db::Device *b)
void device_mismatch_fb (const db::Device *a, const db::Device *b, const std::string &msg)
{
db::NetlistCompareLogger::device_mismatch (a, b);
db::NetlistCompareLogger::device_mismatch (a, b, msg);
}
virtual void match_pins (const db::Pin *a, const db::Pin *b)
@ -248,18 +248,18 @@ public:
db::NetlistCompareLogger::match_pins (a, b);
}
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string &msg)
{
if (cb_pin_mismatch.can_issue ()) {
cb_pin_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::pin_mismatch_fb, a, b);
cb_pin_mismatch.issue<GenericNetlistCompareLogger, const db::Pin *, const db::Pin *, const std::string &> (&GenericNetlistCompareLogger::pin_mismatch_fb, a, b, msg);
} else {
db::NetlistCompareLogger::pin_mismatch (a, b);
}
}
void pin_mismatch_fb (const db::Pin *a, const db::Pin *b)
void pin_mismatch_fb (const db::Pin *a, const db::Pin *b, const std::string &msg)
{
db::NetlistCompareLogger::pin_mismatch (a, b);
db::NetlistCompareLogger::pin_mismatch (a, b, msg);
}
virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
@ -276,18 +276,18 @@ public:
db::NetlistCompareLogger::match_subcircuits (a, b);
}
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg)
{
if (cb_subcircuit_mismatch.can_issue ()) {
cb_subcircuit_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::subcircuit_mismatch_fb, a, b);
cb_subcircuit_mismatch.issue<GenericNetlistCompareLogger, const db::SubCircuit *, const db::SubCircuit *, const std::string &> (&GenericNetlistCompareLogger::subcircuit_mismatch_fb, a, b, msg);
} else {
db::NetlistCompareLogger::subcircuit_mismatch (a, b);
}
}
void subcircuit_mismatch_fb (const db::SubCircuit *a, const db::SubCircuit *b)
void subcircuit_mismatch_fb (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg)
{
db::NetlistCompareLogger::subcircuit_mismatch (a, b);
db::NetlistCompareLogger::subcircuit_mismatch (a, b, msg);
}
gsi::Callback cb_begin_netlist;
@ -339,7 +339,7 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
"@brief This function is called at the end of the compare process.\n"
"This method is called once when the compare run ended.\n"
) +
gsi::callback ("device_class_mismatch", &GenericNetlistCompareLogger::device_class_mismatch, &GenericNetlistCompareLogger::cb_device_class_mismatch, gsi::arg ("a"), gsi::arg ("b"),
gsi::callback ("device_class_mismatch", &GenericNetlistCompareLogger::device_class_mismatch, &GenericNetlistCompareLogger::cb_device_class_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
"@brief This function is called when device classes can't be compared.\n"
"This method is called when a device class can't be mapped to a partner in the other netlist. In this case, "
"this method is called with the one device class and nil for the other class.\n"
@ -354,19 +354,19 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
"some or all subcircuits the pin assignment can't be derived. In this case, \\circuit_skipped will be called once "
"instead of \\begin_circuit and \\end_circuit.\n"
) +
gsi::callback ("end_circuit", &GenericNetlistCompareLogger::end_circuit, &GenericNetlistCompareLogger::cb_end_circuit, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("matching"),
gsi::callback ("end_circuit", &GenericNetlistCompareLogger::end_circuit, &GenericNetlistCompareLogger::cb_end_circuit, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("matching"), gsi::arg ("msg"),
"@brief This function is called at the end of the compare process.\n"
"The 'matching' argument indicates whether the circuits have been identified as identical.\n"
"See \\begin_circuit for details."
) +
gsi::callback ("circuit_skipped", &GenericNetlistCompareLogger::circuit_skipped, &GenericNetlistCompareLogger::cb_circuit_skipped, gsi::arg ("a"), gsi::arg ("b"),
gsi::callback ("circuit_skipped", &GenericNetlistCompareLogger::circuit_skipped, &GenericNetlistCompareLogger::cb_circuit_skipped, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
"@brief This function is called when circuits can't be compared.\n"
"If there is a known circuit pair, but the circuits can be compared - for example because subcircuits can't be identified - this method will be called with "
"both circuits.\n"
"\n"
"This method is called instead of \\begin_circuit and \\end_circuit."
) +
gsi::callback ("circuit_mismatch", &GenericNetlistCompareLogger::circuit_mismatch, &GenericNetlistCompareLogger::cb_circuit_mismatch, gsi::arg ("a"), gsi::arg ("b"),
gsi::callback ("circuit_mismatch", &GenericNetlistCompareLogger::circuit_mismatch, &GenericNetlistCompareLogger::cb_circuit_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
"@brief This function is called when circuits can't be compared.\n"
"This method is called when a circuit can't be mapped to a partner in the other netlist. In this case, "
"this method is called with the one circuit and nil for the other circuit.\n"
@ -379,13 +379,13 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
"If the nets can be paired, but this match is ambiguous, \\match_ambiguous_nets will be called instead.\n"
"If nets can't be matched to a partner, \\net_mismatch will be called.\n"
) +
gsi::callback ("match_ambiguous_nets", &GenericNetlistCompareLogger::match_ambiguous_nets, &GenericNetlistCompareLogger::cb_match_ambiguous_nets, gsi::arg ("a"), gsi::arg ("b"),
gsi::callback ("match_ambiguous_nets", &GenericNetlistCompareLogger::match_ambiguous_nets, &GenericNetlistCompareLogger::cb_match_ambiguous_nets, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
"@brief This function is called when two nets are identified, but this choice is ambiguous.\n"
"This choice is a last-resort fallback to allow continuation of the compare procedure. It is likely that this "
"compare will fail later. Looking for ambiguous nets allows deduction of the origin of this faulty decision. "
"See \\match_nets for more details."
) +
gsi::callback ("net_mismatch", &GenericNetlistCompareLogger::net_mismatch, &GenericNetlistCompareLogger::cb_net_mismatch, gsi::arg ("a"), gsi::arg ("b"),
gsi::callback ("net_mismatch", &GenericNetlistCompareLogger::net_mismatch, &GenericNetlistCompareLogger::cb_net_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
"@brief This function is called when a net can't be paired.\n"
"This method will be called, if a net cannot be identified as identical with another net. The corresponding argument "
"will identify the net and source netlist. The other argument will be nil.\n"
@ -409,7 +409,7 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
"@brief This function is called when two devices are identified but have different device classes.\n"
"See \\match_devices for details.\n"
) +
gsi::callback ("device_mismatch", &GenericNetlistCompareLogger::device_mismatch, &GenericNetlistCompareLogger::cb_device_mismatch, gsi::arg ("a"), gsi::arg ("b"),
gsi::callback ("device_mismatch", &GenericNetlistCompareLogger::device_mismatch, &GenericNetlistCompareLogger::cb_device_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
"@brief This function is called when two devices can't be paired.\n"
"This will report the device considered in a or b. The other argument is nil. "
"See \\match_devices for details.\n"
@ -419,7 +419,7 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
"If two pins are identified as a corresponding pair, this method will be called with both pins.\n"
"If pins can't be matched, \\pin_mismatch will be called with the one pin considered and the other pin being nil."
) +
gsi::callback ("pin_mismatch", &GenericNetlistCompareLogger::pin_mismatch, &GenericNetlistCompareLogger::cb_pin_mismatch, gsi::arg ("a"), gsi::arg ("b"),
gsi::callback ("pin_mismatch", &GenericNetlistCompareLogger::pin_mismatch, &GenericNetlistCompareLogger::cb_pin_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
"@brief This function is called when two pins can't be paired.\n"
"This will report the pin considered in a or b. The other argument is nil. "
"See \\match_pins for details.\n"
@ -429,7 +429,7 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
"If two subcircuits are identified as a corresponding pair, this method will be called with both subcircuits.\n"
"If subcircuits can't be matched, \\subcircuit_mismatch will be called with the one subcircuit considered and the other subcircuit being nil."
) +
gsi::callback ("subcircuit_mismatch", &GenericNetlistCompareLogger::subcircuit_mismatch, &GenericNetlistCompareLogger::cb_subcircuit_mismatch, gsi::arg ("a"), gsi::arg ("b"),
gsi::callback ("subcircuit_mismatch", &GenericNetlistCompareLogger::subcircuit_mismatch, &GenericNetlistCompareLogger::cb_subcircuit_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
"@brief This function is called when two subcircuits can't be paired.\n"
"This will report the subcircuit considered in a or b. The other argument is nil. "
"See \\match_subcircuits for details.\n"

View File

@ -1602,9 +1602,9 @@ static db::Polygon transformed_icplx_dp (const db::Polygon *p, const db::ICplxTr
return p->transformed (t, false /*don't compress*/);
}
static db::Polygon smooth (const db::Polygon *p, db::Coord d)
static db::Polygon smooth (const db::Polygon *p, db::Coord d, bool keep_hv)
{
return db::smooth (*p, d);
return db::smooth (*p, d, keep_hv);
}
static db::Polygon minkowsky_sum_pe (const db::Polygon *p, const db::Edge &e, bool rh)
@ -1787,17 +1787,18 @@ Class<db::Polygon> decl_Polygon ("db", "Polygon",
"\n"
"This method was introduced in version 0.22.\n"
) +
method_ext ("smooth", &smooth, gsi::arg ("d"),
method_ext ("smooth", &smooth, gsi::arg ("d"), gsi::arg ("keep_hv", false),
"@brief Smoothes a polygon\n"
"\n"
"Remove vertices that deviate by more than the distance d from the average contour.\n"
"The value d is basically the roughness which is removed.\n"
"\n"
"@param d The smoothing \"roughness\".\n"
"@param keep_hv If true, horizontal and vertical edges will be preserved always.\n"
"\n"
"@return The smoothed polygon.\n"
"\n"
"This method was introduced in version 0.23.\n"
"This method was introduced in version 0.23. The 'keep_hv' optional parameter was added in version 0.27.\n"
) +
method_ext ("minkowsky_sum", &minkowsky_sum_pe, gsi::arg ("e"), gsi::arg ("resolve_holes"),
"@brief Computes the Minkowsky sum of the polygon and an edge\n"

View File

@ -70,6 +70,27 @@ static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r)
return db::CplxTrans (ly->dbu ()) * r->trans () * db::VCplxTrans (1.0 / ly->dbu ());
}
static db::DCplxTrans si_global_dtrans (const db::RecursiveShapeIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return db::CplxTrans (ly->dbu ()) * r->global_trans () * db::VCplxTrans (1.0 / ly->dbu ());
}
static db::DCplxTrans si_always_apply_dtrans (const db::RecursiveShapeIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return db::CplxTrans (ly->dbu ()) * r->always_apply () * db::VCplxTrans (1.0 / ly->dbu ());
}
static void si_set_global_dtrans (db::RecursiveShapeIterator *r, const db::DCplxTrans &gt)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
r->set_global_trans (db::VCplxTrans (1.0 / ly->dbu ()) * gt * db::CplxTrans (ly->dbu ()));
}
static void select_cells1 (db::RecursiveShapeIterator *r, const std::vector<db::cell_index_type> &cells)
{
std::set<db::cell_index_type> cc;
@ -270,7 +291,47 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n"
"This method has been introduced in version 0.23.\n"
) +
gsi::method ("region", &db::RecursiveShapeIterator::region,
gsi::method ("global_trans=", &db::RecursiveShapeIterator::set_global_trans, gsi::arg ("t"),
"@brief Sets the global transformation to apply to all shapes delivered\n"
"The global transformation will be applied to all shapes delivered by biasing the \"trans\" attribute.\n"
"The search regions apply to the coordinate space after global transformation.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("global_trans", &db::RecursiveShapeIterator::global_trans,
"@brief Gets the global transformation to apply to all shapes delivered\n"
"See also \\global_trans=.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("global_dtrans=", &si_set_global_dtrans,
"@brief Sets the global transformation to apply to all shapes delivered (transformation in micrometer units)\n"
"The global transformation will be applied to all shapes delivered by biasing the \"trans\" attribute.\n"
"The search regions apply to the coordinate space after global transformation.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("global_dtrans", &si_global_dtrans,
"@brief Gets the global transformation to apply to all shapes delivered (in micrometer units)\n"
"See also \\global_dtrans=.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("always_apply_trans", &db::RecursiveShapeIterator::always_apply,
"@brief Gets the global transformation if at top level, unity otherwise\n"
"As the global transformation is only applicable on top level, use this method to transform shapes and instances into their local (cell-level) version "
"while considering the global transformation properly.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("always_apply_dtrans", &si_always_apply_dtrans,
"@brief Gets the global transformation if at top level, unity otherwise (micrometer-unit version)\n"
"As the global transformation is only applicable on top level, use this method to transform shapes and instances into their local (cell-level) version "
"while considering the global transformation properly.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("region", &db::RecursiveShapeIterator::region,
"@brief Gets the basic region that is iterator is using\n"
"The basic region is the overall box the region iterator iterates over. "
"There may be an additional complex region that confines the region iterator. "

View File

@ -611,15 +611,53 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other,
);
}
static inline std::vector<db::Region> as_2region_vector (const std::pair<db::Region, db::Region> &rp)
{
std::vector<db::Region> res;
res.reserve (2);
res.push_back (db::Region (const_cast<db::Region &> (rp.first).take_delegate ()));
res.push_back (db::Region (const_cast<db::Region &> (rp.second).take_delegate ()));
return res;
}
static std::vector<db::Region> andnot (const db::Region *r, const db::Region &other)
{
std::pair<db::Region, db::Region> rp = r->andnot (other);
return as_2region_vector (r->andnot (other));
}
std::vector<db::Region> res;
res.resize (2, db::Region ());
res [0] = rp.first;
res [1] = rp.second;
return res;
static std::vector<db::Region> split_inside (const db::Region *r, const db::Region &other)
{
return as_2region_vector (r->selected_inside_differential (other));
}
static std::vector<db::Region> split_outside (const db::Region *r, const db::Region &other)
{
return as_2region_vector (r->selected_outside_differential (other));
}
static std::vector<db::Region> split_overlapping (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count)
{
return as_2region_vector (r->selected_overlapping_differential (other, min_count, max_count));
}
static std::vector<db::Region> split_covering (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count)
{
return as_2region_vector (r->selected_enclosing_differential (other, min_count, max_count));
}
static std::vector<db::Region> split_interacting_with_region (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count)
{
return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count));
}
static std::vector<db::Region> split_interacting_with_edges (const db::Region *r, const db::Edges &other, size_t min_count, size_t max_count)
{
return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count));
}
static std::vector<db::Region> split_interacting_with_texts (const db::Region *r, const db::Texts &other, size_t min_count, size_t max_count)
{
return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count));
}
template <class Container>
@ -705,6 +743,7 @@ int po_any ();
extern Class<db::ShapeCollection> decl_dbShapeCollection;
Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
constructor ("new", &new_v,
"@brief Default constructor\n"
@ -927,7 +966,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"polygons which have the given perimeter are returned. If \"inverse\" is true, "
"polygons not having the given perimeter are returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_perimeter", with_perimeter2, gsi::arg ("min_perimeter"), gsi::arg ("max_perimeter"), gsi::arg ("inverse"),
"@brief Filter the polygons by perimeter\n"
@ -939,7 +978,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"),
"@brief Filter the polygons by area\n"
@ -947,7 +986,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"polygons which have the given area are returned. If \"inverse\" is true, "
"polygons not having the given area are returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_area", with_area2, gsi::arg ("min_area"), gsi::arg ("max_area"), gsi::arg ("inverse"),
"@brief Filter the polygons by area\n"
@ -959,7 +998,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_holes", with_holes1, gsi::arg ("nholes"), gsi::arg ("inverse"),
"@brief Filters the polygons by their number of holes\n"
@ -967,7 +1006,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"polygons which have the given number of holes are returned. If \"inverse\" is true, "
"polygons not having the given of holes are returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
@ -981,7 +1020,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
@ -991,7 +1030,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"polygons whose bounding box has the given width are returned. If \"inverse\" is true, "
"polygons whose bounding box does not have the given width are returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_bbox_width", with_bbox_width2, gsi::arg ("min_width"), gsi::arg ("max_width"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width\n"
@ -1001,7 +1040,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_bbox_height", with_bbox_height1, gsi::arg ("height"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box height\n"
@ -1009,7 +1048,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"polygons whose bounding box has the given height are returned. If \"inverse\" is true, "
"polygons whose bounding box does not have the given height are returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_bbox_height", with_bbox_height2, gsi::arg ("min_height"), gsi::arg ("max_height"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box height\n"
@ -1019,7 +1058,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_bbox_min", with_bbox_min1, gsi::arg ("dim"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width or height, whichever is smaller\n"
@ -1028,7 +1067,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"are returned. "
"If \"inverse\" is true, all polygons not matching this criterion are returned."
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_bbox_min", with_bbox_min2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width or height, whichever is smaller\n"
@ -1039,7 +1078,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_bbox_max", with_bbox_max1, gsi::arg ("dim"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width or height, whichever is larger\n"
@ -1048,7 +1087,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"are returned. "
"If \"inverse\" is true, all polygons not matching this criterion are returned."
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_bbox_max", with_bbox_max2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box width or height, whichever is larger\n"
@ -1059,7 +1098,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_bbox_aspect_ratio", with_bbox_aspect_ratio1, gsi::arg ("ratio"), gsi::arg ("inverse"),
"@brief Filters the polygons by the aspect ratio of their bounding boxes\n"
@ -1070,7 +1109,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"With 'inverse' set to false, this version filters polygons which have a bounding box aspect ratio equal to the given value. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
@ -1086,7 +1125,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
@ -1099,7 +1138,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"With 'inverse' set to false, this version filters polygons which have an area ratio equal to the given value. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
@ -1115,7 +1154,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
@ -1129,7 +1168,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"With 'inverse' set to false, this version filters polygons which have a relative height equal to the given value. "
"With 'inverse' set to true, all other polygons will be returned.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
@ -1146,7 +1185,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
@ -1154,7 +1193,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@brief Returns a region containing those parts of polygons which are \"strange\"\n"
"Strange parts of polygons are self-overlapping parts or non-orientable parts (i.e. in the \"8\" configuration).\n"
"\n"
"Merged semantics does not apply for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics does not apply for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("snapped", &db::Region::snapped, gsi::arg ("gx"), gsi::arg ("gy"),
"@brief Returns the snapped region\n"
@ -1167,7 +1206,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If gx or gy is 0, no snapping happens in that direction.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("scaled_and_snapped", &db::Region::scaled_and_snapped, gsi::arg ("gx"), gsi::arg ("mx"), gsi::arg ("dx"), gsi::arg ("gy"),gsi::arg ("my"), gsi::arg ("dy"),
"@brief Returns the scaled and snapped region\n"
@ -1183,7 +1222,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If gx or gy is 0, the result is brought on a grid of 1.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.26.1."
) +
@ -1195,7 +1234,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"If gx or gy is 0 or less, the grid is not checked in that direction.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_angle", angle_check1, gsi::arg ("angle"), gsi::arg ("inverse"),
"@brief Returns markers on every corner with the given angle (or not with the given angle)\n"
@ -1205,7 +1244,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The edge pair objects returned will contain both edges forming the angle.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("with_angle", angle_check2, gsi::arg ("amin"), gsi::arg ("amax"), gsi::arg ("inverse"),
"@brief Returns markers on every corner with an angle of more than amin and less than amax (or the opposite)\n"
@ -1215,7 +1254,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The edge pair objects returned will contain both edges forming the angle.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("insert", (void (db::Region::*)(const db::Box &)) &db::Region::insert, gsi::arg ("box"),
"@brief Inserts a box\n"
@ -1290,7 +1329,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("extents", &extents1, gsi::arg ("d"),
"@brief Returns a region with the enlarged bounding boxes of the polygons\n"
@ -1299,7 +1338,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("extents", &extents2, gsi::arg ("dx"), gsi::arg ("dy"),
"@brief Returns a region with the enlarged bounding boxes of the polygons\n"
@ -1308,7 +1347,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("extent_refs", &extent_refs,
"@hide\n"
@ -1436,9 +1475,10 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"See \\round_corners for a description of this method. This version returns a new region instead of "
"modifying self (out-of-place)."
) +
method ("smooth", &db::Region::smooth, gsi::arg ("d"),
method ("smooth", &db::Region::smooth, gsi::arg ("d"), gsi::arg ("keep_hv", false),
"@brief Smoothing\n"
"@param d The smoothing tolerance (in database units)\n"
"@param keep_hv If true, horizontal and vertical edges are maintained\n"
"\n"
"This method will simplify the merged polygons of the region by removing vertexes if the "
"resulting polygon stays equivalent with the original polygon. Equivalence is measured "
@ -1447,9 +1487,10 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"This method modifies the region. \\smoothed is a method that does the same but returns a new "
"region without modifying self. Merged semantics applies for this method.\n"
) +
method ("smoothed", &db::Region::smoothed, gsi::arg ("d"),
method ("smoothed", &db::Region::smoothed, gsi::arg ("d"), gsi::arg ("keep_hv", false),
"@brief Smoothing\n"
"@param d The smoothing tolerance (in database units)\n"
"@param keep_hv If true, horizontal and vertical edges are maintained\n"
"\n"
"See \\smooth for a description of this method. This version returns a new region instead of "
"modifying self (out-of-place). It has been introduced in version 0.25."
@ -1468,7 +1509,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"The mode defines at which bending angle cutoff occurs \n"
"(0:>0, 1:>45, 2:>90, 3:>135, 4:>approx. 168, other:>approx. 179)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The result is a set of polygons which may be overlapping, but are not self-\n"
"intersecting. Polygons may overlap afterwards because they grew big enough to overlap their neighbors.\n"
@ -1490,7 +1531,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method is equivalent to \"size(d, d, mode)\".\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("size", size_ext, gsi::arg ("d"),
"@brief Isotropic sizing (biasing)\n"
@ -1499,7 +1540,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method is equivalent to \"size(d, d, 2)\".\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("sized", (db::Region (db::Region::*) (db::Coord, db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"),
"@brief Returns the anisotropically sized region\n"
@ -1508,7 +1549,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method is returns the sized region (see \\size), but does not modify self.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("sized", (db::Region (db::Region::*) (db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("d"), gsi::arg ("mode"),
"@brief Returns the isotropically sized region\n"
@ -1517,7 +1558,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method is returns the sized region (see \\size), but does not modify self.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("sized", sized_ext, gsi::arg ("d"),
"@brief Isotropic sizing (biasing)\n"
@ -1526,7 +1567,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method is equivalent to \"sized(d, d, 2)\".\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("andnot", &andnot, gsi::arg ("other"),
"@brief Returns the boolean AND and NOT between self and the other region\n"
@ -1623,7 +1664,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons which are covering polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
"\n"
@ -1634,18 +1675,28 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons which are not covering polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
"\n"
"This method has been introduced in version 0.27."
) +
method_ext ("split_covering", &split_covering, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which are completely covering polygons from the other region and the ones which are not at the same time\n"
"\n"
"@return Two new regions: the first containing the result of \\covering, the second the result of \\not_covering\n"
"\n"
"This method is equivalent to calling \\covering and \\not_covering, but is faster when both results are required.\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
"\n"
"This method has been introduced in version 0.27."
) +
method ("select_covering", &db::Region::select_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons of this region which are completely covering polygons from the other region\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
"\n"
@ -1656,7 +1707,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
"\n"
@ -1667,56 +1718,76 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons which are inside polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("not_inside", &db::Region::selected_not_inside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are not completely inside polygons from the other region\n"
"\n"
"@return A new region containing the polygons which are not inside polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("split_inside", &split_inside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are completely inside polygons from the other region and the ones which are not at the same time\n"
"\n"
"@return Two new regions: the first containing the result of \\inside, the second the result of \\not_inside\n"
"\n"
"This method is equivalent to calling \\inside and \\not_inside, but is faster when both results are required.\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
"\n"
"This method has been introduced in version 0.27."
) +
method ("select_inside", &db::Region::select_inside, gsi::arg ("other"),
"@brief Selects the polygons of this region which are completely inside polygons from the other region\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("select_not_inside", &db::Region::select_not_inside, gsi::arg ("other"),
"@brief Selects the polygons of this region which are not completely inside polygons from the other region\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("outside", &db::Region::selected_outside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are completely outside polygons from the other region\n"
"\n"
"@return A new region containing the polygons which are outside polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("not_outside", &db::Region::selected_not_outside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are not completely outside polygons from the other region\n"
"\n"
"@return A new region containing the polygons which are not outside polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("split_outside", &split_outside, gsi::arg ("other"),
"@brief Returns the polygons of this region which are completely outside polygons from the other region and the ones which are not at the same time\n"
"\n"
"@return Two new regions: the first containing the result of \\outside, the second the result of \\not_outside\n"
"\n"
"This method is equivalent to calling \\outside and \\not_outside, but is faster when both results are required.\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
"\n"
"This method has been introduced in version 0.27."
) +
method ("select_outside", &db::Region::select_outside, gsi::arg ("other"),
"@brief Selects the polygons of this region which are completely outside polygons from the other region\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("select_not_outside", &db::Region::select_not_outside, gsi::arg ("other"),
"@brief Selects the polygons of this region which are not completely outside polygons from the other region\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method ("interacting", (db::Region (db::Region::*) (const db::Region &, size_t, size_t) const) &db::Region::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which overlap or touch polygons from the other region\n"
@ -1728,7 +1799,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons overlapping or touching polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
@ -1742,10 +1813,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons not overlapping or touching polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method_ext ("split_interacting", &split_interacting_with_region, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which are interacting with polygons from the other region and the ones which are not at the same time\n"
"\n"
"@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n"
"\n"
"This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
"\n"
"This method has been introduced in version 0.27."
) +
method ("select_interacting", (db::Region &(db::Region::*) (const db::Region &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which overlap or touch polygons from the other region\n"
"\n"
@ -1756,7 +1837,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
@ -1770,7 +1851,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
@ -1784,7 +1865,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons overlapping or touching edges from the edge collection\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.25.\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
@ -1799,11 +1880,21 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons not overlapping or touching edges from the edge collection\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.25\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
) +
method_ext ("split_interacting", &split_interacting_with_edges, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which are interacting with edges from the other edge collection and the ones which are not at the same time\n"
"\n"
"@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n"
"\n"
"This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
"\n"
"This method has been introduced in version 0.27."
) +
method ("select_interacting", (db::Region &(db::Region::*) (const db::Edges &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which overlap or touch edges from the edge collection\n"
"\n"
@ -1814,7 +1905,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.25\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
@ -1829,7 +1920,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.25\n"
"The min_count and max_count arguments have been added in version 0.27.\n"
@ -1844,7 +1935,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons overlapping or touching texts\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
@ -1858,10 +1949,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons not overlapping or touching texts\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
method_ext ("split_interacting", &split_interacting_with_texts, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which are interacting with texts from the other text collection and the ones which are not at the same time\n"
"\n"
"@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n"
"\n"
"This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
"\n"
"This method has been introduced in version 0.27."
) +
method ("select_interacting", (db::Region &(db::Region::*) (const db::Texts &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons of this region which overlap or touch texts\n"
"\n"
@ -1872,7 +1973,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"selected by this method if the number of texts interacting with the polygon is between min_count and max_count "
"(including max_count).\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
@ -1886,7 +1987,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
@ -1895,7 +1996,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons overlapping polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The count options have been introduced in version 0.27."
) +
@ -1904,16 +2005,26 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return A new region containing the polygons not overlapping polygons from the other region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The count options have been introduced in version 0.27."
) +
method_ext ("split_overlapping", &split_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the polygons of this region which are overlapping with polygons from the other region and the ones which are not at the same time\n"
"\n"
"@return Two new regions: the first containing the result of \\overlapping, the second the result of \\not_overlapping\n"
"\n"
"This method is equivalent to calling \\overlapping and \\not_overlapping, but is faster when both results are required.\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
"\n"
"This method has been introduced in version 0.27."
) +
method ("select_overlapping", &db::Region::select_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the polygons from this region which overlap polygons from the other region\n"
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The count options have been introduced in version 0.27."
) +
@ -1922,7 +2033,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (self)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The count options have been introduced in version 0.27."
) +
@ -1935,7 +2046,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.26.1\n"
) +
@ -1945,7 +2056,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.26.1\n"
) +
@ -1955,7 +2066,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The region after the polygons have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.26.1\n"
) +
@ -1965,7 +2076,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The edge collection after the edges have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.26.1\n"
) +
@ -1975,7 +2086,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The text collection after the texts have been selected (from other)\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27\n"
) +
@ -1996,7 +2107,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"The edge collection returned can be manipulated in various ways. See \\Edges for a description of the "
"possibilities of the edge collection.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
factory_ext ("decompose_convex", &decompose_convex<db::Shapes>, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
"@brief Decomposes the region into convex pieces.\n"
@ -2040,7 +2151,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@brief Returns the holes of the region\n"
"This method returns all holes as filled polygons.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"If merge semantics is not enabled, the holes may not be detected if the polygons "
"are taken from a hole-less representation (i.e. GDS2 file). Use explicit merge (\\merge method) "
"in order to merge the polygons and detect holes.\n"
@ -2049,7 +2160,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@brief Returns the hulls of the region\n"
"This method returns all hulls as polygons. The holes will be removed (filles). "
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"If merge semantics is not enabled, the hull may also enclose holes if the polygons "
"are taken from a hole-less representation (i.e. GDS2 file). Use explicit merge (\\merge method) "
"in order to merge the polygons and detect holes.\n"
@ -2067,36 +2178,36 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
method_ext ("rectangles", &rectangles,
"@brief Returns all polygons which are rectangles\n"
"This method returns all polygons in self which are rectangles."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("non_rectangles", &non_rectangles,
"@brief Returns all polygons which are not rectangles\n"
"This method returns all polygons in self which are not rectangles."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("squares", &squares,
"@brief Returns all polygons which are squares\n"
"This method returns all polygons in self which are squares."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("non_squares", &non_squares,
"@brief Returns all polygons which are not squares\n"
"This method returns all polygons in self which are not squares."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
method_ext ("rectilinear", &rectilinear,
"@brief Returns all polygons which are rectilinear\n"
"This method returns all polygons in self which are rectilinear."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("non_rectilinear", &non_rectilinear,
"@brief Returns all polygons which are not rectilinear\n"
"This method returns all polygons in self which are not rectilinear."
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("break", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0),
"@brief Breaks the polygons of the region into smaller ones\n"
@ -2125,7 +2236,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"with a pencil that has the shape of the given region.\n"
"\n"
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method."
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("minkowsky_sum", &minkowsky_sum_pp, gsi::arg ("p"),
"@brief Compute the Minkowsky sum of the region and a polygon\n"
@ -2138,7 +2249,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"the region with a pen that has the shape of the second polygon.\n"
"\n"
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method."
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("minkowsky_sum", &minkowsky_sum_pb, gsi::arg ("b"),
"@brief Compute the Minkowsky sum of the region and a box\n"
@ -2151,7 +2262,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"as the second polygon.\n"
"\n"
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method."
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("minkowsky_sum", &minkowsky_sum_pc, gsi::arg ("b"),
"@brief Compute the Minkowsky sum of the region and a contour of points (a trace)\n"
@ -2165,7 +2276,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"with a pencil that has the shape of the given region.\n"
"\n"
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method."
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
) +
method_ext ("move", &move_p, gsi::arg ("v"),
"@brief Moves the region\n"
@ -2338,7 +2449,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"violations between the original and the shielding features. If not necessary, shielding can be disabled by setting this flag to "
"false. In general, this will improve performance somewhat.\n"
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27."
) +
@ -2380,7 +2491,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
) +
@ -2421,7 +2532,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"violations between the original and the shielding features. If not necessary, shielding can be disabled by setting this flag to "
"false. In general, this will improve performance somewhat.\n"
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27."
) +
@ -2463,7 +2574,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
) +
@ -2506,7 +2617,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
) +
@ -2549,7 +2660,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
) +
@ -2592,7 +2703,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
) +
@ -2635,27 +2746,27 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
) +
method_ext ("area", &area1,
"@brief The area of the region\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"If merged semantics is not enabled, overlapping areas are counted twice.\n"
) +
method_ext ("area", &area2, gsi::arg ("rect"),
"@brief The area of the region (restricted to a rectangle)\n"
"This version will compute the area of the shapes, restricting the computation to the given rectangle.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"If merged semantics is not enabled, overlapping areas are counted twice.\n"
) +
method_ext ("perimeter", &perimeter1,
"@brief The total perimeter of the polygons\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"If merged semantics is not enabled, internal edges are counted as well.\n"
) +
method_ext ("perimeter", &perimeter2, gsi::arg ("rect"),
@ -2664,7 +2775,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"Edges along the border are handled in a special way: they are counted when they are oriented with their inside "
"side toward the rectangle (in other words: outside edges must coincide with the rectangle's border in order to be counted).\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"If merged semantics is not enabled, internal edges are counted as well.\n"
) +
method ("bbox", &db::Region::bbox,

View File

@ -733,7 +733,8 @@ TEST(11_RoundAndSmoothed)
r1_sized -= r1;
db::Region rounded = r1_sized.rounded_corners (3000, 5000, 100);
db::Region smoothed = rounded.smoothed (100);
db::Region smoothed = rounded.smoothed (100, false);
db::Region smoothed_keep_hv = rounded.smoothed (100, true);
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
@ -741,6 +742,7 @@ TEST(11_RoundAndSmoothed)
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1_sized);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), rounded);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), smoothed);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), smoothed_keep_hv);
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au11.gds");

View File

@ -44,22 +44,22 @@ public:
out ("begin_circuit " + circuit2str (a) + " " + circuit2str (b));
}
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching)
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string & /*msg*/)
{
out ("end_circuit " + circuit2str (a) + " " + circuit2str (b) + " " + (matching ? "MATCH" : "NOMATCH"));
}
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/)
{
out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b));
}
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/)
{
out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
}
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string & /*msg*/)
{
out ("device_class_mismatch " + dc2str (a) + " " + dc2str (b));
}
@ -69,12 +69,12 @@ public:
out ("match_nets " + net2str (a) + " " + net2str (b));
}
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string & /*msg*/)
{
out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b));
}
virtual void net_mismatch (const db::Net *a, const db::Net *b)
virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string & /*msg*/)
{
out ("net_mismatch " + net2str (a) + " " + net2str (b));
}
@ -84,7 +84,7 @@ public:
out ("match_devices " + device2str (a) + " " + device2str (b));
}
virtual void device_mismatch (const db::Device *a, const db::Device *b)
virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string & /*msg*/)
{
out ("device_mismatch " + device2str (a) + " " + device2str (b));
}
@ -104,7 +104,7 @@ public:
out ("match_pins " + pin2str (a) + " " + pin2str (b));
}
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string & /*msg*/)
{
out ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
}
@ -114,7 +114,7 @@ public:
out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b));
}
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string & /*msg*/)
{
out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b));
}
@ -954,7 +954,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (good, false);
logger.clear ();
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 1.5, 0.0));
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 1.5, 0.0));
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
@ -980,7 +980,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (good, true);
logger.clear ();
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.0));
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.0));
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
@ -1006,7 +1006,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (good, false);
logger.clear ();
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.2));
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.2));
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
@ -1032,7 +1032,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (good, false);
logger.clear ();
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.4));
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.4));
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
@ -1059,7 +1059,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
logger.clear ();
db::EqualDeviceParameters eq_dp = db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W) + db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.2, 0.0);
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp));
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp));
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),
@ -1086,7 +1086,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
logger.clear ();
eq_dp = db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W) + db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L);
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp));
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp));
good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (),

View File

@ -1219,8 +1219,8 @@ TEST(100)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 5).to_string (), "(0,-100;0,0;50,10;100,-10;150,0;150,-100)");
EXPECT_EQ (smooth (p, 20).to_string (), "(0,-100;0,0;150,0;150,-100)");
EXPECT_EQ (smooth (p, 5, true).to_string (), "(0,-100;0,0;50,10;100,-10;150,0;150,-100)");
EXPECT_EQ (smooth (p, 20, true).to_string (), "(0,-100;0,0;150,0;150,-100)");
}
// smoothing
@ -1238,8 +1238,8 @@ TEST(101)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;50,10;0,0;0,100;150,100;150,0)");
EXPECT_EQ (smooth (p, 20).to_string (), "(0,0;0,100;150,100;150,0)");
EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;50,10;0,0;0,100;150,100;150,0)");
EXPECT_EQ (smooth (p, 20, true).to_string (), "(0,0;0,100;150,100;150,0)");
}
// smoothing
@ -1255,8 +1255,8 @@ TEST(102)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 20).to_string (), "()");
EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;150,0;0,0;50,10)");
EXPECT_EQ (smooth (p, 20, true).to_string (), "()");
EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;150,0;0,0;50,10)");
}
// smoothing
@ -1282,9 +1282,9 @@ TEST(103)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 0).to_string (), "(59881,-249925;56852,-237283;56961,-237258;60061,-236492;63152,-235686;66231,-234839;69300,-233952;69407,-233919;73105,-246382;72992,-246417;69760,-247351;66516,-248243;63261,-249092;59995,-249899)");
EXPECT_EQ (smooth (p, 50).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)");
EXPECT_EQ (smooth (p, 5000).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)");
EXPECT_EQ (smooth (p, 0, true).to_string (), "(59881,-249925;56852,-237283;56961,-237258;60061,-236492;63152,-235686;66231,-234839;69300,-233952;69407,-233919;73105,-246382;72992,-246417;69760,-247351;66516,-248243;63261,-249092;59995,-249899)");
EXPECT_EQ (smooth (p, 50, true).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)");
EXPECT_EQ (smooth (p, 5000, true).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)");
}
// smoothing
@ -1303,7 +1303,8 @@ TEST(104)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 12).to_string (), "(-244,-942;-942,-246;248,943;943,246)");
EXPECT_EQ (smooth (p, 12, false).to_string (), "(-244,-942;-942,-246;248,943;943,246)");
EXPECT_EQ (smooth (p, 12, true).to_string (), "(-245,-942;-942,-247;-942,-246;247,943;248,943;943,246;-244,-942)");
}
// smoothing
@ -1323,11 +1324,46 @@ TEST(105)
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 0).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 50).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 80).to_string (), "(0,0;0,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 90).to_string (), "(0,0;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 100).to_string (), "(0,0;0,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 0, false).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 50, false).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 80, false).to_string (), "(0,0;0,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 90, false).to_string (), "(0,0;100,1100;800,1100;800,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 100, false).to_string (), "(0,0;0,1000;2000,1000;2000,0)");
EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
}
// smoothing
TEST(106)
{
db::Point pattern [] = {
db::Point (0, 0),
db::Point (0, 73235),
db::Point (100, 74568),
db::Point (700, 82468),
db::Point (1200, 90468),
db::Point (2000, 106468),
db::Point (2300, 114468),
db::Point (2700, 130468),
db::Point (2800, 138468),
db::Point (2800, 154468),
db::Point (2700, 162468),
db::Point (2300, 178468),
db::Point (2000, 186468),
db::Point (1200, 202468),
db::Point (700, 210468),
db::Point (100, 218368),
db::Point (0, 219701),
db::Point (0, 272971),
db::Point (126450, 272971),
db::Point (126450, 0),
};
db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 0, false).to_string (), "(0,0;0,73235;100,74568;700,82468;1200,90468;2000,106468;2300,114468;2700,130468;2800,138468;2800,154468;2700,162468;2300,178468;2000,186468;1200,202468;700,210468;100,218368;0,219701;0,272971;126450,272971;126450,0)");
EXPECT_EQ (smooth (p, 100, false).to_string (), "(0,0;100,74568;1200,90468;2300,114468;2800,138468;2700,162468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)");
EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,73235;1200,90468;2300,114468;2800,138468;2800,154468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)");
}
// rounding
@ -1532,7 +1568,7 @@ TEST(203)
in.push_back (pp);
ep.simple_merge (in, out, false /*no cut line*/);
pp = out.front ();
pp = smooth (pp, 1);
pp = smooth (pp, 1, true);
EXPECT_EQ (pp.hull ().size (), size_t (300));
EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true);
@ -1578,7 +1614,7 @@ TEST(204)
in.push_back (pp);
ep.simple_merge (in, out, false /*no cut line*/);
pp = out.front ();
pp = smooth (pp, 1);
pp = smooth (pp, 1, true);
EXPECT_EQ (pp.hull ().size (), size_t (200));
EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true);

View File

@ -107,12 +107,35 @@ TEST(1)
std::string x;
db::RecursiveShapeIterator i0s (g, c0, 0);
x = collect(i0s, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
EXPECT_EQ (i0s.bbox ().to_string (), "(-1200,0;2200,1200)");
i0s.set_global_trans (db::ICplxTrans (2.0));
x = collect(i0s, g);
EXPECT_EQ (x, "[$1](0,200;2000,2400)/[$2](0,200;2000,2400)/[$3](200,0;2200,2200)/[$4](2400,0;4400,2200)/[$4](-2400,0;-200,2000)");
EXPECT_EQ (i0s.bbox ().to_string (), "(-2400,0;4400,2400)");
db::RecursiveShapeIterator i1 (g, c0, 0, db::Box (0, 0, 100, 100));
x = collect(i1, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
i1.set_global_trans (db::ICplxTrans (db::Trans (db::Vector (10, 20))));
i1.set_region (db::Box (10, 20, 110, 120));
x = collect(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
i1.reset ();
x = collect(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
db::RecursiveShapeIterator i1_1inf (g, c0, 0, db::Box (0, 0, 100, 100));
i1_1inf.min_depth(1);
x = collect(i1_1inf, g);
@ -731,7 +754,7 @@ namespace {
public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
mp_boxes->insert (trans * shape.bbox ());
}
@ -766,6 +789,8 @@ TEST(4)
}
// ...
db::Box search_box (2500, 2500, 7500, 7500);
std::set<db::Box> selected_boxes;
@ -794,6 +819,45 @@ TEST(4)
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// with global trans
selected_boxes.clear ();
selected_boxes2.clear ();
db::ICplxTrans ctr (db::Trans (db::Vector (10, 20)));
{
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
for ( ; !iter.at_end (); ++iter) {
selected_boxes.insert (iter->bbox ().transformed (iter.trans ()));
}
}
{
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (b->transformed (ctr))) {
selected_boxes2.insert (b->transformed (ctr));
}
}
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
iter.push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// ...
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
@ -882,6 +946,40 @@ TEST(5)
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
selected_boxes.clear ();
selected_boxes2.clear ();
db::ICplxTrans ctr (db::Trans (db::Vector (10, 20)));
{
db::RecursiveShapeIterator iter = db::RecursiveShapeIterator (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
for ( ; !iter.at_end (); ++iter) {
selected_boxes.insert (iter.trans () * iter->bbox ());
}
}
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (b->transformed (ctr))) {
selected_boxes2.insert (b->transformed (ctr));
}
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
iter.push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
@ -936,7 +1034,7 @@ public:
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
}
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
if (all) {
@ -946,9 +1044,9 @@ public:
return NI_all;
}
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans);
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (always_apply * trans);
if (all) {
m_text += ",all";
}
@ -956,7 +1054,7 @@ public:
return true;
}
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n";
}
@ -971,9 +1069,9 @@ class ReceiverRejectingACellInstanceArray
public:
ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst (iter, inst, region, complex_region, all);
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip;
}
@ -987,9 +1085,9 @@ class ReceiverRejectingACellInstanceArrayExceptOne
public:
ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst (iter, inst, region, complex_region, all);
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
return inst.object ().cell_index () != m_rejected ? NI_all : NI_single;
}
@ -1003,9 +1101,9 @@ class ReceiverRejectingACellInstance
public:
ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { }
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region, all);
LoggingReceiver::new_inst_member (iter, inst, always_apply, trans, region, complex_region, all);
return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected;
}
@ -1127,6 +1225,100 @@ TEST(10)
"end\n"
);
LoggingReceiver lr1_gt;
db::RecursiveShapeIterator i1_gt (g, c0, 0);
i1_gt.set_global_trans (db::ICplxTrans (db::Trans (db::Vector (10, 20))));
i1_gt.push (&lr1_gt);
EXPECT_EQ (lr1_gt.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 10,20,all)\n"
// It's a bit weird to have shape events after new_inst_member, but remember, new_inst_member is a query callback, not an event.
"shape(box (0,0;1000,1000),r0 *1 10,20)\n"
"shape(box (-1000,0;0,1000),r0 *1 10,20)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,20)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,2020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,1020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,3020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 10,6020,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,6020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,8020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,7020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,9020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6010,20,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,20)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,2020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,1020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,3020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6010,6020,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,6020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,8020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,7020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,9020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"end\n"
);
ReceiverRejectingACellInstanceArray rr1 (c2.cell_index ());
db::RecursiveShapeIterator ir1 (g, c0, 0);
ir1.push (&rr1);

View File

@ -354,6 +354,8 @@ TEST(10a)
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_not_interacting (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).first.to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting_differential (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (db::compare (r.selected_interacting (db::Region (db::Box (db::Point (-20, -20), db::Point (30, 30)))), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true);
EXPECT_EQ (r.selected_interacting (db::Region (db::Box (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), "");
db::Region rr = r;
@ -836,6 +838,8 @@ TEST(18a)
EXPECT_EQ (db::compare (o, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
o = r;
EXPECT_EQ (db::compare (o.selected_not_outside (rr), "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
EXPECT_EQ (db::compare (o.selected_outside_differential (rr).first, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
EXPECT_EQ (db::compare (o.selected_outside_differential (rr).second, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
EXPECT_EQ (o.selected_outside (rr).count () + o.selected_not_outside (rr).count (), size_t (6));
EXPECT_EQ (o.selected_outside (rr).hier_count () + o.selected_not_outside (rr).hier_count (), size_t (6));
o.select_not_outside (rr);
@ -848,6 +852,8 @@ TEST(18a)
EXPECT_EQ (o.to_string (), "(20,30;20,50;40,50;40,30)");
o = r;
EXPECT_EQ (db::compare (o.selected_not_inside (rr), "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
EXPECT_EQ (db::compare (o.selected_inside_differential (rr).first, "(20,30;20,50;40,50;40,30)"), true);
EXPECT_EQ (db::compare (o.selected_inside_differential (rr).second, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
EXPECT_EQ (o.selected_inside (rr).count () + o.selected_not_inside (rr).count (), size_t (6));
EXPECT_EQ (o.selected_inside (rr).hier_count () + o.selected_not_inside (rr).hier_count (), size_t (6));
o.select_not_inside (rr);
@ -860,6 +866,8 @@ TEST(18a)
EXPECT_EQ (db::compare (o, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
o = r;
EXPECT_EQ (o.selected_not_interacting (rr).to_string (), "(70,60;70,80;90,80;90,60)");
EXPECT_EQ (db::compare (o.selected_interacting_differential (rr).first, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
EXPECT_EQ (db::compare (o.selected_interacting_differential (rr).second, "(70,60;70,80;90,80;90,60)"), true);
EXPECT_EQ (o.selected_interacting (rr).count () + o.selected_not_interacting (rr).count (), size_t (6));
EXPECT_EQ (o.selected_interacting (rr).hier_count () + o.selected_not_interacting (rr).hier_count (), size_t (6));
o.select_not_interacting (rr);
@ -872,6 +880,8 @@ TEST(18a)
EXPECT_EQ (db::compare (o, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
o = r;
EXPECT_EQ (db::compare (o.selected_not_overlapping (rr), "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
EXPECT_EQ (db::compare (o.selected_overlapping_differential (rr).first, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
EXPECT_EQ (db::compare (o.selected_overlapping_differential (rr).second, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
EXPECT_EQ (o.selected_overlapping (rr).count () + o.selected_not_overlapping (rr).count (), size_t (6));
EXPECT_EQ (o.selected_overlapping (rr).hier_count () + o.selected_not_overlapping (rr).hier_count (), size_t (6));
o.select_not_overlapping (rr);
@ -884,6 +894,8 @@ TEST(18a)
EXPECT_EQ (o.to_string (), "(0,100;0,130;30,130;30,100)");
o = r;
EXPECT_EQ (db::compare (o.selected_not_enclosing (rr), "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60)"), true);
EXPECT_EQ (db::compare (o.selected_enclosing_differential (rr).first, "(0,100;0,130;30,130;30,100)"), true);
EXPECT_EQ (db::compare (o.selected_enclosing_differential (rr).second, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60)"), true);
EXPECT_EQ (o.selected_enclosing (rr).count () + o.selected_not_enclosing (rr).count (), size_t (6));
EXPECT_EQ (o.selected_enclosing (rr).hier_count () + o.selected_not_enclosing (rr).hier_count (), size_t (6));
o.select_not_enclosing (rr);
@ -1506,6 +1518,8 @@ TEST(30a)
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_not_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).first.to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting_differential (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (db::compare (r.selected_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (30, 30)))), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)"), true);
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), "");
db::Region rr = r;
@ -1689,6 +1703,8 @@ TEST(34a)
r.set_merged_semantics (false);
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).first.to_string (), "(0,0;0,200;100,200;100,0)");
EXPECT_EQ (r.selected_interacting_differential (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
db::Texts tt;
tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30))));
tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0))));
@ -1782,6 +1798,7 @@ TEST(35a_interact_with_count_region)
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (rr, 1, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
@ -1797,6 +1814,7 @@ TEST(35a_interact_with_count_region)
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true);
@ -1855,6 +1873,7 @@ TEST(35b_interact_with_count_edge)
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (rr, 2, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
@ -1869,6 +1888,7 @@ TEST(35b_interact_with_count_edge)
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true);
@ -1926,6 +1946,7 @@ TEST(35c_interact_with_count_text)
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (rr, 2, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
@ -1940,6 +1961,7 @@ TEST(35c_interact_with_count_text)
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true);

View File

@ -739,16 +739,18 @@ CODE
# %DRC%
# @name smoothed
# @brief Applies smoothing
# @synopsis expression.smoothed(d)
# @synopsis expression.smoothed(d [, keep_hv ])
#
# This operation acts on polygons and applies polygon smoothing with the tolerance d. See \Layer#smoothed for more details.
# This operation acts on polygons and applies polygon smoothing with the tolerance d. 'keep_hv' indicates
# whether horizontal and vertical edges are maintained. Default is 'no' which means such edges may be distorted.
# See \Layer#smoothed for more details.
#
# The "smoothed" method is available as a plain function or as a method on \DRC# expressions.
# The plain function is equivalent to "primary.smoothed".
def smoothed(d)
def smoothed(d, keep_hv = false)
@engine._context("smoothed") do
DRCOpNodeFilter::new(@engine, self, :new_smoothed, "smoothed", @engine._make_value(d))
DRCOpNodeFilter::new(@engine, self, :new_smoothed, "smoothed", @engine._make_value(d), keep_hv)
end
end

View File

@ -48,6 +48,8 @@ module DRC
@deep = false
@netter = nil
@netter_data = nil
@total_timer = nil
@drc_progress = nil
# initialize the defaults for max_area_ratio, max_vertex_count
dss = RBA::DeepShapeStore::new
@ -58,9 +60,39 @@ module DRC
@verbose = false
@in_context = false
@in_context = nil
end
def shift(x, y)
self._context("shift") do
RBA::DCplxTrans::new(RBA::DVector::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu))
end
end
def magnify(m)
self._context("magnify") do
RBA::DCplxTrans::new(_make_numeric_value(m))
end
end
def rotate(a)
self._context("rotate") do
RBA::DCplxTrans::new(1.0, _make_numeric_value(a), false, RBA::DVector::new)
end
end
def mirror_x
self._context("mirror_x") do
RBA::DCplxTrans::new(1.0, 0.0, true, RBA::DVector::new)
end
end
def mirror_y
self._context("mirror_y") do
RBA::DCplxTrans::new(1.0, 180.0, true, RBA::DVector::new)
end
end
def joined
DRCJoinFlag::new(true)
@ -231,6 +263,27 @@ module DRC
DRCFillOrigin::new(x, y)
end
def tile_size(x, y = nil)
DRCTileSize::new(_make_value(x) * self.dbu, _make_value(y || x) * self.dbu)
end
def tile_step(x, y = nil)
DRCTileStep::new(_make_value(x) * self.dbu, _make_value(y || x) * self.dbu)
end
def tile_origin(x, y)
DRCTileOrigin::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu)
end
def tile_count(x, y)
DRCTileCount::new(_make_numeric_value(x), _make_numeric_value(y))
end
def tile_boundary(b)
b.is_a?(DRCLayer) || raise("'tile_boundary' requires a layer argument")
DRCTileBoundary::new(b)
end
# %DRC%
# @brief Defines SPICE output format (with options)
# @name write_spice
@ -475,15 +528,20 @@ module DRC
# %DRC%
# @name info
# @brief Outputs as message to the logger window
# @brief Outputs as message to the logger or progress window
# @synopsis info(message)
# @synopsis info(message, indent)
# Prints the message to the log window in verbose mode.
# In non-verbose more, nothing is printed.
# In non-verbose more, nothing is printed but a statement is put into the progress window.
# \log is a function that always prints a message.
def info(arg, indent = 0)
@verbose && log(arg, indent)
if @verbose
log(arg, indent)
else
str = (" " * indent) + arg
RBA::Logger::log(str)
end
end
# %DRC%
@ -496,7 +554,7 @@ module DRC
# verbose mode is enabled.
def log(arg, indent = 0)
str = (" " * indent) + arg
str = (" " * indent) + arg
if @log_file
@log_file.puts(str)
else
@ -1486,6 +1544,22 @@ CODE
nil
end
# %DRC%
# @name global_transform
# @brief Gets or sets a global transformation
# @synopsis global_transform
# @synopsis global_transform([ transformations ])
#
# Applies a global transformation to the default source layout.
# See \Source#global_transform for a description of this feature.
def global_transform(*args)
self._context("global_transform") do
@def_source = layout.global_transform(*args)
end
nil
end
# %DRC%
# @name cheat
# @brief Hierarchy cheats
@ -1671,8 +1745,6 @@ CODE
pull_overlapping
rectangles
rectilinear
rotate
rotated
rounded_corners
scale
scaled
@ -1848,9 +1920,10 @@ CODE
def _wrapper_context(func, *args, &proc)
in_context_outer = @in_context
begin
@in_context = true
@in_context = func
return yield(*args)
rescue => ex
RBA::MacroExecutionContext::ignore_next_exception
raise("'" + func + "': " + ex.to_s)
ensure
@in_context = in_context_outer
@ -1862,22 +1935,41 @@ CODE
return yield(*args)
else
begin
@in_context = true
@in_context = func
return yield(*args)
rescue => ex
RBA::MacroExecutionContext::ignore_next_exception
raise("'" + func + "': " + ex.to_s)
ensure
@in_context = false
@in_context = nil
end
end
end
def _result_info(res, indent, prefix = "")
if res.is_a?(Array)
res.each_with_index do |a, index|
_result_info(a, indent, "[#{index + 1}] ")
end
elsif res.is_a?(RBA::Region)
info(prefix + "Polygons (raw): #{res.count} (flat) #{res.hier_count} (hierarchical)", indent)
elsif res.is_a?(RBA::Edges)
info(prefix + "Edges: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent)
elsif res.is_a?(RBA::EdgePairs)
info(prefix + "Edge pairs: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent)
elsif res.is_a?(RBA::Texts)
info(prefix + "Texts: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent)
end
end
def run_timed(desc, obj)
log(desc)
info(desc)
# enable progress
disable_progress = false
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
disable_progress = true
obj.enable_progress(desc)
end
@ -1887,39 +1979,37 @@ CODE
res = yield
t.stop
if @verbose
begin
if @verbose
# Report result statistics
_result_info(res, 1)
mem = RBA::Timer::memory_size
if mem > 0
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M", 1)
else
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s", 1)
end
# Report result statistics
if res.is_a?(RBA::Region)
info("Polygons (raw): #{res.count} (flat) #{res.hier_count} (hierarchical)", 1)
elsif res.is_a?(RBA::Edges)
info("Edges: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1)
elsif res.is_a?(RBA::EdgePairs)
info("Edge pairs: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1)
elsif res.is_a?(RBA::Texts)
info("Texts: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1)
end
mem = RBA::Timer::memory_size
if mem > 0
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M", 1)
else
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s", 1)
ensure
# disable progress again
if disable_progress
obj.disable_progress
end
end
# disable progress
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
obj.disable_progress
end
res
end
def _cmd(obj, method, *args)
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
obj.send(method, *args)
end
end
@ -1949,8 +2039,9 @@ CODE
end
av = args.size.times.collect { |i| "a#{i}" }.join(", ")
tp.queue("_output(res, self.#{method}(#{av}))")
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
tp.execute("Tiled \"#{method}\" in: #{src_line}")
res
end
else
@ -1960,17 +2051,12 @@ CODE
end
res = nil
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
res = obj.send(method, *args)
end
end
# disable progress again
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
obj.disable_progress
end
res
end
@ -2004,8 +2090,9 @@ CODE
end
av = args.size.times.collect { |i| "a#{i}" }.join(", ")
tp.queue("var rr = self.#{method}(#{av}); _output(res1, rr[0]); _output(res2, rr[1])")
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
tp.execute("Tiled \"#{method}\" in: #{src_line}")
res
end
else
@ -2015,17 +2102,12 @@ CODE
end
res = nil
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
res = obj.send(method, *args)
end
end
# disable progress again
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
obj.disable_progress
end
res
end
@ -2045,8 +2127,9 @@ CODE
tp.input("self", obj)
tp.threads = (@tt || 1)
tp.queue("_output(res, _tile ? self.#{method}(_tile.bbox) : self.#{method})")
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
tp.execute("Tiled \"#{method}\" in: #{src_line}")
res
end
res = res.value
@ -2058,29 +2141,24 @@ CODE
end
res = nil
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
res = obj.send(method)
end
end
# disable progress again
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
obj.disable_progress
end
res
end
def _rcmd(obj, method, *args)
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
RBA::Region::new(obj.send(method, *args))
end
end
def _vcmd(obj, method, *args)
run_timed("\"#{method}\" in: #{src_line}", obj) do
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
obj.send(method, *args)
end
end
@ -2126,12 +2204,17 @@ CODE
output_cell
end
def _start
def _start(job_description)
# clearing the selection avoids some nasty problems
view = RBA::LayoutView::current
view && view.cancel
@total_timer = RBA::Timer::new
@total_timer.start
@drc_progress = RBA::AbstractProgress::new(job_description)
end
def _flush
@ -2271,9 +2354,20 @@ CODE
@netter = nil
@netter_data = nil
if final && @log_file
@log_file.close
@log_file = nil
if final
@total_timer.stop
if @verbose
mem = RBA::Timer::memory_size
if mem > 0
info("Total elapsed: #{'%.3f'%(@total_timer.sys+@total_timer.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M")
else
info("Total elapsed: #{'%.3f'%(@total_timer.sys+@total_timer.user)}s")
end
end
_cleanup
end
# force garbage collection
@ -2283,6 +2377,23 @@ CODE
end
def _cleanup
if @log_file
@log_file.close
@log_file = nil
end
# unlocks the UI
if @drc_progress
@drc_progress._destroy
@drc_progress = nil
end
GC.start
end
def _take_data
if ! @netter
@ -2441,7 +2552,7 @@ CODE
end
end
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, cls)
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, global_trans, cls)
if layers.empty? && ! @deep
@ -2455,6 +2566,7 @@ CODE
iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers)
end
iter.shape_flags = shape_flags
iter.global_dtrans = global_trans
sel.each do |s|
if s == "-"
@ -2492,8 +2604,12 @@ CODE
end
# clip if a box is specified
if box && clip && (cls == RBA::Region || cls == RBA::Edge)
r &= RBA::Region::new(box)
# TODO: the whole clip thing could be a part of the Region constructor
if cls == RBA::Region && clip && box
# HACK: deep regions will always clip in the constructor, so skip this
if ! @deep
r &= RBA::Region::new(box)
end
end
end
@ -2582,6 +2698,9 @@ CODE
end
end
data
end
def make_source(layout, cell = nil, path = nil)

View File

@ -983,8 +983,8 @@ CODE
# @name corners
# @brief Selects corners of polygons
# @synopsis layer.corners([ options ])
# @synopsis layer.corners(angle, [ options ])
# @synopsis layer.corners(amin .. amax, [ options ])
# @synopsis layer.corners(angle [, options ])
# @synopsis layer.corners(amin .. amax [, options ])
#
# This method produces markers on the corners of the polygons. An angle criterion can be given which
# selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
@ -1263,6 +1263,7 @@ CODE
self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
block.call(object.transformed(t)) && new_data.insert(object)
end
new_data
end
DRCLayer::new(@engine, new_data)
@ -1285,7 +1286,7 @@ CODE
@engine._wrapper_context("each") do
t = RBA::CplxTrans::new(@engine.dbu)
@engine.run_timed("\"select\" in: #{@engine.src_line}", self.data) do
@engine.run_timed("\"each\" in: #{@engine.src_line}", self.data) do
self.data.send(self.data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
block.call(object.transformed(t))
end
@ -1368,10 +1369,11 @@ CODE
t = RBA::CplxTrans::new(@engine.dbu)
dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu)
@engine.run_timed("\\"select\\" in: " + @engine.src_line, self.data) do
@engine.run_timed("\\"#{f}\\" in: " + @engine.src_line, self.data) do
self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
insert_object_into(new_data, block.call(object.transformed(t)), dbu_trans)
end
new_data
end
DRCLayer::new(@engine, new_data)
@ -1660,6 +1662,7 @@ CODE
@engine._context("andnot") do
check_is_layer(other)
requires_region
other.requires_region
@ -1773,6 +1776,21 @@ CODE
# It returns a new layer containing the selected shapes. A version which modifies self
# is \select_not_covering.
# %DRC%
# @name split_covering
# @brief Returns the results of \covering and \not_covering at the same time
# @synopsis (a, b) = layer.split_covering(other [, options ])
#
# This method returns the polygons covering polygons from the other layer in
# one layer and all others in a second layer. This method is equivalent to calling
# \covering and \not_covering, but is faster than doing this in separate steps:
#
# @code
# (covering, not_covering) = l1.split_covering(l2)
# @/code
#
# The options of this method are the same than \covering.
# %DRC%
# @name select_covering
# @brief Selects shapes or regions of self which completely cover (enclose) one or more shapes from the other region
@ -1849,6 +1867,21 @@ CODE
# It returns a new layer containing the selected shapes. A version which modifies self
# is \select_not_overlapping.
# %DRC%
# @name split_overlapping
# @brief Returns the results of \overlapping and \not_overlapping at the same time
# @synopsis (a, b) = layer.split_overlapping(other [, options ])
#
# This method returns the polygons overlapping polygons from the other layer in
# one layer and all others in a second layer. This method is equivalent to calling
# \overlapping and \not_overlapping, but is faster than doing this in separate steps:
#
# @code
# (overlapping, not_overlapping) = l1.split_overlapping(l2)
# @/code
#
# The options of this method are the same than \overlapping.
# %DRC%
# @name select_overlapping
# @brief Selects shapes or regions of self which overlap shapes from the other region
@ -1923,6 +1956,19 @@ CODE
# @/tr
# @/table
# %DRC%
# @name split_inside
# @brief Returns the results of \inside and \not_inside at the same time
# @synopsis (a, b) = layer.split_inside(other)
#
# This method returns the polygons inside of polygons from the other layer in
# one layer and all others in a second layer. This method is equivalent to calling
# \inside and \not_inside, but is faster than doing this in separate steps:
#
# @code
# (inside, not_inside) = l1.split_inside(l2)
# @/code
# %DRC%
# @name select_inside
# @brief Selects shapes or regions of self which are inside the other region
@ -1995,6 +2041,19 @@ CODE
# @/tr
# @/table
# %DRC%
# @name split_outside
# @brief Returns the results of \outside and \not_outside at the same time
# @synopsis (a, b) = layer.split_outside(other)
#
# This method returns the polygons outside of polygons from the other layer in
# one layer and all others in a second layer. This method is equivalent to calling
# \outside and \not_outside, but is faster than doing this in separate steps:
#
# @code
# (outside, not_outside) = l1.split_outside(l2)
# @/code
# %DRC%
# @name select_outside
# @brief Selects shapes or regions of self which are outside the other region
@ -2149,6 +2208,21 @@ CODE
# @/tr
# @/table
# %DRC%
# @name split_interacting
# @brief Returns the results of \interacting and \not_interacting at the same time
# @synopsis (a, b) = layer.split_interacting(other [, options ])
#
# This method returns the polygons interacting with objects from the other container in
# one layer and all others in a second layer. This method is equivalent to calling
# \interacting and \not_interacting, but is faster than doing this in separate steps:
#
# @code
# (interacting, not_interacting) = l1.split_interacting(l2)
# @/code
#
# The options of this method are the same than \interacting.
# %DRC%
# @name select_interacting
# @brief Selects shapes or regions of self which touch or overlap shapes from the other region
@ -2192,7 +2266,7 @@ CODE
# number of (different) shapes from the other layer. If a min and max count is given, shapes from
# self are selected only if they interact with less than min_count or more than max_count different shapes
# from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
# %DRC%
# @name intersections
# @brief Returns the intersection points of intersecting edge segments for two edge collections
@ -2285,6 +2359,7 @@ CODE
@engine._context("#{f}") do
check_is_layer(other)
if :#{f} != :pull_interacting
requires_region
other.requires_region
@ -2310,11 +2385,16 @@ CODE
%w(| ^ inside not_inside outside not_outside in not_in).each do |f|
eval <<"CODE"
def #{f}(other)
@engine._context("#{f}") do
requires_same_type(other)
requires_edges_or_region
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end
end
CODE
end
@ -2325,12 +2405,14 @@ CODE
@engine._context("#{f}") do
check_is_layer(other)
other.requires_edges_texts_or_region
if self.data.is_a?(RBA::Texts)
other.requires_region
else
other.requires_edges_or_region
end
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end
@ -2342,10 +2424,14 @@ CODE
%w(+).each do |f|
eval <<"CODE"
def #{f}(other)
@engine._context("#{f}") do
requires_same_type(other)
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end
end
CODE
end
@ -2356,7 +2442,7 @@ CODE
@engine._context("#{f}") do
other.requires_edges_texts_or_region
check_is_layer(other)
if self.data.is_a?(RBA::Text)
other.requires_region
elsif self.data.is_a?(RBA::Region)
@ -2381,6 +2467,7 @@ CODE
@engine._context("#{f}") do
check_is_layer(other)
requires_edges_texts_or_region
if self.data.is_a?(RBA::Text)
other.requires_region
@ -2389,6 +2476,7 @@ CODE
else
other.requires_edges_or_region
end
if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args))
DRCLayer::new(@engine, self.data)
@ -2402,14 +2490,39 @@ CODE
CODE
end
%w(overlapping not_overlapping covering not_covering).each do |f|
%w(split_interacting).each do |f|
eval <<"CODE"
def #{f}(other, *args)
@engine._context("#{f}") do
check_is_layer(other)
requires_region
other.requires_edges_texts_or_region
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data, *minmax_count(*args))
[ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ]
end
end
CODE
end
%w(overlapping not_overlapping covering not_covering).each do |f|
eval <<"CODE"
def #{f}(other, *args)
@engine._context("#{f}") do
requires_same_type(other)
requires_region
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(*args)))
end
end
CODE
end
@ -2424,6 +2537,7 @@ CODE
requires_region
requires_same_type(other)
if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args))
DRCLayer::new(@engine, self.data)
@ -2437,6 +2551,24 @@ CODE
CODE
end
%w(split_overlapping split_covering).each do |f|
eval <<"CODE"
def #{f}(other, *args)
@engine._context("#{f}") do
requires_region
other.requires_region
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data, *minmax_count(*args))
[ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ]
end
end
CODE
end
%w(inside not_inside outside not_outside).each do |fi|
f = "select_" + fi
# In tiled mode, there are no modifying versions. Emulate using the non-modifying one.
@ -2447,6 +2579,7 @@ CODE
requires_region
requires_same_type(other)
if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data)
DRCLayer::new(@engine, self.data)
@ -2460,14 +2593,39 @@ CODE
CODE
end
%w(split_inside split_outside).each do |f|
eval <<"CODE"
def #{f}(other)
@engine._context("#{f}") do
check_is_layer(other)
requires_region
other.requires_region
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data)
[ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ]
end
end
CODE
end
%w(inside_part outside_part).each do |f|
eval <<"CODE"
def #{f}(other)
@engine._context("#{f}") do
check_is_layer(other)
other.requires_region
requires_edges
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end
end
CODE
end
@ -2475,11 +2633,17 @@ CODE
%w(intersections).each do |f|
eval <<"CODE"
def #{f}(other)
@engine._context("#{f}") do
check_is_layer(other)
other.requires_edges
requires_edges
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end
end
CODE
end
@ -3496,6 +3660,180 @@ CODE
end
CODE
end
# %DRC%
# @name with_density
# @brief Returns tiles whose density is within a given range
# @synopsis layer.with_density(min_value, max_value [, options ])
# @synopsis layer.with_density(min_value .. max_value [, options ])
#
# This method runs a tiled analysis over the current layout. It reports the tiles whose density
# is between "min_value" and "max_value". "min_value" and "max_value" are given in
# relative units, i.e. within the range of 0 to 1.0 corresponding to a density of 0 to 100%.
#
# "min_value" or "max_value" can be nil or omitted in the ".." range notation.
# In this case, they are taken as "0" and "100%".
#
# The tile size must be specified with the "tile_size" option:
#
# @code
# # reports areas where layer 1/0 density is below 10% on 20x20 um tiles
# low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um))
# @/code
#
# Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)".
# The first value is the horizontal tile dimension, the second value is the vertical tile
# dimension.
#
# A tile overlap can be specified using "tile_step". If the tile step is less than the
# tile size, the tiles will overlap. The layout window given by "tile_size" is moved
# in increments of the tile step:
#
# @code
# # reports areas where layer 1/0 density is below 10% on 30x30 um tiles
# # with a tile step of 20x20 um:
# low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
# @/code
#
# For "tile_step", anisotropic values can be given as well by using two values: the first for the
# horizontal and the second for the vertical tile step.
#
# Another option is "tile_origin" which specifies the location of the first tile's position.
# This is the lower left tile's lower left corner. If no origin is given, the tiles are centered over the
# area investigated.
#
# By default, the tiles will cover the bounding box of the input layer. A separate layer
# can be used in addition. This way, the layout's dimensions can be derived from some
# drawn boundary layer. To specify a separate, additional layer included in the bounding box, use the "tile_boundary" option:
#
# @code
# # reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from
# # layer 0/0:
# cell_frame = input(0, 0)
# low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
# @/code
#
# Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box.
# The computed area is at least the area of the input layer.
#
# Computation of the area can be skipped by explicitly giving a tile count in horizontal and vertical
# direction. With the "tile_origin" option this allows full control over the area covered:
#
# @code
# # reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000
# # (100 and 150 tiles of 20 um each are used in horizontal and vertical direction):
# low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
# @/code
#
# The complementary version of "with_density" is \without_density.
# %DRC%
# @name without_density
# @brief Returns tiles whose density is not within a given range
# @synopsis layer.without_density(min_value, max_value [, options ])
# @synopsis layer.without_density(min_value .. max_value [, options ])
#
# For details about the operations and the operation see \with_density. This version will return the
# tiles where the density is not within the given range.
def _with_density(method, inverse, *args)
requires_region
limits = [ nil, nil ]
nlimits = 0
tile_size = nil
tile_step = nil
tile_origin = nil
tile_count = nil
tile_boundary = nil
n = 1
args.each do |a|
if a.is_a?(DRCTileSize)
tile_size = a.get
elsif a.is_a?(DRCTileStep)
tile_step = a.get
elsif a.is_a?(DRCTileOrigin)
tile_origin = a.get
elsif a.is_a?(DRCTileCount)
tile_count = a.get
elsif a.is_a?(DRCTileBoundary)
tile_boundary = a.get
elsif a.is_a?(Float) || a.is_a?(1.class) || a == nil
nlimits < 2 || raise("Too many values specified")
limits[nlimits] = @engine._make_numeric_value_with_nil(a)
nlimits += 1
elsif a.is_a?(Range)
nlimits == 0 || raise("Either a range or two limits have to be specified, not both")
limits = [ @engine._make_numeric_value_with_nil(a.begin), @engine._make_numeric_value_with_nil(a.end) ]
nlimits = 2
else
raise("Parameter #" + n.to_s + " does not have an expected type")
end
n += 1
end
tile_size || raise("At least the tile_size option needs to be present")
tile_step ||= tile_size
tp = RBA::TilingProcessor::new
tp.dbu = @engine.dbu
tp.scale_to_dbu = false
tp.tile_size(*tile_step)
if tile_size != tile_step
xb = 0.5 * (tile_size[0] - tile_step[0])
yb = 0.5 * (tile_size[1] - tile_step[1])
tp.tile_border(xb, yb)
tp.var("xoverlap", xb / tp.dbu)
tp.var("yoverlap", yb / tp.dbu)
else
tp.var("xoverlap", 0)
tp.var("yoverlap", 0)
end
if tile_origin
tp.tile_origin(*tile_origin)
end
if tile_count
tp.tiles(*tile_count)
end
res = RBA::Region.new
tp.output("res", res)
tp.input("input", self.data)
tp.threads = (@engine.threads || 1)
if tile_boundary
tp.input("boundary", tile_boundary.data)
end
tp.var("vmin", limits[0] || 0.0)
tp.var("vmax", limits[1] || 1.0)
tp.var("inverse", inverse)
tp.queue(<<"TP_SCRIPT")
_tile && (
var bx = _tile.bbox.enlarged(xoverlap, yoverlap);
var d = to_f(input.area(bx)) / to_f(bx.area);
((d > vmin - 1e-10 && d < vmax + 1e-10) != inverse) && _output(res, bx, false)
)
TP_SCRIPT
@engine.run_timed("\"#{method}\" in: #{@engine.src_line}", self.data) do
tp.execute("Tiled \"#{method}\" in: #{@engine.src_line}")
res
end
DRCLayer::new(@engine, res)
end
def with_density(*args)
self._with_density("with_density", false, *args)
end
def without_density(*args)
self._with_density("without_density", true, *args)
end
# %DRC%
# @name scaled
@ -4102,6 +4440,10 @@ END
@data = d
end
def check_is_layer(other)
other.is_a?(DRCLayer) || raise("Argument needs to be a DRC layer")
end
def requires_region
self.data.is_a?(RBA::Region) || raise("Requires a polygon layer")
end

View File

@ -27,6 +27,7 @@ module DRC
@clip = false
@overlapping = false
@tmp_layers = []
@global_trans = RBA::DCplxTrans::new
end
# Conceptual deep copy (not including the temp layers)
@ -70,6 +71,24 @@ module DRC
def cell_obj
@cell
end
def inplace_global_transform(*args)
gt = RBA::DCplxTrans::new
args.each do |a|
if a.is_a?(RBA::DVector) || a.is_a?(RBA::DTrans)
gt = RBA::DCplxTrans::new(a) * gt
elsif a.is_a?(RBA::DCplxTrans)
gt = a * gt
else
raise("Expected a transformation spec instead of #{a.inspect}")
end
end
@global_trans = gt
end
def global_transformation
@global_trans
end
def finish
@tmp_layers.each do |li|
@ -245,8 +264,40 @@ module DRC
# \touching is a similar method which delivers shapes touching
# the search region with their bounding box (without the requirement to overlap)
# %DRC%
# @name global_transform
# @brief Gets or sets a global transformation
# @synopsis global_transform
# @synopsis global_transform([ transformations ])
#
# This method returns a new source representing the transformed layout. It is provided in the spritit of
# \Source#clip and similar methods.
#
# The transformation
# is either given as a RBA::DTrans, RBA::DVector or RBA::DCplxTrans object or as one of the
# following specifications:
#
# @ul
# @li "shift(x, y)": shifts the input layout horizontally by x and vertically by y micrometers
# @li "rotate(a)": rotates the input layout by a degree counter-clockwise
# @li "magnify(m)": magnifies the input layout by the factor m (NOTE: using fractional scale factors may result in small gaps due to grid snapping)
# @li "mirror_x": mirrors the input layout at the x axis
# @li "mirror_y": mirrors the input layout at the y axis
# @/ul
#
# Multiple transformation specs can be given. In that case the transformations are applied right to left.
# Using "global_transform" will reset any global transformation present already.
# Without an argument, the global transformation is reset.
#
# The following example rotates the layout by 90 degree at the origin (0, 0) and then shifts it up by
# 100 micrometers:
#
# @code
# source.global_transform(shift(0, 100.um), rotate(90.0))
# @/code
# export inplace_* as * out-of-place
%w(select cell clip touching overlapping).each do |f|
%w(select cell clip touching overlapping global_transform).each do |f|
eval <<"CODE"
def #{f}(*args)
@engine._context("#{f}") do
@ -274,7 +325,7 @@ CODE
if @box
layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu)
else
layer.insert(RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu)
layer.insert((RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu).transformed(@global_trans))
end
layer
end
@ -326,7 +377,7 @@ CODE
def input(*args)
@engine._context("input") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
end
end
@ -350,7 +401,7 @@ CODE
def labels(*args)
@engine._context("labels") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, RBA::Texts))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, @global_trans, RBA::Texts))
end
end
@ -373,7 +424,7 @@ CODE
def polygons(*args)
@engine._context("polygons") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, RBA::Region))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, @global_trans, RBA::Region))
end
end
@ -399,7 +450,7 @@ CODE
def edges(*args)
@engine._context("edges") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, RBA::Edges))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, @global_trans, RBA::Edges))
end
end
@ -425,7 +476,7 @@ CODE
def edge_pairs(*args)
@engine._context("edge_pairs") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, RBA::EdgePairs))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, @global_trans, RBA::EdgePairs))
end
end
@ -437,7 +488,7 @@ CODE
def make_layer
layers = []
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
end
# %DRC%

View File

@ -322,5 +322,55 @@ module DRC
end
end
# A wrapper for the tile_size option
class DRCTileSize
def initialize(*args)
@xy = args
end
def get
@xy
end
end
# A wrapper for the tile_step option
class DRCTileStep
def initialize(*args)
@xy = args
end
def get
@xy
end
end
# A wrapper for the tile_origin option
class DRCTileOrigin
def initialize(*args)
@xy = args
end
def get
@xy
end
end
# A wrapper for the tile_count option
class DRCTileCount
def initialize(*args)
@xy = args
end
def get
@xy
end
end
# A wrapper for the tile_boundary option
class DRCTileBoundary
def initialize(layer)
@b = layer
end
def get
@b
end
end
end

View File

@ -17,44 +17,52 @@
<text>
module DRC
def DRC.execute_drc(macro, generator, rdb_index = nil)
class DRCExecutable &lt; RBA::Executable
timer = RBA::Timer::new
timer.start
drc = DRCEngine::new
drc._rdb_index = rdb_index
drc._generator = generator
def initialize(macro, generator, rdb_index = nil)
drc_progress = RBA::AbstractProgress::new("DRC: " + macro.path)
@drc = DRCEngine::new
@drc._rdb_index = rdb_index
@drc._generator = generator
begin
# Set a debugger scope so that our errors end up with the debugger set to the DRC's line
RBA::MacroExecutionContext::set_debugger_scope(macro.path)
# No verbosity set in drc engine - we cannot use the engine's logger
RBA::Logger::verbosity &gt;= 10 &amp;&amp; RBA::Logger::info("Running #{macro.path}")
drc.instance_eval(macro.text, macro.path)
# Remove the debugger scope
RBA::MacroExecutionContext::remove_debugger_scope
rescue =&gt; ex
drc.error("In #{macro.path}: #{ex.to_s}")
RBA::MacroExecutionContext::ignore_next_exception
raise ex
ensure
# cleans up and creates layout and report views
drc._finish
# unlocks the UI
drc_progress._destroy
@macro = macro
end
timer.stop
drc.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s")
def execute
@drc._start("DRC: " + @macro.path)
# Set a debugger scope so that our errors end up with the debugger set to the DRC's line
RBA::MacroExecutionContext::set_debugger_scope(@macro.path)
begin
# No verbosity set in drc engine - we cannot use the engine's logger
RBA::Logger::verbosity &gt;= 10 &amp;&amp; RBA::Logger::info("Running #{@macro.path}")
@drc.instance_eval(@macro.text, @macro.path)
rescue =&gt; ex
@drc.error("In #{@macro.path}: #{ex.to_s}")
RBA::MacroExecutionContext::ignore_next_exception
raise ex
end
nil
end
def cleanup
# Remove the debugger scope
RBA::MacroExecutionContext::remove_debugger_scope
# cleans up and creates layout and report views
@drc._finish
end
end
@ -79,11 +87,17 @@ module DRC
# create a template for the macro editor:
create_template(":/drc-templates/drc.lym")
# if available, create a menu branch
if RBA::Application::instance &amp;&amp; RBA::Application::instance.main_window
mw = RBA::Application::instance.main_window
mw.menu.insert_menu("tools_menu.verification_group+", "drc", "DRC")
end
end
# Implements the execute method
def execute(macro)
DRC::execute_drc(macro, @recipe.generator("script" => macro.path))
def executable(macro)
DRCExecutable::new(macro, @recipe.generator("script" => macro.path))
end
end
@ -109,20 +123,20 @@ module DRC
end
# Implements the execute method
def execute(macro)
DRC::execute_drc(macro, @recipe.generator("script" => macro.path))
def executable(macro)
DRCExecutable::new(macro, @recipe.generator("script" => macro.path))
end
end
# A recipe implementation allowing the LVS run to be redone
# A recipe implementation allowing the DRC run to be redone
class DRCRecipe &lt; RBA::Recipe
def initialize
super("drc", "DRC recipe")
end
def execute(params)
def executable(params)
script = params["script"]
if ! script
@ -132,7 +146,7 @@ module DRC
macro = RBA::Macro::macro_by_path(script)
macro || raise("Can't find DRC script #{script} - unable to re-run")
DRC::execute_drc(macro, self.generator("script" => script), params["rdb_index"])
DRCExecutable::new(macro, self.generator("script" => script), params["rdb_index"])
end

View File

@ -1163,6 +1163,36 @@ TEST(29d_holes)
run_test (_this, "29", true);
}
TEST(30_density)
{
run_test (_this, "30", false);
}
TEST(31_globaTransformation)
{
run_test (_this, "31", false);
}
TEST(31d_globalTransformation)
{
run_test (_this, "31", true);
}
TEST(32_globalTransformationWithClip)
{
run_test (_this, "32", false);
}
TEST(32d_globalTransformationWithClip)
{
run_test (_this, "32", true);
}
TEST(33_globalTransformationWithTiles)
{
run_test (_this, "33", true);
}
TEST(40_fill)
{
run_test (_this, "40", false);
@ -1172,3 +1202,4 @@ TEST(41_fillTiled)
{
run_test (_this, "41", false);
}

View File

@ -1387,7 +1387,7 @@ MainService::cm_round_corners ()
std::vector <db::Polygon> in;
ep.merge (primary, in, 0 /*min_wc*/, false /*resolve holes*/, true /*min coherence*/);
for (std::vector <db::Polygon>::iterator p = in.begin (); p != in.end (); ++p) {
*p = smooth (*p, 1);
*p = smooth (*p, 1, true);
}
std::vector <db::Polygon> out = in;

View File

@ -629,6 +629,72 @@ Class<tl::GlobPattern> decl_GlobPattern ("tl", "GlobPattern",
"This class has been introduced in version 0.26."
);
class Executable_Impl
: public tl::Executable, public gsi::ObjectBase
{
public:
Executable_Impl ()
: tl::Executable ()
{
// makes the object owned by the C++ side (registrar). This way we don't need to keep a
// singleton instance.
keep ();
}
virtual tl::Variant execute ()
{
if (execute_cb.can_issue ()) {
return execute_cb.issue<tl::Executable, tl::Variant> (&tl::Executable::execute);
} else {
return tl::Variant ();
}
}
virtual void cleanup ()
{
if (cleanup_cb.can_issue ()) {
cleanup_cb.issue<tl::Executable> (&tl::Executable::cleanup);
}
}
gsi::Callback execute_cb;
gsi::Callback cleanup_cb;
};
}
namespace tl
{
template <> struct type_traits<gsi::Executable_Impl> : public type_traits<tl::Executable> { };
}
namespace gsi
{
Class<tl::Executable> decl_Executable ("tl", "ExecutableBase",
gsi::Methods (),
"@hide\n@alias Executable"
);
Class<Executable_Impl> decl_Executable_Impl (decl_Executable, "tl", "Executable",
gsi::callback ("execute", &Executable_Impl::execute, &Executable_Impl::execute_cb,
"@brief Reimplement this method to provide the functionality of the executable.\n"
"This method is supposed to execute the operation with the given parameters and return the desired output."
) +
gsi::callback ("cleanup", &Executable_Impl::cleanup, &Executable_Impl::cleanup_cb,
"@brief Reimplement this method to provide post-mortem cleanup functionality.\n"
"This method is always called after execute terminated."
),
"@brief A generic executable object\n"
"This object is a delegate for implementing the actual function of some generic executable function. "
"In addition to the plain execution, if offers a post-mortem cleanup callback which is always executed, even "
"if execute's implementation is cancelled in the debugger.\n"
"\n"
"Parameters are kept as a generic key/value map.\n"
"\n"
"This class has been introduced in version 0.27."
);
class Recipe_Impl
: public tl::Recipe, public gsi::ObjectBase
{
@ -641,16 +707,16 @@ public:
keep ();
}
virtual tl::Variant execute (const std::map<std::string, tl::Variant> &params) const
virtual tl::Executable *executable (const std::map<std::string, tl::Variant> &params) const
{
if (execute_cb.can_issue ()) {
return execute_cb.issue<tl::Recipe, tl::Variant, const std::map<std::string, tl::Variant> &> (&tl::Recipe::execute, params);
if (executable_cb.can_issue ()) {
return executable_cb.issue<tl::Recipe, tl::Executable *, const std::map<std::string, tl::Variant> &> (&tl::Recipe::executable, params);
} else {
return tl::Variant ();
return 0;
}
}
gsi::Callback execute_cb;
gsi::Callback executable_cb;
};
}
@ -688,10 +754,13 @@ Class<Recipe_Impl> decl_Recipe_Impl ("tl", "Recipe",
"@brief Delivers the generator string from the given parameters.\n"
"The generator string can be used with \\make to re-run the recipe."
) +
gsi::callback ("execute", &Recipe_Impl::execute, &Recipe_Impl::execute_cb, gsi::arg ("params"),
"@brief Reimplement this method to provide the functionality of the recipe.\n"
"This method is supposed to re-run the recipe with the given parameters and deliver the "
"the intended output object."
gsi::callback ("executable", &Recipe_Impl::executable, &Recipe_Impl::executable_cb, gsi::arg ("params"),
"@brief Reimplement this method to provide an executable object for the actual implementation.\n"
"The reasoning behind this architecture is to supply a cleanup callback. This is useful when the "
"actual function is executed as a script and the script terminates in the debugger. The cleanup callback "
"allows implementing any kind of post-mortem action despite being cancelled in the debugger.\n"
"\n"
"This method has been introduced in version 0.27 and replaces 'execute'."
),
"@brief A facility for providing reproducable recipes\n"
"The idea of this facility is to provide a service by which an object\n"

View File

@ -738,7 +738,7 @@ This function will evaluate the conditions c1 to cn and return the
current primary shape if all conditions renders an empty result.
See <a href="#if_all">if_all</a> for an example how to use the if_... functions.
</p>
<a name="info"/><h2>"info" - Outputs as message to the logger window</h2>
<a name="info"/><h2>"info" - Outputs as message to the logger or progress window</h2>
<keyword name="info"/>
<p>Usage:</p>
<ul>
@ -747,7 +747,7 @@ See <a href="#if_all">if_all</a> for an example how to use the if_... functions.
</ul>
<p>
Prints the message to the log window in verbose mode.
In non-verbose more, nothing is printed.
In non-verbose more, nothing is printed but a statement is put into the progress window.
<a href="#log">log</a> is a function that always prints a message.
</p>
<a name="input"/><h2>"input" - Fetches the shapes from the specified input from the default source</h2>

View File

@ -247,8 +247,8 @@ deliver objects that can be converted into polygons. Such objects are of class <
<p>Usage:</p>
<ul>
<li><tt>layer.corners([ options ])</tt></li>
<li><tt>layer.corners(angle, [ options ])</tt></li>
<li><tt>layer.corners(amin .. amax, [ options ])</tt></li>
<li><tt>layer.corners(angle [, options ])</tt></li>
<li><tt>layer.corners(amin .. amax [, options ])</tt></li>
</ul>
<p>
This method produces markers on the corners of the polygons. An angle criterion can be given which
@ -2732,6 +2732,87 @@ The following image shows the effect of the space check:
</tr>
</table>
</p>
<a name="split_covering"/><h2>"split_covering" - Returns the results of <a href="#covering">covering</a> and <a href="#not_covering">not_covering</a> at the same time</h2>
<keyword name="split_covering"/>
<p>Usage:</p>
<ul>
<li><tt>(a, b) = layer.split_covering(other [, options ])</tt></li>
</ul>
<p>
This method returns the polygons covering polygons from the other layer in
one layer and all others in a second layer. This method is equivalent to calling
<a href="#covering">covering</a> and <a href="#not_covering">not_covering</a>, but is faster than doing this in separate steps:
</p><p>
<pre>
(covering, not_covering) = l1.split_covering(l2)
</pre>
</p><p>
The options of this method are the same than <a href="#covering">covering</a>.
</p>
<a name="split_inside"/><h2>"split_inside" - Returns the results of <a href="#inside">inside</a> and <a href="#not_inside">not_inside</a> at the same time</h2>
<keyword name="split_inside"/>
<p>Usage:</p>
<ul>
<li><tt>(a, b) = layer.split_inside(other)</tt></li>
</ul>
<p>
This method returns the polygons inside of polygons from the other layer in
one layer and all others in a second layer. This method is equivalent to calling
<a href="#inside">inside</a> and <a href="#not_inside">not_inside</a>, but is faster than doing this in separate steps:
</p><p>
<pre>
(inside, not_inside) = l1.split_inside(l2)
</pre>
</p>
<a name="split_interacting"/><h2>"split_interacting" - Returns the results of <a href="#interacting">interacting</a> and <a href="#not_interacting">not_interacting</a> at the same time</h2>
<keyword name="split_interacting"/>
<p>Usage:</p>
<ul>
<li><tt>(a, b) = layer.split_interacting(other [, options ])</tt></li>
</ul>
<p>
This method returns the polygons interacting with objects from the other container in
one layer and all others in a second layer. This method is equivalent to calling
<a href="#interacting">interacting</a> and <a href="#not_interacting">not_interacting</a>, but is faster than doing this in separate steps:
</p><p>
<pre>
(interacting, not_interacting) = l1.split_interacting(l2)
</pre>
</p><p>
The options of this method are the same than <a href="#interacting">interacting</a>.
</p>
<a name="split_outside"/><h2>"split_outside" - Returns the results of <a href="#outside">outside</a> and <a href="#not_outside">not_outside</a> at the same time</h2>
<keyword name="split_outside"/>
<p>Usage:</p>
<ul>
<li><tt>(a, b) = layer.split_outside(other)</tt></li>
</ul>
<p>
This method returns the polygons outside of polygons from the other layer in
one layer and all others in a second layer. This method is equivalent to calling
<a href="#outside">outside</a> and <a href="#not_outside">not_outside</a>, but is faster than doing this in separate steps:
</p><p>
<pre>
(outside, not_outside) = l1.split_outside(l2)
</pre>
</p>
<a name="split_overlapping"/><h2>"split_overlapping" - Returns the results of <a href="#overlapping">overlapping</a> and <a href="#not_overlapping">not_overlapping</a> at the same time</h2>
<keyword name="split_overlapping"/>
<p>Usage:</p>
<ul>
<li><tt>(a, b) = layer.split_overlapping(other [, options ])</tt></li>
</ul>
<p>
This method returns the polygons overlapping polygons from the other layer in
one layer and all others in a second layer. This method is equivalent to calling
<a href="#overlapping">overlapping</a> and <a href="#not_overlapping">not_overlapping</a>, but is faster than doing this in separate steps:
</p><p>
<pre>
(overlapping, not_overlapping) = l1.split_overlapping(l2)
</pre>
</p><p>
The options of this method are the same than <a href="#overlapping">overlapping</a>.
</p>
<a name="squares"/><h2>"squares" - Selects all squares from the input</h2>
<keyword name="squares"/>
<p>Usage:</p>
@ -3147,6 +3228,74 @@ bounding box.
</p><p>
This method is available for polygon layers only.
</p>
<a name="with_density"/><h2>"with_density" - Returns tiles whose density is within a given range</h2>
<keyword name="with_density"/>
<p>Usage:</p>
<ul>
<li><tt>layer.with_density(min_value, max_value [, options ])</tt></li>
<li><tt>layer.with_density(min_value .. max_value [, options ])</tt></li>
</ul>
<p>
This method runs a tiled analysis over the current layout. It reports the tiles whose density
is between "min_value" and "max_value". "min_value" and "max_value" are given in
relative units, i.e. within the range of 0 to 1.0 corresponding to a density of 0 to 100%.
</p><p>
"min_value" or "max_value" can be nil or omitted in the ".." range notation.
In this case, they are taken as "0" and "100%".
</p><p>
The tile size must be specified with the "tile_size" option:
</p><p>
<pre>
# reports areas where layer 1/0 density is below 10% on 20x20 um tiles
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um))
</pre>
</p><p>
Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)".
The first value is the horizontal tile dimension, the second value is the vertical tile
dimension.
</p><p>
A tile overlap can be specified using "tile_step". If the tile step is less than the
tile size, the tiles will overlap. The layout window given by "tile_size" is moved
in increments of the tile step:
</p><p>
<pre>
# reports areas where layer 1/0 density is below 10% on 30x30 um tiles
# with a tile step of 20x20 um:
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
</pre>
</p><p>
For "tile_step", anisotropic values can be given as well by using two values: the first for the
horizontal and the second for the vertical tile step.
</p><p>
Another option is "tile_origin" which specifies the location of the first tile's position.
This is the lower left tile's lower left corner. If no origin is given, the tiles are centered over the
area investigated.
</p><p>
By default, the tiles will cover the bounding box of the input layer. A separate layer
can be used in addition. This way, the layout's dimensions can be derived from some
drawn boundary layer. To specify a separate, additional layer included in the bounding box, use the "tile_boundary" option:
</p><p>
<pre>
# reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from
# layer 0/0:
cell_frame = input(0, 0)
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
</pre>
</p><p>
Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box.
The computed area is at least the area of the input layer.
</p><p>
Computation of the area can be skipped by explicitly giving a tile count in horizontal and vertical
direction. With the "tile_origin" option this allows full control over the area covered:
</p><p>
<pre>
# reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000
# (100 and 150 tiles of 20 um each are used in horizontal and vertical direction):
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
</pre>
</p><p>
The complementary version of "with_density" is <a href="#without_density">without_density</a>.
</p>
<a name="with_holes"/><h2>"with_holes" - Selects all polygons with the specified number of holes</h2>
<keyword name="with_holes"/>
<p>Usage:</p>
@ -3313,6 +3462,17 @@ bounding box.
</p><p>
This method is available for polygon layers only.
</p>
<a name="without_density"/><h2>"without_density" - Returns tiles whose density is not within a given range</h2>
<keyword name="without_density"/>
<p>Usage:</p>
<ul>
<li><tt>layer.without_density(min_value, max_value [, options ])</tt></li>
<li><tt>layer.without_density(min_value .. max_value [, options ])</tt></li>
</ul>
<p>
For details about the operations and the operation see <a href="#with_density">with_density</a>. This version will return the
tiles where the density is not within the given range.
</p>
<a name="without_holes"/><h2>"without_holes" - Selects all polygons with the specified number of holes</h2>
<keyword name="without_holes"/>
<p>Usage:</p>

View File

@ -732,6 +732,8 @@ type_to_s (const gsi::ArgType &a, bool linked, bool for_return)
s += "float"; break;
case gsi::T_string:
s += "string"; break;
case gsi::T_byte_array:
s += "bytes"; break;
case gsi::T_var:
s += "variant"; break;
case gsi::T_object:

View File

@ -326,8 +326,7 @@ HelpSource::produce_index_file (const std::string &path)
m_title_map.clear ();
m_parent_of.clear ();
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Initializing help index")), 1);
progress.can_cancel (false);
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Initializing help index")), 1, false /*can't cancel*/);
scan ("/index.xml", progress);
try {

View File

@ -22,12 +22,15 @@
#include "layLogViewerDialog.h"
#include "layApplication.h"
#include <QMutex>
#include <QMutexLocker>
#include <QTimer>
#include <QClipboard>
#include <QFrame>
#include <QThread>
#include <QAbstractEventDispatcher>
#include <stdio.h>
@ -101,7 +104,7 @@ LogReceiver::begin ()
LogFile::LogFile (size_t max_entries, bool register_global)
: m_error_receiver (this, 0, &LogFile::add_error),
m_warn_receiver (this, 0, &LogFile::add_warn),
m_log_receiver (this, 10, &LogFile::add_info),
m_log_receiver (this, 0, &LogFile::add_info),
m_info_receiver (this, 0, &LogFile::add_info),
m_max_entries (max_entries),
m_generation_id (0),
@ -221,25 +224,39 @@ LogFile::max_entries () const
void
LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued)
{
QMutexLocker locker (&m_lock);
bool can_yield = false;
if (m_max_entries == 0) {
return;
{
QMutexLocker locker (&m_lock);
if (m_max_entries == 0) {
return;
}
if (m_messages.size () >= m_max_entries) {
m_messages.pop_front ();
}
if (mode == LogFileEntry::Warning || mode == LogFileEntry::WarningContinued) {
m_has_warnings = true;
} else if (mode == LogFileEntry::Error || mode == LogFileEntry::ErrorContinued) {
m_has_errors = true;
}
m_messages.push_back (LogFileEntry (mode, msg, continued));
++m_generation_id;
if (lay::ApplicationBase::instance ()->qapp_gui () && QThread::currentThread () == lay::ApplicationBase::instance ()->qapp_gui ()->thread () && (tl::Clock::current () - m_last_yield).seconds () > 0.1) {
m_last_yield = tl::Clock::current ();
can_yield = true;
}
}
if (m_messages.size () >= m_max_entries) {
m_messages.pop_front ();
// use this opportunity to process events
if (can_yield) {
lay::ApplicationBase::instance ()->process_events (QEventLoop::AllEvents);
}
if (mode == LogFileEntry::Warning || mode == LogFileEntry::WarningContinued) {
m_has_warnings = true;
} else if (mode == LogFileEntry::Error || mode == LogFileEntry::ErrorContinued) {
m_has_errors = true;
}
m_messages.push_back (LogFileEntry (mode, msg, continued));
++m_generation_id;
}
int

View File

@ -26,6 +26,7 @@
#include "ui_LogViewerDialog.h"
#include "tlLog.h"
#include "tlTimer.h"
#include "layCommon.h"
#include <QTimer>
@ -227,6 +228,7 @@ private:
size_t m_last_generation_id;
bool m_has_errors, m_has_warnings;
bool m_last_attn;
tl::Clock m_last_yield;
/**
* @brief Adds an error

View File

@ -3003,6 +3003,11 @@ MacroEditorDialog::translate_pseudo_id (size_t &file_id, int &line)
}
}
static void exit_from_macro ()
{
throw tl::ExitException ();
}
void
MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_id, int line, const std::string &eclass, const std::string &emsg, const gsi::StackTraceProvider *stack_trace_provider)
{
@ -3012,7 +3017,7 @@ MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_
}
if (!m_in_exec) {
throw tl::ExitException ();
exit_from_macro ();
}
// avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop
@ -3098,7 +3103,7 @@ MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_
}
if (! m_in_exec) {
throw tl::ExitException ();
exit_from_macro ();
}
}
@ -3106,7 +3111,7 @@ void
MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int line, const gsi::StackTraceProvider *stack_trace_provider)
{
if (!m_in_exec) {
throw tl::ExitException ();
exit_from_macro ();
}
// avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop
@ -3157,7 +3162,7 @@ MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int lin
}
if (! m_in_exec) {
throw tl::ExitException ();
exit_from_macro ();
}
} else if (++m_trace_count == 20) {
@ -3175,7 +3180,7 @@ MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int lin
m_process_events_interval = std::max (0.05, std::min (2.0, (m_last_process_events - start).seconds () * 5.0));
if (!m_in_exec) {
throw tl::ExitException ();
exit_from_macro ();
}
}
@ -3590,6 +3595,9 @@ MacroEditorDialog::run (int stop_stack_depth, lym::Macro *macro)
} catch (tl::ExitException &) {
m_stop_stack_depth = -1;
// .. ignore exit exceptions ..
} catch (tl::BreakException &) {
m_stop_stack_depth = -1;
// .. ignore break exceptions ..
} catch (tl::ScriptError &re) {
m_stop_stack_depth = -1;
handle_error (re);

View File

@ -1548,6 +1548,71 @@ MacroEditorPage::return_pressed ()
return true;
}
static bool is_tab_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0;
}
static bool is_backtab_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0);
}
static bool is_backspace_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Backspace;
}
static bool is_escape_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Escape;
}
static bool is_return_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Return;
}
static bool is_help_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_F1;
}
static bool is_find_next_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_F3;
}
static bool is_find_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0;
}
static bool is_up_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Up;
}
static bool is_down_key (QKeyEvent *ke)
{
return ke->key () == Qt::Key_Down;
}
static bool is_any_known_key (QKeyEvent *ke)
{
return is_tab_key (ke) ||
is_backtab_key (ke) ||
is_backspace_key (ke) ||
is_escape_key (ke) ||
is_return_key (ke) ||
is_help_key (ke) ||
is_find_next_key (ke) ||
is_find_key (ke) ||
is_up_key (ke) ||
is_down_key (ke);
}
bool
MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
{
@ -1555,9 +1620,16 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
if (event->type () == QEvent::ShortcutOverride) {
// override shortcuts
event->accept ();
return true;
// override shortcuts if the collide with keys we accept ourselves
QKeyEvent *ke = dynamic_cast<QKeyEvent *> (event);
if (! ke) {
return false; // should not happen
}
if (is_any_known_key (ke)) {
event->accept ();
return true;
}
} else if (event->type () == QEvent::FocusOut) {
@ -1574,7 +1646,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return false; // should not happen
}
if (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) {
if (is_tab_key (ke)) {
if (mp_completer_popup->isVisible ()) {
complete ();
@ -1583,15 +1655,15 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return tab_key_pressed ();
}
} else if ((ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) {
} else if (is_backtab_key (ke)) {
return back_tab_key_pressed ();
} else if (ke->key () == Qt::Key_Backspace) {
} else if (is_backspace_key (ke)) {
return backspace_pressed ();
} else if (ke->key () == Qt::Key_Escape) {
} else if (is_escape_key (ke)) {
// Handle Esc to return to the before-find position and clear the selection or to hide popup
@ -1606,7 +1678,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return true;
} else if (ke->key () == Qt::Key_Return) {
} else if (is_return_key (ke)) {
if (mp_completer_popup->isVisible ()) {
complete ();
@ -1615,7 +1687,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return return_pressed ();
}
} else if (ke->key () == Qt::Key_F1) {
} else if (is_help_key (ke)) {
QTextCursor c = mp_text->textCursor ();
if (c.selectionStart () == c.selectionEnd ()) {
@ -1625,19 +1697,19 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return true;
} else if (mp_completer_popup->isVisible () && (ke->key () == Qt::Key_Up || ke->key () == Qt::Key_Down)) {
} else if (mp_completer_popup->isVisible () && (is_up_key (ke) || is_down_key (ke))) {
QApplication::sendEvent (mp_completer_list, event);
return true;
} else if (ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0) {
} else if (is_find_key (ke)) {
QTextCursor c = mp_text->textCursor ();
emit search_requested (c.selectedText ());
return true;
} else if (ke->key () == Qt::Key_F3) {
} else if (is_find_next_key (ke)) {
// Jump to the next occurence of the search string

View File

@ -2525,21 +2525,30 @@ MainWindow::cm_new_layout ()
std::string technology = m_initial_technology;
static std::string s_new_cell_cell_name ("TOP");
static double s_new_cell_window_size = 2.0;
static std::vector<db::LayerProperties> s_layers;
double dbu = 0.0;
lay::NewLayoutPropertiesDialog dialog (this);
if (dialog.exec_dialog (technology, s_new_cell_cell_name, dbu, s_new_cell_window_size, m_new_layout_current_panel)) {
if (dialog.exec_dialog (technology, s_new_cell_cell_name, dbu, s_new_cell_window_size, s_layers, m_new_layout_current_panel)) {
lay::CellViewRef cellview = create_or_load_layout (0, 0, technology, m_new_layout_current_panel ? 2 : 1 /*= new view*/);
std::unique_ptr <lay::LayoutHandle> handle (new lay::LayoutHandle (new db::Layout (& manager ()), std::string ()));
handle->rename ("new");
if (dbu > 1e-10) {
cellview->layout ().dbu (dbu);
handle->layout ().dbu (dbu);
}
db::cell_index_type new_ci = cellview->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ());
cellview.set_cell (new_ci);
db::cell_index_type new_ci = handle->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ());
current_view ()->zoom_box_and_set_hier_levels (db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size), std::make_pair (0, 1));
for (std::vector<db::LayerProperties>::const_iterator l = s_layers.begin (); l != s_layers.end (); ++l) {
handle->layout ().insert_layer (*l);
}
lay::LayoutView *mp_view = (m_new_layout_current_panel && current_view ()) ? current_view () : view (create_view ());
unsigned int ci = mp_view->add_layout (handle.release (), true);
mp_view->cellview_ref (ci).set_cell (new_ci);
mp_view->zoom_box_and_set_hier_levels (db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size), std::make_pair (0, 1));
}
}

View File

@ -57,8 +57,10 @@ static bool is_marked_alive (QObject *obj)
// --------------------------------------------------------------------
const double visibility_delay = 1.0;
ProgressReporter::ProgressReporter ()
: m_start_time (), mp_pb (0), m_pw_visible (false)
: mp_pb (0), m_pw_visible (false)
{
// .. nothing yet ..
}
@ -94,22 +96,21 @@ ProgressReporter::register_object (tl::Progress *progress)
tl::ProgressAdaptor::register_object (progress);
if (m_start_time == tl::Clock () && ! m_pw_visible) {
m_start_time = tl::Clock::current ();
}
// make dialog visible after some time has passed
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
set_visible (true);
}
if (progress->is_abstract ()) {
m_active.insert (progress);
if (! m_pw_visible) {
set_visible (true);
}
if (mp_pb) {
mp_pb->update_progress (progress);
}
process_events ();
} else {
update_and_yield ();
m_queued.insert (std::make_pair (progress, tl::Clock::current ()));
}
}
@ -121,46 +122,64 @@ ProgressReporter::unregister_object (tl::Progress *progress)
// close or refresh window
if (begin () == end ()) {
m_queued.clear ();
m_active.clear ();
if (m_pw_visible) {
set_visible (false);
}
m_start_time = tl::Clock ();
if (mp_pb) {
mp_pb->update_progress (0);
}
process_events ();
QApplication::instance ()->removeEventFilter (this);
} else {
update_and_yield ();
m_queued.erase (progress);
std::set<tl::Progress *>::iterator a = m_active.find (progress);
if (a != m_active.end ()) {
m_active.erase (a);
update_and_yield ();
}
}
}
void
ProgressReporter::trigger (tl::Progress * /*progress*/)
ProgressReporter::trigger (tl::Progress *progress)
{
if (begin () != end ()) {
// make dialog visible after some time has passed
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
std::map<tl::Progress *, tl::Clock>::iterator q = m_queued.find (progress);
if (q != m_queued.end () && (tl::Clock::current () - q->second).seconds () > visibility_delay) {
if (! m_pw_visible) {
set_visible (true);
}
m_active.insert (progress);
m_queued.erase (q);
}
if (m_active.find (progress) != m_active.end ()) {
update_and_yield ();
}
}
void
ProgressReporter::yield (tl::Progress * /*progress*/)
ProgressReporter::yield (tl::Progress *progress)
{
// make dialog visible after some time has passed
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
set_visible (true);
std::map<tl::Progress *, tl::Clock>::iterator q = m_queued.find (progress);
if (q != m_queued.end () && (tl::Clock::current () - q->second).seconds () > visibility_delay) {
if (! m_pw_visible) {
set_visible (true);
}
m_active.insert (progress);
m_queued.erase (q);
update_and_yield ();
} else if (m_pw_visible) {
// process events if necessary
}
if (m_active.find (progress) != m_active.end ()) {
process_events ();
}
}
@ -172,11 +191,17 @@ ProgressReporter::update_and_yield ()
return;
}
if (mp_pb && first ()) {
mp_pb->update_progress (first ());
QWidget *w = mp_pb->progress_get_widget ();
if (w) {
first ()->render_progress (w);
if (mp_pb) {
if (first ()) {
mp_pb->update_progress (first ());
QWidget *w = mp_pb->progress_get_widget ();
if (w) {
first ()->render_progress (w);
}
} else if (begin () != end ()) {
mp_pb->update_progress (begin ().operator-> ());
} else {
mp_pb->update_progress (0);
}
}

View File

@ -28,6 +28,8 @@
#include <string>
#include <list>
#include <map>
#include <set>
#include "tlProgress.h"
#include "tlObject.h"
@ -71,9 +73,10 @@ public:
void set_progress_bar (lay::ProgressBar *pb);
private:
tl::Clock m_start_time;
lay::ProgressBar *mp_pb;
bool m_pw_visible;
std::map<tl::Progress *, tl::Clock> m_queued;
std::set<tl::Progress *> m_active;
void process_events ();
void update_and_yield ();

View File

@ -90,13 +90,13 @@ QSize
ProgressBarWidget::sizeHint () const
{
QFontMetrics fm (font ());
return QSize (m_width, fm.height () + 2);
return QSize (fm.width (QString::fromUtf8("100%")) * 4, fm.height () + 2);
}
QSize
ProgressBarWidget::minimumSizeHint () const
{
return QSize (m_width, 1);
return QSize (50, 1);
}
void
@ -149,6 +149,11 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw)
QVBoxLayout *log_layout = new QVBoxLayout (mp_log_frame);
mp_log_label = new QLabel (mp_log_frame);
mp_log_label->setText (QString ());
mp_log_label->setSizePolicy (QSizePolicy (QSizePolicy::Ignored, QSizePolicy::Preferred));
log_layout->addWidget (mp_log_label);
QListView *log_view = new QListView (this);
log_view->setModel (&m_log_file);
log_view->setUniformItemSizes (true);
@ -200,22 +205,22 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw)
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1);
QFrame *progress_bar_frame = new QFrame (bar_frame);
progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain);
progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget (progress_bar_frame, 0, col, 1, 1);
mp_progress_bar_frame = new QFrame (bar_frame);
mp_progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain);
mp_progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget (mp_progress_bar_frame, 0, col, 1, 1);
QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame);
progress_bar_frame->setLayout (pbf_layout);
QGridLayout *pbf_layout = new QGridLayout (mp_progress_bar_frame);
mp_progress_bar_frame->setLayout (pbf_layout);
pbf_layout->setMargin (0);
pbf_layout->setSpacing (0);
mp_progress_bar1 = new ProgressBarWidget (progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar1, 0, 0, 1, 1);
mp_progress_bar2 = new ProgressBarWidget (progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar2, 1, 0, 1, 1);
mp_progress_bar3 = new ProgressBarWidget (progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar3, 2, 0, 1, 1);
mp_progress_bar1 = new ProgressBarWidget (mp_progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar1, 0, 2, 1, 1);
mp_progress_bar2 = new ProgressBarWidget (mp_progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar2, 0, 1, 1, 1);
mp_progress_bar3 = new ProgressBarWidget (mp_progress_bar_frame);
pbf_layout->addWidget (mp_progress_bar3, 0, 0, 1, 1);
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1);
@ -236,11 +241,12 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw)
}
void
ProgressWidget::set_log_visible (bool f)
ProgressWidget::set_log_visible (tl::Progress *progress)
{
if (f != m_log_visible) {
m_log_visible = f;
mp_log_frame->setVisible (f);
if ((progress != 0) != m_log_visible) {
m_log_visible = (progress != 0);
mp_log_frame->setVisible (m_log_visible);
mp_log_label->setText (progress ? tl::to_qstring (progress->desc ()) : QString ());
set_full_width (m_full_width);
}
}
@ -290,11 +296,23 @@ ProgressWidget::remove_widget ()
void
ProgressWidget::set_progress (tl::Progress *progress)
{
lay::ProgressBarWidget *progress_bars[] = { mp_progress_bar1, mp_progress_bar2, mp_progress_bar3 };
if (! progress || progress->is_abstract ()) {
m_log_file.clear ();
if (! progress) {
m_log_file.clear ();
}
m_log_file.set_max_entries (progress ? 1000 : 0);
set_log_visible (progress != 0);
set_log_visible (progress);
mp_progress_bar_frame->hide ();
mp_cancel_button->setEnabled (true);
mp_label->setText (QString ());
return;
}
bool can_cancel = false;
@ -308,8 +326,6 @@ ProgressWidget::set_progress (tl::Progress *progress)
mp_cancel_button->setEnabled (can_cancel);
mp_label->setText (tl::to_qstring (text));
lay::ProgressBarWidget *progress_bars[] = { mp_progress_bar1, mp_progress_bar2, mp_progress_bar3 };
for (size_t i = 0; i < sizeof (progress_bars) / sizeof (progress_bars[0]); ++i) {
lay::ProgressBarWidget *pb = progress_bars[i];
@ -334,6 +350,8 @@ ProgressWidget::set_progress (tl::Progress *progress)
}
mp_progress_bar_frame->show ();
// according to the doc this should not be required, but without, the progress bar does not resize
mp_progress_bar1->parentWidget ()->updateGeometry ();
}

View File

@ -72,6 +72,7 @@ public slots:
private:
QLabel *mp_label;
QFrame *mp_progress_bar_frame;
ProgressBarWidget *mp_progress_bar1, *mp_progress_bar2, *mp_progress_bar3;
QWidget *mp_widget;
int m_widget_col;
@ -79,12 +80,13 @@ private:
QToolButton *mp_cancel_button;
ProgressReporter *mp_pr;
lay::LogFile m_log_file;
QLabel *mp_log_label;
QFrame *mp_log_frame;
bool m_full_width;
int m_left_col, m_right_col;
bool m_log_visible;
void set_log_visible (bool f);
void set_log_visible (tl::Progress *progress);
};
}

View File

@ -1040,7 +1040,7 @@ BEGIN_PROTECTED
query_to_model (model, lq, iq, std::numeric_limits<size_t>::max (), true);
model.end_changes ();
std::unique_ptr <lay::LayoutHandle> handle (new lay::LayoutHandle (new db::Layout (), std::string ()));
std::unique_ptr <lay::LayoutHandle> handle (new lay::LayoutHandle (new db::Layout (mp_view->manager ()), std::string ()));
handle->rename ("query_results");
model.export_layout (handle->layout ());
mp_view->add_layout (handle.release (), true);

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>563</width>
<height>234</height>
<width>594</width>
<height>401</height>
</rect>
</property>
<property name="windowTitle">
@ -50,7 +50,7 @@
<property name="spacing">
<number>6</number>
</property>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QLineEdit" name="window_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -60,13 +60,6 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Database unit</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="3">
<spacer>
<property name="orientation">
@ -80,13 +73,80 @@
</property>
</spacer>
</item>
<item row="2" column="2">
<item row="1" column="1">
<widget class="QLineEdit" name="topcell_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="dbu_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="1" colspan="4">
<widget class="QComboBox" name="tech_cbx"/>
</item>
<item row="5" column="1" colspan="4">
<widget class="QLineEdit" name="layers_le"/>
</item>
<item row="4" column="4">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>141</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>µm</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Top cell</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Database unit</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Technology</string>
</property>
</widget>
</item>
<item row="3" column="4">
<spacer>
<property name="orientation">
@ -100,74 +160,34 @@
</property>
</spacer>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="dbu_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="1" colspan="4">
<widget class="QComboBox" name="tech_cbx"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<item row="3" column="3">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Top cell</string>
<string> (empty for default)</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="topcell_le">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Technology</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Initial window size</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_4">
<item row="5" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>µm</string>
<string>Initial layer(s)</string>
</property>
</widget>
</item>
<item row="2" column="4">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>141</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_7">
<item row="6" column="1" colspan="4">
<widget class="QLabel" name="label_9">
<property name="text">
<string> (empty for default)</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;Specify a comma or blank separated list of layers to create in the usual layer notation, e.g. &quot;1/0 2/0 3/0&quot;, &quot;metal1 via1 metal2&quot; or &quot;metal1 (1/0) via1 (2/0) metal2 (3/0)&quot;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
@ -214,10 +234,12 @@
</layout>
</widget>
<tabstops>
<tabstop>tech_cbx</tabstop>
<tabstop>topcell_le</tabstop>
<tabstop>dbu_le</tabstop>
<tabstop>window_le</tabstop>
<tabstop>buttonBox</tabstop>
<tabstop>layers_le</tabstop>
<tabstop>current_panel_cb</tabstop>
</tabstops>
<resources/>
<connections>

View File

@ -129,7 +129,7 @@ NewLayoutPropertiesDialog::tech_changed ()
}
bool
NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &cell_name, double &dbu, double &size, bool &current_panel)
NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &cell_name, double &dbu, double &size, std::vector<db::LayerProperties> &layers, bool &current_panel)
{
mp_ui->tech_cbx->clear ();
unsigned int technology_index = 0;
@ -151,6 +151,15 @@ NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &ce
mp_ui->topcell_le->setText (tl::to_qstring (cell_name));
mp_ui->current_panel_cb->setChecked (current_panel);
std::string layer_string;
for (std::vector<db::LayerProperties>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
if (l != layers.begin ()) {
layer_string += ", ";
}
layer_string += l->to_string ();
}
mp_ui->layers_le->setText (tl::to_qstring (layer_string));
if (QDialog::exec ()) {
// get the selected technology name
@ -167,8 +176,24 @@ NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &ce
} else {
dbu = 0.0;
}
cell_name = tl::to_string (mp_ui->topcell_le->text ());
current_panel = mp_ui->current_panel_cb->isChecked ();
layers.clear ();
layer_string = tl::to_string (mp_ui->layers_le->text ());
tl::Extractor ex (layer_string.c_str ());
while (! ex.at_end ()) {
db::LayerProperties lp;
try {
lp.read (ex);
} catch (...) {
break;
}
layers.push_back (lp);
ex.test (",");
}
return true;
} else {

View File

@ -328,7 +328,7 @@ public:
NewLayoutPropertiesDialog (QWidget *parent);
virtual ~NewLayoutPropertiesDialog ();
bool exec_dialog (std::string &tech_name, std::string &cell_name, double &dbu, double &window_size, bool &current_panel);
bool exec_dialog (std::string &tech_name, std::string &cell_name, double &dbu, double &window_size, std::vector<db::LayerProperties> &layers, bool &current_panel);
private slots:
void tech_changed ();

View File

@ -305,32 +305,28 @@ SingleIndexedNetlistModel::parent_of (const subcircuit_pair &subcircuits) const
return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0);
}
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status>
SingleIndexedNetlistModel::top_circuit_from_index (size_t index) const
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::top_circuit_from_index(size_t index) const
{
db::Netlist::const_top_down_circuit_iterator none;
return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), db::NetlistCrossReference::None);
return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
}
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status>
SingleIndexedNetlistModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::child_circuit_from_index(const circuit_pair &circuits, size_t index) const
{
db::Circuit::const_child_circuit_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), db::NetlistCrossReference::None);
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
}
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status>
SingleIndexedNetlistModel::circuit_from_index (size_t index) const
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::circuit_from_index(size_t index) const
{
db::Netlist::const_circuit_iterator none;
return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name<db::Circuit> ()), db::NetlistCrossReference::None);
return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
}
std::pair<IndexedNetlistModel::net_pair, IndexedNetlistModel::Status>
SingleIndexedNetlistModel::net_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::net_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::net_from_index(const circuit_pair &circuits, size_t index) const
{
db::Circuit::const_net_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name<db::Net> ()), db::NetlistCrossReference::None);
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name<db::Net> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
}
const db::Net *
@ -394,25 +390,22 @@ SingleIndexedNetlistModel::net_pinref_from_index (const net_pair &nets, size_t i
return attr_by_object_and_index (nets, index, nets.first->begin_pins (), nets.first->end_pins (), none, none, m_pinref_by_net_and_index, sort_by_pin_name<db::NetPinRef> ());
}
std::pair<IndexedNetlistModel::device_pair, IndexedNetlistModel::Status>
SingleIndexedNetlistModel::device_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::device_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::device_from_index(const circuit_pair &circuits, size_t index) const
{
db::Circuit::const_device_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name<db::Device> ()), db::NetlistCrossReference::None);
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name<db::Device> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
}
std::pair<IndexedNetlistModel::pin_pair, IndexedNetlistModel::Status>
SingleIndexedNetlistModel::pin_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::pin_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::pin_from_index(const circuit_pair &circuits, size_t index) const
{
db::Circuit::const_pin_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), db::NetlistCrossReference::None);
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
}
std::pair<IndexedNetlistModel::subcircuit_pair, IndexedNetlistModel::Status>
SingleIndexedNetlistModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::subcircuit_from_index(const circuit_pair &circuits, size_t index) const
{
db::Circuit::const_subcircuit_iterator none;
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name<db::SubCircuit> ()), db::NetlistCrossReference::None);
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name<db::SubCircuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
}
size_t

View File

@ -89,24 +89,24 @@ public:
virtual circuit_pair parent_of (const device_pair &device_pair) const = 0;
virtual circuit_pair parent_of (const subcircuit_pair &subcircuit_pair) const = 0;
virtual std::pair<circuit_pair, Status> top_circuit_from_index (size_t index) const = 0;
virtual std::pair<circuit_pair, Status> child_circuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<circuit_pair, Status> circuit_from_index (size_t index) const = 0;
virtual std::pair<net_pair, Status> net_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > top_circuit_from_index (size_t index) const = 0;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > child_circuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > circuit_from_index (size_t index) const = 0;
virtual std::pair<net_pair, std::pair<Status, std::string> > net_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual const db::Net *second_net_for (const db::Net *first) const = 0;
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const = 0;
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const = 0;
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const = 0;
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const = 0;
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const = 0;
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<pin_pair, Status> pin_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<subcircuit_pair, Status> subcircuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<device_pair, std::pair<Status, std::string> > device_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<pin_pair, std::pair<Status, std::string> > pin_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::pair<subcircuit_pair, std::pair<Status, std::string> > subcircuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
virtual std::string top_circuit_status_hint (size_t /*index*/) const { return std::string (); }
virtual std::string circuit_status_hint (size_t /*index*/) const { return std::string (); }
virtual std::string child_circuit_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, Status> & /*cp*/) const { return std::string (); }
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, std::pair<Status, std::string> > & /*cp*/) const { return std::string (); }
virtual std::string net_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
virtual std::string device_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
virtual std::string pin_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
@ -159,19 +159,19 @@ public:
virtual circuit_pair parent_of (const device_pair &devices) const;
virtual circuit_pair parent_of (const subcircuit_pair &subcircuits) const;
virtual std::pair<circuit_pair, Status> top_circuit_from_index (size_t index) const;
virtual std::pair<circuit_pair, Status> circuit_from_index (size_t index) const;
virtual std::pair<circuit_pair, Status> child_circuit_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<net_pair, Status> net_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > top_circuit_from_index (size_t index) const;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > circuit_from_index (size_t index) const;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > child_circuit_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<net_pair, std::pair<Status, std::string> > net_from_index (const circuit_pair &circuits, size_t index) const;
virtual const db::Net *second_net_for (const db::Net *first) const;
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const;
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const;
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const;
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const;
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const;
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<pin_pair, Status> pin_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<subcircuit_pair, Status> subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<device_pair, std::pair<Status, std::string> > device_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<pin_pair, std::pair<Status, std::string> > pin_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<subcircuit_pair, std::pair<Status, std::string> > subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
virtual size_t circuit_index (const circuit_pair &circuits) const;
virtual size_t net_index (const net_pair &nets) const;

View File

@ -204,10 +204,10 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
mp_view (view),
m_needs_update (true),
m_tabs_need_update (true),
m_hidden_flags_need_update (true),
m_in_update (false),
m_phase (0),
m_do_update_content_dm (this, &LayerControlPanel::do_update_content),
m_do_update_hidden_flags_dm (this, &LayerControlPanel::do_update_hidden_flags),
m_no_stipples (false)
{
setObjectName (QString::fromUtf8 (name));
@ -1661,7 +1661,8 @@ LayerControlPanel::set_text_color (QColor c)
void
LayerControlPanel::update_hidden_flags ()
{
m_do_update_hidden_flags_dm ();
m_hidden_flags_need_update = true;
m_do_update_content_dm ();
}
void
@ -1688,6 +1689,7 @@ LayerControlPanel::begin_updates ()
if (! m_in_update) {
m_in_update = true;
m_hidden_flags_need_update = true;
mp_model->signal_begin_layer_changed (); // this makes the view redraw the data
@ -1718,6 +1720,7 @@ LayerControlPanel::cancel_updates ()
{
m_in_update = false;
m_needs_update = false;
m_hidden_flags_need_update = false;
m_tabs_need_update = false;
}
@ -1833,7 +1836,7 @@ LayerControlPanel::do_update_content ()
mp_layer_list->setCurrentIndex(QModelIndex());
// this makes the view redraw the data and establishes a valid selection scheme
mp_model->signal_layer_changed ();
mp_model->signal_layers_changed ();
// now realize the selection if required
if (! m_new_sel.empty ()) {
@ -1875,6 +1878,14 @@ LayerControlPanel::do_update_content ()
} else {
mp_model->signal_data_changed (); // this makes the view redraw the data
}
if (m_hidden_flags_need_update) {
do_update_hidden_flags ();
m_hidden_flags_need_update = false;
}
}
void
@ -2007,7 +2018,7 @@ LayerControlPanel::update_required (int f)
}
if ((f & 3) != 0) {
m_do_update_hidden_flags_dm ();
m_hidden_flags_need_update = true;
}
m_do_update_content_dm ();

View File

@ -341,10 +341,11 @@ private:
lay::LayoutView *mp_view;
bool m_needs_update;
bool m_tabs_need_update;
bool m_hidden_flags_need_update;
bool m_in_update;
std::vector<size_t> m_new_sel;
int m_phase;
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm, m_do_update_hidden_flags_dm;
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm;
std::set<unsigned int> m_expanded;
bool m_no_stipples;
QLabel *m_no_stipples_label;

View File

@ -421,9 +421,9 @@ LayerTreeModel::signal_begin_layer_changed ()
}
void
LayerTreeModel::signal_layer_changed ()
LayerTreeModel::signal_layers_changed ()
{
// establish a new range of valid iterator indices
// establish a new range of valid iterator indices
m_id_start = m_id_end;
// TODO: is there a more efficient way to compute that?
@ -433,6 +433,21 @@ LayerTreeModel::signal_layer_changed ()
}
m_id_end += max_id + 1;
// update the persistent indexes
QModelIndexList indexes = persistentIndexList ();
QModelIndexList new_indexes;
for (QModelIndexList::const_iterator i = indexes.begin (); i != indexes.end (); ++i) {
lay::LayerPropertiesConstIterator li = iterator (*i);
if (! li.at_end ()) {
new_indexes.push_back (createIndex (li.child_index (), i->column (), (void *) (li.uint () + m_id_start)));
} else {
new_indexes.push_back (QModelIndex ());
}
}
changePersistentIndexList (indexes, new_indexes);
m_test_shapes_cache.clear ();
emit layoutChanged ();
}

View File

@ -235,11 +235,12 @@ public:
/**
* @brief emit a layoutChanged signal
*/
void signal_layer_changed ();
void signal_layers_changed ();
signals:
/**
* @brief This signal is emitted to indicate
* @brief This signal is emitted to indicate the hidden flags need update by the client
* Note this is neither done by the view nor the model. It needs to be implemented elsewhere.
*/
void hidden_flags_need_update ();

View File

@ -266,7 +266,7 @@ LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin
// ensures the deferred method scheduler is present
tl::DeferredMethodScheduler::instance ();
setObjectName (QString::fromUtf8 (name));
setObjectName (QString::fromUtf8(name));
init (manager, parent);
}
@ -2859,6 +2859,8 @@ LayoutView::add_new_layers (const std::vector <unsigned int> &layer_ids, int cv_
// create the layers and do a basic recoloring ..
lay::LayerPropertiesList new_props (get_properties ());
bool was_empty = new_props.begin_const_recursive ().at_end ();
// don't create new layers for those, for which there are layers already: compute a
// set of layers already present
std::set <db::LayerProperties, db::LPLogicalLessFunc> present_layers;
@ -2890,6 +2892,10 @@ LayoutView::add_new_layers (const std::vector <unsigned int> &layer_ids, int cv_
set_properties (new_props);
if (was_empty) {
set_current_layer (new_props.begin_const_recursive ());
}
}
}
@ -3291,6 +3297,18 @@ LayoutView::add_layout (lay::LayoutHandle *layout_handle, bool add_cellview, boo
}
// select the first layer if nothing else is selected
if (cv_index == 0 && ! mp_control_panel->has_selection ()) {
const lay::LayerPropertiesList &lp = get_properties ();
lay::LayerPropertiesConstIterator li = lp.begin_const_recursive ();
while (! li.at_end () && li->has_children ()) {
++li;
}
if (! li.at_end ()) {
mp_control_panel->set_current_layer (li);
}
}
// signal to any observers
file_open_event ();
@ -3456,6 +3474,18 @@ LayoutView::load_layout (const std::string &filename, const db::LoadLayoutOption
// create the initial layer properties
create_initial_layer_props (cv_index, lyp_file, add_other_layers);
// select the first layer if nothing else is selected
if (cv_index == 0 && ! mp_control_panel->has_selection ()) {
const lay::LayerPropertiesList &lp = get_properties ();
lay::LayerPropertiesConstIterator li = lp.begin_const_recursive ();
while (! li.at_end () && li->has_children ()) {
++li;
}
if (! li.at_end ()) {
mp_control_panel->set_current_layer (li);
}
}
// signal to any observers
file_open_event ();
@ -3942,6 +3972,8 @@ LayoutView::cancel ()
{
// cancel all drags and pending edit operations such as move operations.
cancel_edits ();
// re-enable edit mode
enable_edits (true);
// and clear the selection
clear_selection ();
}

View File

@ -199,6 +199,7 @@ LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char
: QFrame (parent),
m_enable_cb (true),
mp_view (view),
m_active_index (-1),
m_split_mode (false),
m_do_update_content_dm (this, &LibrariesView::do_update_content),
m_do_full_update_content_dm (this, &LibrariesView::do_full_update_content)

View File

@ -772,10 +772,7 @@ NetlistBrowserDialog::update_content ()
m_reload_action->setEnabled (l2ndb != 0);
browser_page->enable_updates (false); // Avoid building the internal lists several times ...
if (browser_page->db () != l2ndb) {
db_changed = true;
browser_page->set_db (l2ndb);
}
db_changed = browser_page->set_db (l2ndb);
browser_page->set_max_shape_count (m_max_shape_count);
browser_page->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0);
browser_page->set_window (m_window, m_window_dim);

View File

@ -1598,7 +1598,7 @@ db::NetlistCrossReference::Status
CircuitItemData::status (NetlistBrowserModel *model)
{
size_t index = model->indexer ()->circuit_index (m_cp);
return model->indexer ()->circuit_from_index (index).second;
return model->indexer ()->circuit_from_index (index).second.first;
}
CircuitNetItemData *
@ -1938,7 +1938,7 @@ CircuitNetItemData::status (NetlistBrowserModel *model)
{
if (m_np.first || m_np.second) {
size_t index = model->indexer ()->net_index (m_np);
return model->indexer ()->net_from_index (circuits (), index).second;
return model->indexer ()->net_from_index (circuits (), index).second.first;
} else {
return db::NetlistCrossReference::None;
}
@ -2016,7 +2016,7 @@ CircuitNetDeviceTerminalItemData::tooltip (NetlistBrowserModel *model)
db::NetlistCrossReference::Status
CircuitNetDeviceTerminalItemData::status (NetlistBrowserModel *model)
{
return model->indexer ()->device_from_index (circuits (), model->indexer ()->device_index (dp ())).second;
return model->indexer ()->device_from_index (circuits (), model->indexer ()->device_index (dp ())).second.first;
}
// ----------------------------------------------------------------------------------
@ -2113,7 +2113,7 @@ CircuitNetSubCircuitPinItemData::tooltip (NetlistBrowserModel *model)
db::NetlistCrossReference::Status
CircuitNetSubCircuitPinItemData::status (NetlistBrowserModel *model)
{
return model->indexer ()->subcircuit_from_index (parent ()->circuits (), model->indexer ()->subcircuit_index (subcircuits ())).second;
return model->indexer ()->subcircuit_from_index (parent ()->circuits (), model->indexer ()->subcircuit_index (subcircuits ())).second.first;
}
// ----------------------------------------------------------------------------------
@ -2272,7 +2272,7 @@ db::NetlistCrossReference::Status
CircuitSubCircuitItemData::status (NetlistBrowserModel *model)
{
size_t index = model->indexer ()->subcircuit_index (sp ());
return model->indexer ()->subcircuit_from_index (circuits (), index).second;
return model->indexer ()->subcircuit_from_index (circuits (), index).second.first;
}
// ----------------------------------------------------------------------------------
@ -2371,7 +2371,7 @@ db::NetlistCrossReference::Status
CircuitDeviceItemData::status (NetlistBrowserModel *model)
{
size_t index = model->indexer ()->device_index (m_dp);
return model->indexer ()->device_from_index (circuits (), index).second;
return model->indexer ()->device_from_index (circuits (), index).second.first;
}
// ----------------------------------------------------------------------------------

View File

@ -118,6 +118,7 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
mp_view (0),
m_cv_index (0),
mp_plugin_root (0),
mp_last_db (0),
m_history_ptr (0),
m_signals_enabled (true),
m_enable_updates (true),
@ -606,7 +607,7 @@ NetlistBrowserPage::rerun_macro ()
{
BEGIN_PROTECTED
if (! mp_database->generator ().empty ()) {
if (mp_database.get () && ! mp_database->generator ().empty ()) {
std::map<std::string, tl::Variant> add_pars;
@ -764,12 +765,14 @@ NetlistBrowserPage::show_all (bool f)
}
}
void
bool
NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
{
if (l2ndb == mp_database.get ()) {
// NOTE: mp_last_db mirrors mp_database, but does not automatically fall back to 0 when the DB is deleted. This way we can call
// set_db(0) with the correct behavior after the DB has been destroyed.
if (l2ndb == mp_last_db) {
// not change
return;
return false;
}
if (mp_info_dialog) {
@ -779,6 +782,7 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
db::LayoutVsSchematic *lvsdb = dynamic_cast<db::LayoutVsSchematic *> (l2ndb);
mp_database.reset (l2ndb);
mp_last_db = l2ndb;
rerun_button->setEnabled (mp_database.get () && ! mp_database->generator ().empty ());
if (rerun_button->isEnabled ()) {
@ -800,13 +804,15 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
show_xref->setChecked (lvsdb != 0);
m_signals_enabled = se;
clear_markers ();
clear_highlights ();
m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0);
setup_trees ();
selection_changed_event ();
return true;
}
void
@ -892,6 +898,15 @@ NetlistBrowserPage::setup_trees ()
find_text->setText (QString ());
}
void
NetlistBrowserPage::clear_highlights ()
{
m_current_path = lay::NetlistObjectsPath ();
m_selected_paths.clear ();
update_highlights ();
}
void
NetlistBrowserPage::highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths)
{
@ -900,9 +915,8 @@ NetlistBrowserPage::highlight (const NetlistObjectsPath &current_path, const std
m_current_path = current_path;
m_selected_paths = selected_paths;
clear_markers ();
adjust_view ();
update_highlights ();
adjust_view ();
}
}

View File

@ -91,7 +91,7 @@ public:
/**
* @brief Attaches the page to a L2N DB
*/
void set_db (db::LayoutToNetlist *database);
bool set_db(db::LayoutToNetlist *database);
/**
* @brief Gets the database the page is connected to
@ -228,6 +228,7 @@ private:
unsigned int m_cv_index;
lay::Dispatcher *mp_plugin_root;
tl::weak_ptr<db::LayoutToNetlist> mp_database;
db::LayoutToNetlist *mp_last_db;
std::vector<QModelIndex> m_history;
size_t m_history_ptr;
bool m_signals_enabled;
@ -247,6 +248,7 @@ private:
void adjust_view ();
void clear_markers ();
void highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths);
void clear_highlights ();
std::vector<const db::Net *> selected_nets ();
std::vector<const db::Device *> selected_devices ();
std::vector<const db::SubCircuit *> selected_subcircuits ();

View File

@ -204,10 +204,10 @@ NetlistBrowserTreeModel::search_text (const QModelIndex &index) const
return tl::to_qstring (search_string_from_names (circuits));
}
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status>
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> >
NetlistBrowserTreeModel::cp_status_from_index (const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const
{
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status> cp_status;
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp_status;
void *id = index.internalPointer ();
tl_assert (id != 0);
@ -251,7 +251,7 @@ NetlistBrowserTreeModel::build_circuits_to_index (size_t nprod, const std::pair<
size_t child_nprod = nprod * (count + 1);
for (size_t n = count; n > 0; ) {
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, IndexedNetlistModel::Status> cp = mp_indexer->child_circuit_from_index (circuits, n - 1);
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp = mp_indexer->child_circuit_from_index (circuits, n - 1);
QModelIndex child_index = createIndex (int (n - 1), 0, reinterpret_cast<void *> (size_t (index.internalPointer ()) + nprod * n));
build_circuits_to_index (child_nprod, cp.first, model, child_index, map);
--n;
@ -304,7 +304,7 @@ NetlistBrowserTreeModel::index_from_circuits (const std::pair<const db::Circuit
size_t count = mp_indexer->top_circuit_count ();
for (size_t n = count; n > 0; ) {
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, IndexedNetlistModel::Status> cp = mp_indexer->top_circuit_from_index (n - 1);
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp = mp_indexer->top_circuit_from_index (n - 1);
build_circuits_to_index (count + 1, cp.first, mp_indexer.get (), createIndex (int (n - 1), 0, reinterpret_cast<void *> (n)), m_circuits_to_index);
--n;
}
@ -324,13 +324,13 @@ db::NetlistCrossReference::Status
NetlistBrowserTreeModel::status (const QModelIndex &index) const
{
size_t nprod = 0, nlast = 0, nnlast = 0;
return cp_status_from_index (index, nprod, nlast, nnlast).second;
return cp_status_from_index (index, nprod, nlast, nnlast).second.first;
}
QVariant
NetlistBrowserTreeModel::tooltip (const QModelIndex &index) const
{
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status> cp_status;
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp_status;
size_t nlast = 0;
std::string hint;

View File

@ -88,7 +88,7 @@ private:
QVariant tooltip (const QModelIndex &index) const;
QString search_text (const QModelIndex &index) const;
db::NetlistCrossReference::Status status (const QModelIndex &index) const;
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status> cp_status_from_index (const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const;
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp_status_from_index(const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const;
void build_circuits_to_index (size_t nprod, const std::pair<const db::Circuit *, const db::Circuit *> &circuits, IndexedNetlistModel *model, const QModelIndex &index, std::map<std::pair<const db::Circuit *, const db::Circuit *>, QModelIndex> &map) const;
db::LayoutToNetlist *mp_l2ndb;

View File

@ -263,39 +263,39 @@ IndexedNetlistModel::circuit_pair NetlistCrossReferenceModel::parent_of (const I
return get_parent_of (subcircuit_pair, mp_cross_ref.get (), m_parents_of_subcircuits);
}
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::top_circuit_from_index (size_t index) const
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::top_circuit_from_index (size_t index) const
{
build_top_circuit_list (mp_cross_ref.get (), m_top_level_circuits);
IndexedNetlistModel::circuit_pair cp = m_top_level_circuits [index];
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
tl_assert (data != 0);
return std::make_pair (cp, data->status);
return std::make_pair (cp, std::make_pair (data->status, data->msg));
}
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
{
build_child_circuit_map (mp_cross_ref.get (), m_child_circuits);
IndexedNetlistModel::circuit_pair cp = m_child_circuits [circuits][index];
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
tl_assert (data != 0);
return std::make_pair (cp, data->status);
return std::make_pair (cp, std::make_pair (data->status, data->msg));
}
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::circuit_from_index (size_t index) const
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::circuit_from_index (size_t index) const
{
IndexedNetlistModel::circuit_pair cp = mp_cross_ref->begin_circuits () [index];
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
tl_assert (data != 0);
return std::make_pair (cp, data->status);
return std::make_pair (cp, std::make_pair (data->status, data->msg));
}
std::pair<IndexedNetlistModel::net_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::net_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::net_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::net_from_index (const circuit_pair &circuits, size_t index) const
{
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
tl_assert (data != 0);
return std::make_pair (data->nets [index].pair, data->nets [index].status);
return std::make_pair (data->nets [index].pair, std::make_pair (data->nets [index].status, data->nets [index].msg));
}
const db::Net *NetlistCrossReferenceModel::second_net_for (const db::Net *first) const
@ -484,25 +484,25 @@ IndexedNetlistModel::net_pin_pair NetlistCrossReferenceModel::net_pinref_from_in
return data->pins [index];
}
std::pair<IndexedNetlistModel::device_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::device_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::device_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::device_from_index (const circuit_pair &circuits, size_t index) const
{
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
tl_assert (data != 0);
return std::make_pair (data->devices [index].pair, data->devices [index].status);
return std::make_pair (data->devices [index].pair, std::make_pair (data->devices [index].status, data->devices [index].msg));
}
std::pair<IndexedNetlistModel::pin_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::pin_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::pin_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::pin_from_index (const circuit_pair &circuits, size_t index) const
{
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
tl_assert (data != 0);
return std::make_pair (data->pins [index].pair, data->pins [index].status);
return std::make_pair (data->pins [index].pair, std::make_pair (data->pins [index].status, data->pins [index].msg));
}
std::pair<IndexedNetlistModel::subcircuit_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
{
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
tl_assert (data != 0);
return std::make_pair (data->subcircuits [index].pair, data->subcircuits [index].status);
return std::make_pair (data->subcircuits [index].pair, std::make_pair (data->subcircuits [index].status, data->subcircuits [index].msg));
}
template <class Pair, class Iter>
@ -609,27 +609,37 @@ size_t NetlistCrossReferenceModel::subcircuit_index (const subcircuit_pair &subc
return get_index_of (subcircuits, org_data->subcircuits.begin (), org_data->subcircuits.end (), data->index_of_subcircuits);
}
std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> &cps) const
std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > &cps) const
{
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
std::string msg;
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
if (! cps.first.first || ! cps.first.second) {
return tl::to_string (tr ("No matching circuit found in the other netlist.\n"
"By default, circuits are identified by their name.\n"
"A missing circuit probably means there is no circuit in the other netlist with this name.\n"
"If circuits with different names need to be associated, use 'same_circuits' in the\n"
"LVS script to establish such an association."));
msg = tl::to_string (tr ("No matching circuit found in the other netlist.\n"
"By default, circuits are identified by their name.\n"
"A missing circuit probably means there is no circuit in the other netlist with this name.\n"
"If circuits with different names need to be associated, use 'same_circuits' in the\n"
"LVS script to establish such an association."));
} else {
return tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n"
"Browse the circuit's component list to identify the mismatching elements."));
msg = tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n"
"Browse the circuit's component list to identify the mismatching elements."));
}
} else if (cps.second == db::NetlistCrossReference::Skipped) {
return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n"
"pin-to-pin correspondence could be established for each child circuit.\n"
"This is not the case here. Browse the child circuits to identify the blockers.\n"
"Potential blockers are subcircuits without a corresponding other circuit or circuits\n"
"where some pins could not be mapped to pins from the corresponding other circuit."));
} else if (cps.second.first == db::NetlistCrossReference::Skipped) {
msg = tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n"
"pin-to-pin correspondence could be established for each child circuit.\n"
"This is not the case here. Browse the child circuits to identify the blockers.\n"
"Potential blockers are subcircuits without a corresponding other circuit or circuits\n"
"where some pins could not be mapped to pins from the corresponding other circuit."));
}
return std::string ();
if (! cps.second.second.empty ()) {
if (! msg.empty ()) {
msg += "\n\n";
}
msg += cps.second.second;
}
return msg;
}
std::string NetlistCrossReferenceModel::top_circuit_status_hint (size_t index) const
@ -644,94 +654,149 @@ std::string NetlistCrossReferenceModel::circuit_status_hint (size_t index) const
std::string NetlistCrossReferenceModel::child_circuit_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> cps = child_circuit_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
std::string msg;
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = child_circuit_from_index (circuits, index);
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin\n"
"assignment could not be derived from the nets connected to the pins.\n"
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
"'equivalent_pins' in the LVS script."));
msg = tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin\n"
"assignment could not be derived from the nets connected to the pins.\n"
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
"'equivalent_pins' in the LVS script."));
} else {
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n"
"originating from equivalent circuits.\n"
"If the circuits behind the subcircuits are identical, using 'same_circuits'\n"
"in the LVS script will associate them."));
msg = tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n"
"originating from equivalent circuits.\n"
"If the circuits behind the subcircuits are identical, using 'same_circuits'\n"
"in the LVS script will associate them."));
}
}
return std::string ();
if (! cps.second.second.empty ()) {
if (! msg.empty ()) {
msg += "\n\n";
}
msg += cps.second.second;
}
return msg;
}
std::string NetlistCrossReferenceModel::net_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::net_pair, NetlistCrossReferenceModel::Status> cps = net_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
return tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n"
"counterpart in the other netlist (component-wise and pin/terminal-wise).\n"
"If there already is a net candidate from the other netlist, scan the net members for\n"
"mismatching items (with errors or warnings) and fix these issues.\n"
"Otherwise, look for the corresponding other net.\n"
"Net items not found in the reference netlist indicate additional connections.\n"
"Net items only found in the reference netlist indicate missing connections."));
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) {
return tl::to_string (tr ("Nets match, but the choice was ambiguous. This may lead to mismatching nets in other places.\n"));
std::string msg;
std::pair<IndexedNetlistModel::net_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = net_from_index (circuits, index);
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
msg = tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n"
"counterpart in the other netlist (component-wise and pin/terminal-wise).\n"
"If there already is a net candidate from the other netlist, scan the net members for\n"
"mismatching items (with errors or warnings) and fix these issues.\n"
"Otherwise, look for the corresponding other net.\n"
"Net items not found in the reference netlist indicate additional connections.\n"
"Net items only found in the reference netlist indicate missing connections."));
} else if (cps.second.first == db::NetlistCrossReference::MatchWithWarning) {
msg = tl::to_string (tr ("Nets match, but the choice was ambiguous. This may lead to mismatching nets in other places.\n"));
}
return std::string ();
if (! cps.second.second.empty ()) {
if (! msg.empty ()) {
msg += "\n\n";
}
msg += cps.second.second;
}
return msg;
}
std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::device_pair, NetlistCrossReferenceModel::Status> cps = device_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
std::string msg;
std::pair<IndexedNetlistModel::device_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = device_from_index (circuits, index);
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching device was found in the other netlist.\n"
"Devices are identified by the nets they are attached to. Unmatched devices mean that\n"
"at least one terminal net isn't matched with a corresponding net from the other netlist.\n"
"Make all terminal nets match and the devices will match too."));
msg = tl::to_string (tr ("No matching device was found in the other netlist.\n"
"Devices are identified by the nets they are attached to. Unmatched devices mean that\n"
"at least one terminal net isn't matched with a corresponding net from the other netlist.\n"
"Make all terminal nets match and the devices will match too."));
} else {
return tl::to_string (tr ("Devices don't match topologically.\n"
"Check the terminal connections to identify the terminals not being connected to\n"
"corresponding nets. Either the devices are not connected correctly or the nets\n"
"need to be fixed before the devices will match too."));
msg = tl::to_string (tr ("Devices don't match topologically.\n"
"Check the terminal connections to identify the terminals not being connected to\n"
"corresponding nets. Either the devices are not connected correctly or the nets\n"
"need to be fixed before the devices will match too."));
}
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) {
return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n"
"device classes don't match.\n"
"If the device class is different but should be considered the same, using\n"
"'same_device_classed' in the LVS script will solve this issue."));
} else if (cps.second.first == db::NetlistCrossReference::MatchWithWarning) {
msg = tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n"
"device classes don't match.\n"
"If the device class is different but should be considered the same, using\n"
"'same_device_classed' in the LVS script will solve this issue."));
}
return std::string ();
if (! cps.second.second.empty ()) {
if (! msg.empty ()) {
msg += "\n\n";
}
msg += cps.second.second;
}
return msg;
}
std::string NetlistCrossReferenceModel::pin_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::pin_pair, NetlistCrossReferenceModel::Status> cps = pin_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
std::string msg;
std::pair<IndexedNetlistModel::pin_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = pin_from_index (circuits, index);
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching pin was found in the other netlist.\n"
"Pins are identified by the nets they are attached to - pins on equivalent nets are also\n"
"equivalent. Making the nets match will make the pins match too."));
msg = tl::to_string (tr ("No matching pin was found in the other netlist.\n"
"Pins are identified by the nets they are attached to - pins on equivalent nets are also\n"
"equivalent. Making the nets match will make the pins match too."));
}
}
return std::string ();
if (! cps.second.second.empty ()) {
if (! msg.empty ()) {
msg += "\n\n";
}
msg += cps.second.second;
}
return msg;
}
std::string NetlistCrossReferenceModel::subcircuit_status_hint (const circuit_pair &circuits, size_t index) const
{
std::pair<IndexedNetlistModel::subcircuit_pair, NetlistCrossReferenceModel::Status> cps = subcircuit_from_index (circuits, index);
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
std::string msg;
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = subcircuit_from_index (circuits, index);
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment\n"
"could not be derived from the nets connected to the pins.\n"
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
"'equivalent_pins' in the LVS script."));
msg = tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment\n"
"could not be derived from the nets connected to the pins.\n"
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
"'equivalent_pins' in the LVS script."));
} else {
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n"
"equivalent circuits.\n"
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n"
"will associate them."));
msg = tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n"
"equivalent circuits.\n"
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n"
"will associate them."));
}
}
return std::string ();
if (! cps.second.second.empty ()) {
if (! msg.empty ()) {
msg += "\n\n";
}
msg += cps.second.second;
}
return msg;
}
}

View File

@ -59,24 +59,24 @@ public:
virtual circuit_pair parent_of (const device_pair &device_pair) const;
virtual circuit_pair parent_of (const subcircuit_pair &subcircuit_pair) const;
virtual std::pair<circuit_pair, Status> top_circuit_from_index (size_t index) const;
virtual std::pair<circuit_pair, Status> circuit_from_index (size_t index) const;
virtual std::pair<circuit_pair, Status> child_circuit_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<net_pair, Status> net_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > top_circuit_from_index(size_t index) const;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > circuit_from_index (size_t index) const;
virtual std::pair<circuit_pair, std::pair<Status, std::string> > child_circuit_from_index(const circuit_pair &circuits, size_t index) const;
virtual std::pair<net_pair, std::pair<Status, std::string> > net_from_index (const circuit_pair &circuits, size_t index) const;
virtual const db::Net *second_net_for (const db::Net *first) const;
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const;
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const;
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &nets, size_t index) const;
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const;
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const;
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<pin_pair, Status> pin_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<subcircuit_pair, Status> subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<device_pair, std::pair<Status, std::string> > device_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<pin_pair, std::pair<Status, std::string> > pin_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::pair<subcircuit_pair, std::pair<Status, std::string> > subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
virtual std::string top_circuit_status_hint (size_t index) const;
virtual std::string circuit_status_hint (size_t index) const;
virtual std::string child_circuit_status_hint (const circuit_pair &circuits, size_t index) const;
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, Status> &cp) const;
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, std::pair<Status, std::string> > &cp) const;
virtual std::string net_status_hint (const circuit_pair &circuits, size_t index) const;
virtual std::string device_status_hint (const circuit_pair &circuits, size_t index) const;
virtual std::string pin_status_hint (const circuit_pair &circuits, size_t index) const;

View File

@ -22,7 +22,6 @@
#include "layProperties.h"
#include "layEditable.h"
namespace lay
{

View File

@ -25,6 +25,7 @@
#define HDR_layProperties
#include "laybasicCommon.h"
#include "layEditable.h"
#include <QFrame>
@ -209,7 +210,7 @@ public:
*/
lay::Editable *editable ()
{
return mp_editable;
return mp_editable.get ();
}
/**
@ -229,7 +230,7 @@ signals:
private:
db::Manager *mp_manager;
lay::Editable *mp_editable;
tl::weak_ptr<lay::Editable> mp_editable;
};
}

View File

@ -17,39 +17,52 @@
<text>
module LVS
def self.execute_lvs(macro, generator, l2ndb_index = nil)
class LVSExecutable &lt; RBA::Executable
timer = RBA::Timer::new
timer.start
lvs = LVSEngine::new
lvs._l2ndb_index = l2ndb_index
lvs._generator = generator
def initialize(macro, generator, l2ndb_index = nil)
begin
@lvs = LVSEngine::new
@lvs._l2ndb_index = l2ndb_index
@lvs._generator = generator
# Set a debugger scope so that our errors end up with the debugger set to the LVS's line
RBA::MacroExecutionContext::set_debugger_scope(macro.path)
# No verbosity set in lvs engine - we cannot use the engine's logger
RBA::Logger::verbosity &gt;= 10 &amp;&amp; RBA::Logger::info("Running #{macro.path}")
lvs.instance_eval(macro.text, macro.path)
# Remove the debugger scope
RBA::MacroExecutionContext::remove_debugger_scope
rescue =&gt; ex
lvs.error("In #{macro.path}: #{ex.to_s}")
RBA::MacroExecutionContext::ignore_next_exception
raise ex
ensure
# cleans up and creates layout and report views
lvs._finish
@macro = macro
end
timer.stop
lvs.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s")
def execute
@lvs._start("LVS: " + @macro.path)
# Set a debugger scope so that our errors end up with the debugger set to the LVS's line
RBA::MacroExecutionContext::set_debugger_scope(@macro.path)
begin
# No verbosity set in lvs engine - we cannot use the engine's logger
RBA::Logger::verbosity &gt;= 10 &amp;&amp; RBA::Logger::info("Running #{@macro.path}")
@lvs.instance_eval(@macro.text, @macro.path)
rescue =&gt; ex
@lvs.error("In #{@macro.path}: #{ex.to_s}")
RBA::MacroExecutionContext::ignore_next_exception
raise ex
end
nil
end
def cleanup
# Remove the debugger scope
RBA::MacroExecutionContext::remove_debugger_scope
# cleans up and creates layout and report views
@lvs._finish
end
end
@ -83,8 +96,8 @@ module LVS
end
# Implements the execute method
def execute(macro)
LVS::execute_lvs(macro, @recipe.generator("script" => macro.path))
def executable(macro)
LVSExecutable::new(macro, @recipe.generator("script" => macro.path))
end
end
@ -110,8 +123,8 @@ module LVS
end
# Implements the execute method
def execute(macro)
LVS::execute_lvs(macro, @recipe.generator("script" => macro.path))
def executable(macro)
LVSExecutable::new(macro, @recipe.generator("script" => macro.path))
end
end
@ -123,7 +136,7 @@ module LVS
super("lvs", "LVS recipe")
end
def execute(params)
def executable(params)
script = params["script"]
if ! script
@ -133,7 +146,7 @@ module LVS
macro = RBA::Macro::macro_by_path(script)
macro || raise("Can't find LVS script #{script} - unable to re-run")
LVS::execute_lvs(macro, self.generator("script" => script), params["l2ndb_index"])
LVSExecutable::new(macro, self.generator("script" => script), params["l2ndb_index"])
end

View File

@ -30,7 +30,7 @@
#include "lymMacro.h"
#include "tlFileUtils.h"
void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string &au_netlist, const std::string &layout, bool priv = false)
void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string &au_netlist, const std::string &layout, bool priv = false, const std::string &au_lvsdb_name = std::string ())
{
std::string testsrc = priv ? tl::testsrc_private () : tl::testsrc ();
testsrc = tl::combine_path (tl::combine_path (testsrc, "testdata"), "lvs");
@ -88,6 +88,11 @@ void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string
tl::info << " golden: " << au_cir;
}
EXPECT_EQ (res, true);
if (! au_lvsdb_name.empty ()) {
std::string au_lvsdb = tl::combine_path (testsrc, au_lvsdb_name);
_this->compare_text_files (output_lvsdb, au_lvsdb);
}
}
TEST(1_full)
@ -143,3 +148,9 @@ TEST(16_private)
// test_is_long_runner ();
run_test (_this, "test_16.lvs", "test_16.cir.gz", "test_16.gds.gz", true);
}
TEST(17_private)
{
test_is_long_runner ();
run_test (_this, "test_17.lylvs", "test_17.cir.gz", "test_17.gds.gz", true, "test_17.lvsdb");
}

View File

@ -142,10 +142,12 @@ public:
m_name = name;
}
virtual void execute (const lym::Macro *macro) const
virtual tl::Executable *executable (const lym::Macro *macro) const
{
if (f_execute.can_issue ()) {
f_execute.issue<MacroInterpreter, const lym::Macro *> (&MacroInterpreter::execute, macro);
if (f_executable.can_issue ()) {
return f_executable.issue<MacroInterpreter, tl::Executable *, const lym::Macro *> (&MacroInterpreter::executable, macro);
} else {
return 0;
}
}
@ -240,7 +242,7 @@ public:
}
}
gsi::Callback f_execute;
gsi::Callback f_executable;
private:
tl::RegisteredClass <lym::MacroInterpreter> *mp_registration;
@ -307,7 +309,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
) +
gsi::method ("create_template", &MacroInterpreter::create_template, gsi::arg ("url"),
"@brief Creates a new macro template\n"
"@url The template will be initialized from that URL.\n"
"@param url The template will be initialized from that URL.\n"
"\n"
"This method will create a register a new macro template. It returns a \\Macro object which "
"can be modified in order to adjust the template (for example to set description, add a content, "
@ -378,13 +380,15 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"Before version 0.25 this attribute was a reimplementable method. It has been turned into an attribute for "
"performance reasons in version 0.25.\n"
) +
gsi::callback ("execute", &gsi::MacroInterpreter::execute, &gsi::MacroInterpreter::f_execute, gsi::arg ("macro"),
"@brief Gets called to execute a macro\n"
"This method must be reimplemented to execute the macro. "
"The system will call this script when a macro with interpreter type 'dsl' and the "
"name of this interpreter is run."
gsi::callback ("executable", &gsi::MacroInterpreter::executable, &gsi::MacroInterpreter::f_executable, gsi::arg ("macro"),
"@brief Returns the executable object which implements the macro execution\n"
"This method must be reimplemented to return an \\Executable object for the actual implementation. "
"The system will use this function to execute the script when a macro with interpreter type 'dsl' and the "
"name of this interpreter is run.\n"
"\n"
"@param macro The macro to execute\n"
"\n"
"This method has been introduced in version 0.27 and replaces the 'execute' method.\n"
),
"@brief A custom interpreter for a DSL (domain specific language)\n"
"\n"
@ -413,6 +417,21 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"just evaluates the script text:\n"
"\n"
"@code\n"
"class SimpleExecutable < RBA::Excutable\n"
"\n"
" # Constructor\n"
" def initialize(macro)\n"
" \\@macro = macro\n"
" end\n"
" \n"
" # Implements the execute method\n"
" def execute\n"
" eval(\\@macro.text, nil, \\@macro.path)\n"
" nil\n"
" end\n"
"\n"
"end\n"
"\n"
"class SimpleInterpreter < RBA::MacroInterpreter\n"
"\n"
" # Constructor\n"
@ -427,9 +446,9 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
" mt.description = \"Special;;Simple interpreter macro\"\n"
" end\n"
" \n"
" # Implements the execute method\n"
" def execute(macro)\n"
" eval(macro.text, nil, macro.path)\n"
" # Creates the executable delegate\n"
" def executable(macro)\n"
" SimpleExecutable::new(macro)\n"
" end\n"
"\n"
"end\n"
@ -447,7 +466,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"\n"
"In order to make the above code effective, store the code in an macro, set \"early auto-run\" and restart KLayout.\n"
"\n"
"This class has been introduced in version 0.23.\n"
"This class has been introduced in version 0.23 and modified in 0.27.\n"
);
static lym::Macro *macro_by_path (const std::string &path)

View File

@ -32,10 +32,10 @@
namespace lym
{
void
MacroInterpreter::execute (const lym::Macro *) const
tl::Executable *
MacroInterpreter::executable (const lym::Macro *) const
{
throw tl::Exception (tl::to_string (QObject::tr ("execute() implementation missing for DSL interpreter")));
throw tl::Exception (tl::to_string (QObject::tr ("executable() implementation missing for DSL interpreter")));
}
bool
@ -107,7 +107,10 @@ MacroInterpreter::execute_macro (const lym::Macro *macro)
std::pair<std::string, std::string> et = cls->include_expansion (macro);
if (et.first.empty () || et.first == macro->path ()) {
cls->execute (macro);
std::unique_ptr<tl::Executable> eo (cls->executable (macro));
if (eo.get ()) {
eo->do_execute ();
}
} else {
@ -116,7 +119,10 @@ MacroInterpreter::execute_macro (const lym::Macro *macro)
tmp_macro.assign (*macro);
tmp_macro.set_text (et.second);
tmp_macro.set_file_path (et.first);
cls->execute (&tmp_macro);
std::unique_ptr<tl::Executable> eo (cls->executable (&tmp_macro));
if (eo.get ()) {
eo->do_execute ();
}
}

View File

@ -26,6 +26,7 @@
#include "lymCommon.h"
#include "tlRecipe.h"
#include "gsiObject.h"
#include "tlClassRegistry.h"
@ -63,11 +64,11 @@ public:
}
/**
* @brief Executes the macro
* @brief Creates the executable for a macro
*
* This method must be reimplemented to provide the actual execution of the macro.
* The caller will delete the returned object.
*/
virtual void execute (const lym::Macro *macro) const;
virtual tl::Executable *executable (const lym::Macro *macro) const;
/**
* @brief Returns the storage scheme

View File

@ -146,7 +146,7 @@ public:
m_cell_stack.pop_back ();
}
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
{
db::cell_index_type ci = inst.object ().cell_index ();
if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) {
@ -156,7 +156,7 @@ public:
}
}
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
tl_assert (! m_cell_stack.empty ());
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape);
@ -209,9 +209,9 @@ public:
}
}
virtual void shape (const db::RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * iter->trans (), shape);
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * trans, shape);
}
public:

View File

@ -49,7 +49,11 @@ ProgressAdaptor::~ProgressAdaptor ()
void
ProgressAdaptor::register_object (Progress *progress)
{
bool cancelled = ! mp_objects.empty () && mp_objects.first ()->break_scheduled ();
mp_objects.push_back (progress); // this keeps the outmost one visible. push_front would make the latest one visible.
if (cancelled) {
progress->signal_break ();
}
}
void
@ -130,17 +134,19 @@ ProgressGarbageCollector::~ProgressGarbageCollector ()
// store a pointer but a pointer to a pointer.
static tl::ThreadStorage<ProgressAdaptor **> s_thread_data;
Progress::Progress (const std::string &desc, size_t yield_interval)
: m_desc (desc),
m_final (false),
m_title (desc),
const double yield_timeout = 0.3;
const size_t default_yield_interval = 1000;
Progress::Progress (const std::string &desc, size_t yield_interval, bool can_cancel)
: m_desc (desc), m_title (desc),
m_interval_count (0),
m_yield_interval (yield_interval),
m_yield_interval (yield_interval == 0 ? default_yield_interval : yield_interval),
m_last_value (-1.0),
m_can_cancel (true),
m_cancelled (false)
m_can_cancel (can_cancel),
m_cancelled (false),
m_registered (false)
{
// .. nothing yet ..
m_last_yield = tl::Clock::current ();
}
Progress::~Progress ()
@ -151,9 +157,19 @@ Progress::~Progress ()
void
Progress::initialize ()
{
// The abstract progress does not get test() calls so we need to register it now.
ProgressAdaptor *a = adaptor ();
if (a) {
a->register_object (this);
m_registered = true;
// A pending cancel request may immediately kill the operation - "register_object" will set the cancelled flag then.
if (m_cancelled) {
m_cancelled = false;
throw tl::BreakException ();
}
}
}
@ -161,7 +177,7 @@ void
Progress::shutdown ()
{
ProgressAdaptor *a = adaptor ();
if (a) {
if (a && m_registered) {
a->unregister_object (this);
}
}
@ -194,29 +210,27 @@ Progress::adaptor ()
void
Progress::signal_break ()
{
m_cancelled = true;
if (m_can_cancel) {
m_cancelled = true;
}
}
void
Progress::set_desc (const std::string &d)
{
ProgressAdaptor *a = adaptor ();
if (a && d != m_desc) {
if (d != m_desc) {
m_desc = d;
a->trigger (this);
a->yield (this);
if (m_cancelled) {
m_cancelled = false;
throw tl::BreakException ();
}
test (true);
}
}
bool Progress::test(bool force_yield)
bool Progress::test (bool force_yield)
{
if (m_cancelled) {
m_cancelled = false;
throw tl::BreakException ();
}
if (++m_interval_count >= m_yield_interval || force_yield) {
ProgressAdaptor *a = adaptor ();
@ -228,22 +242,28 @@ bool Progress::test(bool force_yield)
needs_trigger = true;
}
if (m_desc != m_last_desc) {
m_last_desc = m_desc;
needs_trigger = true;
}
m_interval_count = 0;
if (a) {
tl::Clock now = tl::Clock::current ();
if ((now - m_last_yield).seconds () > 0.1) {
if ((now - m_last_yield).seconds () > yield_timeout) {
m_last_yield = now;
if (needs_trigger) {
a->trigger (this);
}
a->yield (this);
}
}
if (m_cancelled) {
m_cancelled = false;
throw tl::BreakException ();
a->yield (this);
}
}
return true;
@ -270,8 +290,8 @@ AbstractProgress::~AbstractProgress ()
// ---------------------------------------------------------------------------------------------
// RelativeProgress implementation
RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval)
: Progress (desc, yield_interval)
RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval, bool can_cancel)
: Progress (desc, yield_interval, can_cancel)
{
m_format = "%.0f%%";
m_unit = double (max_count) / 100.0;
@ -315,8 +335,8 @@ RelativeProgress::set (size_t count, bool force_yield)
// ---------------------------------------------------------------------------------------------
// Progress implementation
AbsoluteProgress::AbsoluteProgress (const std::string &desc, size_t yield_interval)
: Progress (desc, yield_interval)
AbsoluteProgress::AbsoluteProgress (const std::string &desc, size_t yield_interval, bool can_cancel)
: Progress (desc, yield_interval, can_cancel)
{
m_format = "%.0f";
m_unit = 1.0;

Some files were not shown because too many files have changed in this diff Show More