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 += "---------------------------------------------------------------------------------------------------------\n" Usage += "---------------------------------------------------------------------------------------------------------\n"
Usage += "<< Usage of 'build4mac.py' >>\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 += "\n"
Usage += "$ [python] ./build4mac.py \n" Usage += "$ [python] ./build4mac.py \n"
Usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value\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 += " : Ana3: use Python 3.7 from Anaconda3 | \n"
Usage += " : HBAuto: use the latest Python 3.x auto-detected from Homebrew | \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 += " [-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 += " [-m|--make <option>] : option passed to 'make' | '-j4' \n"
Usage += " [-d|--debug] : enable debug mode build | disabled \n" Usage += " [-d|--debug] : enable debug mode build | disabled \n"
Usage += " [-c|--checkcom] : check command-line and exit without building | disabled \n" Usage += " [-c|--checkcom] : check command-line and exit without building | disabled \n"
@ -137,6 +138,7 @@ def Get_Default_Config():
NonOSStdLang = False NonOSStdLang = False
NoQtBindings = False NoQtBindings = False
NoQtUiTools = False
MakeOptions = "-j4" MakeOptions = "-j4"
DebugMode = False DebugMode = False
CheckComOnly = False CheckComOnly = False
@ -157,6 +159,7 @@ def Get_Default_Config():
config['ModulePython'] = ModulePython # Python module to be used config['ModulePython'] = ModulePython # Python module to be used
config['NonOSStdLang'] = NonOSStdLang # True if non-OS-standard language is chosen config['NonOSStdLang'] = NonOSStdLang # True if non-OS-standard language is chosen
config['NoQtBindings'] = NoQtBindings # True if not creating Qt bindings for Ruby scripts 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['MakeOptions'] = MakeOptions # options passed to `make`
config['DebugMode'] = DebugMode # True if debug mode build config['DebugMode'] = DebugMode # True if debug mode build
config['CheckComOnly'] = CheckComOnly # True if only for checking the command line parameters to "build.sh" 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'] ModulePython = config['ModulePython']
NonOSStdLang = config['NonOSStdLang'] NonOSStdLang = config['NonOSStdLang']
NoQtBindings = config['NoQtBindings'] NoQtBindings = config['NoQtBindings']
NoQtUiTools = config['NoQtUiTools']
MakeOptions = config['MakeOptions'] MakeOptions = config['MakeOptions']
DebugMode = config['DebugMode'] DebugMode = config['DebugMode']
CheckComOnly = config['CheckComOnly'] CheckComOnly = config['CheckComOnly']
@ -226,6 +230,12 @@ def Parse_CLI_Args(config):
default=False, default=False,
help="do not create Qt bindings for Ruby scripts" ) 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', p.add_option( '-m', '--make',
dest='make_option', dest='make_option',
help="options passed to `make`" ) help="options passed to `make`" )
@ -268,6 +278,7 @@ def Parse_CLI_Args(config):
type_ruby = "sys", type_ruby = "sys",
type_python = "sys", type_python = "sys",
no_qt_binding = False, no_qt_binding = False,
no_qt_uitools = False,
make_option = "-j4", make_option = "-j4",
debug_build = False, debug_build = False,
check_command = False, check_command = False,
@ -406,6 +417,7 @@ def Parse_CLI_Args(config):
ModuleSet = ( choiceQt5, choiceRuby, choicePython ) ModuleSet = ( choiceQt5, choiceRuby, choicePython )
NoQtBindings = opt.no_qt_binding NoQtBindings = opt.no_qt_binding
NoQtUiTools = opt.no_qt_uitools
MakeOptions = opt.make_option MakeOptions = opt.make_option
DebugMode = opt.debug_build DebugMode = opt.debug_build
CheckComOnly = opt.check_command CheckComOnly = opt.check_command
@ -462,6 +474,7 @@ def Parse_CLI_Args(config):
config['ModulePython'] = ModulePython config['ModulePython'] = ModulePython
config['NonOSStdLang'] = NonOSStdLang config['NonOSStdLang'] = NonOSStdLang
config['NoQtBindings'] = NoQtBindings config['NoQtBindings'] = NoQtBindings
config['NoQtUiTools'] = NoQtUiTools
config['MakeOptions'] = MakeOptions config['MakeOptions'] = MakeOptions
config['DebugMode'] = DebugMode config['DebugMode'] = DebugMode
config['CheckComOnly'] = CheckComOnly config['CheckComOnly'] = CheckComOnly
@ -491,6 +504,7 @@ def Get_Build_Parameters(config):
ModulePython = config['ModulePython'] ModulePython = config['ModulePython']
ModuleSet = config['ModuleSet'] ModuleSet = config['ModuleSet']
NoQtBindings = config['NoQtBindings'] NoQtBindings = config['NoQtBindings']
NoQtUiTools = config['NoQtUiTools']
MakeOptions = config['MakeOptions'] MakeOptions = config['MakeOptions']
DebugMode = config['DebugMode'] DebugMode = config['DebugMode']
CheckComOnly = config['CheckComOnly'] CheckComOnly = config['CheckComOnly']
@ -542,11 +556,14 @@ def Get_Build_Parameters(config):
# (E) want Qt bindings with Ruby scripts? # (E) want Qt bindings with Ruby scripts?
parameters['no_qt_bindings'] = NoQtBindings 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 == "": if not MakeOptions == "":
parameters['make_options'] = MakeOptions parameters['make_options'] = MakeOptions
# (G) about Ruby # (H) about Ruby
if ModuleRuby != "nil": if ModuleRuby != "nil":
parameters['ruby'] = RubyDictionary[ModuleRuby]['exe'] parameters['ruby'] = RubyDictionary[ModuleRuby]['exe']
parameters['rbinc'] = RubyDictionary[ModuleRuby]['inc'] parameters['rbinc'] = RubyDictionary[ModuleRuby]['inc']
@ -554,7 +571,7 @@ def Get_Build_Parameters(config):
if 'inc2' in RubyDictionary[ModuleRuby]: if 'inc2' in RubyDictionary[ModuleRuby]:
parameters['rbinc2'] = RubyDictionary[ModuleRuby]['inc2'] parameters['rbinc2'] = RubyDictionary[ModuleRuby]['inc2']
# (H) about Python # (I) about Python
if ModulePython != "nil": if ModulePython != "nil":
parameters['python'] = PythonDictionary[ModulePython]['exe'] parameters['python'] = PythonDictionary[ModulePython]['exe']
parameters['pyinc'] = PythonDictionary[ModulePython]['inc'] 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['MacBuildDirQAT'] = MacBuildDirQAT # relative path to build directory for QATest
config['MacBuildLog'] = MacBuildLog # relative path to build log file 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 parameters['project_dir'] = ProjectDir
return parameters return parameters
@ -607,11 +624,15 @@ def Run_Build_Command(parameters):
else: else:
cmd_args += " \\\n -with-qtbinding" 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: if 'make_options' in parameters:
cmd_args += " \\\n -option %s" % parameters['make_options'] cmd_args += " \\\n -option %s" % parameters['make_options']
# (G) about Ruby # (H) about Ruby
if 'ruby' in parameters: if 'ruby' in parameters:
cmd_args += " \\\n -ruby %s" % parameters['ruby'] cmd_args += " \\\n -ruby %s" % parameters['ruby']
cmd_args += " \\\n -rbinc %s" % parameters['rbinc'] cmd_args += " \\\n -rbinc %s" % parameters['rbinc']
@ -621,7 +642,7 @@ def Run_Build_Command(parameters):
else: else:
cmd_args += " \\\n -noruby" cmd_args += " \\\n -noruby"
# (H) about Python # (I) about Python
if 'python' in parameters: if 'python' in parameters:
cmd_args += " \\\n -python %s" % parameters['python'] cmd_args += " \\\n -python %s" % parameters['python']
cmd_args += " \\\n -pyinc %s" % parameters['pyinc'] 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 (); return new_edge_pairs.release ();
} }
RegionDelegate * namespace {
AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const
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); min_count = std::max (size_t (1), min_count);
if (max_count < min_count || other.empty ()) { // shortcut
if (! inverse) { if (empty ()) {
return new EmptyRegion (); if (output_mode == Positive || output_mode == Negative) {
return std::make_pair (clone (), (RegionDelegate *) 0);
} else { } 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 ()); bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
#if defined(USE_LOCAL_PROCESSOR)
db::RegionIterator polygons (begin_merged ()); 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; db::local_processor<db::Polygon, db::Edge, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ()); proc.set_base_verbosity (base_verbosity ());
@ -413,71 +462,42 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse,
std::vector<db::Shapes *> results; std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ()); 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 (); return oph.region_pair ();
#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
} }
RegionDelegate * std::pair<RegionDelegate *, RegionDelegate *>
AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const 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 (output_mode == None) {
if (! inverse) { return oph.region_pair ();
return new EmptyRegion ();
} else {
return clone ();
}
} else if (empty ()) {
return clone ();
} }
#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::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; db::local_processor<db::Polygon, db::Text, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ()); 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; std::vector<generic_shape_iterator<db::Text> > others;
others.push_back (other.begin ()); others.push_back (other.begin ());
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ())); proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, std::vector<bool> (), &op, results); return oph.region_pair ();
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
} }
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); min_count = std::max (size_t (1), min_count);
// shortcut // shortcut
if (empty ()) { 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 ()) { } else if (max_count < min_count || other.empty ()) {
// clear, if b is empty and // clear, if b is empty and
// * mode is inside, enclosing or interacting and inverse is false ("inside" or "interacting") // * mode is inside, enclosing or interacting and inverse is false ("inside" or "interacting")
// * mode is outside and inverse is true ("not outside") // * mode is outside and inverse is true ("not outside")
if ((mode <= 0) != inverse) { if ((mode <= 0)) {
return new EmptyRegion (); 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 { } 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 ()); bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
db::RegionIterator polygons (begin_merged ()); 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; db::local_processor<db::Polygon, db::Polygon, db::Polygon> proc;
proc.set_base_verbosity (base_verbosity ()); 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; std::vector<generic_shape_iterator<db::Polygon> > others;
others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ()); others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ());
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ())); proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, std::vector<bool> (), &op, results); return oph.region_pair ();
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
} }
EdgesDelegate * EdgesDelegate *

View File

@ -139,72 +139,107 @@ public:
virtual RegionDelegate *selected_outside (const Region &other) const 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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_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 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 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 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 std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) 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 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 RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
virtual EdgesDelegate *pull_generic (const Edges &other) const; virtual EdgesDelegate *pull_generic (const Edges &other) const;
virtual TextsDelegate *pull_generic (const Texts &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) 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 .. // .. nothing yet ..
} }
CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (db::Region *a, db::Region *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) 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 .. // .. 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) 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 .. // .. 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 { } 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: 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 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 (); return res.release ();
} }
RegionDelegate * namespace
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const
{ {
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 ()); 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. // 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 // 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 (); 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, output_mode, min_count, max_count, true);
db::InteractingLocalOperation op (mode, touching, inverse, 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 ()); 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 ()); 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.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); proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
if (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ())) {
res->set_is_merged (true); return orh.result_pair ();
}
return res;
} }
RegionDelegate * std::pair<RegionDelegate *, RegionDelegate *>
DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const 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 ()); 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 (); const db::DeepLayer &polygons = merged_deep_layer ();
DeepLayer dl_out (polygons.derived ()); db::InteractingWithEdgeLocalOperation op (output_mode, min_count, max_count, true);
db::InteractingWithEdgeLocalOperation op (inverse, 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 ()); 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 ()); 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.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); proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), orh.layers ());
if (! split_after) {
res->set_is_merged (other.is_merged () && (merged_semantics () || is_merged ())); return orh.result_pair ();
}
return res;
} }
RegionDelegate * RegionDelegate *
@ -1706,8 +1758,9 @@ DeepRegion::pull_generic (const Texts &other) const
return res; 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. // with these flag set to true, the resulting polygons are broken again.
bool split_after = false; 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 (); const db::DeepLayer &polygons = merged_deep_layer ();
DeepLayer dl_out (polygons.derived ()); db::InteractingWithTextLocalOperation op (output_mode, min_count, max_count);
db::InteractingWithTextLocalOperation op (inverse, 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 ()); 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 ()); 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.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); proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), orh.layers ());
if (! split_after) {
res->set_is_merged (merged_semantics () || is_merged ()); return orh.result_pair ();
}
return res;
} }
} }

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_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 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 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 RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, 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 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 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 RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
virtual EdgesDelegate *pull_generic (const Edges &other) const; virtual EdgesDelegate *pull_generic (const Edges &other) const;
virtual TextsDelegate *pull_generic (const Texts &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) // 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; 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 // 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 // provided inside the original hierarchy builders. They list the source cells and the target cells

View File

@ -252,6 +252,7 @@ public:
DeviceParameterCompareDelegate () { } DeviceParameterCompareDelegate () { }
virtual ~DeviceParameterCompareDelegate () { } virtual ~DeviceParameterCompareDelegate () { }
virtual DeviceParameterCompareDelegate *clone () const = 0;
virtual bool less (const db::Device &a, const db::Device &b) 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; 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 less (const db::Device &a, const db::Device &b) const;
virtual bool equal (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);
EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const 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 less (const db::Device &a, const db::Device &b) const;
virtual bool equal (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: private:
double m_relative; double m_relative;
}; };
@ -574,6 +585,14 @@ public:
/** /**
* @brief Gets the parameter compare delegate or null if no such delegate is registered * @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 () db::DeviceParameterCompareDelegate *parameter_compare_delegate ()
{ {
return mp_pc_delegate.get (); 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_outside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_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_inside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *selected_not_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_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 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_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 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_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 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_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 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_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 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_inside (const Region &) const { return new EmptyRegion (); }
virtual RegionDelegate *pull_interacting (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 (); } 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); 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> 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) 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 *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); 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, 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, 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 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; 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) compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2)
{ {
if ((iter1.layout () == 0) != (iter2.layout () == 0)) { 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)) { 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 // 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; 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 // if a region is set, the hierarchical appearance is the same only if the layers and
// complex region are identical // complex region are identical
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) { 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_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) { if (all) {
@ -349,6 +354,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
if (m_cell_stack.back ().first) { if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (inst, &mp_target->array_repository ()); db::CellInstArray new_inst (inst, &mp_target->array_repository ());
new_inst.object () = db::CellInst (new_cell); new_inst.object () = db::CellInst (new_cell);
new_inst.transform (always_apply);
new_inst.transform_into (m_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) { 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); (*c)->insert (new_inst);
@ -367,7 +373,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
} }
bool 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) { if (all) {
@ -386,7 +392,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
// for a new cell, create this instance // for a new cell, create this instance
if (m_cell_stack.back ().first) { 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); 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) { 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); (*c)->insert (new_inst);
@ -399,11 +405,11 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
} }
void 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) { 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); 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) { 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) { 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); mp_pipe->push (bb, trans, world, 0, target);
} }
} }

View File

@ -273,9 +273,9 @@ public:
virtual void end (const RecursiveShapeIterator *iter); 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 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 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 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 db::ICplxTrans &trans, 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 &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);
/** /**
* @brief Sets the target layer - shapes will be put there * @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 // 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 // object does not work. We overcome this problem by creating the object with new
// and catching exceptions. // 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 (""); pr->set_desc ("");
try { try {

View File

@ -632,6 +632,9 @@ LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutTo
} }
size_t pin_id = circuit->add_pin (pin).id (); 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) { if (net) {
circuit->connect_pin (pin_id, 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; *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 ()); const db::Net *net = subcircuit.net_for_pin (p->id ());
if (net) { if (net) {
if (separate_lines) { if (separate_lines) {
@ -569,7 +570,7 @@ void std_writer_impl<Keys>::write (const db::SubCircuit &subcircuit, std::map<co
} else { } else {
*mp_stream << " "; *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) { if (separate_lines) {
*mp_stream << endl; *mp_stream << endl;
} }

View File

@ -88,19 +88,19 @@ namespace db
* *
* [xref-def]: * [xref-def]:
* *
* circuit([non] [non] [status]? [circuit-xrefs]) * circuit([non] [non] [status]? [message]? [circuit-xrefs])
* - circuit pair [short key: X] * - circuit pair [short key: X]
* *
* [circuit-xrefs]: * [circuit-xrefs]:
* *
* xref([pair]*) * xref([pair]*) - circuit cross-reference part [short key: Z]
* *
* [pair] * [pair]
* *
* pin([ion] [ion] [status]?) - a pin pair [short key: P] * pin([ion] [ion] [status]? [message]?) - a pin pair [short key: P]
* device([ion] [ion] [status]?) - a device pair [short key: D] * device([ion] [ion] [status]? [message]?) - a device pair [short key: D]
* circuit([ion] [ion] [status]?) - a subcircuit pair [short key: X] * circuit([ion] [ion] [status]? [message]?) - a subcircuit pair [short key: X]
* net([ion] [ion] [status]?) - a net pair [short key: N] * net([ion] [ion] [status]? [message]?) - a net pair [short key: N]
* *
* [non] * [non]
* *
@ -110,6 +110,10 @@ namespace db
* *
* <id> | () * <id> | ()
* *
* [message]
*
* description(<name>) - error description [short key: B]
*
* [status] * [status]
* *
* mismatch | - [short key: 0] * 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) bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::Status &status)
{ {
if (test (skeys::match_key) || test (lkeys::match_key)) { 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); xref->gen_begin_circuit (circuit_a, circuit_b);
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
while (br) { while (br) {
if (read_status (status)) { if (read_status (status)) {
// continue // continue
} else if (read_message (msg)) {
// continue
} else if (test (skeys::xref_key) || test (lkeys::xref_key)) { } else if (test (skeys::xref_key) || test (lkeys::xref_key)) {
read_xrefs_for_circuits (xref, circuit_a, circuit_b); read_xrefs_for_circuits (xref, circuit_a, circuit_b);
} else if (at_end ()) { } 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 (); br.done ();
@ -325,11 +340,13 @@ void LayoutVsSchematicStandardReader::read_net_pair (db::NetlistCrossReference *
ion_b = read_ion (); ion_b = read_ion ();
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
read_status (status); read_status (status);
read_message (msg);
br.done (); 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) 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 (); ion_b = read_ion ();
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
read_status (status); read_status (status);
read_message (msg);
br.done (); 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) 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 (); ion_b = read_ion ();
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
read_status (status); read_status (status);
read_message (msg);
br.done (); 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) 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 (); ion_b = read_ion ();
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
std::string msg;
read_status (status); read_status (status);
read_message (msg);
br.done (); 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); void read_netlist (db::LayoutVsSchematic *lvs);
bool read_status (db::NetlistCrossReference::Status &status); bool read_status (db::NetlistCrossReference::Status &status);
bool read_message (std::string &msg);
void read_xref (db::NetlistCrossReference *xref); 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_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); 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 status_to_s (const db::NetlistCrossReference::Status status);
std::string message_to_s (const std::string &msg);
void write (const db::NetlistCrossReference *xref); 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; 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) { if (net) {
std::map<const db::Net *, unsigned int>::const_iterator i = net2id.find (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> template <class Keys>
std::string std_writer_impl<Keys>::status_to_s (const db::NetlistCrossReference::Status status) 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); const db::NetlistCrossReference::PerCircuitData *pcd = xref->per_circuit_data_for (*c);
tl_assert (pcd != 0); 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; stream () << indent2 << Keys::xref_key << "(" << endl;
for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) { 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) { 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) { 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) { 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; stream () << indent2 << ")" << endl;

View File

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

View File

@ -397,7 +397,7 @@ public:
* @brief A generic categorizer * @brief A generic categorizer
* *
* The objective of this class is to supply a category ID for a given object. * 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> template <class Obj>
class generic_categorizer 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 whether to use a device category in strict mode
device_categorizer.clear_strict_device_categories (); device_categorizer.clear_strict_device_categories ();
@ -3083,7 +3100,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
} else { } else {
if (mp_logger) { 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; good = false;
} }
@ -3130,24 +3147,61 @@ NetlistComparer::derive_pin_equivalence (const db::Circuit *ca, const db::Circui
circuit_pin_mapper->map_pins (cb, pb); 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 bool
NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const 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) { for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
const db::Circuit *cr = sc->circuit_ref (); const db::Circuit *cr = sc->circuit_ref ();
if (is_valid_circuit (cr) && verified_circuits.find (cr) == verified_circuits.end ()) {
// 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 ()) {
return false; return false;
} }
} }
return true; 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> > static std::vector<std::pair<size_t, size_t> >
compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict) 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 * @brief There is a device class mismatch
* "a" is null if there is no match for b and vice versa. * "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 * @brief Begin logging for circuit a and b
@ -74,19 +74,19 @@ public:
/** /**
* @brief End logging for circuit a and b * @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 * @brief Circuits are skipped
* Circuits are skipped if their subcircuits could not be matched. * 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 * @brief There is a circuit mismatch
* "a" is null if there is no match for b and vice versa. * "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 * @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 * Other nets might also match with a and also with b. Matching this a and b is
* an arbitrary decision. * 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 * @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 * nets are known not to match. Still the compare algorithm will proceed as
* if these nets were equivalent to derive further matches. * 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 * @brief Devices a and b match exactly
@ -128,7 +128,7 @@ public:
* @brief Device a or b doesn't match * @brief Device a or b doesn't match
* "a" is null if there is no match for b and vice versa. * "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 * @brief Pins a and b of the current circuit are matched
@ -139,7 +139,7 @@ public:
* @brief Pin a or b doesn't match * @brief Pin a or b doesn't match
* "a" is null if there is no match for b and vice versa. * "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 * @brief Subcircuits a and b match exactly
@ -150,7 +150,7 @@ public:
* @brief SubCircuit a or b doesn't match * @brief SubCircuit a or b doesn't match
* "a" is null if there is no match for b and vice versa. * "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: private:
// No copying // No copying
@ -346,6 +346,7 @@ private:
protected: 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 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; 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); 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_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; 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 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) { if (a) {
m_other_net [a] = b; m_other_net [a] = b;
} }
@ -350,9 +350,9 @@ NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Statu
} }
void 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) { if (a) {
m_other_device [a] = b; m_other_device [a] = b;
} }
@ -362,9 +362,9 @@ NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b,
} }
void 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) { if (a) {
m_other_pin [a] = b; m_other_pin [a] = b;
} }
@ -374,9 +374,9 @@ NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Statu
} }
void 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) { if (a) {
m_other_subcircuit [a] = b; m_other_subcircuit [a] = b;
} }
@ -403,36 +403,37 @@ NetlistCrossReference::sort_circuit ()
} }
void 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->status = status;
mp_per_circuit_data->msg = msg;
m_current_circuits = std::make_pair((const db::Circuit *)0, (const db::Circuit *)0); m_current_circuits = std::make_pair((const db::Circuit *)0, (const db::Circuit *)0);
mp_per_circuit_data = 0; mp_per_circuit_data = 0;
} }
void 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 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 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 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) 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; 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) { } NetPairData () : pair ((const db::Net *)0, (const db::Net *)0), status (None) { }
std::pair<const db::Net *, const db::Net *> pair; std::pair<const db::Net *, const db::Net *> pair;
Status status; Status status;
std::string msg;
}; };
struct DevicePairData struct DevicePairData
{ {
typedef db::Device object_type; 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) { } DevicePairData () : pair ((const db::Device *)0, (const db::Device *)0), status (None) { }
std::pair<const db::Device *, const db::Device *> pair; std::pair<const db::Device *, const db::Device *> pair;
Status status; Status status;
std::string msg;
}; };
struct PinPairData struct PinPairData
{ {
typedef db::Pin object_type; 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) { } PinPairData () : pair ((const db::Pin *)0, (const db::Pin *)0), status (None) { }
std::pair<const db::Pin *, const db::Pin *> pair; std::pair<const db::Pin *, const db::Pin *> pair;
Status status; Status status;
std::string msg;
}; };
struct SubCircuitPairData struct SubCircuitPairData
{ {
typedef db::SubCircuit object_type; 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) { } SubCircuitPairData () : pair ((const db::SubCircuit *)0, (const db::SubCircuit *)0), status (None) { }
std::pair<const db::SubCircuit *, const db::SubCircuit *> pair; std::pair<const db::SubCircuit *, const db::SubCircuit *> pair;
Status status; Status status;
std::string msg;
}; };
struct PerCircuitData struct PerCircuitData
@ -115,6 +119,7 @@ public:
typedef subcircuit_pairs_type::const_iterator subcircuit_pairs_const_iterator; typedef subcircuit_pairs_type::const_iterator subcircuit_pairs_const_iterator;
Status status; Status status;
std::string msg;
net_pairs_type nets; net_pairs_type nets;
device_pairs_type devices; device_pairs_type devices;
pin_pairs_type pins; pin_pairs_type pins;
@ -139,11 +144,11 @@ public:
void gen_begin_netlist (const db::Netlist *a, const db::Netlist *b); 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_end_netlist (const db::Netlist *a, const db::Netlist *b);
void gen_begin_circuit (const db::Circuit *a, const db::Circuit *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_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); 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); 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); 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); void gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg);
// db::NetlistCompareLogger interface // db::NetlistCompareLogger interface
virtual void begin_netlist (const db::Netlist *a, const db::Netlist *b) virtual void begin_netlist (const db::Netlist *a, const db::Netlist *b)
@ -162,77 +167,77 @@ public:
gen_begin_circuit (a, b); 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 (); 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_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_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) 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) 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) 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) 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) 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) 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 (); void clear ();
@ -292,10 +297,10 @@ private:
PerCircuitData *mp_per_circuit_data; PerCircuitData *mp_per_circuit_data;
void establish_pair (const db::Circuit *a, const db::Circuit *b); 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::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); 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); 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); void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg);
void sort_circuit (); void sort_circuit ();
void sort_netlist (); 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_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_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_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 // DeviceClassTwoTerminalDevice implementation

View File

@ -725,7 +725,7 @@ template DB_PUBLIC void split_polygon<> (const db::DSimplePolygon &polygon, std:
// Smoothing tools // Smoothing tools
void 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.clear ();
points.reserve (std::distance (from, to)); 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; 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 // jog configurations with small edges are candidates
can_drop = true; can_drop = true;
} else if (db::vprod_sign (p2 - p1, p1 - p0) < 0) { } 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 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; db::Polygon new_poly;
std::vector <db::Point> new_pts; 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) { if (new_pts.size () >= 3) {
new_poly.assign_hull (new_pts.begin (), new_pts.end (), false /*don't compress*/); new_poly.assign_hull (new_pts.begin (), new_pts.end (), false /*don't compress*/);
for (unsigned int h = 0; h < polygon.holes (); ++h) { for (unsigned int h = 0; h < polygon.holes (); ++h) {
new_pts.clear (); 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) { if (new_pts.size () >= 3) {
new_poly.insert_hole (new_pts.begin (), new_pts.end (), false /*don't compress*/); 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); 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 * @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 to The end of the contour
* @param new_pts The points that make up the new contour * @param new_pts The points that make up the new contour
* @param d The distance that determines the smoothing "roughness" * @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) * @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" * @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_current_layer = d.m_current_layer;
m_shape = d.m_shape; m_shape = d.m_shape;
m_trans = d.m_trans; m_trans = d.m_trans;
m_global_trans = d.m_global_trans;
m_trans_stack = d.m_trans_stack; m_trans_stack = d.m_trans_stack;
m_inst_iterators = d.m_inst_iterators; m_inst_iterators = d.m_inst_iterators;
m_inst_array_iterators = d.m_inst_array_iterators; m_inst_array_iterators = d.m_inst_array_iterators;
@ -286,6 +287,7 @@ RecursiveShapeIterator::init ()
m_shape_quad_id = 0; m_shape_quad_id = 0;
mp_cell = 0; mp_cell = 0;
m_current_layer = 0; m_current_layer = 0;
m_global_trans = cplx_trans_type ();
} }
void 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 void
RecursiveShapeIterator::set_region (const box_type &region) RecursiveShapeIterator::set_region (const box_type &region)
{ {
@ -420,13 +442,13 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
m_inst_quad_id_stack.clear (); m_inst_quad_id_stack.clear ();
m_inst_array_iterators.clear (); m_inst_array_iterators.clear ();
m_cells.clear (); m_cells.clear ();
m_trans = cplx_trans_type (); m_trans = m_global_trans;
m_current_layer = 0; m_current_layer = 0;
m_shape = shape_iterator (); m_shape = shape_iterator ();
m_shape_quad_id = 0; m_shape_quad_id = 0;
m_local_region_stack.clear (); 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 (); m_local_complex_region_stack.clear ();
if (mp_complex_region.get ()) { if (mp_complex_region.get ()) {
@ -571,6 +593,8 @@ RecursiveShapeIterator::bbox () const
} }
} }
box = box.transformed (m_global_trans);
if (m_region != box_type::world ()) { if (m_region != box_type::world ()) {
box &= m_region; box &= m_region;
} }
@ -749,8 +773,8 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
box_type new_region = box_type::world (); box_type new_region = box_type::world ();
// compute the region inside the new cell // compute the region inside the new cell
if (new_region != m_local_region_stack.front ()) { if (new_region != m_region) {
new_region = m_trans.inverted () * m_local_region_stack.front (); new_region = m_trans.inverted () * m_region;
new_region &= cell ()->bbox (); new_region &= cell ()->bbox ();
} }
m_local_region_stack.push_back (new_region); 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; RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all;
if (receiver) { 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) { if (ni == RecursiveShapeReceiver::NI_skip) {
@ -956,7 +980,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
} }
while (! m_inst_array.at_end () && receiver) { 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; break;
} else { } else {
++m_inst_array; ++m_inst_array;
@ -999,7 +1023,7 @@ RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
validate (receiver); validate (receiver);
while (! at_end ()) { 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); 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 * @brief Reset the iterator
*/ */
@ -727,6 +751,7 @@ private:
bool m_shape_inv_prop_sel; bool m_shape_inv_prop_sel;
bool m_overlapping; bool m_overlapping;
std::set<db::cell_index_type> m_start, m_stop; std::set<db::cell_index_type> m_start, m_stop;
cplx_trans_type m_global_trans;
const layout_type *mp_layout; const layout_type *mp_layout;
const cell_type *mp_top_cell; const cell_type *mp_top_cell;
@ -881,7 +906,7 @@ public:
* - NI_single: iterate a single member (the first one) * - NI_single: iterate a single member (the first one)
* - NI_skip: skips the whole array (not a single instance is iterated) * - 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 * @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. * 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 * @brief Delivers a shape
* *
* @param trans The transformation which maps the shape to the top cell. * @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 } // namespace db

View File

@ -265,15 +265,15 @@ Region::rounded_corners (double rinner, double router, unsigned int n) const
} }
void void
Region::smooth (coord_type d) Region::smooth (coord_type d, bool keep_hv)
{ {
process (SmoothingProcessor (d)); process (SmoothingProcessor (d, keep_hv));
} }
Region 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 void

View File

@ -267,6 +267,16 @@ public:
return mp_delegate; 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 * @brief Sets the base verbosity
* *
@ -1132,6 +1142,19 @@ public:
return Region (mp_delegate->selected_not_outside (other)); 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 * @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)); 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 * @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)); 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 * @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)); 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 * @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)); 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 * @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)); 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 * @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)); 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 * @brief Returns all polygons of "other" which are inside polygons of this region
* *
@ -1518,14 +1619,14 @@ public:
/** /**
* @brief Smoothes the region (in-place) * @brief Smoothes the region (in-place)
*/ */
void smooth (coord_type d); void smooth (coord_type d, bool keep_hv);
/** /**
* @brief Returns the smoothed region * @brief Returns the smoothed region
* *
* @param d The smoothing accuracy * @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 * @brief Returns the nth polygon

View File

@ -281,18 +281,25 @@ public:
virtual RegionDelegate *selected_outside (const Region &other) const = 0; virtual RegionDelegate *selected_outside (const Region &other) const = 0;
virtual RegionDelegate *selected_not_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_inside (const Region &other) const = 0;
virtual RegionDelegate *selected_not_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_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 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_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 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_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 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_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 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_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 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_inside (const Region &other) const = 0;
virtual RegionDelegate *pull_interacting (const Region &other) const = 0; virtual RegionDelegate *pull_interacting (const Region &other) const = 0;
virtual EdgesDelegate *pull_interacting (const Edges &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> 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) 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_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (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 .. // .. nothing yet ..
} }
@ -552,8 +552,13 @@ db::Coord interacting_local_operation<TS, TI, TR>::dist () const
template <class TS, class TI, class TR> 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 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); if (m_output_mode == None) {
std::unordered_set<TR> &result = results.front (); 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; 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 ()) { if (c != interaction_counts.end ()) {
count = c->second; count = c->second;
} }
if ((count >= m_min_count && count <= m_max_count) != m_inverse) { bool good = (count >= m_min_count && count <= m_max_count);
const TS &subject = interactions.subject_shape (i->first); if (good) {
result.insert (subject); 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 OnEmptyIntruderHint
interacting_local_operation<TS, TI, TR>::on_empty_intruder_hint () const interacting_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
{ {
if ((m_mode <= 0) != m_inverse) { if ((m_mode <= 0)) {
return OnEmptyIntruderHint::Drop; 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 { } 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> 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> 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) 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_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (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 .. // .. 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> 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 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; std::unordered_map<TR, size_t> counted_results;
bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits<size_t>::max ()); 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); const TR *addressable = push_polygon_to_heap (layout, subject, heap);
scanner.insert1 (addressable, 0); scanner.insert1 (addressable, 0);
if (m_inverse) { if (m_output_mode == Negative || m_output_mode == PositiveAndNegative) {
inserter.init (*addressable); 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 // 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) { 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; bool hit = r->second >= m_min_count && r->second <= m_max_count;
if (hit != m_inverse) { if (hit) {
result.insert (r->first); 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> template <class TS, class TI, class TR>
OnEmptyIntruderHint interacting_with_edge_local_operation<TS, TI, TR>::on_empty_intruder_hint () const 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; return OnEmptyIntruderHint::Drop;
} else { } else if (m_output_mode == Negative) {
return OnEmptyIntruderHint::Copy; 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> 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) 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_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) : m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
{ {
// .. nothing yet .. // .. 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> 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 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; std::unordered_map<TR, size_t> counted_results;
bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits<size_t>::max ()); 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); const TR *addressable = push_polygon_to_heap (layout, interactions.subject_shape (i->first), heap);
scanner.insert1 (addressable, 0); scanner.insert1 (addressable, 0);
if (m_inverse) { if (m_output_mode == Negative || m_output_mode == PositiveAndNegative) {
inserter.init (*addressable); 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 // 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) { 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; bool hit = r->second >= m_min_count && r->second <= m_max_count;
if (hit != m_inverse) { if (hit) {
result.insert (r->first); 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> template <class TS, class TI, class TR>
OnEmptyIntruderHint interacting_with_text_local_operation<TS, TI, TR>::on_empty_intruder_hint () const 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; return OnEmptyIntruderHint::Drop;
} else { } else if (m_output_mode == Negative) {
return OnEmptyIntruderHint::Copy; 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; 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> template <class TS, class TI, class TR>
class interacting_local_operation class interacting_local_operation
: public local_operation<TS, TI, TR> : public local_operation<TS, TI, TR>
{ {
public: 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 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; 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: private:
int m_mode; int m_mode;
bool m_touching; bool m_touching;
bool m_inverse; InteractingOutputMode m_output_mode;
size_t m_min_count, m_max_count; size_t m_min_count, m_max_count;
bool m_other_is_merged; bool m_other_is_merged;
}; };
@ -268,7 +272,7 @@ class interacting_with_edge_local_operation
: public local_operation<TS, TI, TR> : public local_operation<TS, TI, TR>
{ {
public: 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 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; 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; virtual std::string description () const;
private: private:
bool m_inverse; InteractingOutputMode m_output_mode;
size_t m_min_count, m_max_count; size_t m_min_count, m_max_count;
bool m_other_is_merged; bool m_other_is_merged;
}; };
@ -303,7 +307,7 @@ class interacting_with_text_local_operation
: public local_operation<TS, TI, TR> : public local_operation<TS, TI, TR>
{ {
public: 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 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; 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; virtual std::string description () const;
private: private:
bool m_inverse; InteractingOutputMode m_output_mode;
size_t m_min_count, m_max_count; 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 // 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 () { } SmoothingProcessor::~SmoothingProcessor () { }
void void
SmoothingProcessor::process (const db::Polygon &poly, std::vector<db::Polygon> &res) const 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 PolygonProcessorBase
{ {
public: public:
SmoothingProcessor (db::Coord d); SmoothingProcessor (db::Coord d, bool keep_hv);
~SmoothingProcessor (); ~SmoothingProcessor ();
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const; virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const;
@ -517,6 +517,7 @@ public:
private: private:
db::Coord m_d; db::Coord m_d;
bool m_keep_hv;
db::MagnificationReducer m_vars; db::MagnificationReducer m_vars;
}; };

View File

@ -190,17 +190,17 @@ public:
m_circuit = circuit2str (a) + " vs. " + circuit2str (b); 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)); 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)); 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)); out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
} }
@ -210,12 +210,12 @@ public:
out ("match_nets " + net2str (a) + " " + net2str (b)); 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)); 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)); out ("net_mismatch " + net2str (a) + " " + net2str (b));
} }
@ -225,7 +225,7 @@ public:
out ("match_devices " + device2str (a) + " " + device2str (b)); 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)); out ("device_mismatch " + device2str (a) + " " + device2str (b));
} }
@ -245,7 +245,7 @@ public:
out ("match_pins " + pin2str (a) + " " + pin2str (b)); 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)); out ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
} }
@ -255,7 +255,7 @@ public:
out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b)); 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)); 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*/); 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"); 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) 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" "@brief Creates a node extracting strange polygons.\n"
"'strange polygons' are ones which cannot be oriented - e.g. '8' shape polygons." "'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" "@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"), 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" "@brief Creates a node generating rounded corners.\n"

View File

@ -66,18 +66,18 @@ public:
db::NetlistCompareLogger::end_netlist (a, b); 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 ()) { 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 { } else {
db::NetlistCompareLogger::device_class_mismatch (a, b); 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) virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b)
@ -94,46 +94,46 @@ public:
db::NetlistCompareLogger::begin_circuit (a, b); 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 ()) { 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 { } else {
db::NetlistCompareLogger::end_circuit (a, b, matching); 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 ()) { 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 { } else {
db::NetlistCompareLogger::circuit_skipped (a, b); 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 ()) { 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 { } else {
db::NetlistCompareLogger::circuit_mismatch (a, b); 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) virtual void match_nets (const db::Net *a, const db::Net *b)
@ -150,32 +150,32 @@ public:
db::NetlistCompareLogger::match_nets (a, b); 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 ()) { 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 { } else {
db::NetlistCompareLogger::match_ambiguous_nets (a, b); 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 ()) { 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 { } else {
db::NetlistCompareLogger::net_mismatch (a, b); 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) 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); 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 ()) { 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 { } else {
db::NetlistCompareLogger::device_mismatch (a, b); 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) virtual void match_pins (const db::Pin *a, const db::Pin *b)
@ -248,18 +248,18 @@ public:
db::NetlistCompareLogger::match_pins (a, b); 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 ()) { 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 { } else {
db::NetlistCompareLogger::pin_mismatch (a, b); 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) virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
@ -276,18 +276,18 @@ public:
db::NetlistCompareLogger::match_subcircuits (a, b); 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 ()) { 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 { } else {
db::NetlistCompareLogger::subcircuit_mismatch (a, b); 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; 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" "@brief This function is called at the end of the compare process.\n"
"This method is called once when the compare run ended.\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" "@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 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" "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 " "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" "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" "@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" "The 'matching' argument indicates whether the circuits have been identified as identical.\n"
"See \\begin_circuit for details." "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" "@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 " "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" "both circuits.\n"
"\n" "\n"
"This method is called instead of \\begin_circuit and \\end_circuit." "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" "@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 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" "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 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" "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" "@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 " "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. " "compare will fail later. Looking for ambiguous nets allows deduction of the origin of this faulty decision. "
"See \\match_nets for more details." "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" "@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 " "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" "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" "@brief This function is called when two devices are identified but have different device classes.\n"
"See \\match_devices for details.\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" "@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. " "This will report the device considered in a or b. The other argument is nil. "
"See \\match_devices for details.\n" "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 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." "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" "@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. " "This will report the pin considered in a or b. The other argument is nil. "
"See \\match_pins for details.\n" "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 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." "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" "@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. " "This will report the subcircuit considered in a or b. The other argument is nil. "
"See \\match_subcircuits for details.\n" "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*/); 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) 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" "\n"
"This method was introduced in version 0.22.\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" "@brief Smoothes a polygon\n"
"\n" "\n"
"Remove vertices that deviate by more than the distance d from the average contour.\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" "The value d is basically the roughness which is removed.\n"
"\n" "\n"
"@param d The smoothing \"roughness\".\n" "@param d The smoothing \"roughness\".\n"
"@param keep_hv If true, horizontal and vertical edges will be preserved always.\n"
"\n" "\n"
"@return The smoothed polygon.\n" "@return The smoothed polygon.\n"
"\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"), 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" "@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 ()); 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) static void select_cells1 (db::RecursiveShapeIterator *r, const std::vector<db::cell_index_type> &cells)
{ {
std::set<db::cell_index_type> cc; std::set<db::cell_index_type> cc;
@ -270,7 +291,47 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n" "\n"
"This method has been introduced in version 0.23.\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" "@brief Gets the basic region that is iterator is using\n"
"The basic region is the overall box the region iterator iterates over. " "The basic region is the overall box the region iterator iterates over. "
"There may be an additional complex region that confines the region iterator. " "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) 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; static std::vector<db::Region> split_inside (const db::Region *r, const db::Region &other)
res.resize (2, db::Region ()); {
res [0] = rp.first; return as_2region_vector (r->selected_inside_differential (other));
res [1] = rp.second; }
return res;
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> template <class Container>
@ -705,6 +743,7 @@ int po_any ();
extern Class<db::ShapeCollection> decl_dbShapeCollection; extern Class<db::ShapeCollection> decl_dbShapeCollection;
Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region", Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
constructor ("new", &new_v, constructor ("new", &new_v,
"@brief Default constructor\n" "@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 which have the given perimeter are returned. If \"inverse\" is true, "
"polygons not having the given perimeter are returned.\n" "polygons not having the given perimeter are returned.\n"
"\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"), method_ext ("with_perimeter", with_perimeter2, gsi::arg ("min_perimeter"), gsi::arg ("max_perimeter"), gsi::arg ("inverse"),
"@brief Filter the polygons by perimeter\n" "@brief Filter the polygons by perimeter\n"
@ -939,7 +978,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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"), method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"),
"@brief Filter the polygons by area\n" "@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 which have the given area are returned. If \"inverse\" is true, "
"polygons not having the given area are returned.\n" "polygons not having the given area are returned.\n"
"\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"), method_ext ("with_area", with_area2, gsi::arg ("min_area"), gsi::arg ("max_area"), gsi::arg ("inverse"),
"@brief Filter the polygons by area\n" "@brief Filter the polygons by area\n"
@ -959,7 +998,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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"), method_ext ("with_holes", with_holes1, gsi::arg ("nholes"), gsi::arg ("inverse"),
"@brief Filters the polygons by their number of holes\n" "@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 which have the given number of holes are returned. If \"inverse\" is true, "
"polygons not having the given of holes are returned.\n" "polygons not having the given of holes are returned.\n"
"\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" "\n"
"This method has been introduced in version 0.27.\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" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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" "\n"
"This method has been introduced in version 0.27.\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 has the given width are returned. If \"inverse\" is true, "
"polygons whose bounding box does not have the given width are returned.\n" "polygons whose bounding box does not have the given width are returned.\n"
"\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"), 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" "@brief Filter the polygons by bounding box width\n"
@ -1001,7 +1040,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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"), method_ext ("with_bbox_height", with_bbox_height1, gsi::arg ("height"), gsi::arg ("inverse"),
"@brief Filter the polygons by bounding box height\n" "@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 has the given height are returned. If \"inverse\" is true, "
"polygons whose bounding box does not have the given height are returned.\n" "polygons whose bounding box does not have the given height are returned.\n"
"\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"), 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" "@brief Filter the polygons by bounding box height\n"
@ -1019,7 +1058,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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"), 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" "@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. " "are returned. "
"If \"inverse\" is true, all polygons not matching this criterion are returned." "If \"inverse\" is true, all polygons not matching this criterion 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_min", with_bbox_min2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"), 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" "@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" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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"), 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" "@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. " "are returned. "
"If \"inverse\" is true, all polygons not matching this criterion are returned." "If \"inverse\" is true, all polygons not matching this criterion 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_max", with_bbox_max2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"), 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" "@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" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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"), 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" "@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 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" "With 'inverse' set to true, all other polygons will be returned.\n"
"\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" "\n"
"This method has been introduced in version 0.27.\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" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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" "\n"
"This method has been introduced in version 0.27.\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 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" "With 'inverse' set to true, all other polygons will be returned.\n"
"\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" "\n"
"This method has been introduced in version 0.27.\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" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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" "\n"
"This method has been introduced in version 0.27.\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 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" "With 'inverse' set to true, all other polygons will be returned.\n"
"\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" "\n"
"This method has been introduced in version 0.27.\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" "\n"
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
"\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" "\n"
"This method has been introduced in version 0.27.\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" "@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" "Strange parts of polygons are self-overlapping parts or non-orientable parts (i.e. in the \"8\" configuration).\n"
"\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"), method ("snapped", &db::Region::snapped, gsi::arg ("gx"), gsi::arg ("gy"),
"@brief Returns the snapped region\n" "@brief Returns the snapped region\n"
@ -1167,7 +1206,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"If gx or gy is 0, no snapping happens in that direction.\n" "If gx or gy is 0, no snapping happens in that direction.\n"
"\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"), 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" "@brief Returns the scaled and snapped region\n"
@ -1183,7 +1222,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"If gx or gy is 0, the result is brought on a grid of 1.\n" "If gx or gy is 0, the result is brought on a grid of 1.\n"
"\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" "\n"
"This method has been introduced in version 0.26.1." "This method has been introduced in version 0.26.1."
) + ) +
@ -1195,7 +1234,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"If gx or gy is 0 or less, the grid is not checked in that direction.\n" "If gx or gy is 0 or less, the grid is not checked in that direction.\n"
"\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"), 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" "@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" "\n"
"The edge pair objects returned will contain both edges forming the angle.\n" "The edge pair objects returned will contain both edges forming the angle.\n"
"\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"), 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" "@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" "\n"
"The edge pair objects returned will contain both edges forming the angle.\n" "The edge pair objects returned will contain both edges forming the angle.\n"
"\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"), method ("insert", (void (db::Region::*)(const db::Box &)) &db::Region::insert, gsi::arg ("box"),
"@brief Inserts a box\n" "@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 " "The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n" "of these boxes for example.\n"
"\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"), method_ext ("extents", &extents1, gsi::arg ("d"),
"@brief Returns a region with the enlarged bounding boxes of the polygons\n" "@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 " "The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n" "of these boxes for example.\n"
"\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"), method_ext ("extents", &extents2, gsi::arg ("dx"), gsi::arg ("dy"),
"@brief Returns a region with the enlarged bounding boxes of the polygons\n" "@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 " "The boxes will not be merged, so it is possible to determine overlaps "
"of these boxes for example.\n" "of these boxes for example.\n"
"\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, method_ext ("extent_refs", &extent_refs,
"@hide\n" "@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 " "See \\round_corners for a description of this method. This version returns a new region instead of "
"modifying self (out-of-place)." "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" "@brief Smoothing\n"
"@param d The smoothing tolerance (in database units)\n" "@param d The smoothing tolerance (in database units)\n"
"@param keep_hv If true, horizontal and vertical edges are maintained\n"
"\n" "\n"
"This method will simplify the merged polygons of the region by removing vertexes if the " "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 " "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 " "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" "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" "@brief Smoothing\n"
"@param d The smoothing tolerance (in database units)\n" "@param d The smoothing tolerance (in database units)\n"
"@param keep_hv If true, horizontal and vertical edges are maintained\n"
"\n" "\n"
"See \\smooth for a description of this method. This version returns a new region instead of " "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." "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" "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" "(0:>0, 1:>45, 2:>90, 3:>135, 4:>approx. 168, other:>approx. 179)\n"
"\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" "\n"
"The result is a set of polygons which may be overlapping, but are not self-\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" "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" "\n"
"This method is equivalent to \"size(d, d, mode)\".\n" "This method is equivalent to \"size(d, d, mode)\".\n"
"\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"), method_ext ("size", size_ext, gsi::arg ("d"),
"@brief Isotropic sizing (biasing)\n" "@brief Isotropic sizing (biasing)\n"
@ -1499,7 +1540,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"This method is equivalent to \"size(d, d, 2)\".\n" "This method is equivalent to \"size(d, d, 2)\".\n"
"\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"), 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" "@brief Returns the anisotropically sized region\n"
@ -1508,7 +1549,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"This method is returns the sized region (see \\size), but does not modify self.\n" "This method is returns the sized region (see \\size), but does not modify self.\n"
"\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"), 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" "@brief Returns the isotropically sized region\n"
@ -1517,7 +1558,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"This method is returns the sized region (see \\size), but does not modify self.\n" "This method is returns the sized region (see \\size), but does not modify self.\n"
"\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"), method_ext ("sized", sized_ext, gsi::arg ("d"),
"@brief Isotropic sizing (biasing)\n" "@brief Isotropic sizing (biasing)\n"
@ -1526,7 +1567,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"This method is equivalent to \"sized(d, d, 2)\".\n" "This method is equivalent to \"sized(d, d, 2)\".\n"
"\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"), method_ext ("andnot", &andnot, gsi::arg ("other"),
"@brief Returns the boolean AND and NOT between self and the other region\n" "@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" "\n"
"@return A new region containing the polygons which are covering polygons from the other region\n" "@return A new region containing the polygons which are covering polygons from the other region\n"
"\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" "\n"
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n" "This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
"\n" "\n"
@ -1634,18 +1675,28 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"@return A new region containing the polygons which are not covering polygons from the other region\n" "@return A new region containing the polygons which are not covering polygons from the other region\n"
"\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" "\n"
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n" "This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
"\n" "\n"
"This method has been introduced in version 0.27." "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"), 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" "@brief Selects the polygons of this region which are completely covering polygons from the other region\n"
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n" "This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
"\n" "\n"
@ -1656,7 +1707,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n" "This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
"\n" "\n"
@ -1667,56 +1718,76 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"@return A new region containing the polygons which are inside polygons from the other region\n" "@return A new region containing the polygons which are inside polygons from the other region\n"
"\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"), 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" "@brief Returns the polygons of this region which are not completely inside polygons from the other region\n"
"\n" "\n"
"@return A new region containing the polygons which are not inside polygons from the other region\n" "@return A new region containing the polygons which are not inside polygons from the other region\n"
"\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"), 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" "@brief Selects the polygons of this region which are completely inside polygons from the other region\n"
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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"), 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" "@brief Selects the polygons of this region which are not completely inside polygons from the other region\n"
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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"), 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" "@brief Returns the polygons of this region which are completely outside polygons from the other region\n"
"\n" "\n"
"@return A new region containing the polygons which are outside polygons from the other region\n" "@return A new region containing the polygons which are outside polygons from the other region\n"
"\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"), 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" "@brief Returns the polygons of this region which are not completely outside polygons from the other region\n"
"\n" "\n"
"@return A new region containing the polygons which are not outside polygons from the other region\n" "@return A new region containing the polygons which are not outside polygons from the other region\n"
"\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"), 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" "@brief Selects the polygons of this region which are completely outside polygons from the other region\n"
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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"), 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" "@brief Selects the polygons of this region which are not completely outside polygons from the other region\n"
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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"), 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" "@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" "\n"
"@return A new region containing the polygons overlapping or touching polygons from the other region\n" "@return A new region containing the polygons overlapping or touching polygons from the other region\n"
"\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" "\n"
"The min_count and max_count arguments have been added in version 0.27.\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" "\n"
"@return A new region containing the polygons not overlapping or touching polygons from the other region\n" "@return A new region containing the polygons not overlapping or touching polygons from the other region\n"
"\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" "\n"
"The min_count and max_count arguments have been added in version 0.27.\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"), 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" "@brief Selects the polygons from this region which overlap or touch polygons from the other region\n"
"\n" "\n"
@ -1756,7 +1837,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"The min_count and max_count arguments have been added in version 0.27.\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" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"The min_count and max_count arguments have been added in version 0.27.\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" "\n"
"@return A new region containing the polygons overlapping or touching edges from the edge collection\n" "@return A new region containing the polygons overlapping or touching edges from the edge collection\n"
"\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" "\n"
"This method has been introduced in version 0.25.\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" "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" "\n"
"@return A new region containing the polygons not overlapping or touching edges from the edge collection\n" "@return A new region containing the polygons not overlapping or touching edges from the edge collection\n"
"\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" "\n"
"This method has been introduced in version 0.25\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" "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"), 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" "@brief Selects the polygons from this region which overlap or touch edges from the edge collection\n"
"\n" "\n"
@ -1814,7 +1905,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"This method has been introduced in version 0.25\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" "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" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"This method has been introduced in version 0.25\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" "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" "\n"
"@return A new region containing the polygons overlapping or touching texts\n" "@return A new region containing the polygons overlapping or touching texts\n"
"\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" "\n"
"This method has been introduced in version 0.27\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" "\n"
"@return A new region containing the polygons not overlapping or touching texts\n" "@return A new region containing the polygons not overlapping or touching texts\n"
"\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" "\n"
"This method has been introduced in version 0.27\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"), 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" "@brief Selects the polygons of this region which overlap or touch texts\n"
"\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 " "selected by this method if the number of texts interacting with the polygon is between min_count and max_count "
"(including max_count).\n" "(including max_count).\n"
"\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" "\n"
"This method has been introduced in version 0.27\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" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"This method has been introduced in version 0.27\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" "\n"
"@return A new region containing the polygons overlapping polygons from the other region\n" "@return A new region containing the polygons overlapping polygons from the other region\n"
"\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" "\n"
"The count options have been introduced in version 0.27." "The count options have been introduced in version 0.27."
) + ) +
@ -1904,16 +2005,26 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"@return A new region containing the polygons not overlapping polygons from the other region\n" "@return A new region containing the polygons not overlapping polygons from the other region\n"
"\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" "\n"
"The count options have been introduced in version 0.27." "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"), 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" "@brief Selects the polygons from this region which overlap polygons from the other region\n"
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"The count options have been introduced in version 0.27." "The count options have been introduced in version 0.27."
) + ) +
@ -1922,7 +2033,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"@return The region after the polygons have been selected (self)\n" "@return The region after the polygons have been selected (self)\n"
"\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" "\n"
"The count options have been introduced in version 0.27." "The count options have been introduced in version 0.27."
) + ) +
@ -1935,7 +2046,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n" "\n"
"@return The region after the polygons have been selected (from other)\n" "@return The region after the polygons have been selected (from other)\n"
"\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" "\n"
"This method has been introduced in version 0.26.1\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" "\n"
"@return The region after the polygons have been selected (from other)\n" "@return The region after the polygons have been selected (from other)\n"
"\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" "\n"
"This method has been introduced in version 0.26.1\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" "\n"
"@return The region after the polygons have been selected (from other)\n" "@return The region after the polygons have been selected (from other)\n"
"\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" "\n"
"This method has been introduced in version 0.26.1\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" "\n"
"@return The edge collection after the edges have been selected (from other)\n" "@return The edge collection after the edges have been selected (from other)\n"
"\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" "\n"
"This method has been introduced in version 0.26.1\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" "\n"
"@return The text collection after the texts have been selected (from other)\n" "@return The text collection after the texts have been selected (from other)\n"
"\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" "\n"
"This method has been introduced in version 0.27\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 " "The edge collection returned can be manipulated in various ways. See \\Edges for a description of the "
"possibilities of the edge collection.\n" "possibilities of the edge collection.\n"
"\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"), 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" "@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" "@brief Returns the holes of the region\n"
"This method returns all holes as filled polygons.\n" "This method returns all holes as filled polygons.\n"
"\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 " "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) " "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" "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" "@brief Returns the hulls of the region\n"
"This method returns all hulls as polygons. The holes will be removed (filles). " "This method returns all hulls as polygons. The holes will be removed (filles). "
"\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 hull may also enclose holes if the polygons " "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) " "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" "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, method_ext ("rectangles", &rectangles,
"@brief Returns all polygons which are rectangles\n" "@brief Returns all polygons which are rectangles\n"
"This method returns all polygons in self which are rectangles." "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, method_ext ("non_rectangles", &non_rectangles,
"@brief Returns all polygons which are not rectangles\n" "@brief Returns all polygons which are not rectangles\n"
"This method returns all polygons in self which are not rectangles." "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, method_ext ("squares", &squares,
"@brief Returns all polygons which are squares\n" "@brief Returns all polygons which are squares\n"
"This method returns all polygons in self which are squares." "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" "\n"
"This method has been introduced in version 0.27.\n" "This method has been introduced in version 0.27.\n"
) + ) +
method_ext ("non_squares", &non_squares, method_ext ("non_squares", &non_squares,
"@brief Returns all polygons which are not squares\n" "@brief Returns all polygons which are not squares\n"
"This method returns all polygons in self which are not squares." "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" "\n"
"This method has been introduced in version 0.27.\n" "This method has been introduced in version 0.27.\n"
) + ) +
method_ext ("rectilinear", &rectilinear, method_ext ("rectilinear", &rectilinear,
"@brief Returns all polygons which are rectilinear\n" "@brief Returns all polygons which are rectilinear\n"
"This method returns all polygons in self which are rectilinear." "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, method_ext ("non_rectilinear", &non_rectilinear,
"@brief Returns all polygons which are not rectilinear\n" "@brief Returns all polygons which are not rectilinear\n"
"This method returns all polygons in self which are not rectilinear." "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), 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" "@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" "with a pencil that has the shape of the given region.\n"
"\n" "\n"
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method." "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"), method_ext ("minkowsky_sum", &minkowsky_sum_pp, gsi::arg ("p"),
"@brief Compute the Minkowsky sum of the region and a polygon\n" "@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" "the region with a pen that has the shape of the second polygon.\n"
"\n" "\n"
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method." "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"), method_ext ("minkowsky_sum", &minkowsky_sum_pb, gsi::arg ("b"),
"@brief Compute the Minkowsky sum of the region and a box\n" "@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" "as the second polygon.\n"
"\n" "\n"
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method." "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"), 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" "@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" "with a pencil that has the shape of the given region.\n"
"\n" "\n"
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method." "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"), method_ext ("move", &move_p, gsi::arg ("v"),
"@brief Moves the region\n" "@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 " "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" "false. In general, this will improve performance somewhat.\n"
"\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" "\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27." "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. " "\"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" "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\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" "\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." "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 " "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" "false. In general, this will improve performance somewhat.\n"
"\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" "\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27." "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. " "\"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" "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\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" "\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." "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. " "\"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" "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\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" "\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." "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. " "\"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" "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\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" "\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." "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. " "\"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" "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\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" "\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." "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. " "\"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" "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
"\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" "\n"
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." "The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
) + ) +
method_ext ("area", &area1, method_ext ("area", &area1,
"@brief The area of the region\n" "@brief The area of the region\n"
"\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" "If merged semantics is not enabled, overlapping areas are counted twice.\n"
) + ) +
method_ext ("area", &area2, gsi::arg ("rect"), method_ext ("area", &area2, gsi::arg ("rect"),
"@brief The area of the region (restricted to a rectangle)\n" "@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" "This version will compute the area of the shapes, restricting the computation to the given rectangle.\n"
"\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" "If merged semantics is not enabled, overlapping areas are counted twice.\n"
) + ) +
method_ext ("perimeter", &perimeter1, method_ext ("perimeter", &perimeter1,
"@brief The total perimeter of the polygons\n" "@brief The total perimeter of the polygons\n"
"\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" "If merged semantics is not enabled, internal edges are counted as well.\n"
) + ) +
method_ext ("perimeter", &perimeter2, gsi::arg ("rect"), 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 " "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" "side toward the rectangle (in other words: outside edges must coincide with the rectangle's border in order to be counted).\n"
"\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" "If merged semantics is not enabled, internal edges are counted as well.\n"
) + ) +
method ("bbox", &db::Region::bbox, method ("bbox", &db::Region::bbox,

View File

@ -733,7 +733,8 @@ TEST(11_RoundAndSmoothed)
r1_sized -= r1; r1_sized -= r1;
db::Region rounded = r1_sized.rounded_corners (3000, 5000, 100); 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; db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); 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 (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 (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 (12, 0)), smoothed);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), smoothed_keep_hv);
CHECKPOINT(); CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au11.gds"); 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)); 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")); 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)); 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)); 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)); out ("device_class_mismatch " + dc2str (a) + " " + dc2str (b));
} }
@ -69,12 +69,12 @@ public:
out ("match_nets " + net2str (a) + " " + net2str (b)); 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)); 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)); out ("net_mismatch " + net2str (a) + " " + net2str (b));
} }
@ -84,7 +84,7 @@ public:
out ("match_devices " + device2str (a) + " " + device2str (b)); 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)); out ("device_mismatch " + device2str (a) + " " + device2str (b));
} }
@ -104,7 +104,7 @@ public:
out ("match_pins " + pin2str (a) + " " + pin2str (b)); 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)); out ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
} }
@ -114,7 +114,7 @@ public:
out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b)); 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)); out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b));
} }
@ -954,7 +954,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (good, false); EXPECT_EQ (good, false);
logger.clear (); 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); good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (), EXPECT_EQ (logger.text (),
@ -980,7 +980,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (good, true); EXPECT_EQ (good, true);
logger.clear (); 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); good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (), EXPECT_EQ (logger.text (),
@ -1006,7 +1006,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (good, false); EXPECT_EQ (good, false);
logger.clear (); 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); good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (), EXPECT_EQ (logger.text (),
@ -1032,7 +1032,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
EXPECT_EQ (good, false); EXPECT_EQ (good, false);
logger.clear (); 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); good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (), EXPECT_EQ (logger.text (),
@ -1059,7 +1059,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
logger.clear (); logger.clear ();
db::EqualDeviceParameters eq_dp = db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W) + db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.2, 0.0); 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); good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (), EXPECT_EQ (logger.text (),
@ -1086,7 +1086,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
logger.clear (); logger.clear ();
eq_dp = db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W) + db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L); 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); good = comp.compare (&nl1, &nl2);
EXPECT_EQ (logger.text (), EXPECT_EQ (logger.text (),

View File

@ -1219,8 +1219,8 @@ TEST(100)
db::Polygon p; db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); 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, 5, true).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, 20, true).to_string (), "(0,-100;0,0;150,0;150,-100)");
} }
// smoothing // smoothing
@ -1238,8 +1238,8 @@ TEST(101)
db::Polygon p; db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); 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, 5, true).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, 20, true).to_string (), "(0,0;0,100;150,100;150,0)");
} }
// smoothing // smoothing
@ -1255,8 +1255,8 @@ TEST(102)
db::Polygon p; db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
EXPECT_EQ (smooth (p, 20).to_string (), "()"); EXPECT_EQ (smooth (p, 20, true).to_string (), "()");
EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;150,0;0,0;50,10)"); EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;150,0;0,0;50,10)");
} }
// smoothing // smoothing
@ -1282,9 +1282,9 @@ TEST(103)
db::Polygon p; db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); 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, 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).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)"); 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).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)"); EXPECT_EQ (smooth (p, 5000, true).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)");
} }
// smoothing // smoothing
@ -1303,7 +1303,8 @@ TEST(104)
db::Polygon p; db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); 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 // smoothing
@ -1323,11 +1324,46 @@ TEST(105)
db::Polygon p; db::Polygon p;
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0])); 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, 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).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).to_string (), "(0,0;0,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).to_string (), "(0,0;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).to_string (), "(0,0;0,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 // rounding
@ -1532,7 +1568,7 @@ TEST(203)
in.push_back (pp); in.push_back (pp);
ep.simple_merge (in, out, false /*no cut line*/); ep.simple_merge (in, out, false /*no cut line*/);
pp = out.front (); pp = out.front ();
pp = smooth (pp, 1); pp = smooth (pp, 1, true);
EXPECT_EQ (pp.hull ().size (), size_t (300)); EXPECT_EQ (pp.hull ().size (), size_t (300));
EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true); EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true);
@ -1578,7 +1614,7 @@ TEST(204)
in.push_back (pp); in.push_back (pp);
ep.simple_merge (in, out, false /*no cut line*/); ep.simple_merge (in, out, false /*no cut line*/);
pp = out.front (); pp = out.front ();
pp = smooth (pp, 1); pp = smooth (pp, 1, true);
EXPECT_EQ (pp.hull ().size (), size_t (200)); EXPECT_EQ (pp.hull ().size (), size_t (200));
EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true); EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true);

View File

@ -107,12 +107,35 @@ TEST(1)
std::string x; 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)); db::RecursiveShapeIterator i1 (g, c0, 0, db::Box (0, 0, 100, 100));
x = collect(i1, g); x = collect(i1, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
x = collect_with_copy(i1, g); x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)"); 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)); db::RecursiveShapeIterator i1_1inf (g, c0, 0, db::Box (0, 0, 100, 100));
i1_1inf.min_depth(1); i1_1inf.min_depth(1);
x = collect(i1_1inf, g); x = collect(i1_1inf, g);
@ -731,7 +754,7 @@ namespace {
public: public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { } 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 ()); mp_boxes->insert (trans * shape.bbox ());
} }
@ -766,6 +789,8 @@ TEST(4)
} }
// ...
db::Box search_box (2500, 2500, 7500, 7500); db::Box search_box (2500, 2500, 7500, 7500);
std::set<db::Box> selected_boxes; std::set<db::Box> selected_boxes;
@ -794,6 +819,45 @@ TEST(4)
EXPECT_EQ (selected_boxes.size () > 100, true); 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); 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); db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear (); selected_boxes.clear ();
@ -882,6 +946,40 @@ TEST(5)
EXPECT_EQ (selected_boxes.size () > 100, true); 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); 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); db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear (); selected_boxes.clear ();
@ -936,7 +1034,7 @@ public:
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n"; 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 ()); m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
if (all) { if (all) {
@ -946,9 +1044,9 @@ public:
return NI_all; 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) { if (all) {
m_text += ",all"; m_text += ",all";
} }
@ -956,7 +1054,7 @@ public:
return true; 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"; m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n";
} }
@ -971,9 +1069,9 @@ class ReceiverRejectingACellInstanceArray
public: public:
ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { } 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; return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip;
} }
@ -987,9 +1085,9 @@ class ReceiverRejectingACellInstanceArrayExceptOne
public: public:
ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { } 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; return inst.object ().cell_index () != m_rejected ? NI_all : NI_single;
} }
@ -1003,9 +1101,9 @@ class ReceiverRejectingACellInstance
public: public:
ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { } 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; return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected;
} }
@ -1127,6 +1225,100 @@ TEST(10)
"end\n" "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 ()); ReceiverRejectingACellInstanceArray rr1 (c2.cell_index ());
db::RecursiveShapeIterator ir1 (g, c0, 0); db::RecursiveShapeIterator ir1 (g, c0, 0);
ir1.push (&rr1); ir1.push (&rr1);

View File

@ -354,6 +354,8 @@ TEST(10a)
r.set_merged_semantics (false); 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_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_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 (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 (), ""); EXPECT_EQ (r.selected_interacting (db::Region (db::Box (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), "");
db::Region rr = r; 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); EXPECT_EQ (db::compare (o, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
o = r; 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_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).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)); EXPECT_EQ (o.selected_outside (rr).hier_count () + o.selected_not_outside (rr).hier_count (), size_t (6));
o.select_not_outside (rr); o.select_not_outside (rr);
@ -848,6 +852,8 @@ TEST(18a)
EXPECT_EQ (o.to_string (), "(20,30;20,50;40,50;40,30)"); EXPECT_EQ (o.to_string (), "(20,30;20,50;40,50;40,30)");
o = r; 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_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).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)); EXPECT_EQ (o.selected_inside (rr).hier_count () + o.selected_not_inside (rr).hier_count (), size_t (6));
o.select_not_inside (rr); 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); 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; o = r;
EXPECT_EQ (o.selected_not_interacting (rr).to_string (), "(70,60;70,80;90,80;90,60)"); 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).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)); EXPECT_EQ (o.selected_interacting (rr).hier_count () + o.selected_not_interacting (rr).hier_count (), size_t (6));
o.select_not_interacting (rr); 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); 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; 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_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).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)); EXPECT_EQ (o.selected_overlapping (rr).hier_count () + o.selected_not_overlapping (rr).hier_count (), size_t (6));
o.select_not_overlapping (rr); o.select_not_overlapping (rr);
@ -884,6 +894,8 @@ TEST(18a)
EXPECT_EQ (o.to_string (), "(0,100;0,130;30,130;30,100)"); EXPECT_EQ (o.to_string (), "(0,100;0,130;30,130;30,100)");
o = r; 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_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).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)); EXPECT_EQ (o.selected_enclosing (rr).hier_count () + o.selected_not_enclosing (rr).hier_count (), size_t (6));
o.select_not_enclosing (rr); o.select_not_enclosing (rr);
@ -1506,6 +1518,8 @@ TEST(30a)
r.set_merged_semantics (false); 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_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_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 (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 (), ""); EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), "");
db::Region rr = r; db::Region rr = r;
@ -1689,6 +1703,8 @@ TEST(34a)
r.set_merged_semantics (false); 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_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_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; db::Texts tt;
tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30)))); tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30))));
tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0)))); 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, 0, 2).to_string (), "");
EXPECT_EQ (r.selected_interacting (rr, 1, 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 (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, 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, 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, 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).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, 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_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, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 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); 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, 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, 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 (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, 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, 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)"); 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).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, 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_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, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 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); 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, 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, 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 (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, 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, 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)"); 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).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, 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_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, 1, 4).to_string (), "");
EXPECT_EQ (r.selected_not_interacting (rr, 2, 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); 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% # %DRC%
# @name smoothed # @name smoothed
# @brief Applies smoothing # @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 "smoothed" method is available as a plain function or as a method on \DRC# expressions.
# The plain function is equivalent to "primary.smoothed". # The plain function is equivalent to "primary.smoothed".
def smoothed(d) def smoothed(d, keep_hv = false)
@engine._context("smoothed") do @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
end end

View File

@ -48,6 +48,8 @@ module DRC
@deep = false @deep = false
@netter = nil @netter = nil
@netter_data = nil @netter_data = nil
@total_timer = nil
@drc_progress = nil
# initialize the defaults for max_area_ratio, max_vertex_count # initialize the defaults for max_area_ratio, max_vertex_count
dss = RBA::DeepShapeStore::new dss = RBA::DeepShapeStore::new
@ -58,9 +60,39 @@ module DRC
@verbose = false @verbose = false
@in_context = false @in_context = nil
end 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 def joined
DRCJoinFlag::new(true) DRCJoinFlag::new(true)
@ -231,6 +263,27 @@ module DRC
DRCFillOrigin::new(x, y) DRCFillOrigin::new(x, y)
end 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% # %DRC%
# @brief Defines SPICE output format (with options) # @brief Defines SPICE output format (with options)
# @name write_spice # @name write_spice
@ -475,15 +528,20 @@ module DRC
# %DRC% # %DRC%
# @name info # @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)
# @synopsis info(message, indent) # @synopsis info(message, indent)
# Prints the message to the log window in verbose mode. # 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. # \log is a function that always prints a message.
def info(arg, indent = 0) def info(arg, indent = 0)
@verbose && log(arg, indent) if @verbose
log(arg, indent)
else
str = (" " * indent) + arg
RBA::Logger::log(str)
end
end end
# %DRC% # %DRC%
@ -496,7 +554,7 @@ module DRC
# verbose mode is enabled. # verbose mode is enabled.
def log(arg, indent = 0) def log(arg, indent = 0)
str = (" " * indent) + arg str = (" " * indent) + arg
if @log_file if @log_file
@log_file.puts(str) @log_file.puts(str)
else else
@ -1486,6 +1544,22 @@ CODE
nil nil
end 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% # %DRC%
# @name cheat # @name cheat
# @brief Hierarchy cheats # @brief Hierarchy cheats
@ -1671,8 +1745,6 @@ CODE
pull_overlapping pull_overlapping
rectangles rectangles
rectilinear rectilinear
rotate
rotated
rounded_corners rounded_corners
scale scale
scaled scaled
@ -1848,9 +1920,10 @@ CODE
def _wrapper_context(func, *args, &proc) def _wrapper_context(func, *args, &proc)
in_context_outer = @in_context in_context_outer = @in_context
begin begin
@in_context = true @in_context = func
return yield(*args) return yield(*args)
rescue => ex rescue => ex
RBA::MacroExecutionContext::ignore_next_exception
raise("'" + func + "': " + ex.to_s) raise("'" + func + "': " + ex.to_s)
ensure ensure
@in_context = in_context_outer @in_context = in_context_outer
@ -1862,22 +1935,41 @@ CODE
return yield(*args) return yield(*args)
else else
begin begin
@in_context = true @in_context = func
return yield(*args) return yield(*args)
rescue => ex rescue => ex
RBA::MacroExecutionContext::ignore_next_exception
raise("'" + func + "': " + ex.to_s) raise("'" + func + "': " + ex.to_s)
ensure ensure
@in_context = false @in_context = nil
end end
end 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) def run_timed(desc, obj)
log(desc) info(desc)
# enable progress # 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) 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) obj.enable_progress(desc)
end end
@ -1887,39 +1979,37 @@ CODE
res = yield res = yield
t.stop 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 end
mem = RBA::Timer::memory_size ensure
if mem > 0
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M", 1) # disable progress again
else if disable_progress
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s", 1) obj.disable_progress
end end
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 res
end end
def _cmd(obj, method, *args) 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) obj.send(method, *args)
end end
end end
@ -1949,8 +2039,9 @@ CODE
end end
av = args.size.times.collect { |i| "a#{i}" }.join(", ") av = args.size.times.collect { |i| "a#{i}" }.join(", ")
tp.queue("_output(res, self.#{method}(#{av}))") 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}") tp.execute("Tiled \"#{method}\" in: #{src_line}")
res
end end
else else
@ -1960,17 +2051,12 @@ CODE
end end
res = nil 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) res = obj.send(method, *args)
end end
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 res
end end
@ -2004,8 +2090,9 @@ CODE
end end
av = args.size.times.collect { |i| "a#{i}" }.join(", ") av = args.size.times.collect { |i| "a#{i}" }.join(", ")
tp.queue("var rr = self.#{method}(#{av}); _output(res1, rr[0]); _output(res2, rr[1])") 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}") tp.execute("Tiled \"#{method}\" in: #{src_line}")
res
end end
else else
@ -2015,17 +2102,12 @@ CODE
end end
res = nil 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) res = obj.send(method, *args)
end end
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 res
end end
@ -2045,8 +2127,9 @@ CODE
tp.input("self", obj) tp.input("self", obj)
tp.threads = (@tt || 1) tp.threads = (@tt || 1)
tp.queue("_output(res, _tile ? self.#{method}(_tile.bbox) : self.#{method})") 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}") tp.execute("Tiled \"#{method}\" in: #{src_line}")
res
end end
res = res.value res = res.value
@ -2058,29 +2141,24 @@ CODE
end end
res = nil res = nil
run_timed("\"#{method}\" in: #{src_line}", obj) do run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
res = obj.send(method) res = obj.send(method)
end end
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 res
end end
def _rcmd(obj, method, *args) 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)) RBA::Region::new(obj.send(method, *args))
end end
end end
def _vcmd(obj, method, *args) 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) obj.send(method, *args)
end end
end end
@ -2126,12 +2204,17 @@ CODE
output_cell output_cell
end end
def _start def _start(job_description)
# clearing the selection avoids some nasty problems # clearing the selection avoids some nasty problems
view = RBA::LayoutView::current view = RBA::LayoutView::current
view && view.cancel view && view.cancel
@total_timer = RBA::Timer::new
@total_timer.start
@drc_progress = RBA::AbstractProgress::new(job_description)
end end
def _flush def _flush
@ -2271,9 +2354,20 @@ CODE
@netter = nil @netter = nil
@netter_data = nil @netter_data = nil
if final && @log_file if final
@log_file.close
@log_file = nil @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 end
# force garbage collection # force garbage collection
@ -2283,6 +2377,23 @@ CODE
end 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 def _take_data
if ! @netter if ! @netter
@ -2441,7 +2552,7 @@ CODE
end end
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 if layers.empty? && ! @deep
@ -2455,6 +2566,7 @@ CODE
iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers) iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers)
end end
iter.shape_flags = shape_flags iter.shape_flags = shape_flags
iter.global_dtrans = global_trans
sel.each do |s| sel.each do |s|
if s == "-" if s == "-"
@ -2492,8 +2604,12 @@ CODE
end end
# clip if a box is specified # clip if a box is specified
if box && clip && (cls == RBA::Region || cls == RBA::Edge) # TODO: the whole clip thing could be a part of the Region constructor
r &= RBA::Region::new(box) 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
end end
@ -2582,6 +2698,9 @@ CODE
end end
end end
data
end end
def make_source(layout, cell = nil, path = nil) def make_source(layout, cell = nil, path = nil)

View File

@ -983,8 +983,8 @@ CODE
# @name corners # @name corners
# @brief Selects corners of polygons # @brief Selects corners of polygons
# @synopsis layer.corners([ options ]) # @synopsis layer.corners([ options ])
# @synopsis layer.corners(angle, [ options ]) # @synopsis layer.corners(angle [, options ])
# @synopsis layer.corners(amin .. amax, [ options ]) # @synopsis layer.corners(amin .. amax [, options ])
# #
# This method produces markers on the corners of the polygons. An angle criterion can be given which # 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 # 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| self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
block.call(object.transformed(t)) && new_data.insert(object) block.call(object.transformed(t)) && new_data.insert(object)
end end
new_data
end end
DRCLayer::new(@engine, new_data) DRCLayer::new(@engine, new_data)
@ -1285,7 +1286,7 @@ CODE
@engine._wrapper_context("each") do @engine._wrapper_context("each") do
t = RBA::CplxTrans::new(@engine.dbu) 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| self.data.send(self.data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
block.call(object.transformed(t)) block.call(object.transformed(t))
end end
@ -1368,10 +1369,11 @@ CODE
t = RBA::CplxTrans::new(@engine.dbu) t = RBA::CplxTrans::new(@engine.dbu)
dbu_trans = RBA::VCplxTrans::new(1.0 / @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| 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) insert_object_into(new_data, block.call(object.transformed(t)), dbu_trans)
end end
new_data
end end
DRCLayer::new(@engine, new_data) DRCLayer::new(@engine, new_data)
@ -1660,6 +1662,7 @@ CODE
@engine._context("andnot") do @engine._context("andnot") do
check_is_layer(other)
requires_region requires_region
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 # It returns a new layer containing the selected shapes. A version which modifies self
# is \select_not_covering. # 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% # %DRC%
# @name select_covering # @name select_covering
# @brief Selects shapes or regions of self which completely cover (enclose) one or more shapes from the other region # @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 # It returns a new layer containing the selected shapes. A version which modifies self
# is \select_not_overlapping. # 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% # %DRC%
# @name select_overlapping # @name select_overlapping
# @brief Selects shapes or regions of self which overlap shapes from the other region # @brief Selects shapes or regions of self which overlap shapes from the other region
@ -1923,6 +1956,19 @@ CODE
# @/tr # @/tr
# @/table # @/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% # %DRC%
# @name select_inside # @name select_inside
# @brief Selects shapes or regions of self which are inside the other region # @brief Selects shapes or regions of self which are inside the other region
@ -1995,6 +2041,19 @@ CODE
# @/tr # @/tr
# @/table # @/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% # %DRC%
# @name select_outside # @name select_outside
# @brief Selects shapes or regions of self which are outside the other region # @brief Selects shapes or regions of self which are outside the other region
@ -2149,6 +2208,21 @@ CODE
# @/tr # @/tr
# @/table # @/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% # %DRC%
# @name select_interacting # @name select_interacting
# @brief Selects shapes or regions of self which touch or overlap shapes from the other region # @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 # 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 # 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. # from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
# %DRC% # %DRC%
# @name intersections # @name intersections
# @brief Returns the intersection points of intersecting edge segments for two edge collections # @brief Returns the intersection points of intersecting edge segments for two edge collections
@ -2285,6 +2359,7 @@ CODE
@engine._context("#{f}") do @engine._context("#{f}") do
check_is_layer(other)
if :#{f} != :pull_interacting if :#{f} != :pull_interacting
requires_region requires_region
other.requires_region other.requires_region
@ -2310,11 +2385,16 @@ CODE
%w(| ^ inside not_inside outside not_outside in not_in).each do |f| %w(| ^ inside not_inside outside not_outside in not_in).each do |f|
eval <<"CODE" eval <<"CODE"
def #{f}(other) def #{f}(other)
@engine._context("#{f}") do @engine._context("#{f}") do
requires_same_type(other) requires_same_type(other)
requires_edges_or_region requires_edges_or_region
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end end
end end
CODE CODE
end end
@ -2325,12 +2405,14 @@ CODE
@engine._context("#{f}") do @engine._context("#{f}") do
check_is_layer(other)
other.requires_edges_texts_or_region other.requires_edges_texts_or_region
if self.data.is_a?(RBA::Texts) if self.data.is_a?(RBA::Texts)
other.requires_region other.requires_region
else else
other.requires_edges_or_region other.requires_edges_or_region
end end
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end end
@ -2342,10 +2424,14 @@ CODE
%w(+).each do |f| %w(+).each do |f|
eval <<"CODE" eval <<"CODE"
def #{f}(other) def #{f}(other)
@engine._context("#{f}") do @engine._context("#{f}") do
requires_same_type(other) requires_same_type(other)
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end end
end end
CODE CODE
end end
@ -2356,7 +2442,7 @@ CODE
@engine._context("#{f}") do @engine._context("#{f}") do
other.requires_edges_texts_or_region check_is_layer(other)
if self.data.is_a?(RBA::Text) if self.data.is_a?(RBA::Text)
other.requires_region other.requires_region
elsif self.data.is_a?(RBA::Region) elsif self.data.is_a?(RBA::Region)
@ -2381,6 +2467,7 @@ CODE
@engine._context("#{f}") do @engine._context("#{f}") do
check_is_layer(other)
requires_edges_texts_or_region requires_edges_texts_or_region
if self.data.is_a?(RBA::Text) if self.data.is_a?(RBA::Text)
other.requires_region other.requires_region
@ -2389,6 +2476,7 @@ CODE
else else
other.requires_edges_or_region other.requires_edges_or_region
end end
if @engine.is_tiled? if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args)) self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args))
DRCLayer::new(@engine, self.data) DRCLayer::new(@engine, self.data)
@ -2402,14 +2490,39 @@ CODE
CODE CODE
end end
%w(overlapping not_overlapping covering not_covering).each do |f| %w(split_interacting).each do |f|
eval <<"CODE" eval <<"CODE"
def #{f}(other, *args) def #{f}(other, *args)
@engine._context("#{f}") do @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_same_type(other)
requires_region requires_region
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(*args))) DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(*args)))
end end
end end
CODE CODE
end end
@ -2424,6 +2537,7 @@ CODE
requires_region requires_region
requires_same_type(other) requires_same_type(other)
if @engine.is_tiled? if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args)) self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args))
DRCLayer::new(@engine, self.data) DRCLayer::new(@engine, self.data)
@ -2437,6 +2551,24 @@ CODE
CODE CODE
end 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| %w(inside not_inside outside not_outside).each do |fi|
f = "select_" + fi f = "select_" + fi
# In tiled mode, there are no modifying versions. Emulate using the non-modifying one. # In tiled mode, there are no modifying versions. Emulate using the non-modifying one.
@ -2447,6 +2579,7 @@ CODE
requires_region requires_region
requires_same_type(other) requires_same_type(other)
if @engine.is_tiled? if @engine.is_tiled?
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data) self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data)
DRCLayer::new(@engine, self.data) DRCLayer::new(@engine, self.data)
@ -2460,14 +2593,39 @@ CODE
CODE CODE
end 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| %w(inside_part outside_part).each do |f|
eval <<"CODE" eval <<"CODE"
def #{f}(other) def #{f}(other)
@engine._context("#{f}") do @engine._context("#{f}") do
check_is_layer(other)
other.requires_region other.requires_region
requires_edges requires_edges
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end end
end end
CODE CODE
end end
@ -2475,11 +2633,17 @@ CODE
%w(intersections).each do |f| %w(intersections).each do |f|
eval <<"CODE" eval <<"CODE"
def #{f}(other) def #{f}(other)
@engine._context("#{f}") do @engine._context("#{f}") do
check_is_layer(other)
other.requires_edges other.requires_edges
requires_edges requires_edges
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
end end
end end
CODE CODE
end end
@ -3496,6 +3660,180 @@ CODE
end end
CODE CODE
end 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% # %DRC%
# @name scaled # @name scaled
@ -4102,6 +4440,10 @@ END
@data = d @data = d
end end
def check_is_layer(other)
other.is_a?(DRCLayer) || raise("Argument needs to be a DRC layer")
end
def requires_region def requires_region
self.data.is_a?(RBA::Region) || raise("Requires a polygon layer") self.data.is_a?(RBA::Region) || raise("Requires a polygon layer")
end end

View File

@ -27,6 +27,7 @@ module DRC
@clip = false @clip = false
@overlapping = false @overlapping = false
@tmp_layers = [] @tmp_layers = []
@global_trans = RBA::DCplxTrans::new
end end
# Conceptual deep copy (not including the temp layers) # Conceptual deep copy (not including the temp layers)
@ -70,6 +71,24 @@ module DRC
def cell_obj def cell_obj
@cell @cell
end 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 def finish
@tmp_layers.each do |li| @tmp_layers.each do |li|
@ -245,8 +264,40 @@ module DRC
# \touching is a similar method which delivers shapes touching # \touching is a similar method which delivers shapes touching
# the search region with their bounding box (without the requirement to overlap) # 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 # 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" eval <<"CODE"
def #{f}(*args) def #{f}(*args)
@engine._context("#{f}") do @engine._context("#{f}") do
@ -274,7 +325,7 @@ CODE
if @box if @box
layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu) layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu)
else 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 end
layer layer
end end
@ -326,7 +377,7 @@ CODE
def input(*args) def input(*args)
@engine._context("input") do @engine._context("input") do
layers = parse_input_layers(*args) 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
end end
@ -350,7 +401,7 @@ CODE
def labels(*args) def labels(*args)
@engine._context("labels") do @engine._context("labels") do
layers = parse_input_layers(*args) 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
end end
@ -373,7 +424,7 @@ CODE
def polygons(*args) def polygons(*args)
@engine._context("polygons") do @engine._context("polygons") do
layers = parse_input_layers(*args) 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
end end
@ -399,7 +450,7 @@ CODE
def edges(*args) def edges(*args)
@engine._context("edges") do @engine._context("edges") do
layers = parse_input_layers(*args) 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
end end
@ -425,7 +476,7 @@ CODE
def edge_pairs(*args) def edge_pairs(*args)
@engine._context("edge_pairs") do @engine._context("edge_pairs") do
layers = parse_input_layers(*args) 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
end end
@ -437,7 +488,7 @@ CODE
def make_layer def make_layer
layers = [] 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 end
# %DRC% # %DRC%

View File

@ -322,5 +322,55 @@ module DRC
end end
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 end

View File

@ -17,44 +17,52 @@
<text> <text>
module DRC module DRC
def DRC.execute_drc(macro, generator, rdb_index = nil) class DRCExecutable &lt; RBA::Executable
timer = RBA::Timer::new def initialize(macro, generator, rdb_index = nil)
timer.start
drc = DRCEngine::new
drc._rdb_index = rdb_index
drc._generator = generator
drc_progress = RBA::AbstractProgress::new("DRC: " + macro.path) @drc = DRCEngine::new
@drc._rdb_index = rdb_index
@drc._generator = generator
begin @macro = macro
# 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
end end
timer.stop def execute
drc.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s")
@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 end
@ -79,11 +87,17 @@ module DRC
# create a template for the macro editor: # create a template for the macro editor:
create_template(":/drc-templates/drc.lym") 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 end
# Implements the execute method # Implements the execute method
def execute(macro) def executable(macro)
DRC::execute_drc(macro, @recipe.generator("script" => macro.path)) DRCExecutable::new(macro, @recipe.generator("script" => macro.path))
end end
end end
@ -109,20 +123,20 @@ module DRC
end end
# Implements the execute method # Implements the execute method
def execute(macro) def executable(macro)
DRC::execute_drc(macro, @recipe.generator("script" => macro.path)) DRCExecutable::new(macro, @recipe.generator("script" => macro.path))
end end
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 class DRCRecipe &lt; RBA::Recipe
def initialize def initialize
super("drc", "DRC recipe") super("drc", "DRC recipe")
end end
def execute(params) def executable(params)
script = params["script"] script = params["script"]
if ! script if ! script
@ -132,7 +146,7 @@ module DRC
macro = RBA::Macro::macro_by_path(script) macro = RBA::Macro::macro_by_path(script)
macro || raise("Can't find DRC script #{script} - unable to re-run") 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 end

View File

@ -1163,6 +1163,36 @@ TEST(29d_holes)
run_test (_this, "29", true); 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) TEST(40_fill)
{ {
run_test (_this, "40", false); run_test (_this, "40", false);
@ -1172,3 +1202,4 @@ TEST(41_fillTiled)
{ {
run_test (_this, "41", false); run_test (_this, "41", false);
} }

View File

@ -1387,7 +1387,7 @@ MainService::cm_round_corners ()
std::vector <db::Polygon> in; std::vector <db::Polygon> in;
ep.merge (primary, in, 0 /*min_wc*/, false /*resolve holes*/, true /*min coherence*/); 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) { 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; 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." "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 class Recipe_Impl
: public tl::Recipe, public gsi::ObjectBase : public tl::Recipe, public gsi::ObjectBase
{ {
@ -641,16 +707,16 @@ public:
keep (); 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 ()) { if (executable_cb.can_issue ()) {
return execute_cb.issue<tl::Recipe, tl::Variant, const std::map<std::string, tl::Variant> &> (&tl::Recipe::execute, params); return executable_cb.issue<tl::Recipe, tl::Executable *, const std::map<std::string, tl::Variant> &> (&tl::Recipe::executable, params);
} else { } 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" "@brief Delivers the generator string from the given parameters.\n"
"The generator string can be used with \\make to re-run the recipe." "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"), gsi::callback ("executable", &Recipe_Impl::executable, &Recipe_Impl::executable_cb, gsi::arg ("params"),
"@brief Reimplement this method to provide the functionality of the recipe.\n" "@brief Reimplement this method to provide an executable object for the actual implementation.\n"
"This method is supposed to re-run the recipe with the given parameters and deliver the " "The reasoning behind this architecture is to supply a cleanup callback. This is useful when the "
"the intended output object." "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" "@brief A facility for providing reproducable recipes\n"
"The idea of this facility is to provide a service by which an object\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. 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. See <a href="#if_all">if_all</a> for an example how to use the if_... functions.
</p> </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"/> <keyword name="info"/>
<p>Usage:</p> <p>Usage:</p>
<ul> <ul>
@ -747,7 +747,7 @@ See <a href="#if_all">if_all</a> for an example how to use the if_... functions.
</ul> </ul>
<p> <p>
Prints the message to the log window in verbose mode. 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. <a href="#log">log</a> is a function that always prints a message.
</p> </p>
<a name="input"/><h2>"input" - Fetches the shapes from the specified input from the default source</h2> <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> <p>Usage:</p>
<ul> <ul>
<li><tt>layer.corners([ options ])</tt></li> <li><tt>layer.corners([ options ])</tt></li>
<li><tt>layer.corners(angle, [ options ])</tt></li> <li><tt>layer.corners(angle [, options ])</tt></li>
<li><tt>layer.corners(amin .. amax, [ options ])</tt></li> <li><tt>layer.corners(amin .. amax [, options ])</tt></li>
</ul> </ul>
<p> <p>
This method produces markers on the corners of the polygons. An angle criterion can be given which 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> </tr>
</table> </table>
</p> </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> <a name="squares"/><h2>"squares" - Selects all squares from the input</h2>
<keyword name="squares"/> <keyword name="squares"/>
<p>Usage:</p> <p>Usage:</p>
@ -3147,6 +3228,74 @@ bounding box.
</p><p> </p><p>
This method is available for polygon layers only. This method is available for polygon layers only.
</p> </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> <a name="with_holes"/><h2>"with_holes" - Selects all polygons with the specified number of holes</h2>
<keyword name="with_holes"/> <keyword name="with_holes"/>
<p>Usage:</p> <p>Usage:</p>
@ -3313,6 +3462,17 @@ bounding box.
</p><p> </p><p>
This method is available for polygon layers only. This method is available for polygon layers only.
</p> </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> <a name="without_holes"/><h2>"without_holes" - Selects all polygons with the specified number of holes</h2>
<keyword name="without_holes"/> <keyword name="without_holes"/>
<p>Usage:</p> <p>Usage:</p>

View File

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

View File

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

View File

@ -22,12 +22,15 @@
#include "layLogViewerDialog.h" #include "layLogViewerDialog.h"
#include "layApplication.h"
#include <QMutex> #include <QMutex>
#include <QMutexLocker> #include <QMutexLocker>
#include <QTimer> #include <QTimer>
#include <QClipboard> #include <QClipboard>
#include <QFrame> #include <QFrame>
#include <QThread>
#include <QAbstractEventDispatcher>
#include <stdio.h> #include <stdio.h>
@ -101,7 +104,7 @@ LogReceiver::begin ()
LogFile::LogFile (size_t max_entries, bool register_global) LogFile::LogFile (size_t max_entries, bool register_global)
: m_error_receiver (this, 0, &LogFile::add_error), : m_error_receiver (this, 0, &LogFile::add_error),
m_warn_receiver (this, 0, &LogFile::add_warn), 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_info_receiver (this, 0, &LogFile::add_info),
m_max_entries (max_entries), m_max_entries (max_entries),
m_generation_id (0), m_generation_id (0),
@ -221,25 +224,39 @@ LogFile::max_entries () const
void void
LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued) 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) { // use this opportunity to process events
m_messages.pop_front (); 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 int

View File

@ -26,6 +26,7 @@
#include "ui_LogViewerDialog.h" #include "ui_LogViewerDialog.h"
#include "tlLog.h" #include "tlLog.h"
#include "tlTimer.h"
#include "layCommon.h" #include "layCommon.h"
#include <QTimer> #include <QTimer>
@ -227,6 +228,7 @@ private:
size_t m_last_generation_id; size_t m_last_generation_id;
bool m_has_errors, m_has_warnings; bool m_has_errors, m_has_warnings;
bool m_last_attn; bool m_last_attn;
tl::Clock m_last_yield;
/** /**
* @brief Adds an error * @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 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) 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) { 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 // 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) { 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) MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int line, const gsi::StackTraceProvider *stack_trace_provider)
{ {
if (!m_in_exec) { 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 // 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) { if (! m_in_exec) {
throw tl::ExitException (); exit_from_macro ();
} }
} else if (++m_trace_count == 20) { } 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)); m_process_events_interval = std::max (0.05, std::min (2.0, (m_last_process_events - start).seconds () * 5.0));
if (!m_in_exec) { 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 &) { } catch (tl::ExitException &) {
m_stop_stack_depth = -1; m_stop_stack_depth = -1;
// .. ignore exit exceptions .. // .. ignore exit exceptions ..
} catch (tl::BreakException &) {
m_stop_stack_depth = -1;
// .. ignore break exceptions ..
} catch (tl::ScriptError &re) { } catch (tl::ScriptError &re) {
m_stop_stack_depth = -1; m_stop_stack_depth = -1;
handle_error (re); handle_error (re);

View File

@ -1548,6 +1548,71 @@ MacroEditorPage::return_pressed ()
return true; 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 bool
MacroEditorPage::eventFilter (QObject *watched, QEvent *event) MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
{ {
@ -1555,9 +1620,16 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
if (event->type () == QEvent::ShortcutOverride) { if (event->type () == QEvent::ShortcutOverride) {
// override shortcuts // override shortcuts if the collide with keys we accept ourselves
event->accept (); QKeyEvent *ke = dynamic_cast<QKeyEvent *> (event);
return true; if (! ke) {
return false; // should not happen
}
if (is_any_known_key (ke)) {
event->accept ();
return true;
}
} else if (event->type () == QEvent::FocusOut) { } else if (event->type () == QEvent::FocusOut) {
@ -1574,7 +1646,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return false; // should not happen 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 ()) { if (mp_completer_popup->isVisible ()) {
complete (); complete ();
@ -1583,15 +1655,15 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return tab_key_pressed (); 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 (); return back_tab_key_pressed ();
} else if (ke->key () == Qt::Key_Backspace) { } else if (is_backspace_key (ke)) {
return backspace_pressed (); 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 // 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; return true;
} else if (ke->key () == Qt::Key_Return) { } else if (is_return_key (ke)) {
if (mp_completer_popup->isVisible ()) { if (mp_completer_popup->isVisible ()) {
complete (); complete ();
@ -1615,7 +1687,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return return_pressed (); return return_pressed ();
} }
} else if (ke->key () == Qt::Key_F1) { } else if (is_help_key (ke)) {
QTextCursor c = mp_text->textCursor (); QTextCursor c = mp_text->textCursor ();
if (c.selectionStart () == c.selectionEnd ()) { if (c.selectionStart () == c.selectionEnd ()) {
@ -1625,19 +1697,19 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
return true; 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); QApplication::sendEvent (mp_completer_list, event);
return true; 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 (); QTextCursor c = mp_text->textCursor ();
emit search_requested (c.selectedText ()); emit search_requested (c.selectedText ());
return true; 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 // 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; std::string technology = m_initial_technology;
static std::string s_new_cell_cell_name ("TOP"); static std::string s_new_cell_cell_name ("TOP");
static double s_new_cell_window_size = 2.0; static double s_new_cell_window_size = 2.0;
static std::vector<db::LayerProperties> s_layers;
double dbu = 0.0; double dbu = 0.0;
lay::NewLayoutPropertiesDialog dialog (this); 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) { 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 ()); db::cell_index_type new_ci = handle->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ());
cellview.set_cell (new_ci);
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 () ProgressReporter::ProgressReporter ()
: m_start_time (), mp_pb (0), m_pw_visible (false) : mp_pb (0), m_pw_visible (false)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
@ -94,22 +96,21 @@ ProgressReporter::register_object (tl::Progress *progress)
tl::ProgressAdaptor::register_object (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 ()) { if (progress->is_abstract ()) {
m_active.insert (progress);
if (! m_pw_visible) {
set_visible (true);
}
if (mp_pb) { if (mp_pb) {
mp_pb->update_progress (progress); mp_pb->update_progress (progress);
} }
process_events (); process_events ();
} else { } 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 // close or refresh window
if (begin () == end ()) { if (begin () == end ()) {
m_queued.clear ();
m_active.clear ();
if (m_pw_visible) { if (m_pw_visible) {
set_visible (false); set_visible (false);
} }
m_start_time = tl::Clock ();
if (mp_pb) { if (mp_pb) {
mp_pb->update_progress (0); mp_pb->update_progress (0);
} }
process_events (); process_events ();
QApplication::instance ()->removeEventFilter (this); QApplication::instance ()->removeEventFilter (this);
} else { } 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 void
ProgressReporter::trigger (tl::Progress * /*progress*/) ProgressReporter::trigger (tl::Progress *progress)
{ {
if (begin () != end ()) { std::map<tl::Progress *, tl::Clock>::iterator q = m_queued.find (progress);
// make dialog visible after some time has passed if (q != m_queued.end () && (tl::Clock::current () - q->second).seconds () > visibility_delay) {
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) { if (! m_pw_visible) {
set_visible (true); set_visible (true);
} }
m_active.insert (progress);
m_queued.erase (q);
}
if (m_active.find (progress) != m_active.end ()) {
update_and_yield (); update_and_yield ();
} }
} }
void void
ProgressReporter::yield (tl::Progress * /*progress*/) ProgressReporter::yield (tl::Progress *progress)
{ {
// make dialog visible after some time has passed std::map<tl::Progress *, tl::Clock>::iterator q = m_queued.find (progress);
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) { if (q != m_queued.end () && (tl::Clock::current () - q->second).seconds () > visibility_delay) {
set_visible (true); if (! m_pw_visible) {
set_visible (true);
}
m_active.insert (progress);
m_queued.erase (q);
update_and_yield (); update_and_yield ();
} else if (m_pw_visible) { }
// process events if necessary
if (m_active.find (progress) != m_active.end ()) {
process_events (); process_events ();
} }
} }
@ -172,11 +191,17 @@ ProgressReporter::update_and_yield ()
return; return;
} }
if (mp_pb && first ()) { if (mp_pb) {
mp_pb->update_progress (first ()); if (first ()) {
QWidget *w = mp_pb->progress_get_widget (); mp_pb->update_progress (first ());
if (w) { QWidget *w = mp_pb->progress_get_widget ();
first ()->render_progress (w); 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 <string>
#include <list> #include <list>
#include <map>
#include <set>
#include "tlProgress.h" #include "tlProgress.h"
#include "tlObject.h" #include "tlObject.h"
@ -71,9 +73,10 @@ public:
void set_progress_bar (lay::ProgressBar *pb); void set_progress_bar (lay::ProgressBar *pb);
private: private:
tl::Clock m_start_time;
lay::ProgressBar *mp_pb; lay::ProgressBar *mp_pb;
bool m_pw_visible; bool m_pw_visible;
std::map<tl::Progress *, tl::Clock> m_queued;
std::set<tl::Progress *> m_active;
void process_events (); void process_events ();
void update_and_yield (); void update_and_yield ();

View File

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

View File

@ -72,6 +72,7 @@ public slots:
private: private:
QLabel *mp_label; QLabel *mp_label;
QFrame *mp_progress_bar_frame;
ProgressBarWidget *mp_progress_bar1, *mp_progress_bar2, *mp_progress_bar3; ProgressBarWidget *mp_progress_bar1, *mp_progress_bar2, *mp_progress_bar3;
QWidget *mp_widget; QWidget *mp_widget;
int m_widget_col; int m_widget_col;
@ -79,12 +80,13 @@ private:
QToolButton *mp_cancel_button; QToolButton *mp_cancel_button;
ProgressReporter *mp_pr; ProgressReporter *mp_pr;
lay::LogFile m_log_file; lay::LogFile m_log_file;
QLabel *mp_log_label;
QFrame *mp_log_frame; QFrame *mp_log_frame;
bool m_full_width; bool m_full_width;
int m_left_col, m_right_col; int m_left_col, m_right_col;
bool m_log_visible; 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); query_to_model (model, lq, iq, std::numeric_limits<size_t>::max (), true);
model.end_changes (); 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"); handle->rename ("query_results");
model.export_layout (handle->layout ()); model.export_layout (handle->layout ());
mp_view->add_layout (handle.release (), true); mp_view->add_layout (handle.release (), true);

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>563</width> <width>594</width>
<height>234</height> <height>401</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -50,7 +50,7 @@
<property name="spacing"> <property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<item row="3" column="1"> <item row="4" column="1">
<widget class="QLineEdit" name="window_le"> <widget class="QLineEdit" name="window_le">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -60,13 +60,6 @@
</property> </property>
</widget> </widget>
</item> </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"> <item row="1" column="2" colspan="3">
<spacer> <spacer>
<property name="orientation"> <property name="orientation">
@ -80,13 +73,80 @@
</property> </property>
</spacer> </spacer>
</item> </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"> <widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>µm</string> <string>µm</string>
</property> </property>
</widget> </widget>
</item> </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"> <item row="3" column="4">
<spacer> <spacer>
<property name="orientation"> <property name="orientation">
@ -100,74 +160,34 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="2" column="1"> <item row="3" column="3">
<widget class="QLineEdit" name="dbu_le"> <widget class="QLabel" name="label_7">
<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">
<property name="text"> <property name="text">
<string>Top cell</string> <string> (empty for default)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="4" column="0">
<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">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Initial window size</string> <string>Initial window size</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="2"> <item row="5" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_8">
<property name="text"> <property name="text">
<string>µm</string> <string>Initial layer(s)</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="4"> <item row="6" column="1" colspan="4">
<spacer> <widget class="QLabel" name="label_9">
<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">
<property name="text"> <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> </property>
</widget> </widget>
</item> </item>
@ -214,10 +234,12 @@
</layout> </layout>
</widget> </widget>
<tabstops> <tabstops>
<tabstop>tech_cbx</tabstop>
<tabstop>topcell_le</tabstop> <tabstop>topcell_le</tabstop>
<tabstop>dbu_le</tabstop> <tabstop>dbu_le</tabstop>
<tabstop>window_le</tabstop> <tabstop>window_le</tabstop>
<tabstop>buttonBox</tabstop> <tabstop>layers_le</tabstop>
<tabstop>current_panel_cb</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections> <connections>

View File

@ -129,7 +129,7 @@ NewLayoutPropertiesDialog::tech_changed ()
} }
bool 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 (); mp_ui->tech_cbx->clear ();
unsigned int technology_index = 0; 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->topcell_le->setText (tl::to_qstring (cell_name));
mp_ui->current_panel_cb->setChecked (current_panel); 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 ()) { if (QDialog::exec ()) {
// get the selected technology name // get the selected technology name
@ -167,8 +176,24 @@ NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &ce
} else { } else {
dbu = 0.0; dbu = 0.0;
} }
cell_name = tl::to_string (mp_ui->topcell_le->text ()); cell_name = tl::to_string (mp_ui->topcell_le->text ());
current_panel = mp_ui->current_panel_cb->isChecked (); 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; return true;
} else { } else {

View File

@ -328,7 +328,7 @@ public:
NewLayoutPropertiesDialog (QWidget *parent); NewLayoutPropertiesDialog (QWidget *parent);
virtual ~NewLayoutPropertiesDialog (); 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: private slots:
void tech_changed (); 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); return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0);
} }
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status> std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::top_circuit_from_index(size_t index) const
SingleIndexedNetlistModel::top_circuit_from_index (size_t index) const
{ {
db::Netlist::const_top_down_circuit_iterator none; 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> std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::child_circuit_from_index(const circuit_pair &circuits, size_t index) const
SingleIndexedNetlistModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_child_circuit_iterator none; 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> std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::circuit_from_index(size_t index) const
SingleIndexedNetlistModel::circuit_from_index (size_t index) const
{ {
db::Netlist::const_circuit_iterator none; 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> std::pair<IndexedNetlistModel::net_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::net_from_index(const circuit_pair &circuits, size_t index) const
SingleIndexedNetlistModel::net_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_net_iterator none; 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 * 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> ()); 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> std::pair<IndexedNetlistModel::device_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::device_from_index(const circuit_pair &circuits, size_t index) const
SingleIndexedNetlistModel::device_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_device_iterator none; 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> std::pair<IndexedNetlistModel::pin_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::pin_from_index(const circuit_pair &circuits, size_t index) const
SingleIndexedNetlistModel::pin_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_pin_iterator none; 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> std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::subcircuit_from_index(const circuit_pair &circuits, size_t index) const
SingleIndexedNetlistModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
{ {
db::Circuit::const_subcircuit_iterator none; 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 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 device_pair &device_pair) const = 0;
virtual circuit_pair parent_of (const subcircuit_pair &subcircuit_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, std::pair<Status, std::string> > 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, std::pair<Status, std::string> > 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<circuit_pair, std::pair<Status, std::string> > 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<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::Net *second_net_for (const db::Net *first) const = 0;
virtual const db::Circuit *second_circuit_for (const db::Circuit *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 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_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_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 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<device_pair, std::pair<Status, std::string> > 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<pin_pair, std::pair<Status, std::string> > 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<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 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 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 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 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 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 (); } 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 device_pair &devices) const;
virtual circuit_pair parent_of (const subcircuit_pair &subcircuits) 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, std::pair<Status, std::string> > 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, std::pair<Status, std::string> > 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<circuit_pair, std::pair<Status, std::string> > 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<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::Net *second_net_for (const db::Net *first) const;
virtual const db::Circuit *second_circuit_for (const db::Circuit *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 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_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_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 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<device_pair, std::pair<Status, std::string> > 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<pin_pair, std::pair<Status, std::string> > 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<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 circuit_index (const circuit_pair &circuits) const;
virtual size_t net_index (const net_pair &nets) 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), mp_view (view),
m_needs_update (true), m_needs_update (true),
m_tabs_need_update (true), m_tabs_need_update (true),
m_hidden_flags_need_update (true),
m_in_update (false), m_in_update (false),
m_phase (0), m_phase (0),
m_do_update_content_dm (this, &LayerControlPanel::do_update_content), 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) m_no_stipples (false)
{ {
setObjectName (QString::fromUtf8 (name)); setObjectName (QString::fromUtf8 (name));
@ -1661,7 +1661,8 @@ LayerControlPanel::set_text_color (QColor c)
void void
LayerControlPanel::update_hidden_flags () LayerControlPanel::update_hidden_flags ()
{ {
m_do_update_hidden_flags_dm (); m_hidden_flags_need_update = true;
m_do_update_content_dm ();
} }
void void
@ -1688,6 +1689,7 @@ LayerControlPanel::begin_updates ()
if (! m_in_update) { if (! m_in_update) {
m_in_update = true; m_in_update = true;
m_hidden_flags_need_update = true;
mp_model->signal_begin_layer_changed (); // this makes the view redraw the data 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_in_update = false;
m_needs_update = false; m_needs_update = false;
m_hidden_flags_need_update = false;
m_tabs_need_update = false; m_tabs_need_update = false;
} }
@ -1833,7 +1836,7 @@ LayerControlPanel::do_update_content ()
mp_layer_list->setCurrentIndex(QModelIndex()); mp_layer_list->setCurrentIndex(QModelIndex());
// this makes the view redraw the data and establishes a valid selection scheme // 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 // now realize the selection if required
if (! m_new_sel.empty ()) { if (! m_new_sel.empty ()) {
@ -1875,6 +1878,14 @@ LayerControlPanel::do_update_content ()
} else { } else {
mp_model->signal_data_changed (); // this makes the view redraw the data 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 void
@ -2007,7 +2018,7 @@ LayerControlPanel::update_required (int f)
} }
if ((f & 3) != 0) { if ((f & 3) != 0) {
m_do_update_hidden_flags_dm (); m_hidden_flags_need_update = true;
} }
m_do_update_content_dm (); m_do_update_content_dm ();

View File

@ -341,10 +341,11 @@ private:
lay::LayoutView *mp_view; lay::LayoutView *mp_view;
bool m_needs_update; bool m_needs_update;
bool m_tabs_need_update; bool m_tabs_need_update;
bool m_hidden_flags_need_update;
bool m_in_update; bool m_in_update;
std::vector<size_t> m_new_sel; std::vector<size_t> m_new_sel;
int m_phase; 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; std::set<unsigned int> m_expanded;
bool m_no_stipples; bool m_no_stipples;
QLabel *m_no_stipples_label; QLabel *m_no_stipples_label;

View File

@ -421,9 +421,9 @@ LayerTreeModel::signal_begin_layer_changed ()
} }
void 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; m_id_start = m_id_end;
// TODO: is there a more efficient way to compute that? // TODO: is there a more efficient way to compute that?
@ -433,6 +433,21 @@ LayerTreeModel::signal_layer_changed ()
} }
m_id_end += max_id + 1; 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 (); m_test_shapes_cache.clear ();
emit layoutChanged (); emit layoutChanged ();
} }

View File

@ -235,11 +235,12 @@ public:
/** /**
* @brief emit a layoutChanged signal * @brief emit a layoutChanged signal
*/ */
void signal_layer_changed (); void signal_layers_changed ();
signals: 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 (); 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 // ensures the deferred method scheduler is present
tl::DeferredMethodScheduler::instance (); tl::DeferredMethodScheduler::instance ();
setObjectName (QString::fromUtf8 (name)); setObjectName (QString::fromUtf8(name));
init (manager, parent); 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 .. // create the layers and do a basic recoloring ..
lay::LayerPropertiesList new_props (get_properties ()); 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 // don't create new layers for those, for which there are layers already: compute a
// set of layers already present // set of layers already present
std::set <db::LayerProperties, db::LPLogicalLessFunc> present_layers; 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); 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 // signal to any observers
file_open_event (); file_open_event ();
@ -3456,6 +3474,18 @@ LayoutView::load_layout (const std::string &filename, const db::LoadLayoutOption
// create the initial layer properties // create the initial layer properties
create_initial_layer_props (cv_index, lyp_file, add_other_layers); 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 // signal to any observers
file_open_event (); file_open_event ();
@ -3942,6 +3972,8 @@ LayoutView::cancel ()
{ {
// cancel all drags and pending edit operations such as move operations. // cancel all drags and pending edit operations such as move operations.
cancel_edits (); cancel_edits ();
// re-enable edit mode
enable_edits (true);
// and clear the selection // and clear the selection
clear_selection (); clear_selection ();
} }

View File

@ -199,6 +199,7 @@ LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char
: QFrame (parent), : QFrame (parent),
m_enable_cb (true), m_enable_cb (true),
mp_view (view), mp_view (view),
m_active_index (-1),
m_split_mode (false), m_split_mode (false),
m_do_update_content_dm (this, &LibrariesView::do_update_content), m_do_update_content_dm (this, &LibrariesView::do_update_content),
m_do_full_update_content_dm (this, &LibrariesView::do_full_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); m_reload_action->setEnabled (l2ndb != 0);
browser_page->enable_updates (false); // Avoid building the internal lists several times ... browser_page->enable_updates (false); // Avoid building the internal lists several times ...
if (browser_page->db () != l2ndb) { db_changed = browser_page->set_db (l2ndb);
db_changed = true;
browser_page->set_db (l2ndb);
}
browser_page->set_max_shape_count (m_max_shape_count); 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_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); browser_page->set_window (m_window, m_window_dim);

View File

@ -1598,7 +1598,7 @@ db::NetlistCrossReference::Status
CircuitItemData::status (NetlistBrowserModel *model) CircuitItemData::status (NetlistBrowserModel *model)
{ {
size_t index = model->indexer ()->circuit_index (m_cp); 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 * CircuitNetItemData *
@ -1938,7 +1938,7 @@ CircuitNetItemData::status (NetlistBrowserModel *model)
{ {
if (m_np.first || m_np.second) { if (m_np.first || m_np.second) {
size_t index = model->indexer ()->net_index (m_np); 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 { } else {
return db::NetlistCrossReference::None; return db::NetlistCrossReference::None;
} }
@ -2016,7 +2016,7 @@ CircuitNetDeviceTerminalItemData::tooltip (NetlistBrowserModel *model)
db::NetlistCrossReference::Status db::NetlistCrossReference::Status
CircuitNetDeviceTerminalItemData::status (NetlistBrowserModel *model) 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 db::NetlistCrossReference::Status
CircuitNetSubCircuitPinItemData::status (NetlistBrowserModel *model) 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) CircuitSubCircuitItemData::status (NetlistBrowserModel *model)
{ {
size_t index = model->indexer ()->subcircuit_index (sp ()); 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) CircuitDeviceItemData::status (NetlistBrowserModel *model)
{ {
size_t index = model->indexer ()->device_index (m_dp); 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), mp_view (0),
m_cv_index (0), m_cv_index (0),
mp_plugin_root (0), mp_plugin_root (0),
mp_last_db (0),
m_history_ptr (0), m_history_ptr (0),
m_signals_enabled (true), m_signals_enabled (true),
m_enable_updates (true), m_enable_updates (true),
@ -606,7 +607,7 @@ NetlistBrowserPage::rerun_macro ()
{ {
BEGIN_PROTECTED BEGIN_PROTECTED
if (! mp_database->generator ().empty ()) { if (mp_database.get () && ! mp_database->generator ().empty ()) {
std::map<std::string, tl::Variant> add_pars; 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) 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 // not change
return; return false;
} }
if (mp_info_dialog) { if (mp_info_dialog) {
@ -779,6 +782,7 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
db::LayoutVsSchematic *lvsdb = dynamic_cast<db::LayoutVsSchematic *> (l2ndb); db::LayoutVsSchematic *lvsdb = dynamic_cast<db::LayoutVsSchematic *> (l2ndb);
mp_database.reset (l2ndb); mp_database.reset (l2ndb);
mp_last_db = l2ndb;
rerun_button->setEnabled (mp_database.get () && ! mp_database->generator ().empty ()); rerun_button->setEnabled (mp_database.get () && ! mp_database->generator ().empty ());
if (rerun_button->isEnabled ()) { if (rerun_button->isEnabled ()) {
@ -800,13 +804,15 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
show_xref->setChecked (lvsdb != 0); show_xref->setChecked (lvsdb != 0);
m_signals_enabled = se; m_signals_enabled = se;
clear_markers (); clear_highlights ();
m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0); m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0);
setup_trees (); setup_trees ();
selection_changed_event (); selection_changed_event ();
return true;
} }
void void
@ -892,6 +898,15 @@ NetlistBrowserPage::setup_trees ()
find_text->setText (QString ()); find_text->setText (QString ());
} }
void
NetlistBrowserPage::clear_highlights ()
{
m_current_path = lay::NetlistObjectsPath ();
m_selected_paths.clear ();
update_highlights ();
}
void void
NetlistBrowserPage::highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths) 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_current_path = current_path;
m_selected_paths = selected_paths; m_selected_paths = selected_paths;
clear_markers ();
adjust_view ();
update_highlights (); update_highlights ();
adjust_view ();
} }
} }

View File

@ -91,7 +91,7 @@ public:
/** /**
* @brief Attaches the page to a L2N DB * @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 * @brief Gets the database the page is connected to
@ -228,6 +228,7 @@ private:
unsigned int m_cv_index; unsigned int m_cv_index;
lay::Dispatcher *mp_plugin_root; lay::Dispatcher *mp_plugin_root;
tl::weak_ptr<db::LayoutToNetlist> mp_database; tl::weak_ptr<db::LayoutToNetlist> mp_database;
db::LayoutToNetlist *mp_last_db;
std::vector<QModelIndex> m_history; std::vector<QModelIndex> m_history;
size_t m_history_ptr; size_t m_history_ptr;
bool m_signals_enabled; bool m_signals_enabled;
@ -247,6 +248,7 @@ private:
void adjust_view (); void adjust_view ();
void clear_markers (); void clear_markers ();
void highlight (const NetlistObjectsPath &current_path, const std::vector<NetlistObjectsPath> &selected_paths); 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::Net *> selected_nets ();
std::vector<const db::Device *> selected_devices (); std::vector<const db::Device *> selected_devices ();
std::vector<const db::SubCircuit *> selected_subcircuits (); 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)); 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 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 (); void *id = index.internalPointer ();
tl_assert (id != 0); 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); size_t child_nprod = nprod * (count + 1);
for (size_t n = count; n > 0; ) { 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)); 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); build_circuits_to_index (child_nprod, cp.first, model, child_index, map);
--n; --n;
@ -304,7 +304,7 @@ NetlistBrowserTreeModel::index_from_circuits (const std::pair<const db::Circuit
size_t count = mp_indexer->top_circuit_count (); size_t count = mp_indexer->top_circuit_count ();
for (size_t n = count; n > 0; ) { 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); 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; --n;
} }
@ -324,13 +324,13 @@ db::NetlistCrossReference::Status
NetlistBrowserTreeModel::status (const QModelIndex &index) const NetlistBrowserTreeModel::status (const QModelIndex &index) const
{ {
size_t nprod = 0, nlast = 0, nnlast = 0; 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 QVariant
NetlistBrowserTreeModel::tooltip (const QModelIndex &index) const 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; size_t nlast = 0;
std::string hint; std::string hint;

View File

@ -88,7 +88,7 @@ private:
QVariant tooltip (const QModelIndex &index) const; QVariant tooltip (const QModelIndex &index) const;
QString search_text (const QModelIndex &index) const; QString search_text (const QModelIndex &index) const;
db::NetlistCrossReference::Status status (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; 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; 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); 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); build_top_circuit_list (mp_cross_ref.get (), m_top_level_circuits);
IndexedNetlistModel::circuit_pair cp = m_top_level_circuits [index]; IndexedNetlistModel::circuit_pair cp = m_top_level_circuits [index];
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp); const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
tl_assert (data != 0); 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); build_child_circuit_map (mp_cross_ref.get (), m_child_circuits);
IndexedNetlistModel::circuit_pair cp = m_child_circuits [circuits][index]; IndexedNetlistModel::circuit_pair cp = m_child_circuits [circuits][index];
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp); const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
tl_assert (data != 0); 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]; IndexedNetlistModel::circuit_pair cp = mp_cross_ref->begin_circuits () [index];
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp); const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
tl_assert (data != 0); 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); const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
tl_assert (data != 0); 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 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]; 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); const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
tl_assert (data != 0); 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); const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
tl_assert (data != 0); 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); const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
tl_assert (data != 0); 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> 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); 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) { if (! cps.first.first || ! cps.first.second) {
return tl::to_string (tr ("No matching circuit found in the other netlist.\n" msg = tl::to_string (tr ("No matching circuit found in the other netlist.\n"
"By default, circuits are identified by their name.\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" "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" "If circuits with different names need to be associated, use 'same_circuits' in the\n"
"LVS script to establish such an association.")); "LVS script to establish such an association."));
} else { } else {
return tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n" 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.")); "Browse the circuit's component list to identify the mismatching elements."));
} }
} else if (cps.second == db::NetlistCrossReference::Skipped) { } else if (cps.second.first == db::NetlistCrossReference::Skipped) {
return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n" 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" "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" "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" "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.")); "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 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::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); std::string msg;
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
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) { 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" 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" "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" "Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
"'equivalent_pins' in the LVS script.")); "'equivalent_pins' in the LVS script."));
} else { } else {
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n" msg = tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n"
"originating from equivalent circuits.\n" "originating from equivalent circuits.\n"
"If the circuits behind the subcircuits are identical, using 'same_circuits'\n" "If the circuits behind the subcircuits are identical, using 'same_circuits'\n"
"in the LVS script will associate them.")); "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::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); std::string msg;
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" std::pair<IndexedNetlistModel::net_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = net_from_index (circuits, index);
"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" if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
"mismatching items (with errors or warnings) and fix these issues.\n" msg = tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n"
"Otherwise, look for the corresponding other net.\n" "counterpart in the other netlist (component-wise and pin/terminal-wise).\n"
"Net items not found in the reference netlist indicate additional connections.\n" "If there already is a net candidate from the other netlist, scan the net members for\n"
"Net items only found in the reference netlist indicate missing connections.")); "mismatching items (with errors or warnings) and fix these issues.\n"
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) { "Otherwise, look for the corresponding other net.\n"
return tl::to_string (tr ("Nets match, but the choice was ambiguous. This may lead to mismatching nets in other places.\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::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); std::string msg;
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
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) { if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching device was found in the other netlist.\n" 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" "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" "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.")); "Make all terminal nets match and the devices will match too."));
} else { } else {
return tl::to_string (tr ("Devices don't match topologically.\n" msg = tl::to_string (tr ("Devices don't match topologically.\n"
"Check the terminal connections to identify the terminals not being connected to\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" "corresponding nets. Either the devices are not connected correctly or the nets\n"
"need to be fixed before the devices will match too.")); "need to be fixed before the devices will match too."));
} }
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) { } else if (cps.second.first == db::NetlistCrossReference::MatchWithWarning) {
return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n" msg = tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n"
"device classes don't match.\n" "device classes don't match.\n"
"If the device class is different but should be considered the same, using\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.")); "'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::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); std::string msg;
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
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) { if (!cps.first.first || !cps.first.second) {
return tl::to_string (tr ("No matching pin was found in the other netlist.\n" 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" "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.")); "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::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); std::string msg;
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
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) { 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" 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" "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" "Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
"'equivalent_pins' in the LVS script.")); "'equivalent_pins' in the LVS script."));
} else { } else {
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n" msg = tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n"
"equivalent circuits.\n" "equivalent circuits.\n"
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n" "If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n"
"will associate them.")); "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 device_pair &device_pair) const;
virtual circuit_pair parent_of (const subcircuit_pair &subcircuit_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, std::pair<Status, std::string> > 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, std::pair<Status, std::string> > 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<circuit_pair, std::pair<Status, std::string> > 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<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::Net *second_net_for (const db::Net *first) const;
virtual const db::Circuit *second_circuit_for (const db::Circuit *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 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_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_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 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<device_pair, std::pair<Status, std::string> > 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<pin_pair, std::pair<Status, std::string> > 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<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 top_circuit_status_hint (size_t index) const;
virtual std::string 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 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 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 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; virtual std::string pin_status_hint (const circuit_pair &circuits, size_t index) const;

View File

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

View File

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

View File

@ -17,39 +17,52 @@
<text> <text>
module LVS module LVS
def self.execute_lvs(macro, generator, l2ndb_index = nil) class LVSExecutable &lt; RBA::Executable
timer = RBA::Timer::new def initialize(macro, generator, l2ndb_index = nil)
timer.start
lvs = LVSEngine::new
lvs._l2ndb_index = l2ndb_index
lvs._generator = generator
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 @macro = macro
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
end end
timer.stop def execute
lvs.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s")
@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 end
@ -83,8 +96,8 @@ module LVS
end end
# Implements the execute method # Implements the execute method
def execute(macro) def executable(macro)
LVS::execute_lvs(macro, @recipe.generator("script" => macro.path)) LVSExecutable::new(macro, @recipe.generator("script" => macro.path))
end end
end end
@ -110,8 +123,8 @@ module LVS
end end
# Implements the execute method # Implements the execute method
def execute(macro) def executable(macro)
LVS::execute_lvs(macro, @recipe.generator("script" => macro.path)) LVSExecutable::new(macro, @recipe.generator("script" => macro.path))
end end
end end
@ -123,7 +136,7 @@ module LVS
super("lvs", "LVS recipe") super("lvs", "LVS recipe")
end end
def execute(params) def executable(params)
script = params["script"] script = params["script"]
if ! script if ! script
@ -133,7 +146,7 @@ module LVS
macro = RBA::Macro::macro_by_path(script) macro = RBA::Macro::macro_by_path(script)
macro || raise("Can't find LVS script #{script} - unable to re-run") 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 end

View File

@ -30,7 +30,7 @@
#include "lymMacro.h" #include "lymMacro.h"
#include "tlFileUtils.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 (); std::string testsrc = priv ? tl::testsrc_private () : tl::testsrc ();
testsrc = tl::combine_path (tl::combine_path (testsrc, "testdata"), "lvs"); 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; tl::info << " golden: " << au_cir;
} }
EXPECT_EQ (res, true); 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) TEST(1_full)
@ -143,3 +148,9 @@ TEST(16_private)
// test_is_long_runner (); // test_is_long_runner ();
run_test (_this, "test_16.lvs", "test_16.cir.gz", "test_16.gds.gz", true); 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; 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 ()) { if (f_executable.can_issue ()) {
f_execute.issue<MacroInterpreter, const lym::Macro *> (&MacroInterpreter::execute, macro); 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: private:
tl::RegisteredClass <lym::MacroInterpreter> *mp_registration; 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"), gsi::method ("create_template", &MacroInterpreter::create_template, gsi::arg ("url"),
"@brief Creates a new macro template\n" "@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" "\n"
"This method will create a register a new macro template. It returns a \\Macro object which " "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, " "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 " "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" "performance reasons in version 0.25.\n"
) + ) +
gsi::callback ("execute", &gsi::MacroInterpreter::execute, &gsi::MacroInterpreter::f_execute, gsi::arg ("macro"), gsi::callback ("executable", &gsi::MacroInterpreter::executable, &gsi::MacroInterpreter::f_executable, gsi::arg ("macro"),
"@brief Gets called to execute a macro\n" "@brief Returns the executable object which implements the macro execution\n"
"This method must be reimplemented to execute the macro. " "This method must be reimplemented to return an \\Executable object for the actual implementation. "
"The system will call this script when a macro with interpreter type 'dsl' and the " "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." "name of this interpreter is run.\n"
"\n" "\n"
"@param macro The macro to execute\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" "@brief A custom interpreter for a DSL (domain specific language)\n"
"\n" "\n"
@ -413,6 +417,21 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"just evaluates the script text:\n" "just evaluates the script text:\n"
"\n" "\n"
"@code\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" "class SimpleInterpreter < RBA::MacroInterpreter\n"
"\n" "\n"
" # Constructor\n" " # Constructor\n"
@ -427,9 +446,9 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
" mt.description = \"Special;;Simple interpreter macro\"\n" " mt.description = \"Special;;Simple interpreter macro\"\n"
" end\n" " end\n"
" \n" " \n"
" # Implements the execute method\n" " # Creates the executable delegate\n"
" def execute(macro)\n" " def executable(macro)\n"
" eval(macro.text, nil, macro.path)\n" " SimpleExecutable::new(macro)\n"
" end\n" " end\n"
"\n" "\n"
"end\n" "end\n"
@ -447,7 +466,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
"\n" "\n"
"In order to make the above code effective, store the code in an macro, set \"early auto-run\" and restart KLayout.\n" "In order to make the above code effective, store the code in an macro, set \"early auto-run\" and restart KLayout.\n"
"\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) static lym::Macro *macro_by_path (const std::string &path)

View File

@ -32,10 +32,10 @@
namespace lym namespace lym
{ {
void tl::Executable *
MacroInterpreter::execute (const lym::Macro *) const 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 bool
@ -107,7 +107,10 @@ MacroInterpreter::execute_macro (const lym::Macro *macro)
std::pair<std::string, std::string> et = cls->include_expansion (macro); std::pair<std::string, std::string> et = cls->include_expansion (macro);
if (et.first.empty () || et.first == macro->path ()) { 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 { } else {
@ -116,7 +119,10 @@ MacroInterpreter::execute_macro (const lym::Macro *macro)
tmp_macro.assign (*macro); tmp_macro.assign (*macro);
tmp_macro.set_text (et.second); tmp_macro.set_text (et.second);
tmp_macro.set_file_path (et.first); 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 "lymCommon.h"
#include "tlRecipe.h"
#include "gsiObject.h" #include "gsiObject.h"
#include "tlClassRegistry.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 * @brief Returns the storage scheme

View File

@ -146,7 +146,7 @@ public:
m_cell_stack.pop_back (); 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 (); db::cell_index_type ci = inst.object ().cell_index ();
if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) { 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 ()); tl_assert (! m_cell_stack.empty ());
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape); 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: public:

View File

@ -49,7 +49,11 @@ ProgressAdaptor::~ProgressAdaptor ()
void void
ProgressAdaptor::register_object (Progress *progress) 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. 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 void
@ -130,17 +134,19 @@ ProgressGarbageCollector::~ProgressGarbageCollector ()
// store a pointer but a pointer to a pointer. // store a pointer but a pointer to a pointer.
static tl::ThreadStorage<ProgressAdaptor **> s_thread_data; static tl::ThreadStorage<ProgressAdaptor **> s_thread_data;
Progress::Progress (const std::string &desc, size_t yield_interval) const double yield_timeout = 0.3;
: m_desc (desc), const size_t default_yield_interval = 1000;
m_final (false),
m_title (desc), Progress::Progress (const std::string &desc, size_t yield_interval, bool can_cancel)
: m_desc (desc), m_title (desc),
m_interval_count (0), 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_last_value (-1.0),
m_can_cancel (true), m_can_cancel (can_cancel),
m_cancelled (false) m_cancelled (false),
m_registered (false)
{ {
// .. nothing yet .. m_last_yield = tl::Clock::current ();
} }
Progress::~Progress () Progress::~Progress ()
@ -151,9 +157,19 @@ Progress::~Progress ()
void void
Progress::initialize () Progress::initialize ()
{ {
// The abstract progress does not get test() calls so we need to register it now.
ProgressAdaptor *a = adaptor (); ProgressAdaptor *a = adaptor ();
if (a) { if (a) {
a->register_object (this); 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 () Progress::shutdown ()
{ {
ProgressAdaptor *a = adaptor (); ProgressAdaptor *a = adaptor ();
if (a) { if (a && m_registered) {
a->unregister_object (this); a->unregister_object (this);
} }
} }
@ -194,29 +210,27 @@ Progress::adaptor ()
void void
Progress::signal_break () Progress::signal_break ()
{ {
m_cancelled = true; if (m_can_cancel) {
m_cancelled = true;
}
} }
void void
Progress::set_desc (const std::string &d) Progress::set_desc (const std::string &d)
{ {
ProgressAdaptor *a = adaptor (); if (d != m_desc) {
if (a && d != m_desc) {
m_desc = d; m_desc = d;
a->trigger (this); test (true);
a->yield (this);
if (m_cancelled) {
m_cancelled = false;
throw tl::BreakException ();
}
} }
} }
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) { if (++m_interval_count >= m_yield_interval || force_yield) {
ProgressAdaptor *a = adaptor (); ProgressAdaptor *a = adaptor ();
@ -228,22 +242,28 @@ bool Progress::test(bool force_yield)
needs_trigger = true; needs_trigger = true;
} }
if (m_desc != m_last_desc) {
m_last_desc = m_desc;
needs_trigger = true;
}
m_interval_count = 0; m_interval_count = 0;
if (a) { if (a) {
tl::Clock now = tl::Clock::current (); 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; m_last_yield = now;
if (needs_trigger) { if (needs_trigger) {
a->trigger (this); a->trigger (this);
} }
a->yield (this);
}
}
if (m_cancelled) { a->yield (this);
m_cancelled = false;
throw tl::BreakException (); }
} }
return true; return true;
@ -270,8 +290,8 @@ AbstractProgress::~AbstractProgress ()
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// RelativeProgress implementation // RelativeProgress implementation
RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval) RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval, bool can_cancel)
: Progress (desc, yield_interval) : Progress (desc, yield_interval, can_cancel)
{ {
m_format = "%.0f%%"; m_format = "%.0f%%";
m_unit = double (max_count) / 100.0; m_unit = double (max_count) / 100.0;
@ -315,8 +335,8 @@ RelativeProgress::set (size_t count, bool force_yield)
// --------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------
// Progress implementation // Progress implementation
AbsoluteProgress::AbsoluteProgress (const std::string &desc, size_t yield_interval) AbsoluteProgress::AbsoluteProgress (const std::string &desc, size_t yield_interval, bool can_cancel)
: Progress (desc, yield_interval) : Progress (desc, yield_interval, can_cancel)
{ {
m_format = "%.0f"; m_format = "%.0f";
m_unit = 1.0; m_unit = 1.0;

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