mirror of https://github.com/KLayout/klayout.git
Merge branch 'drc-enhancements' into fill-enhancements
This commit is contained in:
commit
8fda92a9c4
|
|
@ -34,7 +34,7 @@ def Get_Default_Config():
|
|||
Usage = "\n"
|
||||
Usage += "---------------------------------------------------------------------------------------------------------\n"
|
||||
Usage += "<< Usage of 'build4mac.py' >>\n"
|
||||
Usage += " for building KLayout 0.26.1 or later on different Apple Mac OSX platforms.\n"
|
||||
Usage += " for building KLayout 0.26.11 or later on different Apple Mac OSX platforms.\n"
|
||||
Usage += "\n"
|
||||
Usage += "$ [python] ./build4mac.py \n"
|
||||
Usage += " option & argument : descriptions (refer to 'macbuild/build4mac_env.py' for details)| default value\n"
|
||||
|
|
@ -58,6 +58,7 @@ def Get_Default_Config():
|
|||
Usage += " : Ana3: use Python 3.7 from Anaconda3 | \n"
|
||||
Usage += " : HBAuto: use the latest Python 3.x auto-detected from Homebrew | \n"
|
||||
Usage += " [-n|--noqtbinding] : don't create Qt bindings for ruby scripts | disabled \n"
|
||||
Usage += " [-u|--noqtuitools] : don't include uitools in Qt binding | disabled \n"
|
||||
Usage += " [-m|--make <option>] : option passed to 'make' | '-j4' \n"
|
||||
Usage += " [-d|--debug] : enable debug mode build | disabled \n"
|
||||
Usage += " [-c|--checkcom] : check command-line and exit without building | disabled \n"
|
||||
|
|
@ -137,6 +138,7 @@ def Get_Default_Config():
|
|||
|
||||
NonOSStdLang = False
|
||||
NoQtBindings = False
|
||||
NoQtUiTools = False
|
||||
MakeOptions = "-j4"
|
||||
DebugMode = False
|
||||
CheckComOnly = False
|
||||
|
|
@ -157,6 +159,7 @@ def Get_Default_Config():
|
|||
config['ModulePython'] = ModulePython # Python module to be used
|
||||
config['NonOSStdLang'] = NonOSStdLang # True if non-OS-standard language is chosen
|
||||
config['NoQtBindings'] = NoQtBindings # True if not creating Qt bindings for Ruby scripts
|
||||
config['NoQtUiTools'] = NoQtUiTools # True if not to include QtUiTools in Qt binding
|
||||
config['MakeOptions'] = MakeOptions # options passed to `make`
|
||||
config['DebugMode'] = DebugMode # True if debug mode build
|
||||
config['CheckComOnly'] = CheckComOnly # True if only for checking the command line parameters to "build.sh"
|
||||
|
|
@ -195,6 +198,7 @@ def Parse_CLI_Args(config):
|
|||
ModulePython = config['ModulePython']
|
||||
NonOSStdLang = config['NonOSStdLang']
|
||||
NoQtBindings = config['NoQtBindings']
|
||||
NoQtUiTools = config['NoQtUiTools']
|
||||
MakeOptions = config['MakeOptions']
|
||||
DebugMode = config['DebugMode']
|
||||
CheckComOnly = config['CheckComOnly']
|
||||
|
|
@ -226,6 +230,12 @@ def Parse_CLI_Args(config):
|
|||
default=False,
|
||||
help="do not create Qt bindings for Ruby scripts" )
|
||||
|
||||
p.add_option( '-u', '--noqtuitools',
|
||||
action='store_true',
|
||||
dest='no_qt_uitools',
|
||||
default=False,
|
||||
help="don't include uitools in Qt binding" )
|
||||
|
||||
p.add_option( '-m', '--make',
|
||||
dest='make_option',
|
||||
help="options passed to `make`" )
|
||||
|
|
@ -268,6 +278,7 @@ def Parse_CLI_Args(config):
|
|||
type_ruby = "sys",
|
||||
type_python = "sys",
|
||||
no_qt_binding = False,
|
||||
no_qt_uitools = False,
|
||||
make_option = "-j4",
|
||||
debug_build = False,
|
||||
check_command = False,
|
||||
|
|
@ -406,6 +417,7 @@ def Parse_CLI_Args(config):
|
|||
ModuleSet = ( choiceQt5, choiceRuby, choicePython )
|
||||
|
||||
NoQtBindings = opt.no_qt_binding
|
||||
NoQtUiTools = opt.no_qt_uitools
|
||||
MakeOptions = opt.make_option
|
||||
DebugMode = opt.debug_build
|
||||
CheckComOnly = opt.check_command
|
||||
|
|
@ -462,6 +474,7 @@ def Parse_CLI_Args(config):
|
|||
config['ModulePython'] = ModulePython
|
||||
config['NonOSStdLang'] = NonOSStdLang
|
||||
config['NoQtBindings'] = NoQtBindings
|
||||
config['NoQtUiTools'] = NoQtUiTools
|
||||
config['MakeOptions'] = MakeOptions
|
||||
config['DebugMode'] = DebugMode
|
||||
config['CheckComOnly'] = CheckComOnly
|
||||
|
|
@ -491,6 +504,7 @@ def Get_Build_Parameters(config):
|
|||
ModulePython = config['ModulePython']
|
||||
ModuleSet = config['ModuleSet']
|
||||
NoQtBindings = config['NoQtBindings']
|
||||
NoQtUiTools = config['NoQtUiTools']
|
||||
MakeOptions = config['MakeOptions']
|
||||
DebugMode = config['DebugMode']
|
||||
CheckComOnly = config['CheckComOnly']
|
||||
|
|
@ -542,11 +556,14 @@ def Get_Build_Parameters(config):
|
|||
# (E) want Qt bindings with Ruby scripts?
|
||||
parameters['no_qt_bindings'] = NoQtBindings
|
||||
|
||||
# (F) options to `make` tool
|
||||
# (F) want QtUiTools?
|
||||
parameters['no_qt_uitools'] = NoQtUiTools
|
||||
|
||||
# (G) options to `make` tool
|
||||
if not MakeOptions == "":
|
||||
parameters['make_options'] = MakeOptions
|
||||
|
||||
# (G) about Ruby
|
||||
# (H) about Ruby
|
||||
if ModuleRuby != "nil":
|
||||
parameters['ruby'] = RubyDictionary[ModuleRuby]['exe']
|
||||
parameters['rbinc'] = RubyDictionary[ModuleRuby]['inc']
|
||||
|
|
@ -554,7 +571,7 @@ def Get_Build_Parameters(config):
|
|||
if 'inc2' in RubyDictionary[ModuleRuby]:
|
||||
parameters['rbinc2'] = RubyDictionary[ModuleRuby]['inc2']
|
||||
|
||||
# (H) about Python
|
||||
# (I) about Python
|
||||
if ModulePython != "nil":
|
||||
parameters['python'] = PythonDictionary[ModulePython]['exe']
|
||||
parameters['pyinc'] = PythonDictionary[ModulePython]['inc']
|
||||
|
|
@ -566,7 +583,7 @@ def Get_Build_Parameters(config):
|
|||
config['MacBuildDirQAT'] = MacBuildDirQAT # relative path to build directory for QATest
|
||||
config['MacBuildLog'] = MacBuildLog # relative path to build log file
|
||||
|
||||
# (I) Extra parameteres needed for deployment
|
||||
# (J) Extra parameters needed for deployment
|
||||
parameters['project_dir'] = ProjectDir
|
||||
return parameters
|
||||
|
||||
|
|
@ -607,11 +624,15 @@ def Run_Build_Command(parameters):
|
|||
else:
|
||||
cmd_args += " \\\n -with-qtbinding"
|
||||
|
||||
# (F) options to `make` tool
|
||||
# (F) want QtUiTools?
|
||||
if parameters['no_qt_uitools']:
|
||||
cmd_args += " \\\n -without-qt-uitools"
|
||||
|
||||
# (G) options to `make` tool
|
||||
if 'make_options' in parameters:
|
||||
cmd_args += " \\\n -option %s" % parameters['make_options']
|
||||
|
||||
# (G) about Ruby
|
||||
# (H) about Ruby
|
||||
if 'ruby' in parameters:
|
||||
cmd_args += " \\\n -ruby %s" % parameters['ruby']
|
||||
cmd_args += " \\\n -rbinc %s" % parameters['rbinc']
|
||||
|
|
@ -621,7 +642,7 @@ def Run_Build_Command(parameters):
|
|||
else:
|
||||
cmd_args += " \\\n -noruby"
|
||||
|
||||
# (H) about Python
|
||||
# (I) about Python
|
||||
if 'python' in parameters:
|
||||
cmd_args += " \\\n -python %s" % parameters['python']
|
||||
cmd_args += " \\\n -pyinc %s" % parameters['pyinc']
|
||||
|
|
|
|||
|
|
@ -378,28 +378,77 @@ AsIfFlatRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &f
|
|||
return new_edge_pairs.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const
|
||||
namespace {
|
||||
|
||||
class OutputPairHolder
|
||||
{
|
||||
public:
|
||||
OutputPairHolder (InteractingOutputMode output_mode, bool merged_semantics)
|
||||
{
|
||||
if (output_mode == None) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (output_mode == Positive || output_mode == Negative || output_mode == PositiveAndNegative) {
|
||||
m_positive.reset (new FlatRegion (merged_semantics));
|
||||
m_results.push_back (& m_positive->raw_polygons ());
|
||||
} else {
|
||||
m_results.push_back ((db::Shapes *) 0);
|
||||
}
|
||||
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
m_negative.reset (new FlatRegion (merged_semantics));
|
||||
m_results.push_back (& m_negative->raw_polygons ());
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *> region_pair ()
|
||||
{
|
||||
return std::make_pair (m_positive.release (), m_negative.release ());
|
||||
}
|
||||
|
||||
const std::vector<db::Shapes *> &results () { return m_results; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<FlatRegion> m_positive, m_negative;
|
||||
std::vector<db::Shapes *> m_results;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
min_count = std::max (size_t (1), min_count);
|
||||
|
||||
if (max_count < min_count || other.empty ()) {
|
||||
if (! inverse) {
|
||||
return new EmptyRegion ();
|
||||
// shortcut
|
||||
if (empty ()) {
|
||||
if (output_mode == Positive || output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return clone ();
|
||||
return std::make_pair (clone (), clone ());
|
||||
}
|
||||
} else if (max_count < min_count || other.empty ()) {
|
||||
if (output_mode == Positive) {
|
||||
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new EmptyRegion (), clone ());
|
||||
}
|
||||
} else if (empty ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
|
||||
|
||||
#if defined(USE_LOCAL_PROCESSOR)
|
||||
|
||||
db::RegionIterator polygons (begin_merged ());
|
||||
|
||||
db::interacting_with_edge_local_operation<db::Polygon, db::Edge, db::Polygon> op (inverse, min_count, max_count, true);
|
||||
db::interacting_with_edge_local_operation<db::Polygon, db::Edge, db::Polygon> op (output_mode, min_count, max_count, true);
|
||||
|
||||
db::local_processor<db::Polygon, db::Edge, db::Polygon> proc;
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
|
|
@ -413,71 +462,42 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse,
|
|||
std::vector<db::Shapes *> results;
|
||||
results.push_back (&output->raw_polygons ());
|
||||
|
||||
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
|
||||
proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
|
||||
|
||||
return output.release ();
|
||||
|
||||
#else
|
||||
std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > counted_results;
|
||||
ResultCountingInserter inserter (counted_results);
|
||||
|
||||
db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve1 (count ());
|
||||
scanner.reserve2 (other.count ());
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (false));
|
||||
region_to_edge_interaction_filter<db::Polygon, db::Edge, ResultCountingInserter> filter (inserter, false, counting /*get all in counting mode*/);
|
||||
|
||||
AddressablePolygonDelivery p (begin_merged ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
if (inverse) {
|
||||
inserter.init (p.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
AddressableEdgeDelivery e (counting ? other.addressable_merged_edges () : other.addressable_edges ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert2 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Edge> ());
|
||||
|
||||
// select hits based on their count
|
||||
|
||||
for (std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> >::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
|
||||
bool hit = r->second >= min_count && r->second <= max_count;
|
||||
if (hit != inverse) {
|
||||
output->insert (*r->first);
|
||||
}
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
#endif
|
||||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
min_count = std::max (size_t (1), min_count);
|
||||
OutputPairHolder oph (output_mode, merged_semantics ());
|
||||
|
||||
if (max_count < min_count || other.empty ()) {
|
||||
if (! inverse) {
|
||||
return new EmptyRegion ();
|
||||
} else {
|
||||
return clone ();
|
||||
}
|
||||
} else if (empty ()) {
|
||||
return clone ();
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
#if defined(USE_LOCAL_PROCESSOR)
|
||||
min_count = std::max (size_t (1), min_count);
|
||||
|
||||
// shortcut
|
||||
if (empty ()) {
|
||||
if (output_mode == Positive || output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (clone (), clone ());
|
||||
}
|
||||
} else if (max_count < min_count || other.empty ()) {
|
||||
if (output_mode == Positive) {
|
||||
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new EmptyRegion (), clone ());
|
||||
}
|
||||
}
|
||||
|
||||
db::RegionIterator polygons (begin_merged ());
|
||||
|
||||
db::interacting_with_text_local_operation<db::Polygon, db::Text, db::Polygon> op (inverse, min_count, max_count);
|
||||
db::interacting_with_text_local_operation<db::Polygon, db::Text, db::Polygon> op (output_mode, min_count, max_count);
|
||||
|
||||
db::local_processor<db::Polygon, db::Text, db::Polygon> proc;
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
|
|
@ -487,84 +507,58 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse,
|
|||
std::vector<generic_shape_iterator<db::Text> > others;
|
||||
others.push_back (other.begin ());
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ()));
|
||||
std::vector<db::Shapes *> results;
|
||||
results.push_back (&output->raw_polygons ());
|
||||
proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
|
||||
|
||||
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
|
||||
|
||||
return output.release ();
|
||||
|
||||
#else
|
||||
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
|
||||
|
||||
std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> > counted_results;
|
||||
ResultCountingInserter inserter (counted_results);
|
||||
|
||||
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve1 (count ());
|
||||
scanner.reserve2 (other.count ());
|
||||
|
||||
region_to_text_interaction_filter<db::Polygon, db::Text, ResultCountingInserter> filter (inserter, false, counting /*get all in counting mode*/);
|
||||
|
||||
AddressablePolygonDelivery p (begin_merged ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
if (inverse) {
|
||||
inserter.init (p.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
AddressableTextDelivery e (other.addressable_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert2 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
|
||||
|
||||
// select hits based on their count
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (true));
|
||||
|
||||
for (std::unordered_map<const db::Polygon *, size_t, std::ptr_hash_from_value<db::Polygon> >::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
|
||||
bool hit = r->second >= min_count && r->second <= max_count;
|
||||
if (hit != inverse) {
|
||||
output->insert (*r->first);
|
||||
}
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
#endif
|
||||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
min_count = std::max (size_t (1), min_count);
|
||||
|
||||
// shortcut
|
||||
if (empty ()) {
|
||||
return clone ();
|
||||
if (output_mode == Positive || output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (clone (), clone ());
|
||||
}
|
||||
} else if (max_count < min_count || other.empty ()) {
|
||||
// clear, if b is empty and
|
||||
// * mode is inside, enclosing or interacting and inverse is false ("inside" or "interacting")
|
||||
// * mode is outside and inverse is true ("not outside")
|
||||
if ((mode <= 0) != inverse) {
|
||||
return new EmptyRegion ();
|
||||
if ((mode <= 0)) {
|
||||
if (output_mode == Positive) {
|
||||
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new EmptyRegion (), clone ());
|
||||
}
|
||||
} else {
|
||||
return clone ();
|
||||
if (output_mode == Positive) {
|
||||
return std::make_pair (clone(), (RegionDelegate *) 0);
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (clone (), new EmptyRegion ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(USE_LOCAL_PROCESSOR)
|
||||
|
||||
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
|
||||
|
||||
db::RegionIterator polygons (begin_merged ());
|
||||
|
||||
db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> op (mode, touching, inverse, min_count, max_count, true);
|
||||
db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> op (mode, touching, output_mode, min_count, max_count, true);
|
||||
|
||||
db::local_processor<db::Polygon, db::Polygon, db::Polygon> proc;
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
|
|
@ -574,121 +568,9 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
|
|||
std::vector<generic_shape_iterator<db::Polygon> > others;
|
||||
others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ());
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ()));
|
||||
std::vector<db::Shapes *> results;
|
||||
results.push_back (&output->raw_polygons ());
|
||||
proc.run_flat (polygons, others, std::vector<bool> (), &op, oph.results ());
|
||||
|
||||
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
|
||||
|
||||
return output.release ();
|
||||
|
||||
#else
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
ep.set_base_verbosity (base_verbosity ());
|
||||
|
||||
size_t n = 0;
|
||||
size_t nstart = 0;
|
||||
|
||||
if (mode < -1) {
|
||||
|
||||
// in enclosing mode self must be primary and other the secondary. For other
|
||||
// modes it's the other way round
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
|
||||
if (mode > 0 || p->box ().touches (other.bbox ())) {
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
}
|
||||
|
||||
nstart = n;
|
||||
|
||||
}
|
||||
|
||||
if (min_count == size_t (1) && max_count == std::numeric_limits<size_t>::max ()) {
|
||||
|
||||
if (mode < 0) {
|
||||
|
||||
// NOTE: on "inside" or "enclosing", the other region must be merged
|
||||
for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) {
|
||||
if (p->box ().touches (bbox ())) {
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (RegionIterator p = other.begin (); ! p.at_end (); ++p) {
|
||||
if (p->box ().touches (bbox ())) {
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
++n;
|
||||
|
||||
} else {
|
||||
|
||||
// with counting we need to separate the other polygons by different properties
|
||||
|
||||
// cannot only have min_count/max_count in outside mode
|
||||
tl_assert (mode <= 0);
|
||||
|
||||
for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) {
|
||||
if (p->box ().touches (bbox ())) {
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
++n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mode >= -1) {
|
||||
|
||||
nstart = n;
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
|
||||
if (mode > 0 || p->box ().touches (other.bbox ())) {
|
||||
ep.insert (*p, n);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// there should be at least one element to look at for primary
|
||||
tl_assert (nstart > 0);
|
||||
|
||||
db::InteractionDetector id (mode, nstart - 1);
|
||||
id.set_include_touching (touching);
|
||||
db::EdgeSink es;
|
||||
ep.process (es, id);
|
||||
id.finish ();
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (false));
|
||||
|
||||
std::map <size_t, size_t> interaction_counts;
|
||||
for (db::InteractionDetector::iterator i = id.begin (); i != id.end () ; ++i) {
|
||||
if (i->first < nstart && i->second >= nstart) {
|
||||
interaction_counts [mode < -1 ? i->first : i->second] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
output->reserve (n);
|
||||
|
||||
n = (mode < -1 ? 0 : nstart);
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) {
|
||||
size_t count = 0;
|
||||
std::map <size_t, size_t>::const_iterator c = interaction_counts.find (n);
|
||||
if (c != interaction_counts.end ()) {
|
||||
count = c->second;
|
||||
}
|
||||
if ((count >= min_count && count <= max_count) != inverse) {
|
||||
output->insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
#endif
|
||||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
|
|
|
|||
|
|
@ -139,72 +139,107 @@ public:
|
|||
|
||||
virtual RegionDelegate *selected_outside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, 1, false, false);
|
||||
return selected_interacting_generic (other, 1, false, Positive, size_t (0), std::numeric_limits<size_t>::max ()).first;
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_outside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, 1, false, true);
|
||||
return selected_interacting_generic (other, 1, false, Negative, size_t (0), std::numeric_limits<size_t>::max ()).first;
|
||||
}
|
||||
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, 1, false, PositiveAndNegative, size_t (0), std::numeric_limits<size_t>::max ());
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_inside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, -1, true, false);
|
||||
return selected_interacting_generic (other, -1, true, Positive, size_t (0), std::numeric_limits<size_t>::max ()).first;
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_inside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, -1, true, true);
|
||||
return selected_interacting_generic (other, -1, true, Negative, size_t (0), std::numeric_limits<size_t>::max ()).first;
|
||||
}
|
||||
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_inside_pair (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, -1, true, PositiveAndNegative, size_t (0), std::numeric_limits<size_t>::max ());
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, -2, false, false, min_count, max_count);
|
||||
return selected_interacting_generic (other, -2, false, Positive, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_enclosing (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, -2, false, true, min_count, max_count);
|
||||
return selected_interacting_generic (other, -2, false, Negative, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_enclosing_pair (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, -2, false, PositiveAndNegative, min_count, max_count);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, true, false, min_count, max_count);
|
||||
return selected_interacting_generic (other, 0, true, Positive, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, true, true, min_count, max_count);
|
||||
return selected_interacting_generic (other, 0, true, Negative, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, true, PositiveAndNegative, min_count, max_count);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, false, min_count, max_count);
|
||||
return selected_interacting_generic (other, Positive, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, true, min_count, max_count);
|
||||
return selected_interacting_generic (other, Negative, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, PositiveAndNegative, min_count, max_count);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, false, min_count, max_count);
|
||||
return selected_interacting_generic (other, Positive, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, true, min_count, max_count);
|
||||
return selected_interacting_generic (other, Negative, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Texts &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, PositiveAndNegative, min_count, max_count);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_overlapping (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, false, false, min_count, max_count);
|
||||
return selected_interacting_generic (other, 0, false, Positive, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, false, true, min_count, max_count);
|
||||
return selected_interacting_generic (other, 0, false, Negative, min_count, max_count).first;
|
||||
}
|
||||
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_overlapping_pair (const Region &other, size_t min_count, size_t max_count) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, false, PositiveAndNegative, min_count, max_count);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *pull_inside (const Region &other) const
|
||||
|
|
@ -245,9 +280,9 @@ protected:
|
|||
|
||||
virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const;
|
||||
virtual EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
|
||||
virtual EdgesDelegate *pull_generic (const Edges &other) const;
|
||||
virtual TextsDelegate *pull_generic (const Texts &other) const;
|
||||
|
|
|
|||
|
|
@ -1060,13 +1060,13 @@ template void CompoundRegionLogicalCaseSelectOperationNode::implement_compute_lo
|
|||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count)
|
||||
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count, b->is_merged ())
|
||||
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse ? Negative : Positive, min_count, max_count, b->is_merged ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (db::Region *a, db::Region *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count)
|
||||
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count, b->is_merged ())
|
||||
: compound_region_generic_operation_node<db::Polygon, db::Polygon, db::Polygon> (&m_op, a, b), m_op (mode, touching, inverse ? Negative : Positive, min_count, max_count, b->is_merged ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -1080,7 +1080,7 @@ CompoundRegionInteractOperationNode::generated_description () const
|
|||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
CompoundRegionInteractWithEdgeOperationNode::CompoundRegionInteractWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, bool inverse, size_t min_count, size_t max_count)
|
||||
: compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon> (&m_op, a, b), m_op (inverse, min_count, max_count, b->is_merged ())
|
||||
: compound_region_generic_operation_node<db::Polygon, db::Edge, db::Polygon> (&m_op, a, b), m_op (inverse ? Negative : Positive, min_count, max_count, b->is_merged ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -753,7 +753,8 @@ public:
|
|||
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::PolygonRef, db::PolygonRef> & /*interactions*/, std::vector<std::unordered_set<db::EdgePair> > & /*results*/, size_t /*max_vertex_count*/, double /*area_ratio*/) const { }
|
||||
|
||||
private:
|
||||
db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> m_op;
|
||||
typedef db::interacting_local_operation<db::Polygon, db::Polygon, db::Polygon> op_type;
|
||||
op_type m_op;
|
||||
};
|
||||
|
||||
class DB_PUBLIC CompoundRegionInteractWithEdgeOperationNode
|
||||
|
|
|
|||
|
|
@ -1519,9 +1519,67 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, c
|
|||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const
|
||||
namespace
|
||||
{
|
||||
|
||||
class InteractingResultHolder
|
||||
{
|
||||
public:
|
||||
InteractingResultHolder (InteractingOutputMode output_mode, bool is_merged, const db::DeepLayer &polygons)
|
||||
: m_output_mode (output_mode), m_is_merged (is_merged)
|
||||
{
|
||||
if (m_output_mode == Positive || m_output_mode == Negative) {
|
||||
m_dl1 = db::DeepLayer (polygons.derived ());
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
m_dl1 = db::DeepLayer (polygons.derived ());
|
||||
m_dl2 = db::DeepLayer (polygons.derived ());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned int> layers () const
|
||||
{
|
||||
std::vector<unsigned int> l;
|
||||
if (m_output_mode == Positive || m_output_mode == Negative) {
|
||||
l.push_back (m_dl1.layer ());
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
l.push_back (m_dl1.layer ());
|
||||
l.push_back (m_dl2.layer ());
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *> result_pair ()
|
||||
{
|
||||
if (m_output_mode == Positive || m_output_mode == Negative) {
|
||||
db::DeepRegion *res = new db::DeepRegion (m_dl1);
|
||||
res->set_is_merged (m_is_merged);
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> (res, 0);
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
db::DeepRegion *res1 = new db::DeepRegion (m_dl1);
|
||||
res1->set_is_merged (m_is_merged);
|
||||
db::DeepRegion *res2 = new db::DeepRegion (m_dl2);
|
||||
res2->set_is_merged (m_is_merged);
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> (res1, res2);
|
||||
} else {
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> (0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
InteractingOutputMode m_output_mode;
|
||||
bool m_is_merged;
|
||||
DeepLayer m_dl1, m_dl2;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
if (output_mode == None) {
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> (0, 0);
|
||||
}
|
||||
|
||||
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
|
||||
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
|
|
@ -1539,9 +1597,7 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
|
|||
// NOTE: on "inside" or with counting, the other polygons must be merged
|
||||
const db::DeepLayer &other_polygons = (mode < 0 || counting) ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
|
||||
|
||||
DeepLayer dl_out (polygons.derived ());
|
||||
|
||||
db::InteractingLocalOperation op (mode, touching, inverse, min_count, max_count, true);
|
||||
db::InteractingLocalOperation op (mode, touching, output_mode, min_count, max_count, true);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ());
|
||||
proc.set_description (progress_desc ());
|
||||
|
|
@ -1553,17 +1609,16 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
|
|||
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
proc.run (&op, polygons.layer (), other_polygons.layer (), dl_out.layer ());
|
||||
bool result_is_merged = (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ()));
|
||||
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
|
||||
|
||||
db::DeepRegion *res = new db::DeepRegion (dl_out);
|
||||
if (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ())) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
return res;
|
||||
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
|
||||
|
||||
return orh.result_pair ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
|
||||
|
||||
|
|
@ -1580,9 +1635,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size
|
|||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (polygons.derived ());
|
||||
|
||||
db::InteractingWithEdgeLocalOperation op (inverse, min_count, max_count, true);
|
||||
db::InteractingWithEdgeLocalOperation op (output_mode, min_count, max_count, true);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::Edge, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
|
||||
proc.set_description (progress_desc ());
|
||||
|
|
@ -1594,13 +1647,12 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size
|
|||
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
bool result_is_merged = (! split_after && other.is_merged () && (merged_semantics () || is_merged ()));
|
||||
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
|
||||
|
||||
db::DeepRegion *res = new db::DeepRegion (dl_out);
|
||||
if (! split_after) {
|
||||
res->set_is_merged (other.is_merged () && (merged_semantics () || is_merged ()));
|
||||
}
|
||||
return res;
|
||||
proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), orh.layers ());
|
||||
|
||||
return orh.result_pair ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
|
|
@ -1706,8 +1758,9 @@ DeepRegion::pull_generic (const Texts &other) const
|
|||
return res;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
DeepRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
bool split_after = false;
|
||||
|
|
@ -1722,9 +1775,7 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size
|
|||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (polygons.derived ());
|
||||
|
||||
db::InteractingWithTextLocalOperation op (inverse, min_count, max_count);
|
||||
db::InteractingWithTextLocalOperation op (output_mode, min_count, max_count);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::TextRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
|
||||
proc.set_description (progress_desc ());
|
||||
|
|
@ -1736,13 +1787,12 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size
|
|||
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
bool result_is_merged = (! split_after && (merged_semantics () || is_merged ()));
|
||||
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
|
||||
|
||||
db::DeepRegion *res = new db::DeepRegion (dl_out);
|
||||
if (! split_after) {
|
||||
res->set_is_merged (merged_semantics () || is_merged ());
|
||||
}
|
||||
return res;
|
||||
proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), orh.layers ());
|
||||
|
||||
return orh.result_pair ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,9 +140,9 @@ protected:
|
|||
|
||||
virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const;
|
||||
virtual EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
|
||||
virtual EdgesDelegate *pull_generic (const Edges &other) const;
|
||||
virtual TextsDelegate *pull_generic (const Texts &other) const;
|
||||
|
|
|
|||
|
|
@ -953,7 +953,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
|
|||
// collects the cell mappings we skip because they are variants (variant building or box variants)
|
||||
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;
|
||||
|
||||
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) {
|
||||
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell () && original_builder.source ().global_trans ().is_unity ()) {
|
||||
|
||||
// This is the case of mapping back to the original. In this case we can use the information
|
||||
// provided inside the original hierarchy builders. They list the source cells and the target cells
|
||||
|
|
|
|||
|
|
@ -252,6 +252,7 @@ public:
|
|||
DeviceParameterCompareDelegate () { }
|
||||
virtual ~DeviceParameterCompareDelegate () { }
|
||||
|
||||
virtual DeviceParameterCompareDelegate *clone () const = 0;
|
||||
virtual bool less (const db::Device &a, const db::Device &b) const = 0;
|
||||
virtual bool equal (const db::Device &a, const db::Device &b) const = 0;
|
||||
};
|
||||
|
|
@ -273,6 +274,11 @@ public:
|
|||
virtual bool less (const db::Device &a, const db::Device &b) const;
|
||||
virtual bool equal (const db::Device &a, const db::Device &b) const;
|
||||
|
||||
virtual DeviceParameterCompareDelegate *clone () const
|
||||
{
|
||||
return new EqualDeviceParameters (*this);
|
||||
}
|
||||
|
||||
EqualDeviceParameters &operator+= (const EqualDeviceParameters &other);
|
||||
|
||||
EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const
|
||||
|
|
@ -298,6 +304,11 @@ public:
|
|||
virtual bool less (const db::Device &a, const db::Device &b) const;
|
||||
virtual bool equal (const db::Device &a, const db::Device &b) const;
|
||||
|
||||
virtual DeviceParameterCompareDelegate *clone () const
|
||||
{
|
||||
return new AllDeviceParametersAreEqual (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_relative;
|
||||
};
|
||||
|
|
@ -574,6 +585,14 @@ public:
|
|||
/**
|
||||
* @brief Gets the parameter compare delegate or null if no such delegate is registered
|
||||
*/
|
||||
const db::DeviceParameterCompareDelegate *parameter_compare_delegate () const
|
||||
{
|
||||
return mp_pc_delegate.get ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the parameter compare delegate or null if no such delegate is registered (non-const version)
|
||||
*/
|
||||
db::DeviceParameterCompareDelegate *parameter_compare_delegate ()
|
||||
{
|
||||
return mp_pc_delegate.get ();
|
||||
|
|
|
|||
|
|
@ -108,18 +108,25 @@ public:
|
|||
|
||||
virtual RegionDelegate *selected_outside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
virtual RegionDelegate *selected_inside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_inside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_inside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
virtual RegionDelegate *selected_enclosing (const Region &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_enclosing (const Region &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_enclosing_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
virtual RegionDelegate *selected_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
virtual RegionDelegate *selected_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Edges &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
virtual RegionDelegate *selected_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Texts &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
virtual RegionDelegate *selected_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_overlapping_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); }
|
||||
virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); }
|
||||
|
|
|
|||
|
|
@ -1280,6 +1280,14 @@ void local_processor<TS, TI, TR>::run (local_operation<TS, TI, TR> *op, unsigned
|
|||
run (op, subject_layer, il, ol);
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
void local_processor<TS, TI, TR>::run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, unsigned int intruder_layer, const std::vector<unsigned int> &output_layers)
|
||||
{
|
||||
std::vector<unsigned int> ol, il;
|
||||
il.push_back (intruder_layer);
|
||||
run (op, subject_layer, il, output_layers);
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
void local_processor<TS, TI, TR>::run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers, unsigned int output_layer)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -419,6 +419,7 @@ public:
|
|||
local_processor (db::Layout *layout = 0, db::Cell *top = 0, const std::set<db::cell_index_type> *breakout_cells = 0);
|
||||
local_processor (db::Layout *subject_layout, db::Cell *subject_top, const db::Layout *intruder_layout, const db::Cell *intruder_cell, const std::set<db::cell_index_type> *subject_breakout_cells = 0, const std::set<db::cell_index_type> *intruder_breakout_cells = 0);
|
||||
void run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, unsigned int intruder_layer, unsigned int output_layers);
|
||||
void run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, unsigned int intruder_layer, const std::vector<unsigned int> &output_layers);
|
||||
void run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers, const std::vector<unsigned int> &output_layers);
|
||||
void run (local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers, unsigned int output_layer);
|
||||
void compute_contexts (local_processor_contexts<TS, TI, TR> &contexts, const local_operation<TS, TI, TR> *op, unsigned int subject_layer, const std::vector<unsigned int> &intruder_layers) const;
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ int
|
|||
compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2)
|
||||
{
|
||||
if ((iter1.layout () == 0) != (iter2.layout () == 0)) {
|
||||
return (iter1.layout () == 0) < (iter2.layout () == 0);
|
||||
return (iter1.layout () == 0) < (iter2.layout () == 0) ? -1 : 1;
|
||||
}
|
||||
if ((iter1.top_cell () == 0) != (iter2.top_cell () == 0)) {
|
||||
return (iter1.top_cell () == 0) < (iter2.top_cell () == 0);
|
||||
return (iter1.top_cell () == 0) < (iter2.top_cell () == 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
// basic source (layout, top_cell) needs to be the same of course
|
||||
|
|
@ -70,6 +70,11 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
|
|||
return iter1.enables () < iter2.enables () ? -1 : 1;
|
||||
}
|
||||
|
||||
// compare global transformations
|
||||
if (! iter1.global_trans ().equal (iter2.global_trans ())) {
|
||||
return iter1.global_trans ().less (iter2.global_trans ()) ? -1 : 1;
|
||||
}
|
||||
|
||||
// if a region is set, the hierarchical appearance is the same only if the layers and
|
||||
// complex region are identical
|
||||
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) {
|
||||
|
|
@ -338,7 +343,7 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
|
|||
}
|
||||
|
||||
HierarchyBuilder::new_inst_mode
|
||||
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
{
|
||||
if (all) {
|
||||
|
||||
|
|
@ -349,6 +354,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
|
|||
if (m_cell_stack.back ().first) {
|
||||
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
|
||||
new_inst.object () = db::CellInst (new_cell);
|
||||
new_inst.transform (always_apply);
|
||||
new_inst.transform_into (m_trans);
|
||||
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
|
||||
(*c)->insert (new_inst);
|
||||
|
|
@ -367,7 +373,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
|
|||
}
|
||||
|
||||
bool
|
||||
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, 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 ®ion, const box_tree_type *complex_region, bool all)
|
||||
{
|
||||
if (all) {
|
||||
|
||||
|
|
@ -386,7 +392,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
|
|||
|
||||
// for a new cell, create this instance
|
||||
if (m_cell_stack.back ().first) {
|
||||
db::CellInstArray new_inst (db::CellInst (new_cell), trans);
|
||||
db::CellInstArray new_inst (db::CellInst (new_cell), always_apply * trans);
|
||||
new_inst.transform_into (m_trans);
|
||||
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
|
||||
(*c)->insert (new_inst);
|
||||
|
|
@ -399,11 +405,11 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
|
|||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box ®ion, 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 ®ion, const box_tree_type *complex_region)
|
||||
{
|
||||
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
|
||||
db::Shapes &shapes = (*c)->shapes (m_target_layer);
|
||||
mp_pipe->push (shape, m_trans, region, complex_region, &shapes);
|
||||
mp_pipe->push (shape, m_trans * apply_always, region, complex_region, &shapes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -528,9 +534,12 @@ ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Box &box, const
|
|||
|
||||
if (complex_region) {
|
||||
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (bb, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
|
||||
mp_pipe->push (*cr & bb, trans, world, 0, target);
|
||||
db::Box bc = *cr & bb;
|
||||
if (! bc.empty ()) {
|
||||
mp_pipe->push (bc, trans, world, 0, target);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (! bb.empty ()) {
|
||||
mp_pipe->push (bb, trans, world, 0, target);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -273,9 +273,9 @@ public:
|
|||
virtual void end (const RecursiveShapeIterator *iter);
|
||||
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box ®ion, const box_tree_type *complex_region);
|
||||
virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell);
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, 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 ®ion, 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 ®ion, const box_tree_type *complex_region);
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box ®ion, 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 ®ion, const box_tree_type *complex_region, bool all);
|
||||
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box ®ion, const box_tree_type *complex_region);
|
||||
|
||||
/**
|
||||
* @brief Sets the target layer - shapes will be put there
|
||||
|
|
|
|||
|
|
@ -1671,7 +1671,9 @@ Layout::do_update ()
|
|||
// HINT: because of some gcc bug, automatic destruction of the tl::Progress
|
||||
// object does not work. We overcome this problem by creating the object with new
|
||||
// and catching exceptions.
|
||||
tl::RelativeProgress *pr = new tl::RelativeProgress (tl::to_string (tr ("Sorting layout")), m_cells_size, 1000);
|
||||
// As this operation is critical we don't want to have it cancelled. Plus: do_update is called during ~LayoutLocker and
|
||||
// if we throw exceptions then, we'll get a runtime assertion.
|
||||
tl::RelativeProgress *pr = new tl::RelativeProgress (tl::to_string (tr ("Sorting layout")), m_cells_size, 0, false /*can't cancel*/);
|
||||
pr->set_desc ("");
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -632,6 +632,9 @@ LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutTo
|
|||
}
|
||||
|
||||
size_t pin_id = circuit->add_pin (pin).id ();
|
||||
// NOTE: because we identify pins by their order and not by ID we need to ensure the pin IDs are
|
||||
// generated sequentially.
|
||||
tl_assert (circuit->pin_count () == pin_id + 1);
|
||||
if (net) {
|
||||
circuit->connect_pin (pin_id, net);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -561,7 +561,8 @@ void std_writer_impl<Keys>::write (const db::SubCircuit &subcircuit, std::map<co
|
|||
*mp_stream << indent << indent2 << Keys::property_key << "(" << p->first.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl;
|
||||
}
|
||||
|
||||
for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p) {
|
||||
unsigned int pin_id = 0;
|
||||
for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p, ++pin_id) {
|
||||
const db::Net *net = subcircuit.net_for_pin (p->id ());
|
||||
if (net) {
|
||||
if (separate_lines) {
|
||||
|
|
@ -569,7 +570,7 @@ void std_writer_impl<Keys>::write (const db::SubCircuit &subcircuit, std::map<co
|
|||
} else {
|
||||
*mp_stream << " ";
|
||||
}
|
||||
*mp_stream << Keys::pin_key << "(" << tl::to_string (p->id ()) << " " << net2id [net] << ")";
|
||||
*mp_stream << Keys::pin_key << "(" << tl::to_string (pin_id) << " " << net2id [net] << ")";
|
||||
if (separate_lines) {
|
||||
*mp_stream << endl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,19 +88,19 @@ namespace db
|
|||
*
|
||||
* [xref-def]:
|
||||
*
|
||||
* circuit([non] [non] [status]? [circuit-xrefs])
|
||||
* circuit([non] [non] [status]? [message]? [circuit-xrefs])
|
||||
* - circuit pair [short key: X]
|
||||
*
|
||||
* [circuit-xrefs]:
|
||||
*
|
||||
* xref([pair]*)
|
||||
* xref([pair]*) - circuit cross-reference part [short key: Z]
|
||||
*
|
||||
* [pair]
|
||||
*
|
||||
* pin([ion] [ion] [status]?) - a pin pair [short key: P]
|
||||
* device([ion] [ion] [status]?) - a device pair [short key: D]
|
||||
* circuit([ion] [ion] [status]?) - a subcircuit pair [short key: X]
|
||||
* net([ion] [ion] [status]?) - a net pair [short key: N]
|
||||
* pin([ion] [ion] [status]? [message]?) - a pin pair [short key: P]
|
||||
* device([ion] [ion] [status]? [message]?) - a device pair [short key: D]
|
||||
* circuit([ion] [ion] [status]? [message]?) - a subcircuit pair [short key: X]
|
||||
* net([ion] [ion] [status]? [message]?) - a net pair [short key: N]
|
||||
*
|
||||
* [non]
|
||||
*
|
||||
|
|
@ -110,6 +110,10 @@ namespace db
|
|||
*
|
||||
* <id> | ()
|
||||
*
|
||||
* [message]
|
||||
*
|
||||
* description(<name>) - error description [short key: B]
|
||||
*
|
||||
* [status]
|
||||
*
|
||||
* mismatch | - [short key: 0]
|
||||
|
|
|
|||
|
|
@ -112,6 +112,18 @@ void LayoutVsSchematicStandardReader::read_netlist (db::LayoutVsSchematic *lvs)
|
|||
}
|
||||
}
|
||||
|
||||
bool LayoutVsSchematicStandardReader::read_message (std::string &msg)
|
||||
{
|
||||
if (test (skeys::description_key) || test (lkeys::description_key)) {
|
||||
Brace br (this);
|
||||
read_word_or_quoted (msg);
|
||||
br.done ();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::Status &status)
|
||||
{
|
||||
if (test (skeys::match_key) || test (lkeys::match_key)) {
|
||||
|
|
@ -189,11 +201,14 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref
|
|||
xref->gen_begin_circuit (circuit_a, circuit_b);
|
||||
|
||||
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
|
||||
std::string msg;
|
||||
|
||||
while (br) {
|
||||
|
||||
if (read_status (status)) {
|
||||
// continue
|
||||
} else if (read_message (msg)) {
|
||||
// continue
|
||||
} else if (test (skeys::xref_key) || test (lkeys::xref_key)) {
|
||||
read_xrefs_for_circuits (xref, circuit_a, circuit_b);
|
||||
} else if (at_end ()) {
|
||||
|
|
@ -204,7 +219,7 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref
|
|||
|
||||
}
|
||||
|
||||
xref->gen_end_circuit (circuit_a, circuit_b, status);
|
||||
xref->gen_end_circuit (circuit_a, circuit_b, status, msg);
|
||||
|
||||
br.done ();
|
||||
|
||||
|
|
@ -325,11 +340,13 @@ void LayoutVsSchematicStandardReader::read_net_pair (db::NetlistCrossReference *
|
|||
ion_b = read_ion ();
|
||||
|
||||
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
|
||||
std::string msg;
|
||||
read_status (status);
|
||||
read_message (msg);
|
||||
|
||||
br.done ();
|
||||
|
||||
xref->gen_nets (net_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), net_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status);
|
||||
xref->gen_nets (net_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), net_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg);
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardReader::read_pin_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b)
|
||||
|
|
@ -341,11 +358,13 @@ void LayoutVsSchematicStandardReader::read_pin_pair (db::NetlistCrossReference *
|
|||
ion_b = read_ion ();
|
||||
|
||||
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
|
||||
std::string msg;
|
||||
read_status (status);
|
||||
read_message (msg);
|
||||
|
||||
br.done ();
|
||||
|
||||
xref->gen_pins (pin_by_numerical_id (circuit_a, ion_a), pin_by_numerical_id (circuit_b, ion_b), status);
|
||||
xref->gen_pins (pin_by_numerical_id (circuit_a, ion_a), pin_by_numerical_id (circuit_b, ion_b), status, msg);
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardReader::read_device_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b)
|
||||
|
|
@ -357,11 +376,13 @@ void LayoutVsSchematicStandardReader::read_device_pair (db::NetlistCrossReferenc
|
|||
ion_b = read_ion ();
|
||||
|
||||
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
|
||||
std::string msg;
|
||||
read_status (status);
|
||||
read_message (msg);
|
||||
|
||||
br.done ();
|
||||
|
||||
xref->gen_devices (device_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), device_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status);
|
||||
xref->gen_devices (device_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), device_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg);
|
||||
}
|
||||
|
||||
void LayoutVsSchematicStandardReader::read_subcircuit_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b)
|
||||
|
|
@ -373,11 +394,13 @@ void LayoutVsSchematicStandardReader::read_subcircuit_pair (db::NetlistCrossRefe
|
|||
ion_b = read_ion ();
|
||||
|
||||
db::NetlistCrossReference::Status status = db::NetlistCrossReference::None;
|
||||
std::string msg;
|
||||
read_status (status);
|
||||
read_message (msg);
|
||||
|
||||
br.done ();
|
||||
|
||||
xref->gen_subcircuits (subcircuit_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), subcircuit_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status);
|
||||
xref->gen_subcircuits (subcircuit_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), subcircuit_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ private:
|
|||
void read_netlist (db::LayoutVsSchematic *lvs);
|
||||
|
||||
bool read_status (db::NetlistCrossReference::Status &status);
|
||||
bool read_message (std::string &msg);
|
||||
void read_xref (db::NetlistCrossReference *xref);
|
||||
void read_xrefs_for_circuits (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b);
|
||||
void read_net_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b);
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ private:
|
|||
}
|
||||
|
||||
std::string status_to_s (const db::NetlistCrossReference::Status status);
|
||||
std::string message_to_s (const std::string &msg);
|
||||
void write (const db::NetlistCrossReference *xref);
|
||||
|
||||
std::map<const db::Circuit *, std::map<const db::Net *, unsigned int> > m_net2id_per_circuit_a, m_net2id_per_circuit_b;
|
||||
|
|
@ -145,7 +146,7 @@ std::string ion_to_s (const Obj *obj)
|
|||
}
|
||||
}
|
||||
|
||||
std::string net_id_to_s (const db::Net *net, const std::map<const db::Net *, unsigned int> &net2id)
|
||||
static std::string net_id_to_s (const db::Net *net, const std::map<const db::Net *, unsigned int> &net2id)
|
||||
{
|
||||
if (net) {
|
||||
std::map<const db::Net *, unsigned int>::const_iterator i = net2id.find (net);
|
||||
|
|
@ -156,6 +157,37 @@ std::string net_id_to_s (const db::Net *net, const std::map<const db::Net *, uns
|
|||
}
|
||||
}
|
||||
|
||||
static void build_pin_index_map (const db::Circuit *c, std::map<const db::Pin *, unsigned int> &pin2index)
|
||||
{
|
||||
if (c) {
|
||||
size_t pi = 0;
|
||||
for (db::Circuit::const_pin_iterator p = c->begin_pins (); p != c->end_pins (); ++p, ++pi) {
|
||||
pin2index.insert (std::make_pair (p.operator-> (), pi));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::string pin_id_to_s (const db::Pin *pin, const std::map<const db::Pin *, unsigned int> &pin2index)
|
||||
{
|
||||
if (pin) {
|
||||
std::map<const db::Pin *, unsigned int>::const_iterator i = pin2index.find (pin);
|
||||
tl_assert (i != pin2index.end ());
|
||||
return tl::to_string (i->second);
|
||||
} else {
|
||||
return "()";
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
std::string std_writer_impl<Keys>::message_to_s (const std::string &msg)
|
||||
{
|
||||
if (msg.empty ()) {
|
||||
return std::string ();
|
||||
} else {
|
||||
return " " + Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
template <class Keys>
|
||||
std::string std_writer_impl<Keys>::status_to_s (const db::NetlistCrossReference::Status status)
|
||||
{
|
||||
|
|
@ -182,23 +214,27 @@ void std_writer_impl<Keys>::write (const db::NetlistCrossReference *xref)
|
|||
const db::NetlistCrossReference::PerCircuitData *pcd = xref->per_circuit_data_for (*c);
|
||||
tl_assert (pcd != 0);
|
||||
|
||||
stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << endl;
|
||||
stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << message_to_s (pcd->msg) << endl;
|
||||
stream () << indent2 << Keys::xref_key << "(" << endl;
|
||||
|
||||
for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) {
|
||||
stream () << indent1 << indent2 << Keys::net_key << "(" << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << " " << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << ")" << endl;
|
||||
stream () << indent1 << indent2 << Keys::net_key << "(" << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << " " << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
|
||||
}
|
||||
|
||||
std::map<const db::Pin *, unsigned int> pin2index_a, pin2index_b;
|
||||
build_pin_index_map (c->first, pin2index_a);
|
||||
build_pin_index_map (c->second, pin2index_b);
|
||||
|
||||
for (db::NetlistCrossReference::PerCircuitData::pin_pairs_const_iterator n = pcd->pins.begin (); n != pcd->pins.end (); ++n) {
|
||||
stream () << indent1 << indent2 << Keys::pin_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
|
||||
stream () << indent1 << indent2 << Keys::pin_key << "(" << pin_id_to_s (n->pair.first, pin2index_a) << " " << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
|
||||
}
|
||||
|
||||
for (db::NetlistCrossReference::PerCircuitData::device_pairs_const_iterator n = pcd->devices.begin (); n != pcd->devices.end (); ++n) {
|
||||
stream () << indent1 << indent2 << Keys::device_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
|
||||
stream () << indent1 << indent2 << Keys::device_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
|
||||
}
|
||||
|
||||
for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_const_iterator n = pcd->subcircuits.begin (); n != pcd->subcircuits.end (); ++n) {
|
||||
stream () << indent1 << indent2 << Keys::circuit_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl;
|
||||
stream () << indent1 << indent2 << Keys::circuit_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl;
|
||||
}
|
||||
|
||||
stream () << indent2 << ")" << endl;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,11 @@ enum OnEmptyIntruderHint {
|
|||
*/
|
||||
Copy,
|
||||
|
||||
/**
|
||||
* @brief Copy the subject shape to the second result
|
||||
*/
|
||||
CopyToSecond,
|
||||
|
||||
/**
|
||||
* @brief Drop the subject shape
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ public:
|
|||
* @brief A generic categorizer
|
||||
*
|
||||
* The objective of this class is to supply a category ID for a given object.
|
||||
* The category ID also identities equivalent objects from netlist A and B.
|
||||
* The category ID also identifies equivalent objects from netlist A and B.
|
||||
*/
|
||||
template <class Obj>
|
||||
class generic_categorizer
|
||||
|
|
@ -2991,6 +2991,23 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
|
|||
}
|
||||
}
|
||||
|
||||
// impose the compare tolerances of the layout (first netlist) on the schematic (second netlist)
|
||||
// TODO: this is kind of clumsy. But it's very important to use the same device sorting for both netlists, so we play this trick.
|
||||
// A better solution was to have a common compare framework for both netlists.
|
||||
for (std::map<size_t, std::pair<const db::DeviceClass *, const db::DeviceClass *> >::const_iterator i = cat2dc.begin (); i != cat2dc.end (); ++i) {
|
||||
|
||||
if (i->second.first && i->second.second) {
|
||||
|
||||
const db::DeviceClass *da = i->second.first;
|
||||
db::DeviceClass *db = const_cast<db::DeviceClass *> (i->second.second);
|
||||
|
||||
const db::DeviceParameterCompareDelegate *cmp = da->parameter_compare_delegate ();
|
||||
db->set_parameter_compare_delegate (cmp ? cmp->clone () : 0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// device whether to use a device category in strict mode
|
||||
|
||||
device_categorizer.clear_strict_device_categories ();
|
||||
|
|
@ -3083,7 +3100,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const
|
|||
} else {
|
||||
|
||||
if (mp_logger) {
|
||||
mp_logger->circuit_skipped (ca, cb);
|
||||
mp_logger->circuit_skipped (ca, cb, generate_subcircuits_not_verified_warning (ca, verified_circuits_a, cb, verified_circuits_b));
|
||||
good = false;
|
||||
}
|
||||
|
||||
|
|
@ -3130,24 +3147,61 @@ NetlistComparer::derive_pin_equivalence (const db::Circuit *ca, const db::Circui
|
|||
circuit_pin_mapper->map_pins (cb, pb);
|
||||
}
|
||||
|
||||
static bool is_valid_circuit (const db::Circuit *c)
|
||||
{
|
||||
// typical via subcircuits attach through one pin. We can safely ignore such subcircuits because they don't
|
||||
// contribute graph edges.
|
||||
return c->pin_count () > 1;
|
||||
}
|
||||
|
||||
bool
|
||||
NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const
|
||||
{
|
||||
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
|
||||
|
||||
const db::Circuit *cr = sc->circuit_ref ();
|
||||
|
||||
// typical via subcircuits attach through one pin. We can safely ignore such subcircuits because they don't
|
||||
// contribute graph edges.
|
||||
if (cr->pin_count () > 1 && verified_circuits.find (cr) == verified_circuits.end ()) {
|
||||
if (is_valid_circuit (cr) && verified_circuits.find (cr) == verified_circuits.end ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<std::string> unverified_names (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
|
||||
std::set<const db::Circuit *> seen;
|
||||
for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) {
|
||||
const db::Circuit *cr = sc->circuit_ref ();
|
||||
if (is_valid_circuit (cr) && seen.find (cr) == seen.end () && verified_circuits.find (cr) == verified_circuits.end ()) {
|
||||
seen.insert (cr);
|
||||
names.push_back (cr->name ());
|
||||
}
|
||||
}
|
||||
|
||||
std::sort (names.begin (), names.end ());
|
||||
return names;
|
||||
}
|
||||
|
||||
std::string
|
||||
NetlistComparer::generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set<const db::Circuit *> &verified_circuits_a, const db::Circuit *cb, const std::set<const db::Circuit *> &verified_circuits_b) const
|
||||
{
|
||||
std::string msg = tl::sprintf (tl::to_string (tr ("Circuits %s and %s could not be compared because the following subcircuits failed to compare:")), ca->name (), cb->name ());
|
||||
|
||||
std::vector<std::string> names_a = unverified_names (ca, verified_circuits_a);
|
||||
if (! names_a.empty ()) {
|
||||
msg += "\n A: " + tl::join (names_a, ",");
|
||||
}
|
||||
|
||||
std::vector<std::string> names_b = unverified_names (cb, verified_circuits_b);
|
||||
if (! names_b.empty ()) {
|
||||
msg += "\n B: " + tl::join (names_b, ",");
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
static std::vector<std::pair<size_t, size_t> >
|
||||
compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ public:
|
|||
* @brief There is a device class mismatch
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void device_class_mismatch (const db::DeviceClass * /*a*/, const db::DeviceClass * /*b*/) { }
|
||||
virtual void device_class_mismatch (const db::DeviceClass * /*a*/, const db::DeviceClass * /*b*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
/**
|
||||
* @brief Begin logging for circuit a and b
|
||||
|
|
@ -74,19 +74,19 @@ public:
|
|||
/**
|
||||
* @brief End logging for circuit a and b
|
||||
*/
|
||||
virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/) { }
|
||||
virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
/**
|
||||
* @brief Circuits are skipped
|
||||
* Circuits are skipped if their subcircuits could not be matched.
|
||||
*/
|
||||
virtual void circuit_skipped (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
|
||||
virtual void circuit_skipped (const db::Circuit * /*a*/, const db::Circuit * /*b*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
/**
|
||||
* @brief There is a circuit mismatch
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { }
|
||||
virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
/**
|
||||
* @brief Nets a and b match exactly
|
||||
|
|
@ -98,7 +98,7 @@ public:
|
|||
* Other nets might also match with a and also with b. Matching this a and b is
|
||||
* an arbitrary decision.
|
||||
*/
|
||||
virtual void match_ambiguous_nets (const db::Net * /*a*/, const db::Net * /*b*/) { }
|
||||
virtual void match_ambiguous_nets (const db::Net * /*a*/, const db::Net * /*b*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
/**
|
||||
* @brief Net a or b doesn't match
|
||||
|
|
@ -107,7 +107,7 @@ public:
|
|||
* nets are known not to match. Still the compare algorithm will proceed as
|
||||
* if these nets were equivalent to derive further matches.
|
||||
*/
|
||||
virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/) { }
|
||||
virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
/**
|
||||
* @brief Devices a and b match exactly
|
||||
|
|
@ -128,7 +128,7 @@ public:
|
|||
* @brief Device a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void device_mismatch (const db::Device * /*a*/, const db::Device * /*b*/) { }
|
||||
virtual void device_mismatch (const db::Device * /*a*/, const db::Device * /*b*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
/**
|
||||
* @brief Pins a and b of the current circuit are matched
|
||||
|
|
@ -139,7 +139,7 @@ public:
|
|||
* @brief Pin a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void pin_mismatch (const db::Pin * /*a*/, const db::Pin * /*b*/) { }
|
||||
virtual void pin_mismatch (const db::Pin * /*a*/, const db::Pin * /*b*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
/**
|
||||
* @brief Subcircuits a and b match exactly
|
||||
|
|
@ -150,7 +150,7 @@ public:
|
|||
* @brief SubCircuit a or b doesn't match
|
||||
* "a" is null if there is no match for b and vice versa.
|
||||
*/
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/) { }
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/, const std::string & /*msg*/ = std::string ()) { }
|
||||
|
||||
private:
|
||||
// No copying
|
||||
|
|
@ -346,6 +346,7 @@ private:
|
|||
protected:
|
||||
bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector<std::pair<const Net *, const Net *> > &net_identity, bool &pin_mismatch, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping) const;
|
||||
bool all_subcircuits_verified (const db::Circuit *c, const std::set<const db::Circuit *> &verified_circuits) const;
|
||||
std::string generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set<const db::Circuit *> &verified_circuits_a, const db::Circuit *cb, const std::set<const db::Circuit *> &verified_circuits_b) const;
|
||||
static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper);
|
||||
void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map<const db::Circuit *, CircuitMapper> &c12_circuit_and_pin_mapping, std::map<const db::Circuit *, CircuitMapper> &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const;
|
||||
void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const;
|
||||
|
|
|
|||
|
|
@ -338,9 +338,9 @@ NetlistCrossReference::establish_pair (const db::Circuit *a, const db::Circuit *
|
|||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Status status)
|
||||
NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Status status, const std::string &msg)
|
||||
{
|
||||
mp_per_circuit_data->nets.push_back (NetPairData (a, b, status));
|
||||
mp_per_circuit_data->nets.push_back (NetPairData (a, b, status, msg));
|
||||
if (a) {
|
||||
m_other_net [a] = b;
|
||||
}
|
||||
|
|
@ -350,9 +350,9 @@ NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Statu
|
|||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b, Status status)
|
||||
NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b, Status status, const std::string &msg)
|
||||
{
|
||||
mp_per_circuit_data->devices.push_back (DevicePairData (a, b, status));
|
||||
mp_per_circuit_data->devices.push_back (DevicePairData (a, b, status, msg));
|
||||
if (a) {
|
||||
m_other_device [a] = b;
|
||||
}
|
||||
|
|
@ -362,9 +362,9 @@ NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b,
|
|||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Status status)
|
||||
NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg)
|
||||
{
|
||||
mp_per_circuit_data->pins.push_back (PinPairData (a, b, status));
|
||||
mp_per_circuit_data->pins.push_back (PinPairData (a, b, status, msg));
|
||||
if (a) {
|
||||
m_other_pin [a] = b;
|
||||
}
|
||||
|
|
@ -374,9 +374,9 @@ NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Statu
|
|||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status)
|
||||
NetlistCrossReference::establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg)
|
||||
{
|
||||
mp_per_circuit_data->subcircuits.push_back (SubCircuitPairData (a, b, status));
|
||||
mp_per_circuit_data->subcircuits.push_back (SubCircuitPairData (a, b, status, msg));
|
||||
if (a) {
|
||||
m_other_subcircuit [a] = b;
|
||||
}
|
||||
|
|
@ -403,36 +403,37 @@ NetlistCrossReference::sort_circuit ()
|
|||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit *, Status status)
|
||||
NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit *, Status status, const std::string &msg)
|
||||
{
|
||||
mp_per_circuit_data->status = status;
|
||||
mp_per_circuit_data->msg = msg;
|
||||
|
||||
m_current_circuits = std::make_pair((const db::Circuit *)0, (const db::Circuit *)0);
|
||||
mp_per_circuit_data = 0;
|
||||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::gen_nets (const db::Net *a, const db::Net *b, Status status)
|
||||
NetlistCrossReference::gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg)
|
||||
{
|
||||
establish_pair (a, b, status);
|
||||
establish_pair (a, b, status, msg);
|
||||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::gen_devices (const db::Device *a, const db::Device *b, Status status)
|
||||
NetlistCrossReference::gen_devices (const db::Device *a, const db::Device *b, Status status, const std::string &msg)
|
||||
{
|
||||
establish_pair (a, b, status);
|
||||
establish_pair (a, b, status, msg);
|
||||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::gen_pins (const db::Pin *a, const db::Pin *b, Status status)
|
||||
NetlistCrossReference::gen_pins (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg)
|
||||
{
|
||||
establish_pair (a, b, status);
|
||||
establish_pair (a, b, status, msg);
|
||||
}
|
||||
|
||||
void
|
||||
NetlistCrossReference::gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status)
|
||||
NetlistCrossReference::gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg)
|
||||
{
|
||||
establish_pair (a, b, status);
|
||||
establish_pair (a, b, status, msg);
|
||||
}
|
||||
|
||||
static void init_data_from_single (const db::Net *net, NetlistCrossReference::PerNetData &data, bool first)
|
||||
|
|
|
|||
|
|
@ -61,44 +61,48 @@ public:
|
|||
{
|
||||
typedef db::Net object_type;
|
||||
|
||||
NetPairData (const db::Net *a, const db::Net *b, Status s) : pair (a, b), status (s) { }
|
||||
NetPairData (const db::Net *a, const db::Net *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { }
|
||||
NetPairData () : pair ((const db::Net *)0, (const db::Net *)0), status (None) { }
|
||||
|
||||
std::pair<const db::Net *, const db::Net *> pair;
|
||||
Status status;
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
struct DevicePairData
|
||||
{
|
||||
typedef db::Device object_type;
|
||||
|
||||
DevicePairData (const db::Device *a, const db::Device *b, Status s) : pair (a, b), status (s) { }
|
||||
DevicePairData (const db::Device *a, const db::Device *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { }
|
||||
DevicePairData () : pair ((const db::Device *)0, (const db::Device *)0), status (None) { }
|
||||
|
||||
std::pair<const db::Device *, const db::Device *> pair;
|
||||
Status status;
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
struct PinPairData
|
||||
{
|
||||
typedef db::Pin object_type;
|
||||
|
||||
PinPairData (const db::Pin *a, const db::Pin *b, Status s) : pair (a, b), status (s) { }
|
||||
PinPairData (const db::Pin *a, const db::Pin *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { }
|
||||
PinPairData () : pair ((const db::Pin *)0, (const db::Pin *)0), status (None) { }
|
||||
|
||||
std::pair<const db::Pin *, const db::Pin *> pair;
|
||||
Status status;
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
struct SubCircuitPairData
|
||||
{
|
||||
typedef db::SubCircuit object_type;
|
||||
|
||||
SubCircuitPairData (const db::SubCircuit *a, const db::SubCircuit *b, Status s) : pair (a, b), status (s) { }
|
||||
SubCircuitPairData (const db::SubCircuit *a, const db::SubCircuit *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { }
|
||||
SubCircuitPairData () : pair ((const db::SubCircuit *)0, (const db::SubCircuit *)0), status (None) { }
|
||||
|
||||
std::pair<const db::SubCircuit *, const db::SubCircuit *> pair;
|
||||
Status status;
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
struct PerCircuitData
|
||||
|
|
@ -115,6 +119,7 @@ public:
|
|||
typedef subcircuit_pairs_type::const_iterator subcircuit_pairs_const_iterator;
|
||||
|
||||
Status status;
|
||||
std::string msg;
|
||||
net_pairs_type nets;
|
||||
device_pairs_type devices;
|
||||
pin_pairs_type pins;
|
||||
|
|
@ -139,11 +144,11 @@ public:
|
|||
void gen_begin_netlist (const db::Netlist *a, const db::Netlist *b);
|
||||
void gen_end_netlist (const db::Netlist *a, const db::Netlist *b);
|
||||
void gen_begin_circuit (const db::Circuit *a, const db::Circuit *b);
|
||||
void gen_end_circuit (const db::Circuit *a, const db::Circuit *b, Status status);
|
||||
void gen_nets (const db::Net *a, const db::Net *b, Status status);
|
||||
void gen_devices (const db::Device *a, const db::Device *b, Status status);
|
||||
void gen_pins (const db::Pin *a, const db::Pin *b, Status status);
|
||||
void gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status);
|
||||
void gen_end_circuit (const db::Circuit *a, const db::Circuit *b, Status status, const std::string &msg);
|
||||
void gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg);
|
||||
void gen_devices (const db::Device *a, const db::Device *b, Status status, const std::string &msg);
|
||||
void gen_pins (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg);
|
||||
void gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg);
|
||||
|
||||
// db::NetlistCompareLogger interface
|
||||
virtual void begin_netlist (const db::Netlist *a, const db::Netlist *b)
|
||||
|
|
@ -162,77 +167,77 @@ public:
|
|||
gen_begin_circuit (a, b);
|
||||
}
|
||||
|
||||
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching)
|
||||
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg)
|
||||
{
|
||||
sort_circuit ();
|
||||
gen_end_circuit (a, b, matching ? Match : NoMatch);
|
||||
gen_end_circuit (a, b, matching ? Match : NoMatch, msg);
|
||||
}
|
||||
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
|
||||
{
|
||||
gen_begin_circuit (a, b);
|
||||
gen_end_circuit (a, b, Skipped);
|
||||
gen_end_circuit (a, b, Skipped, msg);
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
|
||||
{
|
||||
gen_begin_circuit (a, b);
|
||||
gen_end_circuit (a, b, Mismatch);
|
||||
gen_end_circuit (a, b, Mismatch, msg);
|
||||
}
|
||||
|
||||
virtual void match_nets (const db::Net *a, const db::Net *b)
|
||||
{
|
||||
gen_nets (a, b, Match);
|
||||
gen_nets (a, b, Match, std::string ());
|
||||
}
|
||||
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string &msg)
|
||||
{
|
||||
gen_nets (a, b, MatchWithWarning);
|
||||
gen_nets (a, b, MatchWithWarning, msg);
|
||||
}
|
||||
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b)
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string &msg)
|
||||
{
|
||||
gen_nets (a, b, Mismatch);
|
||||
gen_nets (a, b, Mismatch, msg);
|
||||
}
|
||||
|
||||
virtual void match_devices (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
gen_devices (a, b, Match);
|
||||
gen_devices (a, b, Match, std::string ());
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
gen_devices (a, b, MatchWithWarning);
|
||||
gen_devices (a, b, MatchWithWarning, std::string ());
|
||||
}
|
||||
|
||||
virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b)
|
||||
{
|
||||
gen_devices (a, b, MatchWithWarning);
|
||||
gen_devices (a, b, MatchWithWarning, std::string ());
|
||||
}
|
||||
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b)
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string &msg)
|
||||
{
|
||||
gen_devices (a, b, Mismatch);
|
||||
gen_devices (a, b, Mismatch, msg);
|
||||
}
|
||||
|
||||
virtual void match_pins (const db::Pin *a, const db::Pin *b)
|
||||
{
|
||||
gen_pins (a, b, Match);
|
||||
gen_pins (a, b, Match, std::string ());
|
||||
}
|
||||
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string &msg)
|
||||
{
|
||||
gen_pins (a, b, Mismatch);
|
||||
gen_pins (a, b, Mismatch, msg);
|
||||
}
|
||||
|
||||
virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
{
|
||||
gen_subcircuits (a, b, Match);
|
||||
gen_subcircuits (a, b, Match, std::string ());
|
||||
}
|
||||
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg)
|
||||
{
|
||||
gen_subcircuits (a, b, Mismatch);
|
||||
gen_subcircuits (a, b, Mismatch, msg);
|
||||
}
|
||||
|
||||
void clear ();
|
||||
|
|
@ -292,10 +297,10 @@ private:
|
|||
PerCircuitData *mp_per_circuit_data;
|
||||
|
||||
void establish_pair (const db::Circuit *a, const db::Circuit *b);
|
||||
void establish_pair (const db::Net *a, const db::Net *b, Status status);
|
||||
void establish_pair (const db::Device *a, const db::Device *b, Status status);
|
||||
void establish_pair (const db::Pin *a, const db::Pin *b, Status status);
|
||||
void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status);
|
||||
void establish_pair (const db::Net *a, const db::Net *b, Status status, const std::string &msg);
|
||||
void establish_pair (const db::Device *a, const db::Device *b, Status status, const std::string &msg);
|
||||
void establish_pair (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg);
|
||||
void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg);
|
||||
void sort_circuit ();
|
||||
void sort_netlist ();
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_ind (new db::device_
|
|||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_diode (new db::device_class_template<db::DeviceClassDiode> ("DIODE"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_mos3 (new db::device_class_template<db::DeviceClassMOS3Transistor> ("MOS3"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_mos4 (new db::device_class_template<db::DeviceClassMOS4Transistor> ("MOS4"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_bjt3 (new db::device_class_template<db::DeviceClassBJT3Transistor> ("BJT3"));
|
||||
static tl::RegisteredClass<db::DeviceClassTemplateBase> dct_bjt4 (new db::device_class_template<db::DeviceClassBJT4Transistor> ("BJT4"));
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// DeviceClassTwoTerminalDevice implementation
|
||||
|
|
|
|||
|
|
@ -725,7 +725,7 @@ template DB_PUBLIC void split_polygon<> (const db::DSimplePolygon &polygon, std:
|
|||
// Smoothing tools
|
||||
|
||||
void
|
||||
smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &points, db::Coord d)
|
||||
smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &points, db::Coord d, bool keep_hv)
|
||||
{
|
||||
points.clear ();
|
||||
points.reserve (std::distance (from, to));
|
||||
|
|
@ -781,7 +781,9 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon
|
|||
|
||||
bool can_drop = false;
|
||||
|
||||
if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) {
|
||||
if (keep_hv && (p1.x () == p0.x () || p1.y () == p0.y () || p2.x () == p1.x () || p2.y () == p1.y ())) {
|
||||
// keep points which participate in either a vertical or horizontal edge
|
||||
} else if (db::Coord (p1.distance(p0)) <= d && db::sprod_sign (p2 - p1, p0 - pm1) > 0 && std::abs (db::vprod (p2 - p1, p0 - pm1)) < 0.8 * p2.distance (p1) * p0.distance (pm1)) {
|
||||
// jog configurations with small edges are candidates
|
||||
can_drop = true;
|
||||
} else if (db::vprod_sign (p2 - p1, p1 - p0) < 0) {
|
||||
|
|
@ -839,19 +841,19 @@ smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon
|
|||
}
|
||||
|
||||
db::Polygon
|
||||
smooth (const db::Polygon &polygon, db::Coord d)
|
||||
smooth (const db::Polygon &polygon, db::Coord d, bool keep_hv)
|
||||
{
|
||||
db::Polygon new_poly;
|
||||
std::vector <db::Point> new_pts;
|
||||
|
||||
smooth_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, d);
|
||||
smooth_contour (polygon.begin_hull (), polygon.end_hull (), new_pts, d, keep_hv);
|
||||
if (new_pts.size () >= 3) {
|
||||
|
||||
new_poly.assign_hull (new_pts.begin (), new_pts.end (), false /*don't compress*/);
|
||||
|
||||
for (unsigned int h = 0; h < polygon.holes (); ++h) {
|
||||
new_pts.clear ();
|
||||
smooth_contour (polygon.begin_hole (h), polygon.end_hole (h), new_pts, d);
|
||||
smooth_contour (polygon.begin_hole (h), polygon.end_hole (h), new_pts, d, keep_hv);
|
||||
if (new_pts.size () >= 3) {
|
||||
new_poly.insert_hole (new_pts.begin (), new_pts.end (), false /*don't compress*/);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -449,6 +449,8 @@ db::Polygon DB_PUBLIC compute_rounded (const db::Polygon &poly, double rinner, d
|
|||
*/
|
||||
db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner, double router, unsigned int n);
|
||||
|
||||
#define KLAYOUT_SMOOTH_HAS_KEEP_HV 1
|
||||
|
||||
/**
|
||||
* @brief Smooth a contour
|
||||
*
|
||||
|
|
@ -458,13 +460,14 @@ db::DPolygon DB_PUBLIC compute_rounded (const db::DPolygon &poly, double rinner,
|
|||
* @param to The end of the contour
|
||||
* @param new_pts The points that make up the new contour
|
||||
* @param d The distance that determines the smoothing "roughness"
|
||||
* @param keep_hv If true, vertical and horizontal edges are maintained
|
||||
*/
|
||||
void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, db::Coord d);
|
||||
void DB_PUBLIC smooth_contour (db::Polygon::polygon_contour_iterator from, db::Polygon::polygon_contour_iterator to, std::vector <db::Point> &new_pts, db::Coord d, bool keep_hv);
|
||||
|
||||
/**
|
||||
* @brief Smooth a polygon (apply smoothing to the whole polygon)
|
||||
*/
|
||||
db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d);
|
||||
db::Polygon DB_PUBLIC smooth (const db::Polygon &poly, db::Coord d, bool keep_hv);
|
||||
|
||||
/**
|
||||
* @brief Returns a value indicating whether the polygon is an "strange polygon"
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
|
|||
m_current_layer = d.m_current_layer;
|
||||
m_shape = d.m_shape;
|
||||
m_trans = d.m_trans;
|
||||
m_global_trans = d.m_global_trans;
|
||||
m_trans_stack = d.m_trans_stack;
|
||||
m_inst_iterators = d.m_inst_iterators;
|
||||
m_inst_array_iterators = d.m_inst_array_iterators;
|
||||
|
|
@ -286,6 +287,7 @@ RecursiveShapeIterator::init ()
|
|||
m_shape_quad_id = 0;
|
||||
mp_cell = 0;
|
||||
m_current_layer = 0;
|
||||
m_global_trans = cplx_trans_type ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -318,6 +320,26 @@ RecursiveShapeIterator::init_region (const RecursiveShapeIterator::region_type &
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::set_global_trans (const cplx_trans_type &tr)
|
||||
{
|
||||
if (m_global_trans != tr) {
|
||||
m_global_trans = tr;
|
||||
m_needs_reinit = true;
|
||||
}
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator::cplx_trans_type &
|
||||
RecursiveShapeIterator::always_apply () const
|
||||
{
|
||||
if (m_trans_stack.empty ()) {
|
||||
return m_global_trans;
|
||||
} else {
|
||||
static cplx_trans_type unity;
|
||||
return unity;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RecursiveShapeIterator::set_region (const box_type ®ion)
|
||||
{
|
||||
|
|
@ -420,13 +442,13 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
|||
m_inst_quad_id_stack.clear ();
|
||||
m_inst_array_iterators.clear ();
|
||||
m_cells.clear ();
|
||||
m_trans = cplx_trans_type ();
|
||||
m_trans = m_global_trans;
|
||||
m_current_layer = 0;
|
||||
m_shape = shape_iterator ();
|
||||
m_shape_quad_id = 0;
|
||||
|
||||
m_local_region_stack.clear ();
|
||||
m_local_region_stack.push_back (m_region);
|
||||
m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
|
||||
|
||||
m_local_complex_region_stack.clear ();
|
||||
if (mp_complex_region.get ()) {
|
||||
|
|
@ -571,6 +593,8 @@ RecursiveShapeIterator::bbox () const
|
|||
}
|
||||
}
|
||||
|
||||
box = box.transformed (m_global_trans);
|
||||
|
||||
if (m_region != box_type::world ()) {
|
||||
box &= m_region;
|
||||
}
|
||||
|
|
@ -749,8 +773,8 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
|
|||
box_type new_region = box_type::world ();
|
||||
|
||||
// compute the region inside the new cell
|
||||
if (new_region != m_local_region_stack.front ()) {
|
||||
new_region = m_trans.inverted () * m_local_region_stack.front ();
|
||||
if (new_region != m_region) {
|
||||
new_region = m_trans.inverted () * m_region;
|
||||
new_region &= cell ()->bbox ();
|
||||
}
|
||||
m_local_region_stack.push_back (new_region);
|
||||
|
|
@ -911,7 +935,7 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
|
|||
|
||||
RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all;
|
||||
if (receiver) {
|
||||
ni = receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
|
||||
ni = receiver->new_inst (this, m_inst->cell_inst (), always_apply (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
|
||||
}
|
||||
|
||||
if (ni == RecursiveShapeReceiver::NI_skip) {
|
||||
|
|
@ -956,7 +980,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
|
|||
}
|
||||
|
||||
while (! m_inst_array.at_end () && receiver) {
|
||||
if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
|
||||
if (receiver->new_inst_member (this, m_inst->cell_inst (), always_apply (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
|
||||
break;
|
||||
} else {
|
||||
++m_inst_array;
|
||||
|
|
@ -999,7 +1023,7 @@ RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
|
|||
validate (receiver);
|
||||
|
||||
while (! at_end ()) {
|
||||
receiver->shape (this, *m_shape, m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
|
||||
receiver->shape (this, *m_shape, always_apply (), m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
|
||||
next (receiver);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -391,6 +391,30 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a global transformation
|
||||
*
|
||||
* The global transformation will be applied to all shapes delivered by biasing the "trans" attribute
|
||||
*/
|
||||
void set_global_trans (const cplx_trans_type &tr);
|
||||
|
||||
/**
|
||||
* @brief Gets the global transformation
|
||||
*/
|
||||
cplx_trans_type global_trans () const
|
||||
{
|
||||
return m_global_trans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the transformation which is to be applied always in push mode
|
||||
*
|
||||
* The reasoning behind this method is that in push mode and with the presence of a global transformation we need to
|
||||
* somehow reflect the fact that the top-level is transformed. Instead of transforming every shape and instance we use
|
||||
* this attribute. It is unity for all cells below top level and equal to the global transformation for the top cell.
|
||||
*/
|
||||
const cplx_trans_type &always_apply () const;
|
||||
|
||||
/**
|
||||
* @brief Reset the iterator
|
||||
*/
|
||||
|
|
@ -727,6 +751,7 @@ private:
|
|||
bool m_shape_inv_prop_sel;
|
||||
bool m_overlapping;
|
||||
std::set<db::cell_index_type> m_start, m_stop;
|
||||
cplx_trans_type m_global_trans;
|
||||
|
||||
const layout_type *mp_layout;
|
||||
const cell_type *mp_top_cell;
|
||||
|
|
@ -881,7 +906,7 @@ public:
|
|||
* - NI_single: iterate a single member (the first one)
|
||||
* - NI_skip: skips the whole array (not a single instance is iterated)
|
||||
*/
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
|
||||
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
|
||||
|
||||
/**
|
||||
* @brief Enters a new array member of the instance
|
||||
|
|
@ -894,14 +919,14 @@ public:
|
|||
*
|
||||
* If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered.
|
||||
*/
|
||||
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
|
||||
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
|
||||
|
||||
/**
|
||||
* @brief Delivers a shape
|
||||
*
|
||||
* @param trans The transformation which maps the shape to the top cell.
|
||||
*/
|
||||
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
|
||||
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
|
|
|||
|
|
@ -265,15 +265,15 @@ Region::rounded_corners (double rinner, double router, unsigned int n) const
|
|||
}
|
||||
|
||||
void
|
||||
Region::smooth (coord_type d)
|
||||
Region::smooth (coord_type d, bool keep_hv)
|
||||
{
|
||||
process (SmoothingProcessor (d));
|
||||
process (SmoothingProcessor (d, keep_hv));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::smoothed (coord_type d) const
|
||||
Region::smoothed (coord_type d, bool keep_hv) const
|
||||
{
|
||||
return processed (SmoothingProcessor (d));
|
||||
return processed (SmoothingProcessor (d, keep_hv));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -267,6 +267,16 @@ public:
|
|||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Takes the underlying delegate object
|
||||
*/
|
||||
RegionDelegate *take_delegate ()
|
||||
{
|
||||
RegionDelegate *delegate = mp_delegate;
|
||||
mp_delegate = 0;
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the base verbosity
|
||||
*
|
||||
|
|
@ -1132,6 +1142,19 @@ public:
|
|||
return Region (mp_delegate->selected_not_outside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which are completly outside polygons from the other region and the opposite ones at the same time
|
||||
*
|
||||
* This method is equivalent to calling selected_outside and selected_not_outside, but faster.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Region, Region> selected_outside_differential (const Region &other) const
|
||||
{
|
||||
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_outside_pair (other);
|
||||
return std::pair<Region, Region> (Region (p.first), Region (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which are completly inside polygons from the other region
|
||||
*
|
||||
|
|
@ -1178,6 +1201,19 @@ public:
|
|||
return Region (mp_delegate->selected_not_inside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which are completly inside polygons from the other region and the opposite ones at the same time
|
||||
*
|
||||
* This method is equivalent to calling selected_inside and selected_not_inside, but faster.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Region, Region> selected_inside_differential (const Region &other) const
|
||||
{
|
||||
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_inside_pair (other);
|
||||
return std::pair<Region, Region> (Region (p.first), Region (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which are enclosing polygons from the other region
|
||||
*
|
||||
|
|
@ -1224,6 +1260,19 @@ public:
|
|||
return Region (mp_delegate->selected_not_enclosing (other, min_count, max_count));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which are completly enclosing polygons from the other region and the opposite ones at the same time
|
||||
*
|
||||
* This method is equivalent to calling selected_enclosing and selected_not_enclosing, but faster.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Region, Region> selected_enclosing_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
|
||||
{
|
||||
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_enclosing_pair (other, min_count, max_count);
|
||||
return std::pair<Region, Region> (Region (p.first), Region (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which overlap or touch polygons from the other region
|
||||
*
|
||||
|
|
@ -1278,6 +1327,19 @@ public:
|
|||
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which are interacting with polygons from the other region and the opposite ones at the same time
|
||||
*
|
||||
* This method is equivalent to calling selected_interacting and selected_not_interacting, but faster.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Region, Region> selected_interacting_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
|
||||
{
|
||||
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
|
||||
return std::pair<Region, Region> (Region (p.first), Region (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which overlap or touch edges from the given edge collection
|
||||
*
|
||||
|
|
@ -1324,6 +1386,19 @@ public:
|
|||
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which are interacting with edges from the other region and the opposite ones at the same time
|
||||
*
|
||||
* This method is equivalent to calling selected_interacting and selected_not_interacting, but faster.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Region, Region> selected_interacting_differential (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
|
||||
{
|
||||
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
|
||||
return std::pair<Region, Region> (Region (p.first), Region (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which overlap or touch texts from the text collection
|
||||
*
|
||||
|
|
@ -1370,6 +1445,19 @@ public:
|
|||
return Region (mp_delegate->selected_not_interacting (other, min_count, max_count));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which are interacting with texts from the other region and the opposite ones at the same time
|
||||
*
|
||||
* This method is equivalent to calling selected_interacting and selected_not_interacting, but faster.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Region, Region> selected_interacting_differential (const Texts &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
|
||||
{
|
||||
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
|
||||
return std::pair<Region, Region> (Region (p.first), Region (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which overlap polygons from the other region
|
||||
*
|
||||
|
|
@ -1416,6 +1504,19 @@ public:
|
|||
return Region (mp_delegate->selected_not_overlapping (other, min_count, max_count));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which are overlapping polygons from the other region and the opposite ones at the same time
|
||||
*
|
||||
* This method is equivalent to calling selected_overlapping and selected_not_overlapping, but faster.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Region, Region> selected_overlapping_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
|
||||
{
|
||||
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->selected_overlapping_pair (other, min_count, max_count);
|
||||
return std::pair<Region, Region> (Region (p.first), Region (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of "other" which are inside polygons of this region
|
||||
*
|
||||
|
|
@ -1518,14 +1619,14 @@ public:
|
|||
/**
|
||||
* @brief Smoothes the region (in-place)
|
||||
*/
|
||||
void smooth (coord_type d);
|
||||
void smooth (coord_type d, bool keep_hv);
|
||||
|
||||
/**
|
||||
* @brief Returns the smoothed region
|
||||
*
|
||||
* @param d The smoothing accuracy
|
||||
*/
|
||||
Region smoothed (coord_type d) const;
|
||||
Region smoothed (coord_type d, bool keep_hv) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the nth polygon
|
||||
|
|
|
|||
|
|
@ -281,18 +281,25 @@ public:
|
|||
|
||||
virtual RegionDelegate *selected_outside (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_outside (const Region &other) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_inside (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_inside (const Region &other) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_inside_pair (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_not_enclosing (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_enclosing_pair (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_interacting_pair (const Texts &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_overlapping_pair (const Region &other, size_t min_count, size_t max_count) const = 0;
|
||||
virtual RegionDelegate *pull_inside (const Region &other) const = 0;
|
||||
virtual RegionDelegate *pull_interacting (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0;
|
||||
|
|
|
|||
|
|
@ -537,8 +537,8 @@ private:
|
|||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
interacting_local_operation<TS, TI, TR>::interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count, bool other_is_merged)
|
||||
: m_mode (mode), m_touching (touching), m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
|
||||
interacting_local_operation<TS, TI, TR>::interacting_local_operation (int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged)
|
||||
: m_mode (mode), m_touching (touching), m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -552,8 +552,13 @@ db::Coord interacting_local_operation<TS, TI, TR>::dist () const
|
|||
template <class TS, class TI, class TR>
|
||||
void interacting_local_operation<TS, TI, TR>::do_compute_local (db::Layout * /*layout*/, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
tl_assert (results.size () == 1);
|
||||
std::unordered_set<TR> &result = results.front ();
|
||||
if (m_output_mode == None) {
|
||||
return;
|
||||
} else if (m_output_mode == Positive || m_output_mode == Negative) {
|
||||
tl_assert (results.size () == 1);
|
||||
} else {
|
||||
tl_assert (results.size () == 2);
|
||||
}
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
|
|
@ -652,9 +657,21 @@ void interacting_local_operation<TS, TI, TR>::do_compute_local (db::Layout * /*l
|
|||
if (c != interaction_counts.end ()) {
|
||||
count = c->second;
|
||||
}
|
||||
if ((count >= m_min_count && count <= m_max_count) != m_inverse) {
|
||||
const TS &subject = interactions.subject_shape (i->first);
|
||||
result.insert (subject);
|
||||
bool good = (count >= m_min_count && count <= m_max_count);
|
||||
if (good) {
|
||||
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
|
||||
const TS &subject = interactions.subject_shape (i->first);
|
||||
results [0].insert (subject);
|
||||
}
|
||||
} else {
|
||||
if (m_output_mode == Negative) {
|
||||
const TS &subject = interactions.subject_shape (i->first);
|
||||
// Yes, it's "positive_result" as this is the first one.
|
||||
results [0].insert (subject);
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
const TS &subject = interactions.subject_shape (i->first);
|
||||
results [1].insert (subject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -663,11 +680,22 @@ template <class TS, class TI, class TR>
|
|||
OnEmptyIntruderHint
|
||||
interacting_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
|
||||
{
|
||||
if ((m_mode <= 0) != m_inverse) {
|
||||
return OnEmptyIntruderHint::Drop;
|
||||
if ((m_mode <= 0)) {
|
||||
if (m_output_mode == Positive) {
|
||||
return OnEmptyIntruderHint::Drop;
|
||||
} else if (m_output_mode == Negative) {
|
||||
return OnEmptyIntruderHint::Copy;
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
return OnEmptyIntruderHint::CopyToSecond;
|
||||
}
|
||||
} else {
|
||||
return OnEmptyIntruderHint::Copy;
|
||||
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
|
||||
return OnEmptyIntruderHint::Copy;
|
||||
} else if (m_output_mode == Negative) {
|
||||
return OnEmptyIntruderHint::Drop;
|
||||
}
|
||||
}
|
||||
return OnEmptyIntruderHint::Ignore;
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
|
|
@ -761,8 +789,8 @@ template class DB_PUBLIC pull_local_operation<db::Polygon, db::Polygon, db::Poly
|
|||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
interacting_with_edge_local_operation<TS, TI, TR>::interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count, bool other_is_merged)
|
||||
: m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
|
||||
interacting_with_edge_local_operation<TS, TI, TR>::interacting_with_edge_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged)
|
||||
: m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -777,6 +805,14 @@ db::Coord interacting_with_edge_local_operation<TS, TI, TR>::dist () const
|
|||
template <class TS, class TI, class TR>
|
||||
void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
if (m_output_mode == None) {
|
||||
return;
|
||||
} else if (m_output_mode == Positive || m_output_mode == Negative) {
|
||||
tl_assert (results.size () == 1);
|
||||
} else {
|
||||
tl_assert (results.size () == 2);
|
||||
}
|
||||
|
||||
std::unordered_map<TR, size_t> counted_results;
|
||||
bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits<size_t>::max ());
|
||||
|
||||
|
|
@ -829,7 +865,7 @@ void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::La
|
|||
const TR *addressable = push_polygon_to_heap (layout, subject, heap);
|
||||
|
||||
scanner.insert1 (addressable, 0);
|
||||
if (m_inverse) {
|
||||
if (m_output_mode == Negative || m_output_mode == PositiveAndNegative) {
|
||||
inserter.init (*addressable);
|
||||
}
|
||||
|
||||
|
|
@ -839,13 +875,18 @@ void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::La
|
|||
|
||||
// select hits based on their count
|
||||
|
||||
tl_assert (results.size () == 1);
|
||||
std::unordered_set<TR> &result = results.front ();
|
||||
|
||||
for (typename std::unordered_map<TR, size_t>::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
|
||||
bool hit = r->second >= m_min_count && r->second <= m_max_count;
|
||||
if (hit != m_inverse) {
|
||||
result.insert (r->first);
|
||||
if (hit) {
|
||||
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
|
||||
results [0].insert (r->first);
|
||||
}
|
||||
} else {
|
||||
if (m_output_mode == Negative) {
|
||||
results [0].insert (r->first);
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
results [1].insert (r->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -853,10 +894,14 @@ void interacting_with_edge_local_operation<TS, TI, TR>::do_compute_local (db::La
|
|||
template <class TS, class TI, class TR>
|
||||
OnEmptyIntruderHint interacting_with_edge_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
|
||||
{
|
||||
if (!m_inverse) {
|
||||
if (m_output_mode == Positive) {
|
||||
return OnEmptyIntruderHint::Drop;
|
||||
} else {
|
||||
} else if (m_output_mode == Negative) {
|
||||
return OnEmptyIntruderHint::Copy;
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
return OnEmptyIntruderHint::CopyToSecond;
|
||||
} else {
|
||||
return OnEmptyIntruderHint::Ignore;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1000,8 +1045,8 @@ template class DB_PUBLIC pull_with_text_local_operation<db::Polygon, db::Text, d
|
|||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
interacting_with_text_local_operation<TS, TI, TR>::interacting_with_text_local_operation (bool inverse, size_t min_count, size_t max_count)
|
||||
: m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
|
||||
interacting_with_text_local_operation<TS, TI, TR>::interacting_with_text_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count)
|
||||
: m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -1017,6 +1062,14 @@ db::Coord interacting_with_text_local_operation<TS, TI, TR>::dist () const
|
|||
template <class TS, class TI, class TR>
|
||||
void interacting_with_text_local_operation<TS, TI, TR>::do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
if (m_output_mode == None) {
|
||||
return;
|
||||
} else if (m_output_mode == Positive || m_output_mode == Negative) {
|
||||
tl_assert (results.size () == 1);
|
||||
} else {
|
||||
tl_assert (results.size () == 2);
|
||||
}
|
||||
|
||||
std::unordered_map<TR, size_t> counted_results;
|
||||
bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits<size_t>::max ());
|
||||
|
||||
|
|
@ -1042,7 +1095,7 @@ void interacting_with_text_local_operation<TS, TI, TR>::do_compute_local (db::La
|
|||
const TR *addressable = push_polygon_to_heap (layout, interactions.subject_shape (i->first), heap);
|
||||
|
||||
scanner.insert1 (addressable, 0);
|
||||
if (m_inverse) {
|
||||
if (m_output_mode == Negative || m_output_mode == PositiveAndNegative) {
|
||||
inserter.init (*addressable);
|
||||
}
|
||||
|
||||
|
|
@ -1052,13 +1105,19 @@ void interacting_with_text_local_operation<TS, TI, TR>::do_compute_local (db::La
|
|||
|
||||
// select hits based on their count
|
||||
|
||||
tl_assert (results.size () == 1);
|
||||
std::unordered_set<TR> &result = results.front ();
|
||||
|
||||
for (typename std::unordered_map<TR, size_t>::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) {
|
||||
bool hit = r->second >= m_min_count && r->second <= m_max_count;
|
||||
if (hit != m_inverse) {
|
||||
result.insert (r->first);
|
||||
if (hit) {
|
||||
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
|
||||
results [0].insert (r->first);
|
||||
}
|
||||
} else {
|
||||
if (m_output_mode == Negative) {
|
||||
// Yes. It's "positive"! This is the first output.
|
||||
results [0].insert (r->first);
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
results [1].insert (r->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1066,10 +1125,14 @@ void interacting_with_text_local_operation<TS, TI, TR>::do_compute_local (db::La
|
|||
template <class TS, class TI, class TR>
|
||||
OnEmptyIntruderHint interacting_with_text_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
|
||||
{
|
||||
if (!m_inverse) {
|
||||
if (m_output_mode == Positive) {
|
||||
return OnEmptyIntruderHint::Drop;
|
||||
} else {
|
||||
} else if (m_output_mode == Negative) {
|
||||
return OnEmptyIntruderHint::Copy;
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
return OnEmptyIntruderHint::CopyToSecond;
|
||||
} else {
|
||||
return OnEmptyIntruderHint::Ignore;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -222,12 +222,16 @@ private:
|
|||
|
||||
typedef check_local_operation<db::PolygonRef, db::PolygonRef> CheckLocalOperation;
|
||||
|
||||
enum InteractingOutputMode {
|
||||
None = 0, Positive = 1, Negative = 2, PositiveAndNegative = 3
|
||||
};
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
class interacting_local_operation
|
||||
: public local_operation<TS, TI, TR>
|
||||
{
|
||||
public:
|
||||
interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count, bool other_is_merged);
|
||||
interacting_local_operation (int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged);
|
||||
|
||||
virtual db::Coord dist () const;
|
||||
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
|
||||
|
|
@ -237,7 +241,7 @@ public:
|
|||
private:
|
||||
int m_mode;
|
||||
bool m_touching;
|
||||
bool m_inverse;
|
||||
InteractingOutputMode m_output_mode;
|
||||
size_t m_min_count, m_max_count;
|
||||
bool m_other_is_merged;
|
||||
};
|
||||
|
|
@ -268,7 +272,7 @@ class interacting_with_edge_local_operation
|
|||
: public local_operation<TS, TI, TR>
|
||||
{
|
||||
public:
|
||||
interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count, bool other_is_merged);
|
||||
interacting_with_edge_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged);
|
||||
|
||||
virtual db::Coord dist () const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
|
||||
|
|
@ -276,7 +280,7 @@ public:
|
|||
virtual std::string description () const;
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
InteractingOutputMode m_output_mode;
|
||||
size_t m_min_count, m_max_count;
|
||||
bool m_other_is_merged;
|
||||
};
|
||||
|
|
@ -303,7 +307,7 @@ class interacting_with_text_local_operation
|
|||
: public local_operation<TS, TI, TR>
|
||||
{
|
||||
public:
|
||||
interacting_with_text_local_operation (bool inverse, size_t min_count, size_t max_count);
|
||||
interacting_with_text_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count);
|
||||
|
||||
virtual db::Coord dist () const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
|
||||
|
|
@ -311,7 +315,7 @@ public:
|
|||
virtual std::string description () const;
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
InteractingOutputMode m_output_mode;
|
||||
size_t m_min_count, m_max_count;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -868,14 +868,14 @@ StrangePolygonCheckProcessor::process (const db::Polygon &poly, std::vector<db::
|
|||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Smoothing processor
|
||||
|
||||
SmoothingProcessor::SmoothingProcessor (db::Coord d) : m_d (d) { }
|
||||
SmoothingProcessor::SmoothingProcessor (db::Coord d, bool keep_hv) : m_d (d), m_keep_hv (keep_hv) { }
|
||||
|
||||
SmoothingProcessor::~SmoothingProcessor () { }
|
||||
|
||||
void
|
||||
SmoothingProcessor::process (const db::Polygon &poly, std::vector<db::Polygon> &res) const
|
||||
{
|
||||
res.push_back (db::smooth (poly, m_d));
|
||||
res.push_back (db::smooth (poly, m_d, m_keep_hv));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -504,7 +504,7 @@ class DB_PUBLIC SmoothingProcessor
|
|||
: public PolygonProcessorBase
|
||||
{
|
||||
public:
|
||||
SmoothingProcessor (db::Coord d);
|
||||
SmoothingProcessor (db::Coord d, bool keep_hv);
|
||||
~SmoothingProcessor ();
|
||||
|
||||
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const;
|
||||
|
|
@ -517,6 +517,7 @@ public:
|
|||
|
||||
private:
|
||||
db::Coord m_d;
|
||||
bool m_keep_hv;
|
||||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -190,17 +190,17 @@ public:
|
|||
m_circuit = circuit2str (a) + " vs. " + circuit2str (b);
|
||||
}
|
||||
|
||||
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
|
||||
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("device_class_mismatch " + device_class2str (a) + " " + device_class2str (b));
|
||||
}
|
||||
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
|
@ -210,12 +210,12 @@ public:
|
|||
out ("match_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b)
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("net_mismatch " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
|
@ -225,7 +225,7 @@ public:
|
|||
out ("match_devices " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b)
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("device_mismatch " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
|
@ -245,7 +245,7 @@ public:
|
|||
out ("match_pins " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
|
@ -255,7 +255,7 @@ public:
|
|||
out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,10 +185,10 @@ static db::CompoundRegionOperationNode *new_strange_polygons_filter (db::Compoun
|
|||
return new db::CompoundRegionProcessingOperationNode (new db::StrangePolygonCheckProcessor (), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d)
|
||||
static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d, bool keep_hv)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d), input, true /*processor is owned*/, d);
|
||||
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d, keep_hv), input, true /*processor is owned*/, d);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_rounded_corners (db::CompoundRegionOperationNode *input, double rinner, double router, unsigned int n)
|
||||
|
|
@ -572,9 +572,10 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
"@brief Creates a node extracting strange polygons.\n"
|
||||
"'strange polygons' are ones which cannot be oriented - e.g. '8' shape polygons."
|
||||
) +
|
||||
gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"),
|
||||
gsi::constructor ("new_smoothed", &new_smoothed, gsi::arg ("input"), gsi::arg ("d"), gsi::arg ("keep_hv", false),
|
||||
"@brief Creates a node smoothing the polygons.\n"
|
||||
"@param d The tolerance to be applied for the smoothing."
|
||||
"@param d The tolerance to be applied for the smoothing.\n"
|
||||
"@param keep_hv If true, horizontal and vertical edges are maintained.\n"
|
||||
) +
|
||||
gsi::constructor ("new_rounded_corners", &new_rounded_corners, gsi::arg ("input"), gsi::arg ("rinner"), gsi::arg ("router"), gsi::arg ("n"),
|
||||
"@brief Creates a node generating rounded corners.\n"
|
||||
|
|
|
|||
|
|
@ -66,18 +66,18 @@ public:
|
|||
db::NetlistCompareLogger::end_netlist (a, b);
|
||||
}
|
||||
|
||||
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
|
||||
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string &msg)
|
||||
{
|
||||
if (cb_device_class_mismatch.can_issue ()) {
|
||||
cb_device_class_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::device_class_mismatch_fb, a, b);
|
||||
cb_device_class_mismatch.issue<GenericNetlistCompareLogger, const db::DeviceClass *, const db::DeviceClass *, const std::string &> (&GenericNetlistCompareLogger::device_class_mismatch_fb, a, b, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::device_class_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void device_class_mismatch_fb (const db::DeviceClass *a, const db::DeviceClass *b)
|
||||
void device_class_mismatch_fb (const db::DeviceClass *a, const db::DeviceClass *b, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::device_class_mismatch (a, b);
|
||||
db::NetlistCompareLogger::device_class_mismatch (a, b, msg);
|
||||
}
|
||||
|
||||
virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b)
|
||||
|
|
@ -94,46 +94,46 @@ public:
|
|||
db::NetlistCompareLogger::begin_circuit (a, b);
|
||||
}
|
||||
|
||||
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching)
|
||||
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg)
|
||||
{
|
||||
if (cb_end_circuit.can_issue ()) {
|
||||
cb_end_circuit.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::end_circuit_fb, a, b, matching);
|
||||
cb_end_circuit.issue<GenericNetlistCompareLogger, const db::Circuit *, const db::Circuit *, bool, const std::string &> (&GenericNetlistCompareLogger::end_circuit_fb, a, b, matching, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::end_circuit (a, b, matching);
|
||||
}
|
||||
}
|
||||
|
||||
void end_circuit_fb (const db::Circuit *a, const db::Circuit *b, bool matching)
|
||||
void end_circuit_fb (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::end_circuit (a, b, matching);
|
||||
db::NetlistCompareLogger::end_circuit (a, b, matching, msg);
|
||||
}
|
||||
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
|
||||
{
|
||||
if (cb_circuit_skipped.can_issue ()) {
|
||||
cb_circuit_skipped.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::circuit_skipped_fb, a, b);
|
||||
cb_circuit_skipped.issue<GenericNetlistCompareLogger, const db::Circuit *, const db::Circuit *, const std::string &> (&GenericNetlistCompareLogger::circuit_skipped_fb, a, b, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::circuit_skipped (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void circuit_skipped_fb (const db::Circuit *a, const db::Circuit *b)
|
||||
void circuit_skipped_fb (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::circuit_skipped (a, b);
|
||||
db::NetlistCompareLogger::circuit_skipped (a, b, msg);
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
|
||||
{
|
||||
if (cb_circuit_mismatch.can_issue ()) {
|
||||
cb_circuit_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::circuit_mismatch_fb, a, b);
|
||||
cb_circuit_mismatch.issue<GenericNetlistCompareLogger, const db::Circuit *, const db::Circuit *, const std::string &> (&GenericNetlistCompareLogger::circuit_mismatch_fb, a, b, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::circuit_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void circuit_mismatch_fb (const db::Circuit *a, const db::Circuit *b)
|
||||
void circuit_mismatch_fb (const db::Circuit *a, const db::Circuit *b, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::circuit_mismatch (a, b);
|
||||
db::NetlistCompareLogger::circuit_mismatch (a, b, msg);
|
||||
}
|
||||
|
||||
virtual void match_nets (const db::Net *a, const db::Net *b)
|
||||
|
|
@ -150,32 +150,32 @@ public:
|
|||
db::NetlistCompareLogger::match_nets (a, b);
|
||||
}
|
||||
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string &msg)
|
||||
{
|
||||
if (cb_match_ambiguous_nets.can_issue ()) {
|
||||
cb_match_ambiguous_nets.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::match_ambiguous_nets_fb, a, b);
|
||||
cb_match_ambiguous_nets.issue<GenericNetlistCompareLogger, const db::Net *, const db::Net *, const std::string &> (&GenericNetlistCompareLogger::match_ambiguous_nets_fb, a, b, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::match_ambiguous_nets (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void match_ambiguous_nets_fb (const db::Net *a, const db::Net *b)
|
||||
void match_ambiguous_nets_fb (const db::Net *a, const db::Net *b, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::match_ambiguous_nets (a, b);
|
||||
db::NetlistCompareLogger::match_ambiguous_nets (a, b, msg);
|
||||
}
|
||||
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b)
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string &msg)
|
||||
{
|
||||
if (cb_net_mismatch.can_issue ()) {
|
||||
cb_net_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::net_mismatch_fb, a, b);
|
||||
cb_net_mismatch.issue<GenericNetlistCompareLogger, const db::Net *, const db::Net *, const std::string &> (&GenericNetlistCompareLogger::net_mismatch_fb, a, b, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::net_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void net_mismatch_fb (const db::Net *a, const db::Net *b)
|
||||
void net_mismatch_fb (const db::Net *a, const db::Net *b, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::net_mismatch (a, b);
|
||||
db::NetlistCompareLogger::net_mismatch (a, b, msg);
|
||||
}
|
||||
|
||||
virtual void match_devices (const db::Device *a, const db::Device *b)
|
||||
|
|
@ -220,18 +220,18 @@ public:
|
|||
db::NetlistCompareLogger::match_devices_with_different_device_classes (a, b);
|
||||
}
|
||||
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b)
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string &msg)
|
||||
{
|
||||
if (cb_device_mismatch.can_issue ()) {
|
||||
cb_device_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::device_mismatch_fb, a, b);
|
||||
cb_device_mismatch.issue<GenericNetlistCompareLogger, const db::Device *, const db::Device *, const std::string &> (&GenericNetlistCompareLogger::device_mismatch_fb, a, b, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::device_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void device_mismatch_fb (const db::Device *a, const db::Device *b)
|
||||
void device_mismatch_fb (const db::Device *a, const db::Device *b, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::device_mismatch (a, b);
|
||||
db::NetlistCompareLogger::device_mismatch (a, b, msg);
|
||||
}
|
||||
|
||||
virtual void match_pins (const db::Pin *a, const db::Pin *b)
|
||||
|
|
@ -248,18 +248,18 @@ public:
|
|||
db::NetlistCompareLogger::match_pins (a, b);
|
||||
}
|
||||
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string &msg)
|
||||
{
|
||||
if (cb_pin_mismatch.can_issue ()) {
|
||||
cb_pin_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::pin_mismatch_fb, a, b);
|
||||
cb_pin_mismatch.issue<GenericNetlistCompareLogger, const db::Pin *, const db::Pin *, const std::string &> (&GenericNetlistCompareLogger::pin_mismatch_fb, a, b, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::pin_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void pin_mismatch_fb (const db::Pin *a, const db::Pin *b)
|
||||
void pin_mismatch_fb (const db::Pin *a, const db::Pin *b, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::pin_mismatch (a, b);
|
||||
db::NetlistCompareLogger::pin_mismatch (a, b, msg);
|
||||
}
|
||||
|
||||
virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
|
|
@ -276,18 +276,18 @@ public:
|
|||
db::NetlistCompareLogger::match_subcircuits (a, b);
|
||||
}
|
||||
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg)
|
||||
{
|
||||
if (cb_subcircuit_mismatch.can_issue ()) {
|
||||
cb_subcircuit_mismatch.issue<GenericNetlistCompareLogger> (&GenericNetlistCompareLogger::subcircuit_mismatch_fb, a, b);
|
||||
cb_subcircuit_mismatch.issue<GenericNetlistCompareLogger, const db::SubCircuit *, const db::SubCircuit *, const std::string &> (&GenericNetlistCompareLogger::subcircuit_mismatch_fb, a, b, msg);
|
||||
} else {
|
||||
db::NetlistCompareLogger::subcircuit_mismatch (a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void subcircuit_mismatch_fb (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
void subcircuit_mismatch_fb (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg)
|
||||
{
|
||||
db::NetlistCompareLogger::subcircuit_mismatch (a, b);
|
||||
db::NetlistCompareLogger::subcircuit_mismatch (a, b, msg);
|
||||
}
|
||||
|
||||
gsi::Callback cb_begin_netlist;
|
||||
|
|
@ -339,7 +339,7 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
|
|||
"@brief This function is called at the end of the compare process.\n"
|
||||
"This method is called once when the compare run ended.\n"
|
||||
) +
|
||||
gsi::callback ("device_class_mismatch", &GenericNetlistCompareLogger::device_class_mismatch, &GenericNetlistCompareLogger::cb_device_class_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
gsi::callback ("device_class_mismatch", &GenericNetlistCompareLogger::device_class_mismatch, &GenericNetlistCompareLogger::cb_device_class_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
|
||||
"@brief This function is called when device classes can't be compared.\n"
|
||||
"This method is called when a device class can't be mapped to a partner in the other netlist. In this case, "
|
||||
"this method is called with the one device class and nil for the other class.\n"
|
||||
|
|
@ -354,19 +354,19 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
|
|||
"some or all subcircuits the pin assignment can't be derived. In this case, \\circuit_skipped will be called once "
|
||||
"instead of \\begin_circuit and \\end_circuit.\n"
|
||||
) +
|
||||
gsi::callback ("end_circuit", &GenericNetlistCompareLogger::end_circuit, &GenericNetlistCompareLogger::cb_end_circuit, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("matching"),
|
||||
gsi::callback ("end_circuit", &GenericNetlistCompareLogger::end_circuit, &GenericNetlistCompareLogger::cb_end_circuit, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("matching"), gsi::arg ("msg"),
|
||||
"@brief This function is called at the end of the compare process.\n"
|
||||
"The 'matching' argument indicates whether the circuits have been identified as identical.\n"
|
||||
"See \\begin_circuit for details."
|
||||
) +
|
||||
gsi::callback ("circuit_skipped", &GenericNetlistCompareLogger::circuit_skipped, &GenericNetlistCompareLogger::cb_circuit_skipped, gsi::arg ("a"), gsi::arg ("b"),
|
||||
gsi::callback ("circuit_skipped", &GenericNetlistCompareLogger::circuit_skipped, &GenericNetlistCompareLogger::cb_circuit_skipped, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
|
||||
"@brief This function is called when circuits can't be compared.\n"
|
||||
"If there is a known circuit pair, but the circuits can be compared - for example because subcircuits can't be identified - this method will be called with "
|
||||
"both circuits.\n"
|
||||
"\n"
|
||||
"This method is called instead of \\begin_circuit and \\end_circuit."
|
||||
) +
|
||||
gsi::callback ("circuit_mismatch", &GenericNetlistCompareLogger::circuit_mismatch, &GenericNetlistCompareLogger::cb_circuit_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
gsi::callback ("circuit_mismatch", &GenericNetlistCompareLogger::circuit_mismatch, &GenericNetlistCompareLogger::cb_circuit_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
|
||||
"@brief This function is called when circuits can't be compared.\n"
|
||||
"This method is called when a circuit can't be mapped to a partner in the other netlist. In this case, "
|
||||
"this method is called with the one circuit and nil for the other circuit.\n"
|
||||
|
|
@ -379,13 +379,13 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
|
|||
"If the nets can be paired, but this match is ambiguous, \\match_ambiguous_nets will be called instead.\n"
|
||||
"If nets can't be matched to a partner, \\net_mismatch will be called.\n"
|
||||
) +
|
||||
gsi::callback ("match_ambiguous_nets", &GenericNetlistCompareLogger::match_ambiguous_nets, &GenericNetlistCompareLogger::cb_match_ambiguous_nets, gsi::arg ("a"), gsi::arg ("b"),
|
||||
gsi::callback ("match_ambiguous_nets", &GenericNetlistCompareLogger::match_ambiguous_nets, &GenericNetlistCompareLogger::cb_match_ambiguous_nets, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
|
||||
"@brief This function is called when two nets are identified, but this choice is ambiguous.\n"
|
||||
"This choice is a last-resort fallback to allow continuation of the compare procedure. It is likely that this "
|
||||
"compare will fail later. Looking for ambiguous nets allows deduction of the origin of this faulty decision. "
|
||||
"See \\match_nets for more details."
|
||||
) +
|
||||
gsi::callback ("net_mismatch", &GenericNetlistCompareLogger::net_mismatch, &GenericNetlistCompareLogger::cb_net_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
gsi::callback ("net_mismatch", &GenericNetlistCompareLogger::net_mismatch, &GenericNetlistCompareLogger::cb_net_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
|
||||
"@brief This function is called when a net can't be paired.\n"
|
||||
"This method will be called, if a net cannot be identified as identical with another net. The corresponding argument "
|
||||
"will identify the net and source netlist. The other argument will be nil.\n"
|
||||
|
|
@ -409,7 +409,7 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
|
|||
"@brief This function is called when two devices are identified but have different device classes.\n"
|
||||
"See \\match_devices for details.\n"
|
||||
) +
|
||||
gsi::callback ("device_mismatch", &GenericNetlistCompareLogger::device_mismatch, &GenericNetlistCompareLogger::cb_device_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
gsi::callback ("device_mismatch", &GenericNetlistCompareLogger::device_mismatch, &GenericNetlistCompareLogger::cb_device_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
|
||||
"@brief This function is called when two devices can't be paired.\n"
|
||||
"This will report the device considered in a or b. The other argument is nil. "
|
||||
"See \\match_devices for details.\n"
|
||||
|
|
@ -419,7 +419,7 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
|
|||
"If two pins are identified as a corresponding pair, this method will be called with both pins.\n"
|
||||
"If pins can't be matched, \\pin_mismatch will be called with the one pin considered and the other pin being nil."
|
||||
) +
|
||||
gsi::callback ("pin_mismatch", &GenericNetlistCompareLogger::pin_mismatch, &GenericNetlistCompareLogger::cb_pin_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
gsi::callback ("pin_mismatch", &GenericNetlistCompareLogger::pin_mismatch, &GenericNetlistCompareLogger::cb_pin_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
|
||||
"@brief This function is called when two pins can't be paired.\n"
|
||||
"This will report the pin considered in a or b. The other argument is nil. "
|
||||
"See \\match_pins for details.\n"
|
||||
|
|
@ -429,7 +429,7 @@ Class<GenericNetlistCompareLogger> decl_GenericNetlistCompareLogger (decl_dbNetl
|
|||
"If two subcircuits are identified as a corresponding pair, this method will be called with both subcircuits.\n"
|
||||
"If subcircuits can't be matched, \\subcircuit_mismatch will be called with the one subcircuit considered and the other subcircuit being nil."
|
||||
) +
|
||||
gsi::callback ("subcircuit_mismatch", &GenericNetlistCompareLogger::subcircuit_mismatch, &GenericNetlistCompareLogger::cb_subcircuit_mismatch, gsi::arg ("a"), gsi::arg ("b"),
|
||||
gsi::callback ("subcircuit_mismatch", &GenericNetlistCompareLogger::subcircuit_mismatch, &GenericNetlistCompareLogger::cb_subcircuit_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"),
|
||||
"@brief This function is called when two subcircuits can't be paired.\n"
|
||||
"This will report the subcircuit considered in a or b. The other argument is nil. "
|
||||
"See \\match_subcircuits for details.\n"
|
||||
|
|
|
|||
|
|
@ -1602,9 +1602,9 @@ static db::Polygon transformed_icplx_dp (const db::Polygon *p, const db::ICplxTr
|
|||
return p->transformed (t, false /*don't compress*/);
|
||||
}
|
||||
|
||||
static db::Polygon smooth (const db::Polygon *p, db::Coord d)
|
||||
static db::Polygon smooth (const db::Polygon *p, db::Coord d, bool keep_hv)
|
||||
{
|
||||
return db::smooth (*p, d);
|
||||
return db::smooth (*p, d, keep_hv);
|
||||
}
|
||||
|
||||
static db::Polygon minkowsky_sum_pe (const db::Polygon *p, const db::Edge &e, bool rh)
|
||||
|
|
@ -1787,17 +1787,18 @@ Class<db::Polygon> decl_Polygon ("db", "Polygon",
|
|||
"\n"
|
||||
"This method was introduced in version 0.22.\n"
|
||||
) +
|
||||
method_ext ("smooth", &smooth, gsi::arg ("d"),
|
||||
method_ext ("smooth", &smooth, gsi::arg ("d"), gsi::arg ("keep_hv", false),
|
||||
"@brief Smoothes a polygon\n"
|
||||
"\n"
|
||||
"Remove vertices that deviate by more than the distance d from the average contour.\n"
|
||||
"The value d is basically the roughness which is removed.\n"
|
||||
"\n"
|
||||
"@param d The smoothing \"roughness\".\n"
|
||||
"@param keep_hv If true, horizontal and vertical edges will be preserved always.\n"
|
||||
"\n"
|
||||
"@return The smoothed polygon.\n"
|
||||
"\n"
|
||||
"This method was introduced in version 0.23.\n"
|
||||
"This method was introduced in version 0.23. The 'keep_hv' optional parameter was added in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("minkowsky_sum", &minkowsky_sum_pe, gsi::arg ("e"), gsi::arg ("resolve_holes"),
|
||||
"@brief Computes the Minkowsky sum of the polygon and an edge\n"
|
||||
|
|
|
|||
|
|
@ -70,6 +70,27 @@ static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r)
|
|||
return db::CplxTrans (ly->dbu ()) * r->trans () * db::VCplxTrans (1.0 / ly->dbu ());
|
||||
}
|
||||
|
||||
static db::DCplxTrans si_global_dtrans (const db::RecursiveShapeIterator *r)
|
||||
{
|
||||
const db::Layout *ly = r->layout ();
|
||||
tl_assert (ly != 0);
|
||||
return db::CplxTrans (ly->dbu ()) * r->global_trans () * db::VCplxTrans (1.0 / ly->dbu ());
|
||||
}
|
||||
|
||||
static db::DCplxTrans si_always_apply_dtrans (const db::RecursiveShapeIterator *r)
|
||||
{
|
||||
const db::Layout *ly = r->layout ();
|
||||
tl_assert (ly != 0);
|
||||
return db::CplxTrans (ly->dbu ()) * r->always_apply () * db::VCplxTrans (1.0 / ly->dbu ());
|
||||
}
|
||||
|
||||
static void si_set_global_dtrans (db::RecursiveShapeIterator *r, const db::DCplxTrans >)
|
||||
{
|
||||
const db::Layout *ly = r->layout ();
|
||||
tl_assert (ly != 0);
|
||||
r->set_global_trans (db::VCplxTrans (1.0 / ly->dbu ()) * gt * db::CplxTrans (ly->dbu ()));
|
||||
}
|
||||
|
||||
static void select_cells1 (db::RecursiveShapeIterator *r, const std::vector<db::cell_index_type> &cells)
|
||||
{
|
||||
std::set<db::cell_index_type> cc;
|
||||
|
|
@ -270,7 +291,47 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method ("region", &db::RecursiveShapeIterator::region,
|
||||
gsi::method ("global_trans=", &db::RecursiveShapeIterator::set_global_trans, gsi::arg ("t"),
|
||||
"@brief Sets the global transformation to apply to all shapes delivered\n"
|
||||
"The global transformation will be applied to all shapes delivered by biasing the \"trans\" attribute.\n"
|
||||
"The search regions apply to the coordinate space after global transformation.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("global_trans", &db::RecursiveShapeIterator::global_trans,
|
||||
"@brief Gets the global transformation to apply to all shapes delivered\n"
|
||||
"See also \\global_trans=.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("global_dtrans=", &si_set_global_dtrans,
|
||||
"@brief Sets the global transformation to apply to all shapes delivered (transformation in micrometer units)\n"
|
||||
"The global transformation will be applied to all shapes delivered by biasing the \"trans\" attribute.\n"
|
||||
"The search regions apply to the coordinate space after global transformation.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("global_dtrans", &si_global_dtrans,
|
||||
"@brief Gets the global transformation to apply to all shapes delivered (in micrometer units)\n"
|
||||
"See also \\global_dtrans=.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("always_apply_trans", &db::RecursiveShapeIterator::always_apply,
|
||||
"@brief Gets the global transformation if at top level, unity otherwise\n"
|
||||
"As the global transformation is only applicable on top level, use this method to transform shapes and instances into their local (cell-level) version "
|
||||
"while considering the global transformation properly.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("always_apply_dtrans", &si_always_apply_dtrans,
|
||||
"@brief Gets the global transformation if at top level, unity otherwise (micrometer-unit version)\n"
|
||||
"As the global transformation is only applicable on top level, use this method to transform shapes and instances into their local (cell-level) version "
|
||||
"while considering the global transformation properly.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("region", &db::RecursiveShapeIterator::region,
|
||||
"@brief Gets the basic region that is iterator is using\n"
|
||||
"The basic region is the overall box the region iterator iterates over. "
|
||||
"There may be an additional complex region that confines the region iterator. "
|
||||
|
|
|
|||
|
|
@ -611,15 +611,53 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other,
|
|||
);
|
||||
}
|
||||
|
||||
static inline std::vector<db::Region> as_2region_vector (const std::pair<db::Region, db::Region> &rp)
|
||||
{
|
||||
std::vector<db::Region> res;
|
||||
res.reserve (2);
|
||||
res.push_back (db::Region (const_cast<db::Region &> (rp.first).take_delegate ()));
|
||||
res.push_back (db::Region (const_cast<db::Region &> (rp.second).take_delegate ()));
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::vector<db::Region> andnot (const db::Region *r, const db::Region &other)
|
||||
{
|
||||
std::pair<db::Region, db::Region> rp = r->andnot (other);
|
||||
return as_2region_vector (r->andnot (other));
|
||||
}
|
||||
|
||||
std::vector<db::Region> res;
|
||||
res.resize (2, db::Region ());
|
||||
res [0] = rp.first;
|
||||
res [1] = rp.second;
|
||||
return res;
|
||||
static std::vector<db::Region> split_inside (const db::Region *r, const db::Region &other)
|
||||
{
|
||||
return as_2region_vector (r->selected_inside_differential (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Region> split_outside (const db::Region *r, const db::Region &other)
|
||||
{
|
||||
return as_2region_vector (r->selected_outside_differential (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Region> split_overlapping (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count)
|
||||
{
|
||||
return as_2region_vector (r->selected_overlapping_differential (other, min_count, max_count));
|
||||
}
|
||||
|
||||
static std::vector<db::Region> split_covering (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count)
|
||||
{
|
||||
return as_2region_vector (r->selected_enclosing_differential (other, min_count, max_count));
|
||||
}
|
||||
|
||||
static std::vector<db::Region> split_interacting_with_region (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count)
|
||||
{
|
||||
return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count));
|
||||
}
|
||||
|
||||
static std::vector<db::Region> split_interacting_with_edges (const db::Region *r, const db::Edges &other, size_t min_count, size_t max_count)
|
||||
{
|
||||
return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count));
|
||||
}
|
||||
|
||||
static std::vector<db::Region> split_interacting_with_texts (const db::Region *r, const db::Texts &other, size_t min_count, size_t max_count)
|
||||
{
|
||||
return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count));
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
|
|
@ -705,6 +743,7 @@ int po_any ();
|
|||
|
||||
extern Class<db::ShapeCollection> decl_dbShapeCollection;
|
||||
|
||||
|
||||
Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
||||
constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
|
|
@ -927,7 +966,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"polygons which have the given perimeter are returned. If \"inverse\" is true, "
|
||||
"polygons not having the given perimeter are returned.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_perimeter", with_perimeter2, gsi::arg ("min_perimeter"), gsi::arg ("max_perimeter"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by perimeter\n"
|
||||
|
|
@ -939,7 +978,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by area\n"
|
||||
|
|
@ -947,7 +986,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"polygons which have the given area are returned. If \"inverse\" is true, "
|
||||
"polygons not having the given area are returned.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_area", with_area2, gsi::arg ("min_area"), gsi::arg ("max_area"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by area\n"
|
||||
|
|
@ -959,7 +998,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_holes", with_holes1, gsi::arg ("nholes"), gsi::arg ("inverse"),
|
||||
"@brief Filters the polygons by their number of holes\n"
|
||||
|
|
@ -967,7 +1006,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"polygons which have the given number of holes are returned. If \"inverse\" is true, "
|
||||
"polygons not having the given of holes are returned.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -981,7 +1020,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -991,7 +1030,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"polygons whose bounding box has the given width are returned. If \"inverse\" is true, "
|
||||
"polygons whose bounding box does not have the given width are returned.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_bbox_width", with_bbox_width2, gsi::arg ("min_width"), gsi::arg ("max_width"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by bounding box width\n"
|
||||
|
|
@ -1001,7 +1040,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_bbox_height", with_bbox_height1, gsi::arg ("height"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by bounding box height\n"
|
||||
|
|
@ -1009,7 +1048,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"polygons whose bounding box has the given height are returned. If \"inverse\" is true, "
|
||||
"polygons whose bounding box does not have the given height are returned.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_bbox_height", with_bbox_height2, gsi::arg ("min_height"), gsi::arg ("max_height"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by bounding box height\n"
|
||||
|
|
@ -1019,7 +1058,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_bbox_min", with_bbox_min1, gsi::arg ("dim"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by bounding box width or height, whichever is smaller\n"
|
||||
|
|
@ -1028,7 +1067,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"are returned. "
|
||||
"If \"inverse\" is true, all polygons not matching this criterion are returned."
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_bbox_min", with_bbox_min2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by bounding box width or height, whichever is smaller\n"
|
||||
|
|
@ -1039,7 +1078,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_bbox_max", with_bbox_max1, gsi::arg ("dim"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by bounding box width or height, whichever is larger\n"
|
||||
|
|
@ -1048,7 +1087,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"are returned. "
|
||||
"If \"inverse\" is true, all polygons not matching this criterion are returned."
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_bbox_max", with_bbox_max2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"),
|
||||
"@brief Filter the polygons by bounding box width or height, whichever is larger\n"
|
||||
|
|
@ -1059,7 +1098,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_bbox_aspect_ratio", with_bbox_aspect_ratio1, gsi::arg ("ratio"), gsi::arg ("inverse"),
|
||||
"@brief Filters the polygons by the aspect ratio of their bounding boxes\n"
|
||||
|
|
@ -1070,7 +1109,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"With 'inverse' set to false, this version filters polygons which have a bounding box aspect ratio equal to the given value. "
|
||||
"With 'inverse' set to true, all other polygons will be returned.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1086,7 +1125,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1099,7 +1138,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"With 'inverse' set to false, this version filters polygons which have an area ratio equal to the given value. "
|
||||
"With 'inverse' set to true, all other polygons will be returned.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1115,7 +1154,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1129,7 +1168,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"With 'inverse' set to false, this version filters polygons which have a relative height equal to the given value. "
|
||||
"With 'inverse' set to true, all other polygons will be returned.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1146,7 +1185,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1154,7 +1193,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"@brief Returns a region containing those parts of polygons which are \"strange\"\n"
|
||||
"Strange parts of polygons are self-overlapping parts or non-orientable parts (i.e. in the \"8\" configuration).\n"
|
||||
"\n"
|
||||
"Merged semantics does not apply for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics does not apply for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("snapped", &db::Region::snapped, gsi::arg ("gx"), gsi::arg ("gy"),
|
||||
"@brief Returns the snapped region\n"
|
||||
|
|
@ -1167,7 +1206,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If gx or gy is 0, no snapping happens in that direction.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("scaled_and_snapped", &db::Region::scaled_and_snapped, gsi::arg ("gx"), gsi::arg ("mx"), gsi::arg ("dx"), gsi::arg ("gy"),gsi::arg ("my"), gsi::arg ("dy"),
|
||||
"@brief Returns the scaled and snapped region\n"
|
||||
|
|
@ -1183,7 +1222,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If gx or gy is 0, the result is brought on a grid of 1.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1."
|
||||
) +
|
||||
|
|
@ -1195,7 +1234,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"If gx or gy is 0 or less, the grid is not checked in that direction.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_angle", angle_check1, gsi::arg ("angle"), gsi::arg ("inverse"),
|
||||
"@brief Returns markers on every corner with the given angle (or not with the given angle)\n"
|
||||
|
|
@ -1205,7 +1244,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"The edge pair objects returned will contain both edges forming the angle.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("with_angle", angle_check2, gsi::arg ("amin"), gsi::arg ("amax"), gsi::arg ("inverse"),
|
||||
"@brief Returns markers on every corner with an angle of more than amin and less than amax (or the opposite)\n"
|
||||
|
|
@ -1215,7 +1254,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"The edge pair objects returned will contain both edges forming the angle.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("insert", (void (db::Region::*)(const db::Box &)) &db::Region::insert, gsi::arg ("box"),
|
||||
"@brief Inserts a box\n"
|
||||
|
|
@ -1290,7 +1329,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"The boxes will not be merged, so it is possible to determine overlaps "
|
||||
"of these boxes for example.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("extents", &extents1, gsi::arg ("d"),
|
||||
"@brief Returns a region with the enlarged bounding boxes of the polygons\n"
|
||||
|
|
@ -1299,7 +1338,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"The boxes will not be merged, so it is possible to determine overlaps "
|
||||
"of these boxes for example.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("extents", &extents2, gsi::arg ("dx"), gsi::arg ("dy"),
|
||||
"@brief Returns a region with the enlarged bounding boxes of the polygons\n"
|
||||
|
|
@ -1308,7 +1347,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"The boxes will not be merged, so it is possible to determine overlaps "
|
||||
"of these boxes for example.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("extent_refs", &extent_refs,
|
||||
"@hide\n"
|
||||
|
|
@ -1436,9 +1475,10 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"See \\round_corners for a description of this method. This version returns a new region instead of "
|
||||
"modifying self (out-of-place)."
|
||||
) +
|
||||
method ("smooth", &db::Region::smooth, gsi::arg ("d"),
|
||||
method ("smooth", &db::Region::smooth, gsi::arg ("d"), gsi::arg ("keep_hv", false),
|
||||
"@brief Smoothing\n"
|
||||
"@param d The smoothing tolerance (in database units)\n"
|
||||
"@param keep_hv If true, horizontal and vertical edges are maintained\n"
|
||||
"\n"
|
||||
"This method will simplify the merged polygons of the region by removing vertexes if the "
|
||||
"resulting polygon stays equivalent with the original polygon. Equivalence is measured "
|
||||
|
|
@ -1447,9 +1487,10 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"This method modifies the region. \\smoothed is a method that does the same but returns a new "
|
||||
"region without modifying self. Merged semantics applies for this method.\n"
|
||||
) +
|
||||
method ("smoothed", &db::Region::smoothed, gsi::arg ("d"),
|
||||
method ("smoothed", &db::Region::smoothed, gsi::arg ("d"), gsi::arg ("keep_hv", false),
|
||||
"@brief Smoothing\n"
|
||||
"@param d The smoothing tolerance (in database units)\n"
|
||||
"@param keep_hv If true, horizontal and vertical edges are maintained\n"
|
||||
"\n"
|
||||
"See \\smooth for a description of this method. This version returns a new region instead of "
|
||||
"modifying self (out-of-place). It has been introduced in version 0.25."
|
||||
|
|
@ -1468,7 +1509,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"The mode defines at which bending angle cutoff occurs \n"
|
||||
"(0:>0, 1:>45, 2:>90, 3:>135, 4:>approx. 168, other:>approx. 179)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The result is a set of polygons which may be overlapping, but are not self-\n"
|
||||
"intersecting. Polygons may overlap afterwards because they grew big enough to overlap their neighbors.\n"
|
||||
|
|
@ -1490,7 +1531,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This method is equivalent to \"size(d, d, mode)\".\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("size", size_ext, gsi::arg ("d"),
|
||||
"@brief Isotropic sizing (biasing)\n"
|
||||
|
|
@ -1499,7 +1540,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This method is equivalent to \"size(d, d, 2)\".\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("sized", (db::Region (db::Region::*) (db::Coord, db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"),
|
||||
"@brief Returns the anisotropically sized region\n"
|
||||
|
|
@ -1508,7 +1549,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This method is returns the sized region (see \\size), but does not modify self.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("sized", (db::Region (db::Region::*) (db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("d"), gsi::arg ("mode"),
|
||||
"@brief Returns the isotropically sized region\n"
|
||||
|
|
@ -1517,7 +1558,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This method is returns the sized region (see \\size), but does not modify self.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("sized", sized_ext, gsi::arg ("d"),
|
||||
"@brief Isotropic sizing (biasing)\n"
|
||||
|
|
@ -1526,7 +1567,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"This method is equivalent to \"sized(d, d, 2)\".\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("andnot", &andnot, gsi::arg ("other"),
|
||||
"@brief Returns the boolean AND and NOT between self and the other region\n"
|
||||
|
|
@ -1623,7 +1664,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons which are covering polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
|
||||
"\n"
|
||||
|
|
@ -1634,18 +1675,28 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons which are not covering polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method_ext ("split_covering", &split_covering, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Returns the polygons of this region which are completely covering polygons from the other region and the ones which are not at the same time\n"
|
||||
"\n"
|
||||
"@return Two new regions: the first containing the result of \\covering, the second the result of \\not_covering\n"
|
||||
"\n"
|
||||
"This method is equivalent to calling \\covering and \\not_covering, but is faster when both results are required.\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("select_covering", &db::Region::select_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Selects the polygons of this region which are completely covering polygons from the other region\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
|
||||
"\n"
|
||||
|
|
@ -1656,7 +1707,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n"
|
||||
"\n"
|
||||
|
|
@ -1667,56 +1718,76 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons which are inside polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("not_inside", &db::Region::selected_not_inside, gsi::arg ("other"),
|
||||
"@brief Returns the polygons of this region which are not completely inside polygons from the other region\n"
|
||||
"\n"
|
||||
"@return A new region containing the polygons which are not inside polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("split_inside", &split_inside, gsi::arg ("other"),
|
||||
"@brief Returns the polygons of this region which are completely inside polygons from the other region and the ones which are not at the same time\n"
|
||||
"\n"
|
||||
"@return Two new regions: the first containing the result of \\inside, the second the result of \\not_inside\n"
|
||||
"\n"
|
||||
"This method is equivalent to calling \\inside and \\not_inside, but is faster when both results are required.\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("select_inside", &db::Region::select_inside, gsi::arg ("other"),
|
||||
"@brief Selects the polygons of this region which are completely inside polygons from the other region\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("select_not_inside", &db::Region::select_not_inside, gsi::arg ("other"),
|
||||
"@brief Selects the polygons of this region which are not completely inside polygons from the other region\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("outside", &db::Region::selected_outside, gsi::arg ("other"),
|
||||
"@brief Returns the polygons of this region which are completely outside polygons from the other region\n"
|
||||
"\n"
|
||||
"@return A new region containing the polygons which are outside polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("not_outside", &db::Region::selected_not_outside, gsi::arg ("other"),
|
||||
"@brief Returns the polygons of this region which are not completely outside polygons from the other region\n"
|
||||
"\n"
|
||||
"@return A new region containing the polygons which are not outside polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("split_outside", &split_outside, gsi::arg ("other"),
|
||||
"@brief Returns the polygons of this region which are completely outside polygons from the other region and the ones which are not at the same time\n"
|
||||
"\n"
|
||||
"@return Two new regions: the first containing the result of \\outside, the second the result of \\not_outside\n"
|
||||
"\n"
|
||||
"This method is equivalent to calling \\outside and \\not_outside, but is faster when both results are required.\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("select_outside", &db::Region::select_outside, gsi::arg ("other"),
|
||||
"@brief Selects the polygons of this region which are completely outside polygons from the other region\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("select_not_outside", &db::Region::select_not_outside, gsi::arg ("other"),
|
||||
"@brief Selects the polygons of this region which are not completely outside polygons from the other region\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method ("interacting", (db::Region (db::Region::*) (const db::Region &, size_t, size_t) const) &db::Region::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Returns the polygons of this region which overlap or touch polygons from the other region\n"
|
||||
|
|
@ -1728,7 +1799,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons overlapping or touching polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The min_count and max_count arguments have been added in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1742,10 +1813,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons not overlapping or touching polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The min_count and max_count arguments have been added in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("split_interacting", &split_interacting_with_region, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Returns the polygons of this region which are interacting with polygons from the other region and the ones which are not at the same time\n"
|
||||
"\n"
|
||||
"@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n"
|
||||
"\n"
|
||||
"This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("select_interacting", (db::Region &(db::Region::*) (const db::Region &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Selects the polygons from this region which overlap or touch polygons from the other region\n"
|
||||
"\n"
|
||||
|
|
@ -1756,7 +1837,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The min_count and max_count arguments have been added in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1770,7 +1851,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The min_count and max_count arguments have been added in version 0.27.\n"
|
||||
) +
|
||||
|
|
@ -1784,7 +1865,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons overlapping or touching edges from the edge collection\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25.\n"
|
||||
"The min_count and max_count arguments have been added in version 0.27.\n"
|
||||
|
|
@ -1799,11 +1880,21 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons not overlapping or touching edges from the edge collection\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25\n"
|
||||
"The min_count and max_count arguments have been added in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("split_interacting", &split_interacting_with_edges, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Returns the polygons of this region which are interacting with edges from the other edge collection and the ones which are not at the same time\n"
|
||||
"\n"
|
||||
"@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n"
|
||||
"\n"
|
||||
"This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("select_interacting", (db::Region &(db::Region::*) (const db::Edges &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Selects the polygons from this region which overlap or touch edges from the edge collection\n"
|
||||
"\n"
|
||||
|
|
@ -1814,7 +1905,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25\n"
|
||||
"The min_count and max_count arguments have been added in version 0.27.\n"
|
||||
|
|
@ -1829,7 +1920,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25\n"
|
||||
"The min_count and max_count arguments have been added in version 0.27.\n"
|
||||
|
|
@ -1844,7 +1935,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons overlapping or touching texts\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
|
|
@ -1858,10 +1949,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons not overlapping or touching texts\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
method_ext ("split_interacting", &split_interacting_with_texts, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Returns the polygons of this region which are interacting with texts from the other text collection and the ones which are not at the same time\n"
|
||||
"\n"
|
||||
"@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n"
|
||||
"\n"
|
||||
"This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("select_interacting", (db::Region &(db::Region::*) (const db::Texts &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Selects the polygons of this region which overlap or touch texts\n"
|
||||
"\n"
|
||||
|
|
@ -1872,7 +1973,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"selected by this method if the number of texts interacting with the polygon is between min_count and max_count "
|
||||
"(including max_count).\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
|
|
@ -1886,7 +1987,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
|
|
@ -1895,7 +1996,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons overlapping polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The count options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -1904,16 +2005,26 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return A new region containing the polygons not overlapping polygons from the other region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The count options have been introduced in version 0.27."
|
||||
) +
|
||||
method_ext ("split_overlapping", &split_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Returns the polygons of this region which are overlapping with polygons from the other region and the ones which are not at the same time\n"
|
||||
"\n"
|
||||
"@return Two new regions: the first containing the result of \\overlapping, the second the result of \\not_overlapping\n"
|
||||
"\n"
|
||||
"This method is equivalent to calling \\overlapping and \\not_overlapping, but is faster when both results are required.\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
method ("select_overlapping", &db::Region::select_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
|
||||
"@brief Selects the polygons from this region which overlap polygons from the other region\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The count options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -1922,7 +2033,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The count options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -1935,7 +2046,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (from other)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1\n"
|
||||
) +
|
||||
|
|
@ -1945,7 +2056,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (from other)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1\n"
|
||||
) +
|
||||
|
|
@ -1955,7 +2066,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The region after the polygons have been selected (from other)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1\n"
|
||||
) +
|
||||
|
|
@ -1965,7 +2076,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The edge collection after the edges have been selected (from other)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1\n"
|
||||
) +
|
||||
|
|
@ -1975,7 +2086,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\n"
|
||||
"@return The text collection after the texts have been selected (from other)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
|
|
@ -1996,7 +2107,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"The edge collection returned can be manipulated in various ways. See \\Edges for a description of the "
|
||||
"possibilities of the edge collection.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
factory_ext ("decompose_convex", &decompose_convex<db::Shapes>, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
|
||||
"@brief Decomposes the region into convex pieces.\n"
|
||||
|
|
@ -2040,7 +2151,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"@brief Returns the holes of the region\n"
|
||||
"This method returns all holes as filled polygons.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"If merge semantics is not enabled, the holes may not be detected if the polygons "
|
||||
"are taken from a hole-less representation (i.e. GDS2 file). Use explicit merge (\\merge method) "
|
||||
"in order to merge the polygons and detect holes.\n"
|
||||
|
|
@ -2049,7 +2160,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"@brief Returns the hulls of the region\n"
|
||||
"This method returns all hulls as polygons. The holes will be removed (filles). "
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"If merge semantics is not enabled, the hull may also enclose holes if the polygons "
|
||||
"are taken from a hole-less representation (i.e. GDS2 file). Use explicit merge (\\merge method) "
|
||||
"in order to merge the polygons and detect holes.\n"
|
||||
|
|
@ -2067,36 +2178,36 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
method_ext ("rectangles", &rectangles,
|
||||
"@brief Returns all polygons which are rectangles\n"
|
||||
"This method returns all polygons in self which are rectangles."
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("non_rectangles", &non_rectangles,
|
||||
"@brief Returns all polygons which are not rectangles\n"
|
||||
"This method returns all polygons in self which are not rectangles."
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("squares", &squares,
|
||||
"@brief Returns all polygons which are squares\n"
|
||||
"This method returns all polygons in self which are squares."
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("non_squares", &non_squares,
|
||||
"@brief Returns all polygons which are not squares\n"
|
||||
"This method returns all polygons in self which are not squares."
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("rectilinear", &rectilinear,
|
||||
"@brief Returns all polygons which are rectilinear\n"
|
||||
"This method returns all polygons in self which are rectilinear."
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("non_rectilinear", &non_rectilinear,
|
||||
"@brief Returns all polygons which are not rectilinear\n"
|
||||
"This method returns all polygons in self which are not rectilinear."
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("break", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0),
|
||||
"@brief Breaks the polygons of the region into smaller ones\n"
|
||||
|
|
@ -2125,7 +2236,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"with a pencil that has the shape of the given region.\n"
|
||||
"\n"
|
||||
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method."
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("minkowsky_sum", &minkowsky_sum_pp, gsi::arg ("p"),
|
||||
"@brief Compute the Minkowsky sum of the region and a polygon\n"
|
||||
|
|
@ -2138,7 +2249,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"the region with a pen that has the shape of the second polygon.\n"
|
||||
"\n"
|
||||
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method."
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("minkowsky_sum", &minkowsky_sum_pb, gsi::arg ("b"),
|
||||
"@brief Compute the Minkowsky sum of the region and a box\n"
|
||||
|
|
@ -2151,7 +2262,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"as the second polygon.\n"
|
||||
"\n"
|
||||
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method."
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("minkowsky_sum", &minkowsky_sum_pc, gsi::arg ("b"),
|
||||
"@brief Compute the Minkowsky sum of the region and a contour of points (a trace)\n"
|
||||
|
|
@ -2165,7 +2276,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"with a pencil that has the shape of the given region.\n"
|
||||
"\n"
|
||||
"The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method."
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
) +
|
||||
method_ext ("move", &move_p, gsi::arg ("v"),
|
||||
"@brief Moves the region\n"
|
||||
|
|
@ -2338,7 +2449,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"violations between the original and the shielding features. If not necessary, shielding can be disabled by setting this flag to "
|
||||
"false. In general, this will improve performance somewhat.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The 'shielded' and 'negative' options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -2380,7 +2491,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
|
||||
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -2421,7 +2532,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"violations between the original and the shielding features. If not necessary, shielding can be disabled by setting this flag to "
|
||||
"false. In general, this will improve performance somewhat.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The 'shielded' and 'negative' options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -2463,7 +2574,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
|
||||
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -2506,7 +2617,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
|
||||
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -2549,7 +2660,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
|
||||
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -2592,7 +2703,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
|
||||
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
|
||||
) +
|
||||
|
|
@ -2635,27 +2746,27 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. "
|
||||
"\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"\n"
|
||||
"The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27."
|
||||
) +
|
||||
method_ext ("area", &area1,
|
||||
"@brief The area of the region\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"If merged semantics is not enabled, overlapping areas are counted twice.\n"
|
||||
) +
|
||||
method_ext ("area", &area2, gsi::arg ("rect"),
|
||||
"@brief The area of the region (restricted to a rectangle)\n"
|
||||
"This version will compute the area of the shapes, restricting the computation to the given rectangle.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"If merged semantics is not enabled, overlapping areas are counted twice.\n"
|
||||
) +
|
||||
method_ext ("perimeter", &perimeter1,
|
||||
"@brief The total perimeter of the polygons\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"If merged semantics is not enabled, internal edges are counted as well.\n"
|
||||
) +
|
||||
method_ext ("perimeter", &perimeter2, gsi::arg ("rect"),
|
||||
|
|
@ -2664,7 +2775,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"Edges along the border are handled in a special way: they are counted when they are oriented with their inside "
|
||||
"side toward the rectangle (in other words: outside edges must coincide with the rectangle's border in order to be counted).\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
|
||||
"If merged semantics is not enabled, internal edges are counted as well.\n"
|
||||
) +
|
||||
method ("bbox", &db::Region::bbox,
|
||||
|
|
|
|||
|
|
@ -733,7 +733,8 @@ TEST(11_RoundAndSmoothed)
|
|||
r1_sized -= r1;
|
||||
|
||||
db::Region rounded = r1_sized.rounded_corners (3000, 5000, 100);
|
||||
db::Region smoothed = rounded.smoothed (100);
|
||||
db::Region smoothed = rounded.smoothed (100, false);
|
||||
db::Region smoothed_keep_hv = rounded.smoothed (100, true);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
|
@ -741,6 +742,7 @@ TEST(11_RoundAndSmoothed)
|
|||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r1_sized);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), rounded);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), smoothed);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), smoothed_keep_hv);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au11.gds");
|
||||
|
|
|
|||
|
|
@ -44,22 +44,22 @@ public:
|
|||
out ("begin_circuit " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching)
|
||||
virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string & /*msg*/)
|
||||
{
|
||||
out ("end_circuit " + circuit2str (a) + " " + circuit2str (b) + " " + (matching ? "MATCH" : "NOMATCH"));
|
||||
}
|
||||
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b)
|
||||
virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b)
|
||||
virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b));
|
||||
}
|
||||
|
||||
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b)
|
||||
virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("device_class_mismatch " + dc2str (a) + " " + dc2str (b));
|
||||
}
|
||||
|
|
@ -69,12 +69,12 @@ public:
|
|||
out ("match_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b)
|
||||
virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b)
|
||||
virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("net_mismatch " + net2str (a) + " " + net2str (b));
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ public:
|
|||
out ("match_devices " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b)
|
||||
virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("device_mismatch " + device2str (a) + " " + device2str (b));
|
||||
}
|
||||
|
|
@ -104,7 +104,7 @@ public:
|
|||
out ("match_pins " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b)
|
||||
virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("pin_mismatch " + pin2str (a) + " " + pin2str (b));
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@ public:
|
|||
out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b)
|
||||
virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string & /*msg*/)
|
||||
{
|
||||
out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b));
|
||||
}
|
||||
|
|
@ -954,7 +954,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
|
|||
EXPECT_EQ (good, false);
|
||||
|
||||
logger.clear ();
|
||||
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 1.5, 0.0));
|
||||
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 1.5, 0.0));
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
|
|
@ -980,7 +980,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
|
|||
EXPECT_EQ (good, true);
|
||||
|
||||
logger.clear ();
|
||||
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.0));
|
||||
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.0));
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
|
|
@ -1006,7 +1006,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
|
|||
EXPECT_EQ (good, false);
|
||||
|
||||
logger.clear ();
|
||||
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.2));
|
||||
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.2));
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
|
|
@ -1032,7 +1032,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
|
|||
EXPECT_EQ (good, false);
|
||||
|
||||
logger.clear ();
|
||||
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.4));
|
||||
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.4));
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
|
|
@ -1059,7 +1059,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
|
|||
|
||||
logger.clear ();
|
||||
db::EqualDeviceParameters eq_dp = db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W) + db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.2, 0.0);
|
||||
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp));
|
||||
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp));
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
|
|
@ -1086,7 +1086,7 @@ TEST(5_BufferTwoPathsDifferentParameters)
|
|||
|
||||
logger.clear ();
|
||||
eq_dp = db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W) + db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L);
|
||||
nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp));
|
||||
nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp));
|
||||
good = comp.compare (&nl1, &nl2);
|
||||
|
||||
EXPECT_EQ (logger.text (),
|
||||
|
|
|
|||
|
|
@ -1219,8 +1219,8 @@ TEST(100)
|
|||
db::Polygon p;
|
||||
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
|
||||
|
||||
EXPECT_EQ (smooth (p, 5).to_string (), "(0,-100;0,0;50,10;100,-10;150,0;150,-100)");
|
||||
EXPECT_EQ (smooth (p, 20).to_string (), "(0,-100;0,0;150,0;150,-100)");
|
||||
EXPECT_EQ (smooth (p, 5, true).to_string (), "(0,-100;0,0;50,10;100,-10;150,0;150,-100)");
|
||||
EXPECT_EQ (smooth (p, 20, true).to_string (), "(0,-100;0,0;150,0;150,-100)");
|
||||
}
|
||||
|
||||
// smoothing
|
||||
|
|
@ -1238,8 +1238,8 @@ TEST(101)
|
|||
db::Polygon p;
|
||||
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
|
||||
|
||||
EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;50,10;0,0;0,100;150,100;150,0)");
|
||||
EXPECT_EQ (smooth (p, 20).to_string (), "(0,0;0,100;150,100;150,0)");
|
||||
EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;50,10;0,0;0,100;150,100;150,0)");
|
||||
EXPECT_EQ (smooth (p, 20, true).to_string (), "(0,0;0,100;150,100;150,0)");
|
||||
}
|
||||
|
||||
// smoothing
|
||||
|
|
@ -1255,8 +1255,8 @@ TEST(102)
|
|||
db::Polygon p;
|
||||
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
|
||||
|
||||
EXPECT_EQ (smooth (p, 20).to_string (), "()");
|
||||
EXPECT_EQ (smooth (p, 5).to_string (), "(100,-10;150,0;0,0;50,10)");
|
||||
EXPECT_EQ (smooth (p, 20, true).to_string (), "()");
|
||||
EXPECT_EQ (smooth (p, 5, true).to_string (), "(100,-10;150,0;0,0;50,10)");
|
||||
}
|
||||
|
||||
// smoothing
|
||||
|
|
@ -1282,9 +1282,9 @@ TEST(103)
|
|||
db::Polygon p;
|
||||
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
|
||||
|
||||
EXPECT_EQ (smooth (p, 0).to_string (), "(59881,-249925;56852,-237283;56961,-237258;60061,-236492;63152,-235686;66231,-234839;69300,-233952;69407,-233919;73105,-246382;72992,-246417;69760,-247351;66516,-248243;63261,-249092;59995,-249899)");
|
||||
EXPECT_EQ (smooth (p, 50).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)");
|
||||
EXPECT_EQ (smooth (p, 5000).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)");
|
||||
EXPECT_EQ (smooth (p, 0, true).to_string (), "(59881,-249925;56852,-237283;56961,-237258;60061,-236492;63152,-235686;66231,-234839;69300,-233952;69407,-233919;73105,-246382;72992,-246417;69760,-247351;66516,-248243;63261,-249092;59995,-249899)");
|
||||
EXPECT_EQ (smooth (p, 50, true).to_string (), "(59881,-249925;56852,-237283;63152,-235686;69407,-233919;73105,-246382;69760,-247351)");
|
||||
EXPECT_EQ (smooth (p, 5000, true).to_string (), "(59881,-249925;56852,-237283;69407,-233919;73105,-246382)");
|
||||
}
|
||||
|
||||
// smoothing
|
||||
|
|
@ -1303,7 +1303,8 @@ TEST(104)
|
|||
db::Polygon p;
|
||||
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
|
||||
|
||||
EXPECT_EQ (smooth (p, 12).to_string (), "(-244,-942;-942,-246;248,943;943,246)");
|
||||
EXPECT_EQ (smooth (p, 12, false).to_string (), "(-244,-942;-942,-246;248,943;943,246)");
|
||||
EXPECT_EQ (smooth (p, 12, true).to_string (), "(-245,-942;-942,-247;-942,-246;247,943;248,943;943,246;-244,-942)");
|
||||
}
|
||||
|
||||
// smoothing
|
||||
|
|
@ -1323,11 +1324,46 @@ TEST(105)
|
|||
db::Polygon p;
|
||||
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
|
||||
|
||||
EXPECT_EQ (smooth (p, 0).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 50).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 80).to_string (), "(0,0;0,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 90).to_string (), "(0,0;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 100).to_string (), "(0,0;0,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 0, false).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 50, false).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 80, false).to_string (), "(0,0;0,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 90, false).to_string (), "(0,0;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 100, false).to_string (), "(0,0;0,1000;2000,1000;2000,0)");
|
||||
EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,1000;100,1000;100,1100;800,1100;800,1000;2000,1000;2000,0)");
|
||||
}
|
||||
|
||||
// smoothing
|
||||
TEST(106)
|
||||
{
|
||||
db::Point pattern [] = {
|
||||
db::Point (0, 0),
|
||||
db::Point (0, 73235),
|
||||
db::Point (100, 74568),
|
||||
db::Point (700, 82468),
|
||||
db::Point (1200, 90468),
|
||||
db::Point (2000, 106468),
|
||||
db::Point (2300, 114468),
|
||||
db::Point (2700, 130468),
|
||||
db::Point (2800, 138468),
|
||||
db::Point (2800, 154468),
|
||||
db::Point (2700, 162468),
|
||||
db::Point (2300, 178468),
|
||||
db::Point (2000, 186468),
|
||||
db::Point (1200, 202468),
|
||||
db::Point (700, 210468),
|
||||
db::Point (100, 218368),
|
||||
db::Point (0, 219701),
|
||||
db::Point (0, 272971),
|
||||
db::Point (126450, 272971),
|
||||
db::Point (126450, 0),
|
||||
};
|
||||
|
||||
db::Polygon p;
|
||||
p.assign_hull (&pattern[0], &pattern[0] + sizeof (pattern) / sizeof (pattern[0]));
|
||||
|
||||
EXPECT_EQ (smooth (p, 0, false).to_string (), "(0,0;0,73235;100,74568;700,82468;1200,90468;2000,106468;2300,114468;2700,130468;2800,138468;2800,154468;2700,162468;2300,178468;2000,186468;1200,202468;700,210468;100,218368;0,219701;0,272971;126450,272971;126450,0)");
|
||||
EXPECT_EQ (smooth (p, 100, false).to_string (), "(0,0;100,74568;1200,90468;2300,114468;2800,138468;2700,162468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)");
|
||||
EXPECT_EQ (smooth (p, 100, true).to_string (), "(0,0;0,73235;1200,90468;2300,114468;2800,138468;2800,154468;2000,186468;700,210468;0,219701;0,272971;126450,272971;126450,0)");
|
||||
}
|
||||
|
||||
// rounding
|
||||
|
|
@ -1532,7 +1568,7 @@ TEST(203)
|
|||
in.push_back (pp);
|
||||
ep.simple_merge (in, out, false /*no cut line*/);
|
||||
pp = out.front ();
|
||||
pp = smooth (pp, 1);
|
||||
pp = smooth (pp, 1, true);
|
||||
|
||||
EXPECT_EQ (pp.hull ().size (), size_t (300));
|
||||
EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true);
|
||||
|
|
@ -1578,7 +1614,7 @@ TEST(204)
|
|||
in.push_back (pp);
|
||||
ep.simple_merge (in, out, false /*no cut line*/);
|
||||
pp = out.front ();
|
||||
pp = smooth (pp, 1);
|
||||
pp = smooth (pp, 1, true);
|
||||
|
||||
EXPECT_EQ (pp.hull ().size (), size_t (200));
|
||||
EXPECT_EQ (extract_rad (pp, rinner, router, n, &pr), true);
|
||||
|
|
|
|||
|
|
@ -107,12 +107,35 @@ TEST(1)
|
|||
|
||||
std::string x;
|
||||
|
||||
db::RecursiveShapeIterator i0s (g, c0, 0);
|
||||
x = collect(i0s, g);
|
||||
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
|
||||
EXPECT_EQ (i0s.bbox ().to_string (), "(-1200,0;2200,1200)");
|
||||
|
||||
i0s.set_global_trans (db::ICplxTrans (2.0));
|
||||
x = collect(i0s, g);
|
||||
EXPECT_EQ (x, "[$1](0,200;2000,2400)/[$2](0,200;2000,2400)/[$3](200,0;2200,2200)/[$4](2400,0;4400,2200)/[$4](-2400,0;-200,2000)");
|
||||
EXPECT_EQ (i0s.bbox ().to_string (), "(-2400,0;4400,2400)");
|
||||
|
||||
db::RecursiveShapeIterator i1 (g, c0, 0, db::Box (0, 0, 100, 100));
|
||||
x = collect(i1, g);
|
||||
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
|
||||
x = collect_with_copy(i1, g);
|
||||
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
|
||||
|
||||
i1.set_global_trans (db::ICplxTrans (db::Trans (db::Vector (10, 20))));
|
||||
i1.set_region (db::Box (10, 20, 110, 120));
|
||||
x = collect(i1, g);
|
||||
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
|
||||
x = collect_with_copy(i1, g);
|
||||
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
|
||||
|
||||
i1.reset ();
|
||||
x = collect(i1, g);
|
||||
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
|
||||
x = collect_with_copy(i1, g);
|
||||
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
|
||||
|
||||
db::RecursiveShapeIterator i1_1inf (g, c0, 0, db::Box (0, 0, 100, 100));
|
||||
i1_1inf.min_depth(1);
|
||||
x = collect(i1_1inf, g);
|
||||
|
|
@ -731,7 +754,7 @@ namespace {
|
|||
public:
|
||||
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
|
||||
|
||||
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
mp_boxes->insert (trans * shape.bbox ());
|
||||
}
|
||||
|
|
@ -766,6 +789,8 @@ TEST(4)
|
|||
|
||||
}
|
||||
|
||||
// ...
|
||||
|
||||
db::Box search_box (2500, 2500, 7500, 7500);
|
||||
|
||||
std::set<db::Box> selected_boxes;
|
||||
|
|
@ -794,6 +819,45 @@ TEST(4)
|
|||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
// with global trans
|
||||
|
||||
selected_boxes.clear ();
|
||||
selected_boxes2.clear ();
|
||||
db::ICplxTrans ctr (db::Trans (db::Vector (10, 20)));
|
||||
|
||||
{
|
||||
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
|
||||
iter.set_global_trans (ctr);
|
||||
for ( ; !iter.at_end (); ++iter) {
|
||||
selected_boxes.insert (iter->bbox ().transformed (iter.trans ()));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
|
||||
if (search_box.overlaps (b->transformed (ctr))) {
|
||||
selected_boxes2.insert (b->transformed (ctr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
// push mode
|
||||
{
|
||||
selected_boxes.clear ();
|
||||
FlatPusher pusher (&selected_boxes);
|
||||
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
|
||||
iter.set_global_trans (ctr);
|
||||
iter.push (&pusher);
|
||||
}
|
||||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
// ...
|
||||
|
||||
db::Box search_box2 (500, 500, 1000, 1000);
|
||||
|
||||
selected_boxes.clear ();
|
||||
|
|
@ -882,6 +946,40 @@ TEST(5)
|
|||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
selected_boxes.clear ();
|
||||
selected_boxes2.clear ();
|
||||
|
||||
db::ICplxTrans ctr (db::Trans (db::Vector (10, 20)));
|
||||
|
||||
{
|
||||
db::RecursiveShapeIterator iter = db::RecursiveShapeIterator (g, c0, 0, search_box, true);
|
||||
iter.set_global_trans (ctr);
|
||||
for ( ; !iter.at_end (); ++iter) {
|
||||
selected_boxes.insert (iter.trans () * iter->bbox ());
|
||||
}
|
||||
}
|
||||
|
||||
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
|
||||
if (search_box.overlaps (b->transformed (ctr))) {
|
||||
selected_boxes2.insert (b->transformed (ctr));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
// push mode
|
||||
{
|
||||
selected_boxes.clear ();
|
||||
FlatPusher pusher (&selected_boxes);
|
||||
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
|
||||
iter.set_global_trans (ctr);
|
||||
iter.push (&pusher);
|
||||
}
|
||||
|
||||
EXPECT_EQ (selected_boxes.size () > 100, true);
|
||||
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
|
||||
|
||||
db::Box search_box2 (500, 500, 1000, 1000);
|
||||
|
||||
selected_boxes.clear ();
|
||||
|
|
@ -936,7 +1034,7 @@ public:
|
|||
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
|
||||
}
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
{
|
||||
m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
|
||||
if (all) {
|
||||
|
|
@ -946,9 +1044,9 @@ public:
|
|||
return NI_all;
|
||||
}
|
||||
|
||||
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
|
||||
{
|
||||
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans);
|
||||
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (always_apply * trans);
|
||||
if (all) {
|
||||
m_text += ",all";
|
||||
}
|
||||
|
|
@ -956,7 +1054,7 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n";
|
||||
}
|
||||
|
|
@ -971,9 +1069,9 @@ class ReceiverRejectingACellInstanceArray
|
|||
public:
|
||||
ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { }
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, 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 ®ion, const box_tree_type *complex_region, bool all)
|
||||
{
|
||||
LoggingReceiver::new_inst (iter, inst, region, complex_region, all);
|
||||
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
|
||||
return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip;
|
||||
}
|
||||
|
||||
|
|
@ -987,9 +1085,9 @@ class ReceiverRejectingACellInstanceArrayExceptOne
|
|||
public:
|
||||
ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { }
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box ®ion, 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 ®ion, const box_tree_type *complex_region, bool all)
|
||||
{
|
||||
LoggingReceiver::new_inst (iter, inst, region, complex_region, all);
|
||||
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
|
||||
return inst.object ().cell_index () != m_rejected ? NI_all : NI_single;
|
||||
}
|
||||
|
||||
|
|
@ -1003,9 +1101,9 @@ class ReceiverRejectingACellInstance
|
|||
public:
|
||||
ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { }
|
||||
|
||||
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, 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 ®ion, const box_tree_type *complex_region, bool all)
|
||||
{
|
||||
LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region, all);
|
||||
LoggingReceiver::new_inst_member (iter, inst, always_apply, trans, region, complex_region, all);
|
||||
return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected;
|
||||
}
|
||||
|
||||
|
|
@ -1127,6 +1225,100 @@ TEST(10)
|
|||
"end\n"
|
||||
);
|
||||
|
||||
LoggingReceiver lr1_gt;
|
||||
db::RecursiveShapeIterator i1_gt (g, c0, 0);
|
||||
i1_gt.set_global_trans (db::ICplxTrans (db::Trans (db::Vector (10, 20))));
|
||||
i1_gt.push (&lr1_gt);
|
||||
|
||||
EXPECT_EQ (lr1_gt.text (),
|
||||
"begin\n"
|
||||
"new_inst($2,all)\n"
|
||||
"new_inst_member($2,r0 *1 10,20,all)\n"
|
||||
// It's a bit weird to have shape events after new_inst_member, but remember, new_inst_member is a query callback, not an event.
|
||||
"shape(box (0,0;1000,1000),r0 *1 10,20)\n"
|
||||
"shape(box (-1000,0;0,1000),r0 *1 10,20)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 10,20)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 10,2020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3010,1020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3010,3020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 10,6020,all)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 10,6020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 10,8020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3010,7020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 3010,9020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 6010,20,all)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 6010,20)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 6010,2020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 9010,1020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 9010,3020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"new_inst_member($2,r0 *1 6010,6020,all)\n"
|
||||
"enter_cell($2)\n"
|
||||
"new_inst($3,all)\n"
|
||||
"new_inst_member($3,r0 *1 0,0,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 6010,6020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 0,2000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 6010,8020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,1000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 9010,7020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"new_inst_member($3,r0 *1 3000,3000,all)\n"
|
||||
"enter_cell($3)\n"
|
||||
"shape(box (1000,-500;2000,500),r0 *1 9010,9020)\n"
|
||||
"leave_cell($3)\n"
|
||||
"leave_cell($2)\n"
|
||||
"end\n"
|
||||
);
|
||||
|
||||
ReceiverRejectingACellInstanceArray rr1 (c2.cell_index ());
|
||||
db::RecursiveShapeIterator ir1 (g, c0, 0);
|
||||
ir1.push (&rr1);
|
||||
|
|
|
|||
|
|
@ -354,6 +354,8 @@ TEST(10a)
|
|||
r.set_merged_semantics (false);
|
||||
EXPECT_EQ (r.selected_interacting (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
EXPECT_EQ (r.selected_not_interacting (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).first.to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (db::compare (r.selected_interacting (db::Region (db::Box (db::Point (-20, -20), db::Point (30, 30)))), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true);
|
||||
EXPECT_EQ (r.selected_interacting (db::Region (db::Box (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), "");
|
||||
db::Region rr = r;
|
||||
|
|
@ -836,6 +838,8 @@ TEST(18a)
|
|||
EXPECT_EQ (db::compare (o, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
|
||||
o = r;
|
||||
EXPECT_EQ (db::compare (o.selected_not_outside (rr), "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_outside_differential (rr).first, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_outside_differential (rr).second, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
|
||||
EXPECT_EQ (o.selected_outside (rr).count () + o.selected_not_outside (rr).count (), size_t (6));
|
||||
EXPECT_EQ (o.selected_outside (rr).hier_count () + o.selected_not_outside (rr).hier_count (), size_t (6));
|
||||
o.select_not_outside (rr);
|
||||
|
|
@ -848,6 +852,8 @@ TEST(18a)
|
|||
EXPECT_EQ (o.to_string (), "(20,30;20,50;40,50;40,30)");
|
||||
o = r;
|
||||
EXPECT_EQ (db::compare (o.selected_not_inside (rr), "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_inside_differential (rr).first, "(20,30;20,50;40,50;40,30)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_inside_differential (rr).second, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
|
||||
EXPECT_EQ (o.selected_inside (rr).count () + o.selected_not_inside (rr).count (), size_t (6));
|
||||
EXPECT_EQ (o.selected_inside (rr).hier_count () + o.selected_not_inside (rr).hier_count (), size_t (6));
|
||||
o.select_not_inside (rr);
|
||||
|
|
@ -860,6 +866,8 @@ TEST(18a)
|
|||
EXPECT_EQ (db::compare (o, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
|
||||
o = r;
|
||||
EXPECT_EQ (o.selected_not_interacting (rr).to_string (), "(70,60;70,80;90,80;90,60)");
|
||||
EXPECT_EQ (db::compare (o.selected_interacting_differential (rr).first, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_interacting_differential (rr).second, "(70,60;70,80;90,80;90,60)"), true);
|
||||
EXPECT_EQ (o.selected_interacting (rr).count () + o.selected_not_interacting (rr).count (), size_t (6));
|
||||
EXPECT_EQ (o.selected_interacting (rr).hier_count () + o.selected_not_interacting (rr).hier_count (), size_t (6));
|
||||
o.select_not_interacting (rr);
|
||||
|
|
@ -872,6 +880,8 @@ TEST(18a)
|
|||
EXPECT_EQ (db::compare (o, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
|
||||
o = r;
|
||||
EXPECT_EQ (db::compare (o.selected_not_overlapping (rr), "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_overlapping_differential (rr).first, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_overlapping_differential (rr).second, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true);
|
||||
EXPECT_EQ (o.selected_overlapping (rr).count () + o.selected_not_overlapping (rr).count (), size_t (6));
|
||||
EXPECT_EQ (o.selected_overlapping (rr).hier_count () + o.selected_not_overlapping (rr).hier_count (), size_t (6));
|
||||
o.select_not_overlapping (rr);
|
||||
|
|
@ -884,6 +894,8 @@ TEST(18a)
|
|||
EXPECT_EQ (o.to_string (), "(0,100;0,130;30,130;30,100)");
|
||||
o = r;
|
||||
EXPECT_EQ (db::compare (o.selected_not_enclosing (rr), "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_enclosing_differential (rr).first, "(0,100;0,130;30,130;30,100)"), true);
|
||||
EXPECT_EQ (db::compare (o.selected_enclosing_differential (rr).second, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60)"), true);
|
||||
EXPECT_EQ (o.selected_enclosing (rr).count () + o.selected_not_enclosing (rr).count (), size_t (6));
|
||||
EXPECT_EQ (o.selected_enclosing (rr).hier_count () + o.selected_not_enclosing (rr).hier_count (), size_t (6));
|
||||
o.select_not_enclosing (rr);
|
||||
|
|
@ -1506,6 +1518,8 @@ TEST(30a)
|
|||
r.set_merged_semantics (false);
|
||||
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
EXPECT_EQ (r.selected_not_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).first.to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (db::compare (r.selected_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (30, 30)))), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)"), true);
|
||||
EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), "");
|
||||
db::Region rr = r;
|
||||
|
|
@ -1689,6 +1703,8 @@ TEST(34a)
|
|||
r.set_merged_semantics (false);
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
EXPECT_EQ (r.selected_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).first.to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
db::Texts tt;
|
||||
tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30))));
|
||||
tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0))));
|
||||
|
|
@ -1782,6 +1798,7 @@ TEST(35a_interact_with_count_region)
|
|||
EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (rr, 1, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
|
|
@ -1797,6 +1814,7 @@ TEST(35a_interact_with_count_region)
|
|||
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
|
||||
EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true);
|
||||
|
|
@ -1855,6 +1873,7 @@ TEST(35b_interact_with_count_edge)
|
|||
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (rr, 2, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
|
|
@ -1869,6 +1888,7 @@ TEST(35b_interact_with_count_edge)
|
|||
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
|
||||
EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true);
|
||||
|
|
@ -1926,6 +1946,7 @@ TEST(35c_interact_with_count_text)
|
|||
EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (rr, 2, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
|
|
@ -1940,6 +1961,7 @@ TEST(35c_interact_with_count_text)
|
|||
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), "");
|
||||
EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true);
|
||||
|
|
|
|||
|
|
@ -739,16 +739,18 @@ CODE
|
|||
# %DRC%
|
||||
# @name smoothed
|
||||
# @brief Applies smoothing
|
||||
# @synopsis expression.smoothed(d)
|
||||
# @synopsis expression.smoothed(d [, keep_hv ])
|
||||
#
|
||||
# This operation acts on polygons and applies polygon smoothing with the tolerance d. See \Layer#smoothed for more details.
|
||||
# This operation acts on polygons and applies polygon smoothing with the tolerance d. 'keep_hv' indicates
|
||||
# whether horizontal and vertical edges are maintained. Default is 'no' which means such edges may be distorted.
|
||||
# See \Layer#smoothed for more details.
|
||||
#
|
||||
# The "smoothed" method is available as a plain function or as a method on \DRC# expressions.
|
||||
# The plain function is equivalent to "primary.smoothed".
|
||||
|
||||
def smoothed(d)
|
||||
def smoothed(d, keep_hv = false)
|
||||
@engine._context("smoothed") do
|
||||
DRCOpNodeFilter::new(@engine, self, :new_smoothed, "smoothed", @engine._make_value(d))
|
||||
DRCOpNodeFilter::new(@engine, self, :new_smoothed, "smoothed", @engine._make_value(d), keep_hv)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ module DRC
|
|||
@deep = false
|
||||
@netter = nil
|
||||
@netter_data = nil
|
||||
@total_timer = nil
|
||||
@drc_progress = nil
|
||||
|
||||
# initialize the defaults for max_area_ratio, max_vertex_count
|
||||
dss = RBA::DeepShapeStore::new
|
||||
|
|
@ -58,9 +60,39 @@ module DRC
|
|||
|
||||
@verbose = false
|
||||
|
||||
@in_context = false
|
||||
@in_context = nil
|
||||
|
||||
end
|
||||
|
||||
def shift(x, y)
|
||||
self._context("shift") do
|
||||
RBA::DCplxTrans::new(RBA::DVector::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu))
|
||||
end
|
||||
end
|
||||
|
||||
def magnify(m)
|
||||
self._context("magnify") do
|
||||
RBA::DCplxTrans::new(_make_numeric_value(m))
|
||||
end
|
||||
end
|
||||
|
||||
def rotate(a)
|
||||
self._context("rotate") do
|
||||
RBA::DCplxTrans::new(1.0, _make_numeric_value(a), false, RBA::DVector::new)
|
||||
end
|
||||
end
|
||||
|
||||
def mirror_x
|
||||
self._context("mirror_x") do
|
||||
RBA::DCplxTrans::new(1.0, 0.0, true, RBA::DVector::new)
|
||||
end
|
||||
end
|
||||
|
||||
def mirror_y
|
||||
self._context("mirror_y") do
|
||||
RBA::DCplxTrans::new(1.0, 180.0, true, RBA::DVector::new)
|
||||
end
|
||||
end
|
||||
|
||||
def joined
|
||||
DRCJoinFlag::new(true)
|
||||
|
|
@ -231,6 +263,27 @@ module DRC
|
|||
DRCFillOrigin::new(x, y)
|
||||
end
|
||||
|
||||
def tile_size(x, y = nil)
|
||||
DRCTileSize::new(_make_value(x) * self.dbu, _make_value(y || x) * self.dbu)
|
||||
end
|
||||
|
||||
def tile_step(x, y = nil)
|
||||
DRCTileStep::new(_make_value(x) * self.dbu, _make_value(y || x) * self.dbu)
|
||||
end
|
||||
|
||||
def tile_origin(x, y)
|
||||
DRCTileOrigin::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu)
|
||||
end
|
||||
|
||||
def tile_count(x, y)
|
||||
DRCTileCount::new(_make_numeric_value(x), _make_numeric_value(y))
|
||||
end
|
||||
|
||||
def tile_boundary(b)
|
||||
b.is_a?(DRCLayer) || raise("'tile_boundary' requires a layer argument")
|
||||
DRCTileBoundary::new(b)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @brief Defines SPICE output format (with options)
|
||||
# @name write_spice
|
||||
|
|
@ -475,15 +528,20 @@ module DRC
|
|||
|
||||
# %DRC%
|
||||
# @name info
|
||||
# @brief Outputs as message to the logger window
|
||||
# @brief Outputs as message to the logger or progress window
|
||||
# @synopsis info(message)
|
||||
# @synopsis info(message, indent)
|
||||
# Prints the message to the log window in verbose mode.
|
||||
# In non-verbose more, nothing is printed.
|
||||
# In non-verbose more, nothing is printed but a statement is put into the progress window.
|
||||
# \log is a function that always prints a message.
|
||||
|
||||
def info(arg, indent = 0)
|
||||
@verbose && log(arg, indent)
|
||||
if @verbose
|
||||
log(arg, indent)
|
||||
else
|
||||
str = (" " * indent) + arg
|
||||
RBA::Logger::log(str)
|
||||
end
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -496,7 +554,7 @@ module DRC
|
|||
# verbose mode is enabled.
|
||||
|
||||
def log(arg, indent = 0)
|
||||
str = (" " * indent) + arg
|
||||
str = (" " * indent) + arg
|
||||
if @log_file
|
||||
@log_file.puts(str)
|
||||
else
|
||||
|
|
@ -1486,6 +1544,22 @@ CODE
|
|||
nil
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name global_transform
|
||||
# @brief Gets or sets a global transformation
|
||||
# @synopsis global_transform
|
||||
# @synopsis global_transform([ transformations ])
|
||||
#
|
||||
# Applies a global transformation to the default source layout.
|
||||
# See \Source#global_transform for a description of this feature.
|
||||
|
||||
def global_transform(*args)
|
||||
self._context("global_transform") do
|
||||
@def_source = layout.global_transform(*args)
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name cheat
|
||||
# @brief Hierarchy cheats
|
||||
|
|
@ -1671,8 +1745,6 @@ CODE
|
|||
pull_overlapping
|
||||
rectangles
|
||||
rectilinear
|
||||
rotate
|
||||
rotated
|
||||
rounded_corners
|
||||
scale
|
||||
scaled
|
||||
|
|
@ -1848,9 +1920,10 @@ CODE
|
|||
def _wrapper_context(func, *args, &proc)
|
||||
in_context_outer = @in_context
|
||||
begin
|
||||
@in_context = true
|
||||
@in_context = func
|
||||
return yield(*args)
|
||||
rescue => ex
|
||||
RBA::MacroExecutionContext::ignore_next_exception
|
||||
raise("'" + func + "': " + ex.to_s)
|
||||
ensure
|
||||
@in_context = in_context_outer
|
||||
|
|
@ -1862,22 +1935,41 @@ CODE
|
|||
return yield(*args)
|
||||
else
|
||||
begin
|
||||
@in_context = true
|
||||
@in_context = func
|
||||
return yield(*args)
|
||||
rescue => ex
|
||||
RBA::MacroExecutionContext::ignore_next_exception
|
||||
raise("'" + func + "': " + ex.to_s)
|
||||
ensure
|
||||
@in_context = false
|
||||
@in_context = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def _result_info(res, indent, prefix = "")
|
||||
if res.is_a?(Array)
|
||||
res.each_with_index do |a, index|
|
||||
_result_info(a, indent, "[#{index + 1}] ")
|
||||
end
|
||||
elsif res.is_a?(RBA::Region)
|
||||
info(prefix + "Polygons (raw): #{res.count} (flat) #{res.hier_count} (hierarchical)", indent)
|
||||
elsif res.is_a?(RBA::Edges)
|
||||
info(prefix + "Edges: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent)
|
||||
elsif res.is_a?(RBA::EdgePairs)
|
||||
info(prefix + "Edge pairs: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent)
|
||||
elsif res.is_a?(RBA::Texts)
|
||||
info(prefix + "Texts: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent)
|
||||
end
|
||||
end
|
||||
|
||||
def run_timed(desc, obj)
|
||||
|
||||
log(desc)
|
||||
info(desc)
|
||||
|
||||
# enable progress
|
||||
disable_progress = false
|
||||
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
|
||||
disable_progress = true
|
||||
obj.enable_progress(desc)
|
||||
end
|
||||
|
||||
|
|
@ -1887,39 +1979,37 @@ CODE
|
|||
res = yield
|
||||
t.stop
|
||||
|
||||
if @verbose
|
||||
begin
|
||||
|
||||
if @verbose
|
||||
|
||||
# Report result statistics
|
||||
_result_info(res, 1)
|
||||
|
||||
mem = RBA::Timer::memory_size
|
||||
if mem > 0
|
||||
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M", 1)
|
||||
else
|
||||
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s", 1)
|
||||
end
|
||||
|
||||
# Report result statistics
|
||||
if res.is_a?(RBA::Region)
|
||||
info("Polygons (raw): #{res.count} (flat) #{res.hier_count} (hierarchical)", 1)
|
||||
elsif res.is_a?(RBA::Edges)
|
||||
info("Edges: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1)
|
||||
elsif res.is_a?(RBA::EdgePairs)
|
||||
info("Edge pairs: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1)
|
||||
elsif res.is_a?(RBA::Texts)
|
||||
info("Texts: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1)
|
||||
end
|
||||
|
||||
mem = RBA::Timer::memory_size
|
||||
if mem > 0
|
||||
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M", 1)
|
||||
else
|
||||
info("Elapsed: #{'%.3f'%(t.sys+t.user)}s", 1)
|
||||
ensure
|
||||
|
||||
# disable progress again
|
||||
if disable_progress
|
||||
obj.disable_progress
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# disable progress
|
||||
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
|
||||
obj.disable_progress
|
||||
end
|
||||
|
||||
res
|
||||
|
||||
end
|
||||
|
||||
def _cmd(obj, method, *args)
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
obj.send(method, *args)
|
||||
end
|
||||
end
|
||||
|
|
@ -1949,8 +2039,9 @@ CODE
|
|||
end
|
||||
av = args.size.times.collect { |i| "a#{i}" }.join(", ")
|
||||
tp.queue("_output(res, self.#{method}(#{av}))")
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
tp.execute("Tiled \"#{method}\" in: #{src_line}")
|
||||
res
|
||||
end
|
||||
|
||||
else
|
||||
|
|
@ -1960,17 +2051,12 @@ CODE
|
|||
end
|
||||
|
||||
res = nil
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
res = obj.send(method, *args)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# disable progress again
|
||||
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
|
||||
obj.disable_progress
|
||||
end
|
||||
|
||||
res
|
||||
|
||||
end
|
||||
|
|
@ -2004,8 +2090,9 @@ CODE
|
|||
end
|
||||
av = args.size.times.collect { |i| "a#{i}" }.join(", ")
|
||||
tp.queue("var rr = self.#{method}(#{av}); _output(res1, rr[0]); _output(res2, rr[1])")
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
tp.execute("Tiled \"#{method}\" in: #{src_line}")
|
||||
res
|
||||
end
|
||||
|
||||
else
|
||||
|
|
@ -2015,17 +2102,12 @@ CODE
|
|||
end
|
||||
|
||||
res = nil
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
res = obj.send(method, *args)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# disable progress again
|
||||
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
|
||||
obj.disable_progress
|
||||
end
|
||||
|
||||
res
|
||||
|
||||
end
|
||||
|
|
@ -2045,8 +2127,9 @@ CODE
|
|||
tp.input("self", obj)
|
||||
tp.threads = (@tt || 1)
|
||||
tp.queue("_output(res, _tile ? self.#{method}(_tile.bbox) : self.#{method})")
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
tp.execute("Tiled \"#{method}\" in: #{src_line}")
|
||||
res
|
||||
end
|
||||
|
||||
res = res.value
|
||||
|
|
@ -2058,29 +2141,24 @@ CODE
|
|||
end
|
||||
|
||||
res = nil
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
res = obj.send(method)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# disable progress again
|
||||
if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts)
|
||||
obj.disable_progress
|
||||
end
|
||||
|
||||
res
|
||||
|
||||
end
|
||||
|
||||
def _rcmd(obj, method, *args)
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
RBA::Region::new(obj.send(method, *args))
|
||||
end
|
||||
end
|
||||
|
||||
def _vcmd(obj, method, *args)
|
||||
run_timed("\"#{method}\" in: #{src_line}", obj) do
|
||||
run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do
|
||||
obj.send(method, *args)
|
||||
end
|
||||
end
|
||||
|
|
@ -2126,12 +2204,17 @@ CODE
|
|||
output_cell
|
||||
end
|
||||
|
||||
def _start
|
||||
def _start(job_description)
|
||||
|
||||
# clearing the selection avoids some nasty problems
|
||||
view = RBA::LayoutView::current
|
||||
view && view.cancel
|
||||
|
||||
@total_timer = RBA::Timer::new
|
||||
@total_timer.start
|
||||
|
||||
@drc_progress = RBA::AbstractProgress::new(job_description)
|
||||
|
||||
end
|
||||
|
||||
def _flush
|
||||
|
|
@ -2271,9 +2354,20 @@ CODE
|
|||
@netter = nil
|
||||
@netter_data = nil
|
||||
|
||||
if final && @log_file
|
||||
@log_file.close
|
||||
@log_file = nil
|
||||
if final
|
||||
|
||||
@total_timer.stop
|
||||
if @verbose
|
||||
mem = RBA::Timer::memory_size
|
||||
if mem > 0
|
||||
info("Total elapsed: #{'%.3f'%(@total_timer.sys+@total_timer.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M")
|
||||
else
|
||||
info("Total elapsed: #{'%.3f'%(@total_timer.sys+@total_timer.user)}s")
|
||||
end
|
||||
end
|
||||
|
||||
_cleanup
|
||||
|
||||
end
|
||||
|
||||
# force garbage collection
|
||||
|
|
@ -2283,6 +2377,23 @@ CODE
|
|||
|
||||
end
|
||||
|
||||
def _cleanup
|
||||
|
||||
if @log_file
|
||||
@log_file.close
|
||||
@log_file = nil
|
||||
end
|
||||
|
||||
# unlocks the UI
|
||||
if @drc_progress
|
||||
@drc_progress._destroy
|
||||
@drc_progress = nil
|
||||
end
|
||||
|
||||
GC.start
|
||||
|
||||
end
|
||||
|
||||
def _take_data
|
||||
|
||||
if ! @netter
|
||||
|
|
@ -2441,7 +2552,7 @@ CODE
|
|||
end
|
||||
end
|
||||
|
||||
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, cls)
|
||||
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, global_trans, cls)
|
||||
|
||||
if layers.empty? && ! @deep
|
||||
|
||||
|
|
@ -2455,6 +2566,7 @@ CODE
|
|||
iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers)
|
||||
end
|
||||
iter.shape_flags = shape_flags
|
||||
iter.global_dtrans = global_trans
|
||||
|
||||
sel.each do |s|
|
||||
if s == "-"
|
||||
|
|
@ -2492,8 +2604,12 @@ CODE
|
|||
end
|
||||
|
||||
# clip if a box is specified
|
||||
if box && clip && (cls == RBA::Region || cls == RBA::Edge)
|
||||
r &= RBA::Region::new(box)
|
||||
# TODO: the whole clip thing could be a part of the Region constructor
|
||||
if cls == RBA::Region && clip && box
|
||||
# HACK: deep regions will always clip in the constructor, so skip this
|
||||
if ! @deep
|
||||
r &= RBA::Region::new(box)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -2582,6 +2698,9 @@ CODE
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
data
|
||||
|
||||
end
|
||||
|
||||
def make_source(layout, cell = nil, path = nil)
|
||||
|
|
|
|||
|
|
@ -983,8 +983,8 @@ CODE
|
|||
# @name corners
|
||||
# @brief Selects corners of polygons
|
||||
# @synopsis layer.corners([ options ])
|
||||
# @synopsis layer.corners(angle, [ options ])
|
||||
# @synopsis layer.corners(amin .. amax, [ options ])
|
||||
# @synopsis layer.corners(angle [, options ])
|
||||
# @synopsis layer.corners(amin .. amax [, options ])
|
||||
#
|
||||
# This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||
# selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
|
||||
|
|
@ -1263,6 +1263,7 @@ CODE
|
|||
self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
|
||||
block.call(object.transformed(t)) && new_data.insert(object)
|
||||
end
|
||||
new_data
|
||||
end
|
||||
DRCLayer::new(@engine, new_data)
|
||||
|
||||
|
|
@ -1285,7 +1286,7 @@ CODE
|
|||
@engine._wrapper_context("each") do
|
||||
|
||||
t = RBA::CplxTrans::new(@engine.dbu)
|
||||
@engine.run_timed("\"select\" in: #{@engine.src_line}", self.data) do
|
||||
@engine.run_timed("\"each\" in: #{@engine.src_line}", self.data) do
|
||||
self.data.send(self.data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
|
||||
block.call(object.transformed(t))
|
||||
end
|
||||
|
|
@ -1368,10 +1369,11 @@ CODE
|
|||
t = RBA::CplxTrans::new(@engine.dbu)
|
||||
dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu)
|
||||
|
||||
@engine.run_timed("\\"select\\" in: " + @engine.src_line, self.data) do
|
||||
@engine.run_timed("\\"#{f}\\" in: " + @engine.src_line, self.data) do
|
||||
self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object|
|
||||
insert_object_into(new_data, block.call(object.transformed(t)), dbu_trans)
|
||||
end
|
||||
new_data
|
||||
end
|
||||
|
||||
DRCLayer::new(@engine, new_data)
|
||||
|
|
@ -1660,6 +1662,7 @@ CODE
|
|||
|
||||
@engine._context("andnot") do
|
||||
|
||||
check_is_layer(other)
|
||||
requires_region
|
||||
other.requires_region
|
||||
|
||||
|
|
@ -1773,6 +1776,21 @@ CODE
|
|||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_not_covering.
|
||||
|
||||
# %DRC%
|
||||
# @name split_covering
|
||||
# @brief Returns the results of \covering and \not_covering at the same time
|
||||
# @synopsis (a, b) = layer.split_covering(other [, options ])
|
||||
#
|
||||
# This method returns the polygons covering polygons from the other layer in
|
||||
# one layer and all others in a second layer. This method is equivalent to calling
|
||||
# \covering and \not_covering, but is faster than doing this in separate steps:
|
||||
#
|
||||
# @code
|
||||
# (covering, not_covering) = l1.split_covering(l2)
|
||||
# @/code
|
||||
#
|
||||
# The options of this method are the same than \covering.
|
||||
|
||||
# %DRC%
|
||||
# @name select_covering
|
||||
# @brief Selects shapes or regions of self which completely cover (enclose) one or more shapes from the other region
|
||||
|
|
@ -1849,6 +1867,21 @@ CODE
|
|||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_not_overlapping.
|
||||
|
||||
# %DRC%
|
||||
# @name split_overlapping
|
||||
# @brief Returns the results of \overlapping and \not_overlapping at the same time
|
||||
# @synopsis (a, b) = layer.split_overlapping(other [, options ])
|
||||
#
|
||||
# This method returns the polygons overlapping polygons from the other layer in
|
||||
# one layer and all others in a second layer. This method is equivalent to calling
|
||||
# \overlapping and \not_overlapping, but is faster than doing this in separate steps:
|
||||
#
|
||||
# @code
|
||||
# (overlapping, not_overlapping) = l1.split_overlapping(l2)
|
||||
# @/code
|
||||
#
|
||||
# The options of this method are the same than \overlapping.
|
||||
|
||||
# %DRC%
|
||||
# @name select_overlapping
|
||||
# @brief Selects shapes or regions of self which overlap shapes from the other region
|
||||
|
|
@ -1923,6 +1956,19 @@ CODE
|
|||
# @/tr
|
||||
# @/table
|
||||
|
||||
# %DRC%
|
||||
# @name split_inside
|
||||
# @brief Returns the results of \inside and \not_inside at the same time
|
||||
# @synopsis (a, b) = layer.split_inside(other)
|
||||
#
|
||||
# This method returns the polygons inside of polygons from the other layer in
|
||||
# one layer and all others in a second layer. This method is equivalent to calling
|
||||
# \inside and \not_inside, but is faster than doing this in separate steps:
|
||||
#
|
||||
# @code
|
||||
# (inside, not_inside) = l1.split_inside(l2)
|
||||
# @/code
|
||||
|
||||
# %DRC%
|
||||
# @name select_inside
|
||||
# @brief Selects shapes or regions of self which are inside the other region
|
||||
|
|
@ -1995,6 +2041,19 @@ CODE
|
|||
# @/tr
|
||||
# @/table
|
||||
|
||||
# %DRC%
|
||||
# @name split_outside
|
||||
# @brief Returns the results of \outside and \not_outside at the same time
|
||||
# @synopsis (a, b) = layer.split_outside(other)
|
||||
#
|
||||
# This method returns the polygons outside of polygons from the other layer in
|
||||
# one layer and all others in a second layer. This method is equivalent to calling
|
||||
# \outside and \not_outside, but is faster than doing this in separate steps:
|
||||
#
|
||||
# @code
|
||||
# (outside, not_outside) = l1.split_outside(l2)
|
||||
# @/code
|
||||
|
||||
# %DRC%
|
||||
# @name select_outside
|
||||
# @brief Selects shapes or regions of self which are outside the other region
|
||||
|
|
@ -2149,6 +2208,21 @@ CODE
|
|||
# @/tr
|
||||
# @/table
|
||||
|
||||
# %DRC%
|
||||
# @name split_interacting
|
||||
# @brief Returns the results of \interacting and \not_interacting at the same time
|
||||
# @synopsis (a, b) = layer.split_interacting(other [, options ])
|
||||
#
|
||||
# This method returns the polygons interacting with objects from the other container in
|
||||
# one layer and all others in a second layer. This method is equivalent to calling
|
||||
# \interacting and \not_interacting, but is faster than doing this in separate steps:
|
||||
#
|
||||
# @code
|
||||
# (interacting, not_interacting) = l1.split_interacting(l2)
|
||||
# @/code
|
||||
#
|
||||
# The options of this method are the same than \interacting.
|
||||
|
||||
# %DRC%
|
||||
# @name select_interacting
|
||||
# @brief Selects shapes or regions of self which touch or overlap shapes from the other region
|
||||
|
|
@ -2192,7 +2266,7 @@ CODE
|
|||
# number of (different) shapes from the other layer. If a min and max count is given, shapes from
|
||||
# self are selected only if they interact with less than min_count or more than max_count different shapes
|
||||
# from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
|
||||
|
||||
|
||||
# %DRC%
|
||||
# @name intersections
|
||||
# @brief Returns the intersection points of intersecting edge segments for two edge collections
|
||||
|
|
@ -2285,6 +2359,7 @@ CODE
|
|||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
if :#{f} != :pull_interacting
|
||||
requires_region
|
||||
other.requires_region
|
||||
|
|
@ -2310,11 +2385,16 @@ CODE
|
|||
%w(| ^ inside not_inside outside not_outside in not_in).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
requires_same_type(other)
|
||||
requires_edges_or_region
|
||||
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
|
@ -2325,12 +2405,14 @@ CODE
|
|||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
other.requires_edges_texts_or_region
|
||||
if self.data.is_a?(RBA::Texts)
|
||||
other.requires_region
|
||||
else
|
||||
other.requires_edges_or_region
|
||||
end
|
||||
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
|
||||
|
||||
end
|
||||
|
|
@ -2342,10 +2424,14 @@ CODE
|
|||
%w(+).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
requires_same_type(other)
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
|
@ -2356,7 +2442,7 @@ CODE
|
|||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
other.requires_edges_texts_or_region
|
||||
check_is_layer(other)
|
||||
if self.data.is_a?(RBA::Text)
|
||||
other.requires_region
|
||||
elsif self.data.is_a?(RBA::Region)
|
||||
|
|
@ -2381,6 +2467,7 @@ CODE
|
|||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
requires_edges_texts_or_region
|
||||
if self.data.is_a?(RBA::Text)
|
||||
other.requires_region
|
||||
|
|
@ -2389,6 +2476,7 @@ CODE
|
|||
else
|
||||
other.requires_edges_or_region
|
||||
end
|
||||
|
||||
if @engine.is_tiled?
|
||||
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args))
|
||||
DRCLayer::new(@engine, self.data)
|
||||
|
|
@ -2402,14 +2490,39 @@ CODE
|
|||
CODE
|
||||
end
|
||||
|
||||
%w(overlapping not_overlapping covering not_covering).each do |f|
|
||||
%w(split_interacting).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other, *args)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
requires_region
|
||||
other.requires_edges_texts_or_region
|
||||
|
||||
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data, *minmax_count(*args))
|
||||
[ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ]
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
%w(overlapping not_overlapping covering not_covering).each do |f|
|
||||
eval <<"CODE"
|
||||
|
||||
def #{f}(other, *args)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
requires_same_type(other)
|
||||
requires_region
|
||||
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(*args)))
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
|
@ -2424,6 +2537,7 @@ CODE
|
|||
|
||||
requires_region
|
||||
requires_same_type(other)
|
||||
|
||||
if @engine.is_tiled?
|
||||
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args))
|
||||
DRCLayer::new(@engine, self.data)
|
||||
|
|
@ -2437,6 +2551,24 @@ CODE
|
|||
CODE
|
||||
end
|
||||
|
||||
%w(split_overlapping split_covering).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other, *args)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
requires_region
|
||||
other.requires_region
|
||||
|
||||
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data, *minmax_count(*args))
|
||||
[ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ]
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
%w(inside not_inside outside not_outside).each do |fi|
|
||||
f = "select_" + fi
|
||||
# In tiled mode, there are no modifying versions. Emulate using the non-modifying one.
|
||||
|
|
@ -2447,6 +2579,7 @@ CODE
|
|||
|
||||
requires_region
|
||||
requires_same_type(other)
|
||||
|
||||
if @engine.is_tiled?
|
||||
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data)
|
||||
DRCLayer::new(@engine, self.data)
|
||||
|
|
@ -2460,14 +2593,39 @@ CODE
|
|||
CODE
|
||||
end
|
||||
|
||||
%w(split_inside split_outside).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
requires_region
|
||||
other.requires_region
|
||||
|
||||
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data)
|
||||
[ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ]
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
%w(inside_part outside_part).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
other.requires_region
|
||||
requires_edges
|
||||
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
|
@ -2475,11 +2633,17 @@ CODE
|
|||
%w(intersections).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
other.requires_edges
|
||||
requires_edges
|
||||
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
|
@ -3496,6 +3660,180 @@ CODE
|
|||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name with_density
|
||||
# @brief Returns tiles whose density is within a given range
|
||||
# @synopsis layer.with_density(min_value, max_value [, options ])
|
||||
# @synopsis layer.with_density(min_value .. max_value [, options ])
|
||||
#
|
||||
# This method runs a tiled analysis over the current layout. It reports the tiles whose density
|
||||
# is between "min_value" and "max_value". "min_value" and "max_value" are given in
|
||||
# relative units, i.e. within the range of 0 to 1.0 corresponding to a density of 0 to 100%.
|
||||
#
|
||||
# "min_value" or "max_value" can be nil or omitted in the ".." range notation.
|
||||
# In this case, they are taken as "0" and "100%".
|
||||
#
|
||||
# The tile size must be specified with the "tile_size" option:
|
||||
#
|
||||
# @code
|
||||
# # reports areas where layer 1/0 density is below 10% on 20x20 um tiles
|
||||
# low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um))
|
||||
# @/code
|
||||
#
|
||||
# Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)".
|
||||
# The first value is the horizontal tile dimension, the second value is the vertical tile
|
||||
# dimension.
|
||||
#
|
||||
# A tile overlap can be specified using "tile_step". If the tile step is less than the
|
||||
# tile size, the tiles will overlap. The layout window given by "tile_size" is moved
|
||||
# in increments of the tile step:
|
||||
#
|
||||
# @code
|
||||
# # reports areas where layer 1/0 density is below 10% on 30x30 um tiles
|
||||
# # with a tile step of 20x20 um:
|
||||
# low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
|
||||
# @/code
|
||||
#
|
||||
# For "tile_step", anisotropic values can be given as well by using two values: the first for the
|
||||
# horizontal and the second for the vertical tile step.
|
||||
#
|
||||
# Another option is "tile_origin" which specifies the location of the first tile's position.
|
||||
# This is the lower left tile's lower left corner. If no origin is given, the tiles are centered over the
|
||||
# area investigated.
|
||||
#
|
||||
# By default, the tiles will cover the bounding box of the input layer. A separate layer
|
||||
# can be used in addition. This way, the layout's dimensions can be derived from some
|
||||
# drawn boundary layer. To specify a separate, additional layer included in the bounding box, use the "tile_boundary" option:
|
||||
#
|
||||
# @code
|
||||
# # reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from
|
||||
# # layer 0/0:
|
||||
# cell_frame = input(0, 0)
|
||||
# low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
|
||||
# @/code
|
||||
#
|
||||
# Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box.
|
||||
# The computed area is at least the area of the input layer.
|
||||
#
|
||||
# Computation of the area can be skipped by explicitly giving a tile count in horizontal and vertical
|
||||
# direction. With the "tile_origin" option this allows full control over the area covered:
|
||||
#
|
||||
# @code
|
||||
# # reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000
|
||||
# # (100 and 150 tiles of 20 um each are used in horizontal and vertical direction):
|
||||
# low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
|
||||
# @/code
|
||||
#
|
||||
# The complementary version of "with_density" is \without_density.
|
||||
|
||||
# %DRC%
|
||||
# @name without_density
|
||||
# @brief Returns tiles whose density is not within a given range
|
||||
# @synopsis layer.without_density(min_value, max_value [, options ])
|
||||
# @synopsis layer.without_density(min_value .. max_value [, options ])
|
||||
#
|
||||
# For details about the operations and the operation see \with_density. This version will return the
|
||||
# tiles where the density is not within the given range.
|
||||
|
||||
def _with_density(method, inverse, *args)
|
||||
|
||||
requires_region
|
||||
|
||||
limits = [ nil, nil ]
|
||||
nlimits = 0
|
||||
tile_size = nil
|
||||
tile_step = nil
|
||||
tile_origin = nil
|
||||
tile_count = nil
|
||||
tile_boundary = nil
|
||||
|
||||
n = 1
|
||||
args.each do |a|
|
||||
if a.is_a?(DRCTileSize)
|
||||
tile_size = a.get
|
||||
elsif a.is_a?(DRCTileStep)
|
||||
tile_step = a.get
|
||||
elsif a.is_a?(DRCTileOrigin)
|
||||
tile_origin = a.get
|
||||
elsif a.is_a?(DRCTileCount)
|
||||
tile_count = a.get
|
||||
elsif a.is_a?(DRCTileBoundary)
|
||||
tile_boundary = a.get
|
||||
elsif a.is_a?(Float) || a.is_a?(1.class) || a == nil
|
||||
nlimits < 2 || raise("Too many values specified")
|
||||
limits[nlimits] = @engine._make_numeric_value_with_nil(a)
|
||||
nlimits += 1
|
||||
elsif a.is_a?(Range)
|
||||
nlimits == 0 || raise("Either a range or two limits have to be specified, not both")
|
||||
limits = [ @engine._make_numeric_value_with_nil(a.begin), @engine._make_numeric_value_with_nil(a.end) ]
|
||||
nlimits = 2
|
||||
else
|
||||
raise("Parameter #" + n.to_s + " does not have an expected type")
|
||||
end
|
||||
n += 1
|
||||
end
|
||||
|
||||
tile_size || raise("At least the tile_size option needs to be present")
|
||||
tile_step ||= tile_size
|
||||
|
||||
tp = RBA::TilingProcessor::new
|
||||
tp.dbu = @engine.dbu
|
||||
tp.scale_to_dbu = false
|
||||
tp.tile_size(*tile_step)
|
||||
if tile_size != tile_step
|
||||
xb = 0.5 * (tile_size[0] - tile_step[0])
|
||||
yb = 0.5 * (tile_size[1] - tile_step[1])
|
||||
tp.tile_border(xb, yb)
|
||||
tp.var("xoverlap", xb / tp.dbu)
|
||||
tp.var("yoverlap", yb / tp.dbu)
|
||||
else
|
||||
tp.var("xoverlap", 0)
|
||||
tp.var("yoverlap", 0)
|
||||
end
|
||||
if tile_origin
|
||||
tp.tile_origin(*tile_origin)
|
||||
end
|
||||
if tile_count
|
||||
tp.tiles(*tile_count)
|
||||
end
|
||||
|
||||
res = RBA::Region.new
|
||||
tp.output("res", res)
|
||||
tp.input("input", self.data)
|
||||
tp.threads = (@engine.threads || 1)
|
||||
if tile_boundary
|
||||
tp.input("boundary", tile_boundary.data)
|
||||
end
|
||||
|
||||
tp.var("vmin", limits[0] || 0.0)
|
||||
tp.var("vmax", limits[1] || 1.0)
|
||||
tp.var("inverse", inverse)
|
||||
tp.queue(<<"TP_SCRIPT")
|
||||
_tile && (
|
||||
var bx = _tile.bbox.enlarged(xoverlap, yoverlap);
|
||||
var d = to_f(input.area(bx)) / to_f(bx.area);
|
||||
((d > vmin - 1e-10 && d < vmax + 1e-10) != inverse) && _output(res, bx, false)
|
||||
)
|
||||
TP_SCRIPT
|
||||
|
||||
@engine.run_timed("\"#{method}\" in: #{@engine.src_line}", self.data) do
|
||||
tp.execute("Tiled \"#{method}\" in: #{@engine.src_line}")
|
||||
res
|
||||
end
|
||||
|
||||
DRCLayer::new(@engine, res)
|
||||
|
||||
end
|
||||
|
||||
def with_density(*args)
|
||||
self._with_density("with_density", false, *args)
|
||||
end
|
||||
|
||||
def without_density(*args)
|
||||
self._with_density("without_density", true, *args)
|
||||
end
|
||||
|
||||
|
||||
# %DRC%
|
||||
# @name scaled
|
||||
|
|
@ -4102,6 +4440,10 @@ END
|
|||
@data = d
|
||||
end
|
||||
|
||||
def check_is_layer(other)
|
||||
other.is_a?(DRCLayer) || raise("Argument needs to be a DRC layer")
|
||||
end
|
||||
|
||||
def requires_region
|
||||
self.data.is_a?(RBA::Region) || raise("Requires a polygon layer")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ module DRC
|
|||
@clip = false
|
||||
@overlapping = false
|
||||
@tmp_layers = []
|
||||
@global_trans = RBA::DCplxTrans::new
|
||||
end
|
||||
|
||||
# Conceptual deep copy (not including the temp layers)
|
||||
|
|
@ -70,6 +71,24 @@ module DRC
|
|||
def cell_obj
|
||||
@cell
|
||||
end
|
||||
|
||||
def inplace_global_transform(*args)
|
||||
gt = RBA::DCplxTrans::new
|
||||
args.each do |a|
|
||||
if a.is_a?(RBA::DVector) || a.is_a?(RBA::DTrans)
|
||||
gt = RBA::DCplxTrans::new(a) * gt
|
||||
elsif a.is_a?(RBA::DCplxTrans)
|
||||
gt = a * gt
|
||||
else
|
||||
raise("Expected a transformation spec instead of #{a.inspect}")
|
||||
end
|
||||
end
|
||||
@global_trans = gt
|
||||
end
|
||||
|
||||
def global_transformation
|
||||
@global_trans
|
||||
end
|
||||
|
||||
def finish
|
||||
@tmp_layers.each do |li|
|
||||
|
|
@ -245,8 +264,40 @@ module DRC
|
|||
# \touching is a similar method which delivers shapes touching
|
||||
# the search region with their bounding box (without the requirement to overlap)
|
||||
|
||||
# %DRC%
|
||||
# @name global_transform
|
||||
# @brief Gets or sets a global transformation
|
||||
# @synopsis global_transform
|
||||
# @synopsis global_transform([ transformations ])
|
||||
#
|
||||
# This method returns a new source representing the transformed layout. It is provided in the spritit of
|
||||
# \Source#clip and similar methods.
|
||||
#
|
||||
# The transformation
|
||||
# is either given as a RBA::DTrans, RBA::DVector or RBA::DCplxTrans object or as one of the
|
||||
# following specifications:
|
||||
#
|
||||
# @ul
|
||||
# @li "shift(x, y)": shifts the input layout horizontally by x and vertically by y micrometers
|
||||
# @li "rotate(a)": rotates the input layout by a degree counter-clockwise
|
||||
# @li "magnify(m)": magnifies the input layout by the factor m (NOTE: using fractional scale factors may result in small gaps due to grid snapping)
|
||||
# @li "mirror_x": mirrors the input layout at the x axis
|
||||
# @li "mirror_y": mirrors the input layout at the y axis
|
||||
# @/ul
|
||||
#
|
||||
# Multiple transformation specs can be given. In that case the transformations are applied right to left.
|
||||
# Using "global_transform" will reset any global transformation present already.
|
||||
# Without an argument, the global transformation is reset.
|
||||
#
|
||||
# The following example rotates the layout by 90 degree at the origin (0, 0) and then shifts it up by
|
||||
# 100 micrometers:
|
||||
#
|
||||
# @code
|
||||
# source.global_transform(shift(0, 100.um), rotate(90.0))
|
||||
# @/code
|
||||
|
||||
# export inplace_* as * out-of-place
|
||||
%w(select cell clip touching overlapping).each do |f|
|
||||
%w(select cell clip touching overlapping global_transform).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(*args)
|
||||
@engine._context("#{f}") do
|
||||
|
|
@ -274,7 +325,7 @@ CODE
|
|||
if @box
|
||||
layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu)
|
||||
else
|
||||
layer.insert(RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu)
|
||||
layer.insert((RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu).transformed(@global_trans))
|
||||
end
|
||||
layer
|
||||
end
|
||||
|
|
@ -326,7 +377,7 @@ CODE
|
|||
def input(*args)
|
||||
@engine._context("input") do
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -350,7 +401,7 @@ CODE
|
|||
def labels(*args)
|
||||
@engine._context("labels") do
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, RBA::Texts))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, @global_trans, RBA::Texts))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -373,7 +424,7 @@ CODE
|
|||
def polygons(*args)
|
||||
@engine._context("polygons") do
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, RBA::Region))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, @global_trans, RBA::Region))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -399,7 +450,7 @@ CODE
|
|||
def edges(*args)
|
||||
@engine._context("edges") do
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, RBA::Edges))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, @global_trans, RBA::Edges))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -425,7 +476,7 @@ CODE
|
|||
def edge_pairs(*args)
|
||||
@engine._context("edge_pairs") do
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, RBA::EdgePairs))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, @global_trans, RBA::EdgePairs))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -437,7 +488,7 @@ CODE
|
|||
|
||||
def make_layer
|
||||
layers = []
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
|
|||
|
|
@ -322,5 +322,55 @@ module DRC
|
|||
end
|
||||
end
|
||||
|
||||
# A wrapper for the tile_size option
|
||||
class DRCTileSize
|
||||
def initialize(*args)
|
||||
@xy = args
|
||||
end
|
||||
def get
|
||||
@xy
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for the tile_step option
|
||||
class DRCTileStep
|
||||
def initialize(*args)
|
||||
@xy = args
|
||||
end
|
||||
def get
|
||||
@xy
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for the tile_origin option
|
||||
class DRCTileOrigin
|
||||
def initialize(*args)
|
||||
@xy = args
|
||||
end
|
||||
def get
|
||||
@xy
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for the tile_count option
|
||||
class DRCTileCount
|
||||
def initialize(*args)
|
||||
@xy = args
|
||||
end
|
||||
def get
|
||||
@xy
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for the tile_boundary option
|
||||
class DRCTileBoundary
|
||||
def initialize(layer)
|
||||
@b = layer
|
||||
end
|
||||
def get
|
||||
@b
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -17,44 +17,52 @@
|
|||
<text>
|
||||
module DRC
|
||||
|
||||
def DRC.execute_drc(macro, generator, rdb_index = nil)
|
||||
class DRCExecutable < RBA::Executable
|
||||
|
||||
timer = RBA::Timer::new
|
||||
timer.start
|
||||
drc = DRCEngine::new
|
||||
drc._rdb_index = rdb_index
|
||||
drc._generator = generator
|
||||
def initialize(macro, generator, rdb_index = nil)
|
||||
|
||||
drc_progress = RBA::AbstractProgress::new("DRC: " + macro.path)
|
||||
@drc = DRCEngine::new
|
||||
@drc._rdb_index = rdb_index
|
||||
@drc._generator = generator
|
||||
|
||||
begin
|
||||
|
||||
# Set a debugger scope so that our errors end up with the debugger set to the DRC's line
|
||||
RBA::MacroExecutionContext::set_debugger_scope(macro.path)
|
||||
# No verbosity set in drc engine - we cannot use the engine's logger
|
||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{macro.path}")
|
||||
drc.instance_eval(macro.text, macro.path)
|
||||
# Remove the debugger scope
|
||||
RBA::MacroExecutionContext::remove_debugger_scope
|
||||
|
||||
rescue => ex
|
||||
|
||||
drc.error("In #{macro.path}: #{ex.to_s}")
|
||||
RBA::MacroExecutionContext::ignore_next_exception
|
||||
raise ex
|
||||
|
||||
ensure
|
||||
|
||||
# cleans up and creates layout and report views
|
||||
drc._finish
|
||||
|
||||
# unlocks the UI
|
||||
drc_progress._destroy
|
||||
@macro = macro
|
||||
|
||||
end
|
||||
|
||||
timer.stop
|
||||
drc.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s")
|
||||
def execute
|
||||
|
||||
@drc._start("DRC: " + @macro.path)
|
||||
|
||||
# Set a debugger scope so that our errors end up with the debugger set to the DRC's line
|
||||
RBA::MacroExecutionContext::set_debugger_scope(@macro.path)
|
||||
|
||||
begin
|
||||
|
||||
# No verbosity set in drc engine - we cannot use the engine's logger
|
||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
||||
@drc.instance_eval(@macro.text, @macro.path)
|
||||
|
||||
rescue => ex
|
||||
|
||||
@drc.error("In #{@macro.path}: #{ex.to_s}")
|
||||
RBA::MacroExecutionContext::ignore_next_exception
|
||||
raise ex
|
||||
|
||||
end
|
||||
|
||||
nil
|
||||
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
||||
# Remove the debugger scope
|
||||
RBA::MacroExecutionContext::remove_debugger_scope
|
||||
|
||||
# cleans up and creates layout and report views
|
||||
@drc._finish
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -79,11 +87,17 @@ module DRC
|
|||
# create a template for the macro editor:
|
||||
create_template(":/drc-templates/drc.lym")
|
||||
|
||||
# if available, create a menu branch
|
||||
if RBA::Application::instance && RBA::Application::instance.main_window
|
||||
mw = RBA::Application::instance.main_window
|
||||
mw.menu.insert_menu("tools_menu.verification_group+", "drc", "DRC")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Implements the execute method
|
||||
def execute(macro)
|
||||
DRC::execute_drc(macro, @recipe.generator("script" => macro.path))
|
||||
def executable(macro)
|
||||
DRCExecutable::new(macro, @recipe.generator("script" => macro.path))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -109,20 +123,20 @@ module DRC
|
|||
end
|
||||
|
||||
# Implements the execute method
|
||||
def execute(macro)
|
||||
DRC::execute_drc(macro, @recipe.generator("script" => macro.path))
|
||||
def executable(macro)
|
||||
DRCExecutable::new(macro, @recipe.generator("script" => macro.path))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A recipe implementation allowing the LVS run to be redone
|
||||
# A recipe implementation allowing the DRC run to be redone
|
||||
class DRCRecipe < RBA::Recipe
|
||||
|
||||
def initialize
|
||||
super("drc", "DRC recipe")
|
||||
end
|
||||
|
||||
def execute(params)
|
||||
def executable(params)
|
||||
|
||||
script = params["script"]
|
||||
if ! script
|
||||
|
|
@ -132,7 +146,7 @@ module DRC
|
|||
macro = RBA::Macro::macro_by_path(script)
|
||||
macro || raise("Can't find DRC script #{script} - unable to re-run")
|
||||
|
||||
DRC::execute_drc(macro, self.generator("script" => script), params["rdb_index"])
|
||||
DRCExecutable::new(macro, self.generator("script" => script), params["rdb_index"])
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1163,6 +1163,36 @@ TEST(29d_holes)
|
|||
run_test (_this, "29", true);
|
||||
}
|
||||
|
||||
TEST(30_density)
|
||||
{
|
||||
run_test (_this, "30", false);
|
||||
}
|
||||
|
||||
TEST(31_globaTransformation)
|
||||
{
|
||||
run_test (_this, "31", false);
|
||||
}
|
||||
|
||||
TEST(31d_globalTransformation)
|
||||
{
|
||||
run_test (_this, "31", true);
|
||||
}
|
||||
|
||||
TEST(32_globalTransformationWithClip)
|
||||
{
|
||||
run_test (_this, "32", false);
|
||||
}
|
||||
|
||||
TEST(32d_globalTransformationWithClip)
|
||||
{
|
||||
run_test (_this, "32", true);
|
||||
}
|
||||
|
||||
TEST(33_globalTransformationWithTiles)
|
||||
{
|
||||
run_test (_this, "33", true);
|
||||
}
|
||||
|
||||
TEST(40_fill)
|
||||
{
|
||||
run_test (_this, "40", false);
|
||||
|
|
@ -1172,3 +1202,4 @@ TEST(41_fillTiled)
|
|||
{
|
||||
run_test (_this, "41", false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1387,7 +1387,7 @@ MainService::cm_round_corners ()
|
|||
std::vector <db::Polygon> in;
|
||||
ep.merge (primary, in, 0 /*min_wc*/, false /*resolve holes*/, true /*min coherence*/);
|
||||
for (std::vector <db::Polygon>::iterator p = in.begin (); p != in.end (); ++p) {
|
||||
*p = smooth (*p, 1);
|
||||
*p = smooth (*p, 1, true);
|
||||
}
|
||||
|
||||
std::vector <db::Polygon> out = in;
|
||||
|
|
|
|||
|
|
@ -629,6 +629,72 @@ Class<tl::GlobPattern> decl_GlobPattern ("tl", "GlobPattern",
|
|||
"This class has been introduced in version 0.26."
|
||||
);
|
||||
|
||||
class Executable_Impl
|
||||
: public tl::Executable, public gsi::ObjectBase
|
||||
{
|
||||
public:
|
||||
Executable_Impl ()
|
||||
: tl::Executable ()
|
||||
{
|
||||
// makes the object owned by the C++ side (registrar). This way we don't need to keep a
|
||||
// singleton instance.
|
||||
keep ();
|
||||
}
|
||||
|
||||
virtual tl::Variant execute ()
|
||||
{
|
||||
if (execute_cb.can_issue ()) {
|
||||
return execute_cb.issue<tl::Executable, tl::Variant> (&tl::Executable::execute);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void cleanup ()
|
||||
{
|
||||
if (cleanup_cb.can_issue ()) {
|
||||
cleanup_cb.issue<tl::Executable> (&tl::Executable::cleanup);
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback execute_cb;
|
||||
gsi::Callback cleanup_cb;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
template <> struct type_traits<gsi::Executable_Impl> : public type_traits<tl::Executable> { };
|
||||
}
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
Class<tl::Executable> decl_Executable ("tl", "ExecutableBase",
|
||||
gsi::Methods (),
|
||||
"@hide\n@alias Executable"
|
||||
);
|
||||
|
||||
Class<Executable_Impl> decl_Executable_Impl (decl_Executable, "tl", "Executable",
|
||||
gsi::callback ("execute", &Executable_Impl::execute, &Executable_Impl::execute_cb,
|
||||
"@brief Reimplement this method to provide the functionality of the executable.\n"
|
||||
"This method is supposed to execute the operation with the given parameters and return the desired output."
|
||||
) +
|
||||
gsi::callback ("cleanup", &Executable_Impl::cleanup, &Executable_Impl::cleanup_cb,
|
||||
"@brief Reimplement this method to provide post-mortem cleanup functionality.\n"
|
||||
"This method is always called after execute terminated."
|
||||
),
|
||||
"@brief A generic executable object\n"
|
||||
"This object is a delegate for implementing the actual function of some generic executable function. "
|
||||
"In addition to the plain execution, if offers a post-mortem cleanup callback which is always executed, even "
|
||||
"if execute's implementation is cancelled in the debugger.\n"
|
||||
"\n"
|
||||
"Parameters are kept as a generic key/value map.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.27."
|
||||
);
|
||||
|
||||
class Recipe_Impl
|
||||
: public tl::Recipe, public gsi::ObjectBase
|
||||
{
|
||||
|
|
@ -641,16 +707,16 @@ public:
|
|||
keep ();
|
||||
}
|
||||
|
||||
virtual tl::Variant execute (const std::map<std::string, tl::Variant> ¶ms) const
|
||||
virtual tl::Executable *executable (const std::map<std::string, tl::Variant> ¶ms) const
|
||||
{
|
||||
if (execute_cb.can_issue ()) {
|
||||
return execute_cb.issue<tl::Recipe, tl::Variant, const std::map<std::string, tl::Variant> &> (&tl::Recipe::execute, params);
|
||||
if (executable_cb.can_issue ()) {
|
||||
return executable_cb.issue<tl::Recipe, tl::Executable *, const std::map<std::string, tl::Variant> &> (&tl::Recipe::executable, params);
|
||||
} else {
|
||||
return tl::Variant ();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback execute_cb;
|
||||
gsi::Callback executable_cb;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -688,10 +754,13 @@ Class<Recipe_Impl> decl_Recipe_Impl ("tl", "Recipe",
|
|||
"@brief Delivers the generator string from the given parameters.\n"
|
||||
"The generator string can be used with \\make to re-run the recipe."
|
||||
) +
|
||||
gsi::callback ("execute", &Recipe_Impl::execute, &Recipe_Impl::execute_cb, gsi::arg ("params"),
|
||||
"@brief Reimplement this method to provide the functionality of the recipe.\n"
|
||||
"This method is supposed to re-run the recipe with the given parameters and deliver the "
|
||||
"the intended output object."
|
||||
gsi::callback ("executable", &Recipe_Impl::executable, &Recipe_Impl::executable_cb, gsi::arg ("params"),
|
||||
"@brief Reimplement this method to provide an executable object for the actual implementation.\n"
|
||||
"The reasoning behind this architecture is to supply a cleanup callback. This is useful when the "
|
||||
"actual function is executed as a script and the script terminates in the debugger. The cleanup callback "
|
||||
"allows implementing any kind of post-mortem action despite being cancelled in the debugger.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27 and replaces 'execute'."
|
||||
),
|
||||
"@brief A facility for providing reproducable recipes\n"
|
||||
"The idea of this facility is to provide a service by which an object\n"
|
||||
|
|
|
|||
|
|
@ -738,7 +738,7 @@ This function will evaluate the conditions c1 to cn and return the
|
|||
current primary shape if all conditions renders an empty result.
|
||||
See <a href="#if_all">if_all</a> for an example how to use the if_... functions.
|
||||
</p>
|
||||
<a name="info"/><h2>"info" - Outputs as message to the logger window</h2>
|
||||
<a name="info"/><h2>"info" - Outputs as message to the logger or progress window</h2>
|
||||
<keyword name="info"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -747,7 +747,7 @@ See <a href="#if_all">if_all</a> for an example how to use the if_... functions.
|
|||
</ul>
|
||||
<p>
|
||||
Prints the message to the log window in verbose mode.
|
||||
In non-verbose more, nothing is printed.
|
||||
In non-verbose more, nothing is printed but a statement is put into the progress window.
|
||||
<a href="#log">log</a> is a function that always prints a message.
|
||||
</p>
|
||||
<a name="input"/><h2>"input" - Fetches the shapes from the specified input from the default source</h2>
|
||||
|
|
|
|||
|
|
@ -247,8 +247,8 @@ deliver objects that can be converted into polygons. Such objects are of class <
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.corners([ options ])</tt></li>
|
||||
<li><tt>layer.corners(angle, [ options ])</tt></li>
|
||||
<li><tt>layer.corners(amin .. amax, [ options ])</tt></li>
|
||||
<li><tt>layer.corners(angle [, options ])</tt></li>
|
||||
<li><tt>layer.corners(amin .. amax [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method produces markers on the corners of the polygons. An angle criterion can be given which
|
||||
|
|
@ -2732,6 +2732,87 @@ The following image shows the effect of the space check:
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="split_covering"/><h2>"split_covering" - Returns the results of <a href="#covering">covering</a> and <a href="#not_covering">not_covering</a> at the same time</h2>
|
||||
<keyword name="split_covering"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>(a, b) = layer.split_covering(other [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method returns the polygons covering polygons from the other layer in
|
||||
one layer and all others in a second layer. This method is equivalent to calling
|
||||
<a href="#covering">covering</a> and <a href="#not_covering">not_covering</a>, but is faster than doing this in separate steps:
|
||||
</p><p>
|
||||
<pre>
|
||||
(covering, not_covering) = l1.split_covering(l2)
|
||||
</pre>
|
||||
</p><p>
|
||||
The options of this method are the same than <a href="#covering">covering</a>.
|
||||
</p>
|
||||
<a name="split_inside"/><h2>"split_inside" - Returns the results of <a href="#inside">inside</a> and <a href="#not_inside">not_inside</a> at the same time</h2>
|
||||
<keyword name="split_inside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>(a, b) = layer.split_inside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method returns the polygons inside of polygons from the other layer in
|
||||
one layer and all others in a second layer. This method is equivalent to calling
|
||||
<a href="#inside">inside</a> and <a href="#not_inside">not_inside</a>, but is faster than doing this in separate steps:
|
||||
</p><p>
|
||||
<pre>
|
||||
(inside, not_inside) = l1.split_inside(l2)
|
||||
</pre>
|
||||
</p>
|
||||
<a name="split_interacting"/><h2>"split_interacting" - Returns the results of <a href="#interacting">interacting</a> and <a href="#not_interacting">not_interacting</a> at the same time</h2>
|
||||
<keyword name="split_interacting"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>(a, b) = layer.split_interacting(other [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method returns the polygons interacting with objects from the other container in
|
||||
one layer and all others in a second layer. This method is equivalent to calling
|
||||
<a href="#interacting">interacting</a> and <a href="#not_interacting">not_interacting</a>, but is faster than doing this in separate steps:
|
||||
</p><p>
|
||||
<pre>
|
||||
(interacting, not_interacting) = l1.split_interacting(l2)
|
||||
</pre>
|
||||
</p><p>
|
||||
The options of this method are the same than <a href="#interacting">interacting</a>.
|
||||
</p>
|
||||
<a name="split_outside"/><h2>"split_outside" - Returns the results of <a href="#outside">outside</a> and <a href="#not_outside">not_outside</a> at the same time</h2>
|
||||
<keyword name="split_outside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>(a, b) = layer.split_outside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method returns the polygons outside of polygons from the other layer in
|
||||
one layer and all others in a second layer. This method is equivalent to calling
|
||||
<a href="#outside">outside</a> and <a href="#not_outside">not_outside</a>, but is faster than doing this in separate steps:
|
||||
</p><p>
|
||||
<pre>
|
||||
(outside, not_outside) = l1.split_outside(l2)
|
||||
</pre>
|
||||
</p>
|
||||
<a name="split_overlapping"/><h2>"split_overlapping" - Returns the results of <a href="#overlapping">overlapping</a> and <a href="#not_overlapping">not_overlapping</a> at the same time</h2>
|
||||
<keyword name="split_overlapping"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>(a, b) = layer.split_overlapping(other [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method returns the polygons overlapping polygons from the other layer in
|
||||
one layer and all others in a second layer. This method is equivalent to calling
|
||||
<a href="#overlapping">overlapping</a> and <a href="#not_overlapping">not_overlapping</a>, but is faster than doing this in separate steps:
|
||||
</p><p>
|
||||
<pre>
|
||||
(overlapping, not_overlapping) = l1.split_overlapping(l2)
|
||||
</pre>
|
||||
</p><p>
|
||||
The options of this method are the same than <a href="#overlapping">overlapping</a>.
|
||||
</p>
|
||||
<a name="squares"/><h2>"squares" - Selects all squares from the input</h2>
|
||||
<keyword name="squares"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -3147,6 +3228,74 @@ bounding box.
|
|||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="with_density"/><h2>"with_density" - Returns tiles whose density is within a given range</h2>
|
||||
<keyword name="with_density"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.with_density(min_value, max_value [, options ])</tt></li>
|
||||
<li><tt>layer.with_density(min_value .. max_value [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method runs a tiled analysis over the current layout. It reports the tiles whose density
|
||||
is between "min_value" and "max_value". "min_value" and "max_value" are given in
|
||||
relative units, i.e. within the range of 0 to 1.0 corresponding to a density of 0 to 100%.
|
||||
</p><p>
|
||||
"min_value" or "max_value" can be nil or omitted in the ".." range notation.
|
||||
In this case, they are taken as "0" and "100%".
|
||||
</p><p>
|
||||
The tile size must be specified with the "tile_size" option:
|
||||
</p><p>
|
||||
<pre>
|
||||
# reports areas where layer 1/0 density is below 10% on 20x20 um tiles
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um))
|
||||
</pre>
|
||||
</p><p>
|
||||
Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)".
|
||||
The first value is the horizontal tile dimension, the second value is the vertical tile
|
||||
dimension.
|
||||
</p><p>
|
||||
A tile overlap can be specified using "tile_step". If the tile step is less than the
|
||||
tile size, the tiles will overlap. The layout window given by "tile_size" is moved
|
||||
in increments of the tile step:
|
||||
</p><p>
|
||||
<pre>
|
||||
# reports areas where layer 1/0 density is below 10% on 30x30 um tiles
|
||||
# with a tile step of 20x20 um:
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
|
||||
</pre>
|
||||
</p><p>
|
||||
For "tile_step", anisotropic values can be given as well by using two values: the first for the
|
||||
horizontal and the second for the vertical tile step.
|
||||
</p><p>
|
||||
Another option is "tile_origin" which specifies the location of the first tile's position.
|
||||
This is the lower left tile's lower left corner. If no origin is given, the tiles are centered over the
|
||||
area investigated.
|
||||
</p><p>
|
||||
By default, the tiles will cover the bounding box of the input layer. A separate layer
|
||||
can be used in addition. This way, the layout's dimensions can be derived from some
|
||||
drawn boundary layer. To specify a separate, additional layer included in the bounding box, use the "tile_boundary" option:
|
||||
</p><p>
|
||||
<pre>
|
||||
# reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from
|
||||
# layer 0/0:
|
||||
cell_frame = input(0, 0)
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
|
||||
</pre>
|
||||
</p><p>
|
||||
Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box.
|
||||
The computed area is at least the area of the input layer.
|
||||
</p><p>
|
||||
Computation of the area can be skipped by explicitly giving a tile count in horizontal and vertical
|
||||
direction. With the "tile_origin" option this allows full control over the area covered:
|
||||
</p><p>
|
||||
<pre>
|
||||
# reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000
|
||||
# (100 and 150 tiles of 20 um each are used in horizontal and vertical direction):
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
|
||||
</pre>
|
||||
</p><p>
|
||||
The complementary version of "with_density" is <a href="#without_density">without_density</a>.
|
||||
</p>
|
||||
<a name="with_holes"/><h2>"with_holes" - Selects all polygons with the specified number of holes</h2>
|
||||
<keyword name="with_holes"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -3313,6 +3462,17 @@ bounding box.
|
|||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="without_density"/><h2>"without_density" - Returns tiles whose density is not within a given range</h2>
|
||||
<keyword name="without_density"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.without_density(min_value, max_value [, options ])</tt></li>
|
||||
<li><tt>layer.without_density(min_value .. max_value [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
For details about the operations and the operation see <a href="#with_density">with_density</a>. This version will return the
|
||||
tiles where the density is not within the given range.
|
||||
</p>
|
||||
<a name="without_holes"/><h2>"without_holes" - Selects all polygons with the specified number of holes</h2>
|
||||
<keyword name="without_holes"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -732,6 +732,8 @@ type_to_s (const gsi::ArgType &a, bool linked, bool for_return)
|
|||
s += "float"; break;
|
||||
case gsi::T_string:
|
||||
s += "string"; break;
|
||||
case gsi::T_byte_array:
|
||||
s += "bytes"; break;
|
||||
case gsi::T_var:
|
||||
s += "variant"; break;
|
||||
case gsi::T_object:
|
||||
|
|
|
|||
|
|
@ -326,8 +326,7 @@ HelpSource::produce_index_file (const std::string &path)
|
|||
m_title_map.clear ();
|
||||
m_parent_of.clear ();
|
||||
|
||||
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Initializing help index")), 1);
|
||||
progress.can_cancel (false);
|
||||
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Initializing help index")), 1, false /*can't cancel*/);
|
||||
scan ("/index.xml", progress);
|
||||
try {
|
||||
|
||||
|
|
|
|||
|
|
@ -22,12 +22,15 @@
|
|||
|
||||
|
||||
#include "layLogViewerDialog.h"
|
||||
#include "layApplication.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QTimer>
|
||||
#include <QClipboard>
|
||||
#include <QFrame>
|
||||
#include <QThread>
|
||||
#include <QAbstractEventDispatcher>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
|
@ -101,7 +104,7 @@ LogReceiver::begin ()
|
|||
LogFile::LogFile (size_t max_entries, bool register_global)
|
||||
: m_error_receiver (this, 0, &LogFile::add_error),
|
||||
m_warn_receiver (this, 0, &LogFile::add_warn),
|
||||
m_log_receiver (this, 10, &LogFile::add_info),
|
||||
m_log_receiver (this, 0, &LogFile::add_info),
|
||||
m_info_receiver (this, 0, &LogFile::add_info),
|
||||
m_max_entries (max_entries),
|
||||
m_generation_id (0),
|
||||
|
|
@ -221,25 +224,39 @@ LogFile::max_entries () const
|
|||
void
|
||||
LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued)
|
||||
{
|
||||
QMutexLocker locker (&m_lock);
|
||||
bool can_yield = false;
|
||||
|
||||
if (m_max_entries == 0) {
|
||||
return;
|
||||
{
|
||||
QMutexLocker locker (&m_lock);
|
||||
|
||||
if (m_max_entries == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_messages.size () >= m_max_entries) {
|
||||
m_messages.pop_front ();
|
||||
}
|
||||
|
||||
if (mode == LogFileEntry::Warning || mode == LogFileEntry::WarningContinued) {
|
||||
m_has_warnings = true;
|
||||
} else if (mode == LogFileEntry::Error || mode == LogFileEntry::ErrorContinued) {
|
||||
m_has_errors = true;
|
||||
}
|
||||
|
||||
m_messages.push_back (LogFileEntry (mode, msg, continued));
|
||||
|
||||
++m_generation_id;
|
||||
|
||||
if (lay::ApplicationBase::instance ()->qapp_gui () && QThread::currentThread () == lay::ApplicationBase::instance ()->qapp_gui ()->thread () && (tl::Clock::current () - m_last_yield).seconds () > 0.1) {
|
||||
m_last_yield = tl::Clock::current ();
|
||||
can_yield = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_messages.size () >= m_max_entries) {
|
||||
m_messages.pop_front ();
|
||||
// use this opportunity to process events
|
||||
if (can_yield) {
|
||||
lay::ApplicationBase::instance ()->process_events (QEventLoop::AllEvents);
|
||||
}
|
||||
|
||||
if (mode == LogFileEntry::Warning || mode == LogFileEntry::WarningContinued) {
|
||||
m_has_warnings = true;
|
||||
} else if (mode == LogFileEntry::Error || mode == LogFileEntry::ErrorContinued) {
|
||||
m_has_errors = true;
|
||||
}
|
||||
|
||||
m_messages.push_back (LogFileEntry (mode, msg, continued));
|
||||
|
||||
++m_generation_id;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "ui_LogViewerDialog.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlTimer.h"
|
||||
#include "layCommon.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
|
@ -227,6 +228,7 @@ private:
|
|||
size_t m_last_generation_id;
|
||||
bool m_has_errors, m_has_warnings;
|
||||
bool m_last_attn;
|
||||
tl::Clock m_last_yield;
|
||||
|
||||
/**
|
||||
* @brief Adds an error
|
||||
|
|
|
|||
|
|
@ -3003,6 +3003,11 @@ MacroEditorDialog::translate_pseudo_id (size_t &file_id, int &line)
|
|||
}
|
||||
}
|
||||
|
||||
static void exit_from_macro ()
|
||||
{
|
||||
throw tl::ExitException ();
|
||||
}
|
||||
|
||||
void
|
||||
MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_id, int line, const std::string &eclass, const std::string &emsg, const gsi::StackTraceProvider *stack_trace_provider)
|
||||
{
|
||||
|
|
@ -3012,7 +3017,7 @@ MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_
|
|||
}
|
||||
|
||||
if (!m_in_exec) {
|
||||
throw tl::ExitException ();
|
||||
exit_from_macro ();
|
||||
}
|
||||
|
||||
// avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop
|
||||
|
|
@ -3098,7 +3103,7 @@ MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_
|
|||
}
|
||||
|
||||
if (! m_in_exec) {
|
||||
throw tl::ExitException ();
|
||||
exit_from_macro ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3106,7 +3111,7 @@ void
|
|||
MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int line, const gsi::StackTraceProvider *stack_trace_provider)
|
||||
{
|
||||
if (!m_in_exec) {
|
||||
throw tl::ExitException ();
|
||||
exit_from_macro ();
|
||||
}
|
||||
|
||||
// avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop
|
||||
|
|
@ -3157,7 +3162,7 @@ MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int lin
|
|||
}
|
||||
|
||||
if (! m_in_exec) {
|
||||
throw tl::ExitException ();
|
||||
exit_from_macro ();
|
||||
}
|
||||
|
||||
} else if (++m_trace_count == 20) {
|
||||
|
|
@ -3175,7 +3180,7 @@ MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int lin
|
|||
m_process_events_interval = std::max (0.05, std::min (2.0, (m_last_process_events - start).seconds () * 5.0));
|
||||
|
||||
if (!m_in_exec) {
|
||||
throw tl::ExitException ();
|
||||
exit_from_macro ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3590,6 +3595,9 @@ MacroEditorDialog::run (int stop_stack_depth, lym::Macro *macro)
|
|||
} catch (tl::ExitException &) {
|
||||
m_stop_stack_depth = -1;
|
||||
// .. ignore exit exceptions ..
|
||||
} catch (tl::BreakException &) {
|
||||
m_stop_stack_depth = -1;
|
||||
// .. ignore break exceptions ..
|
||||
} catch (tl::ScriptError &re) {
|
||||
m_stop_stack_depth = -1;
|
||||
handle_error (re);
|
||||
|
|
|
|||
|
|
@ -1548,6 +1548,71 @@ MacroEditorPage::return_pressed ()
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool is_tab_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0;
|
||||
}
|
||||
|
||||
static bool is_backtab_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0);
|
||||
}
|
||||
|
||||
static bool is_backspace_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_Backspace;
|
||||
}
|
||||
|
||||
static bool is_escape_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_Escape;
|
||||
}
|
||||
|
||||
static bool is_return_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_Return;
|
||||
}
|
||||
|
||||
static bool is_help_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_F1;
|
||||
}
|
||||
|
||||
static bool is_find_next_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_F3;
|
||||
}
|
||||
|
||||
static bool is_find_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0;
|
||||
}
|
||||
|
||||
static bool is_up_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_Up;
|
||||
}
|
||||
|
||||
static bool is_down_key (QKeyEvent *ke)
|
||||
{
|
||||
return ke->key () == Qt::Key_Down;
|
||||
}
|
||||
|
||||
|
||||
static bool is_any_known_key (QKeyEvent *ke)
|
||||
{
|
||||
return is_tab_key (ke) ||
|
||||
is_backtab_key (ke) ||
|
||||
is_backspace_key (ke) ||
|
||||
is_escape_key (ke) ||
|
||||
is_return_key (ke) ||
|
||||
is_help_key (ke) ||
|
||||
is_find_next_key (ke) ||
|
||||
is_find_key (ke) ||
|
||||
is_up_key (ke) ||
|
||||
is_down_key (ke);
|
||||
}
|
||||
|
||||
bool
|
||||
MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
|
||||
{
|
||||
|
|
@ -1555,9 +1620,16 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
|
|||
|
||||
if (event->type () == QEvent::ShortcutOverride) {
|
||||
|
||||
// override shortcuts
|
||||
event->accept ();
|
||||
return true;
|
||||
// override shortcuts if the collide with keys we accept ourselves
|
||||
QKeyEvent *ke = dynamic_cast<QKeyEvent *> (event);
|
||||
if (! ke) {
|
||||
return false; // should not happen
|
||||
}
|
||||
|
||||
if (is_any_known_key (ke)) {
|
||||
event->accept ();
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (event->type () == QEvent::FocusOut) {
|
||||
|
||||
|
|
@ -1574,7 +1646,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
|
|||
return false; // should not happen
|
||||
}
|
||||
|
||||
if (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) == 0) {
|
||||
if (is_tab_key (ke)) {
|
||||
|
||||
if (mp_completer_popup->isVisible ()) {
|
||||
complete ();
|
||||
|
|
@ -1583,15 +1655,15 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
|
|||
return tab_key_pressed ();
|
||||
}
|
||||
|
||||
} else if ((ke->key () == Qt::Key_Backtab || (ke->key () == Qt::Key_Tab && (ke->modifiers () & Qt::ShiftModifier) != 0))) {
|
||||
} else if (is_backtab_key (ke)) {
|
||||
|
||||
return back_tab_key_pressed ();
|
||||
|
||||
} else if (ke->key () == Qt::Key_Backspace) {
|
||||
} else if (is_backspace_key (ke)) {
|
||||
|
||||
return backspace_pressed ();
|
||||
|
||||
} else if (ke->key () == Qt::Key_Escape) {
|
||||
} else if (is_escape_key (ke)) {
|
||||
|
||||
// Handle Esc to return to the before-find position and clear the selection or to hide popup
|
||||
|
||||
|
|
@ -1606,7 +1678,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
|
|||
|
||||
return true;
|
||||
|
||||
} else if (ke->key () == Qt::Key_Return) {
|
||||
} else if (is_return_key (ke)) {
|
||||
|
||||
if (mp_completer_popup->isVisible ()) {
|
||||
complete ();
|
||||
|
|
@ -1615,7 +1687,7 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
|
|||
return return_pressed ();
|
||||
}
|
||||
|
||||
} else if (ke->key () == Qt::Key_F1) {
|
||||
} else if (is_help_key (ke)) {
|
||||
|
||||
QTextCursor c = mp_text->textCursor ();
|
||||
if (c.selectionStart () == c.selectionEnd ()) {
|
||||
|
|
@ -1625,19 +1697,19 @@ MacroEditorPage::eventFilter (QObject *watched, QEvent *event)
|
|||
|
||||
return true;
|
||||
|
||||
} else if (mp_completer_popup->isVisible () && (ke->key () == Qt::Key_Up || ke->key () == Qt::Key_Down)) {
|
||||
} else if (mp_completer_popup->isVisible () && (is_up_key (ke) || is_down_key (ke))) {
|
||||
|
||||
QApplication::sendEvent (mp_completer_list, event);
|
||||
return true;
|
||||
|
||||
} else if (ke->key () == Qt::Key_F && (ke->modifiers () & Qt::ControlModifier) != 0) {
|
||||
} else if (is_find_key (ke)) {
|
||||
|
||||
QTextCursor c = mp_text->textCursor ();
|
||||
emit search_requested (c.selectedText ());
|
||||
|
||||
return true;
|
||||
|
||||
} else if (ke->key () == Qt::Key_F3) {
|
||||
} else if (is_find_next_key (ke)) {
|
||||
|
||||
// Jump to the next occurence of the search string
|
||||
|
||||
|
|
|
|||
|
|
@ -2525,21 +2525,30 @@ MainWindow::cm_new_layout ()
|
|||
std::string technology = m_initial_technology;
|
||||
static std::string s_new_cell_cell_name ("TOP");
|
||||
static double s_new_cell_window_size = 2.0;
|
||||
static std::vector<db::LayerProperties> s_layers;
|
||||
|
||||
double dbu = 0.0;
|
||||
|
||||
lay::NewLayoutPropertiesDialog dialog (this);
|
||||
if (dialog.exec_dialog (technology, s_new_cell_cell_name, dbu, s_new_cell_window_size, m_new_layout_current_panel)) {
|
||||
if (dialog.exec_dialog (technology, s_new_cell_cell_name, dbu, s_new_cell_window_size, s_layers, m_new_layout_current_panel)) {
|
||||
|
||||
lay::CellViewRef cellview = create_or_load_layout (0, 0, technology, m_new_layout_current_panel ? 2 : 1 /*= new view*/);
|
||||
std::unique_ptr <lay::LayoutHandle> handle (new lay::LayoutHandle (new db::Layout (& manager ()), std::string ()));
|
||||
handle->rename ("new");
|
||||
|
||||
if (dbu > 1e-10) {
|
||||
cellview->layout ().dbu (dbu);
|
||||
handle->layout ().dbu (dbu);
|
||||
}
|
||||
db::cell_index_type new_ci = cellview->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ());
|
||||
cellview.set_cell (new_ci);
|
||||
db::cell_index_type new_ci = handle->layout ().add_cell (s_new_cell_cell_name.empty () ? 0 : s_new_cell_cell_name.c_str ());
|
||||
|
||||
current_view ()->zoom_box_and_set_hier_levels (db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size), std::make_pair (0, 1));
|
||||
for (std::vector<db::LayerProperties>::const_iterator l = s_layers.begin (); l != s_layers.end (); ++l) {
|
||||
handle->layout ().insert_layer (*l);
|
||||
}
|
||||
|
||||
lay::LayoutView *mp_view = (m_new_layout_current_panel && current_view ()) ? current_view () : view (create_view ());
|
||||
|
||||
unsigned int ci = mp_view->add_layout (handle.release (), true);
|
||||
mp_view->cellview_ref (ci).set_cell (new_ci);
|
||||
mp_view->zoom_box_and_set_hier_levels (db::DBox (-0.5 * s_new_cell_window_size, -0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size, 0.5 * s_new_cell_window_size), std::make_pair (0, 1));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,10 @@ static bool is_marked_alive (QObject *obj)
|
|||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
const double visibility_delay = 1.0;
|
||||
|
||||
ProgressReporter::ProgressReporter ()
|
||||
: m_start_time (), mp_pb (0), m_pw_visible (false)
|
||||
: mp_pb (0), m_pw_visible (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -94,22 +96,21 @@ ProgressReporter::register_object (tl::Progress *progress)
|
|||
|
||||
tl::ProgressAdaptor::register_object (progress);
|
||||
|
||||
if (m_start_time == tl::Clock () && ! m_pw_visible) {
|
||||
m_start_time = tl::Clock::current ();
|
||||
}
|
||||
|
||||
// make dialog visible after some time has passed
|
||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||
set_visible (true);
|
||||
}
|
||||
|
||||
if (progress->is_abstract ()) {
|
||||
|
||||
m_active.insert (progress);
|
||||
|
||||
if (! m_pw_visible) {
|
||||
set_visible (true);
|
||||
}
|
||||
|
||||
if (mp_pb) {
|
||||
mp_pb->update_progress (progress);
|
||||
}
|
||||
process_events ();
|
||||
|
||||
} else {
|
||||
update_and_yield ();
|
||||
m_queued.insert (std::make_pair (progress, tl::Clock::current ()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,46 +122,64 @@ ProgressReporter::unregister_object (tl::Progress *progress)
|
|||
// close or refresh window
|
||||
if (begin () == end ()) {
|
||||
|
||||
m_queued.clear ();
|
||||
m_active.clear ();
|
||||
|
||||
if (m_pw_visible) {
|
||||
set_visible (false);
|
||||
}
|
||||
|
||||
m_start_time = tl::Clock ();
|
||||
|
||||
if (mp_pb) {
|
||||
mp_pb->update_progress (0);
|
||||
}
|
||||
|
||||
process_events ();
|
||||
|
||||
QApplication::instance ()->removeEventFilter (this);
|
||||
|
||||
} else {
|
||||
update_and_yield ();
|
||||
|
||||
m_queued.erase (progress);
|
||||
|
||||
std::set<tl::Progress *>::iterator a = m_active.find (progress);
|
||||
if (a != m_active.end ()) {
|
||||
m_active.erase (a);
|
||||
update_and_yield ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProgressReporter::trigger (tl::Progress * /*progress*/)
|
||||
ProgressReporter::trigger (tl::Progress *progress)
|
||||
{
|
||||
if (begin () != end ()) {
|
||||
// make dialog visible after some time has passed
|
||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||
std::map<tl::Progress *, tl::Clock>::iterator q = m_queued.find (progress);
|
||||
if (q != m_queued.end () && (tl::Clock::current () - q->second).seconds () > visibility_delay) {
|
||||
if (! m_pw_visible) {
|
||||
set_visible (true);
|
||||
}
|
||||
m_active.insert (progress);
|
||||
m_queued.erase (q);
|
||||
}
|
||||
|
||||
if (m_active.find (progress) != m_active.end ()) {
|
||||
update_and_yield ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProgressReporter::yield (tl::Progress * /*progress*/)
|
||||
ProgressReporter::yield (tl::Progress *progress)
|
||||
{
|
||||
// make dialog visible after some time has passed
|
||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||
set_visible (true);
|
||||
std::map<tl::Progress *, tl::Clock>::iterator q = m_queued.find (progress);
|
||||
if (q != m_queued.end () && (tl::Clock::current () - q->second).seconds () > visibility_delay) {
|
||||
if (! m_pw_visible) {
|
||||
set_visible (true);
|
||||
}
|
||||
m_active.insert (progress);
|
||||
m_queued.erase (q);
|
||||
update_and_yield ();
|
||||
} else if (m_pw_visible) {
|
||||
// process events if necessary
|
||||
}
|
||||
|
||||
if (m_active.find (progress) != m_active.end ()) {
|
||||
process_events ();
|
||||
}
|
||||
}
|
||||
|
|
@ -172,11 +191,17 @@ ProgressReporter::update_and_yield ()
|
|||
return;
|
||||
}
|
||||
|
||||
if (mp_pb && first ()) {
|
||||
mp_pb->update_progress (first ());
|
||||
QWidget *w = mp_pb->progress_get_widget ();
|
||||
if (w) {
|
||||
first ()->render_progress (w);
|
||||
if (mp_pb) {
|
||||
if (first ()) {
|
||||
mp_pb->update_progress (first ());
|
||||
QWidget *w = mp_pb->progress_get_widget ();
|
||||
if (w) {
|
||||
first ()->render_progress (w);
|
||||
}
|
||||
} else if (begin () != end ()) {
|
||||
mp_pb->update_progress (begin ().operator-> ());
|
||||
} else {
|
||||
mp_pb->update_progress (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "tlProgress.h"
|
||||
#include "tlObject.h"
|
||||
|
|
@ -71,9 +73,10 @@ public:
|
|||
void set_progress_bar (lay::ProgressBar *pb);
|
||||
|
||||
private:
|
||||
tl::Clock m_start_time;
|
||||
lay::ProgressBar *mp_pb;
|
||||
bool m_pw_visible;
|
||||
std::map<tl::Progress *, tl::Clock> m_queued;
|
||||
std::set<tl::Progress *> m_active;
|
||||
|
||||
void process_events ();
|
||||
void update_and_yield ();
|
||||
|
|
|
|||
|
|
@ -90,13 +90,13 @@ QSize
|
|||
ProgressBarWidget::sizeHint () const
|
||||
{
|
||||
QFontMetrics fm (font ());
|
||||
return QSize (m_width, fm.height () + 2);
|
||||
return QSize (fm.width (QString::fromUtf8("100%")) * 4, fm.height () + 2);
|
||||
}
|
||||
|
||||
QSize
|
||||
ProgressBarWidget::minimumSizeHint () const
|
||||
{
|
||||
return QSize (m_width, 1);
|
||||
return QSize (50, 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -149,6 +149,11 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw)
|
|||
|
||||
QVBoxLayout *log_layout = new QVBoxLayout (mp_log_frame);
|
||||
|
||||
mp_log_label = new QLabel (mp_log_frame);
|
||||
mp_log_label->setText (QString ());
|
||||
mp_log_label->setSizePolicy (QSizePolicy (QSizePolicy::Ignored, QSizePolicy::Preferred));
|
||||
log_layout->addWidget (mp_log_label);
|
||||
|
||||
QListView *log_view = new QListView (this);
|
||||
log_view->setModel (&m_log_file);
|
||||
log_view->setUniformItemSizes (true);
|
||||
|
|
@ -200,22 +205,22 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw)
|
|||
|
||||
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1);
|
||||
|
||||
QFrame *progress_bar_frame = new QFrame (bar_frame);
|
||||
progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain);
|
||||
progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
layout->addWidget (progress_bar_frame, 0, col, 1, 1);
|
||||
mp_progress_bar_frame = new QFrame (bar_frame);
|
||||
mp_progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain);
|
||||
mp_progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
layout->addWidget (mp_progress_bar_frame, 0, col, 1, 1);
|
||||
|
||||
QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame);
|
||||
progress_bar_frame->setLayout (pbf_layout);
|
||||
QGridLayout *pbf_layout = new QGridLayout (mp_progress_bar_frame);
|
||||
mp_progress_bar_frame->setLayout (pbf_layout);
|
||||
pbf_layout->setMargin (0);
|
||||
pbf_layout->setSpacing (0);
|
||||
|
||||
mp_progress_bar1 = new ProgressBarWidget (progress_bar_frame);
|
||||
pbf_layout->addWidget (mp_progress_bar1, 0, 0, 1, 1);
|
||||
mp_progress_bar2 = new ProgressBarWidget (progress_bar_frame);
|
||||
pbf_layout->addWidget (mp_progress_bar2, 1, 0, 1, 1);
|
||||
mp_progress_bar3 = new ProgressBarWidget (progress_bar_frame);
|
||||
pbf_layout->addWidget (mp_progress_bar3, 2, 0, 1, 1);
|
||||
mp_progress_bar1 = new ProgressBarWidget (mp_progress_bar_frame);
|
||||
pbf_layout->addWidget (mp_progress_bar1, 0, 2, 1, 1);
|
||||
mp_progress_bar2 = new ProgressBarWidget (mp_progress_bar_frame);
|
||||
pbf_layout->addWidget (mp_progress_bar2, 0, 1, 1, 1);
|
||||
mp_progress_bar3 = new ProgressBarWidget (mp_progress_bar_frame);
|
||||
pbf_layout->addWidget (mp_progress_bar3, 0, 0, 1, 1);
|
||||
|
||||
layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1);
|
||||
|
||||
|
|
@ -236,11 +241,12 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw)
|
|||
}
|
||||
|
||||
void
|
||||
ProgressWidget::set_log_visible (bool f)
|
||||
ProgressWidget::set_log_visible (tl::Progress *progress)
|
||||
{
|
||||
if (f != m_log_visible) {
|
||||
m_log_visible = f;
|
||||
mp_log_frame->setVisible (f);
|
||||
if ((progress != 0) != m_log_visible) {
|
||||
m_log_visible = (progress != 0);
|
||||
mp_log_frame->setVisible (m_log_visible);
|
||||
mp_log_label->setText (progress ? tl::to_qstring (progress->desc ()) : QString ());
|
||||
set_full_width (m_full_width);
|
||||
}
|
||||
}
|
||||
|
|
@ -290,11 +296,23 @@ ProgressWidget::remove_widget ()
|
|||
void
|
||||
ProgressWidget::set_progress (tl::Progress *progress)
|
||||
{
|
||||
lay::ProgressBarWidget *progress_bars[] = { mp_progress_bar1, mp_progress_bar2, mp_progress_bar3 };
|
||||
|
||||
if (! progress || progress->is_abstract ()) {
|
||||
m_log_file.clear ();
|
||||
|
||||
if (! progress) {
|
||||
m_log_file.clear ();
|
||||
}
|
||||
m_log_file.set_max_entries (progress ? 1000 : 0);
|
||||
set_log_visible (progress != 0);
|
||||
|
||||
set_log_visible (progress);
|
||||
|
||||
mp_progress_bar_frame->hide ();
|
||||
mp_cancel_button->setEnabled (true);
|
||||
mp_label->setText (QString ());
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
bool can_cancel = false;
|
||||
|
|
@ -308,8 +326,6 @@ ProgressWidget::set_progress (tl::Progress *progress)
|
|||
mp_cancel_button->setEnabled (can_cancel);
|
||||
mp_label->setText (tl::to_qstring (text));
|
||||
|
||||
lay::ProgressBarWidget *progress_bars[] = { mp_progress_bar1, mp_progress_bar2, mp_progress_bar3 };
|
||||
|
||||
for (size_t i = 0; i < sizeof (progress_bars) / sizeof (progress_bars[0]); ++i) {
|
||||
|
||||
lay::ProgressBarWidget *pb = progress_bars[i];
|
||||
|
|
@ -334,6 +350,8 @@ ProgressWidget::set_progress (tl::Progress *progress)
|
|||
|
||||
}
|
||||
|
||||
mp_progress_bar_frame->show ();
|
||||
|
||||
// according to the doc this should not be required, but without, the progress bar does not resize
|
||||
mp_progress_bar1->parentWidget ()->updateGeometry ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ public slots:
|
|||
|
||||
private:
|
||||
QLabel *mp_label;
|
||||
QFrame *mp_progress_bar_frame;
|
||||
ProgressBarWidget *mp_progress_bar1, *mp_progress_bar2, *mp_progress_bar3;
|
||||
QWidget *mp_widget;
|
||||
int m_widget_col;
|
||||
|
|
@ -79,12 +80,13 @@ private:
|
|||
QToolButton *mp_cancel_button;
|
||||
ProgressReporter *mp_pr;
|
||||
lay::LogFile m_log_file;
|
||||
QLabel *mp_log_label;
|
||||
QFrame *mp_log_frame;
|
||||
bool m_full_width;
|
||||
int m_left_col, m_right_col;
|
||||
bool m_log_visible;
|
||||
|
||||
void set_log_visible (bool f);
|
||||
void set_log_visible (tl::Progress *progress);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1040,7 +1040,7 @@ BEGIN_PROTECTED
|
|||
query_to_model (model, lq, iq, std::numeric_limits<size_t>::max (), true);
|
||||
model.end_changes ();
|
||||
|
||||
std::unique_ptr <lay::LayoutHandle> handle (new lay::LayoutHandle (new db::Layout (), std::string ()));
|
||||
std::unique_ptr <lay::LayoutHandle> handle (new lay::LayoutHandle (new db::Layout (mp_view->manager ()), std::string ()));
|
||||
handle->rename ("query_results");
|
||||
model.export_layout (handle->layout ());
|
||||
mp_view->add_layout (handle.release (), true);
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>563</width>
|
||||
<height>234</height>
|
||||
<width>594</width>
|
||||
<height>401</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="window_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
|
|
@ -60,13 +60,6 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Database unit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" colspan="3">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
|
|
@ -80,13 +73,80 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="topcell_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="dbu_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="4">
|
||||
<widget class="QComboBox" name="tech_cbx"/>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="4">
|
||||
<widget class="QLineEdit" name="layers_le"/>
|
||||
</item>
|
||||
<item row="4" column="4">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>141</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>µm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>µm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Top cell</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Database unit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Technology</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
|
|
@ -100,74 +160,34 @@
|
|||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="dbu_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="4">
|
||||
<widget class="QComboBox" name="tech_cbx"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Top cell</string>
|
||||
<string> (empty for default)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="topcell_le">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Technology</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Initial window size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>µm</string>
|
||||
<string>Initial layer(s)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>141</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<item row="6" column="1" colspan="4">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string> (empty for default)</string>
|
||||
<string><html><head/><body>Specify a comma or blank separated list of layers to create in the usual layer notation, e.g. "1/0 2/0 3/0", "metal1 via1 metal2" or "metal1 (1/0) via1 (2/0) metal2 (3/0)"</body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -214,10 +234,12 @@
|
|||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>tech_cbx</tabstop>
|
||||
<tabstop>topcell_le</tabstop>
|
||||
<tabstop>dbu_le</tabstop>
|
||||
<tabstop>window_le</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
<tabstop>layers_le</tabstop>
|
||||
<tabstop>current_panel_cb</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ NewLayoutPropertiesDialog::tech_changed ()
|
|||
}
|
||||
|
||||
bool
|
||||
NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &cell_name, double &dbu, double &size, bool ¤t_panel)
|
||||
NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &cell_name, double &dbu, double &size, std::vector<db::LayerProperties> &layers, bool ¤t_panel)
|
||||
{
|
||||
mp_ui->tech_cbx->clear ();
|
||||
unsigned int technology_index = 0;
|
||||
|
|
@ -151,6 +151,15 @@ NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &ce
|
|||
mp_ui->topcell_le->setText (tl::to_qstring (cell_name));
|
||||
mp_ui->current_panel_cb->setChecked (current_panel);
|
||||
|
||||
std::string layer_string;
|
||||
for (std::vector<db::LayerProperties>::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
if (l != layers.begin ()) {
|
||||
layer_string += ", ";
|
||||
}
|
||||
layer_string += l->to_string ();
|
||||
}
|
||||
mp_ui->layers_le->setText (tl::to_qstring (layer_string));
|
||||
|
||||
if (QDialog::exec ()) {
|
||||
|
||||
// get the selected technology name
|
||||
|
|
@ -167,8 +176,24 @@ NewLayoutPropertiesDialog::exec_dialog (std::string &technology, std::string &ce
|
|||
} else {
|
||||
dbu = 0.0;
|
||||
}
|
||||
|
||||
cell_name = tl::to_string (mp_ui->topcell_le->text ());
|
||||
current_panel = mp_ui->current_panel_cb->isChecked ();
|
||||
|
||||
layers.clear ();
|
||||
layer_string = tl::to_string (mp_ui->layers_le->text ());
|
||||
tl::Extractor ex (layer_string.c_str ());
|
||||
while (! ex.at_end ()) {
|
||||
db::LayerProperties lp;
|
||||
try {
|
||||
lp.read (ex);
|
||||
} catch (...) {
|
||||
break;
|
||||
}
|
||||
layers.push_back (lp);
|
||||
ex.test (",");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ public:
|
|||
NewLayoutPropertiesDialog (QWidget *parent);
|
||||
virtual ~NewLayoutPropertiesDialog ();
|
||||
|
||||
bool exec_dialog (std::string &tech_name, std::string &cell_name, double &dbu, double &window_size, bool ¤t_panel);
|
||||
bool exec_dialog (std::string &tech_name, std::string &cell_name, double &dbu, double &window_size, std::vector<db::LayerProperties> &layers, bool ¤t_panel);
|
||||
|
||||
private slots:
|
||||
void tech_changed ();
|
||||
|
|
|
|||
|
|
@ -305,32 +305,28 @@ SingleIndexedNetlistModel::parent_of (const subcircuit_pair &subcircuits) const
|
|||
return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0);
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status>
|
||||
SingleIndexedNetlistModel::top_circuit_from_index (size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::top_circuit_from_index(size_t index) const
|
||||
{
|
||||
db::Netlist::const_top_down_circuit_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), db::NetlistCrossReference::None);
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status>
|
||||
SingleIndexedNetlistModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::child_circuit_from_index(const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_child_circuit_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), db::NetlistCrossReference::None);
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, IndexedNetlistModel::Status>
|
||||
SingleIndexedNetlistModel::circuit_from_index (size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::circuit_from_index(size_t index) const
|
||||
{
|
||||
db::Netlist::const_circuit_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name<db::Circuit> ()), db::NetlistCrossReference::None);
|
||||
return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name<db::Circuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::net_pair, IndexedNetlistModel::Status>
|
||||
SingleIndexedNetlistModel::net_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::net_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::net_from_index(const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_net_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name<db::Net> ()), db::NetlistCrossReference::None);
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name<db::Net> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
const db::Net *
|
||||
|
|
@ -394,25 +390,22 @@ SingleIndexedNetlistModel::net_pinref_from_index (const net_pair &nets, size_t i
|
|||
return attr_by_object_and_index (nets, index, nets.first->begin_pins (), nets.first->end_pins (), none, none, m_pinref_by_net_and_index, sort_by_pin_name<db::NetPinRef> ());
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::device_pair, IndexedNetlistModel::Status>
|
||||
SingleIndexedNetlistModel::device_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::device_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::device_from_index(const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_device_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name<db::Device> ()), db::NetlistCrossReference::None);
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name<db::Device> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::pin_pair, IndexedNetlistModel::Status>
|
||||
SingleIndexedNetlistModel::pin_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::pin_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::pin_from_index(const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_pin_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), db::NetlistCrossReference::None);
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, IndexedNetlistModel::Status>
|
||||
SingleIndexedNetlistModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<IndexedNetlistModel::Status, std::string> > SingleIndexedNetlistModel::subcircuit_from_index(const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
db::Circuit::const_subcircuit_iterator none;
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name<db::SubCircuit> ()), db::NetlistCrossReference::None);
|
||||
return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name<db::SubCircuit> ()), std::make_pair (db::NetlistCrossReference::None, std::string ()));
|
||||
}
|
||||
|
||||
size_t
|
||||
|
|
|
|||
|
|
@ -89,24 +89,24 @@ public:
|
|||
virtual circuit_pair parent_of (const device_pair &device_pair) const = 0;
|
||||
virtual circuit_pair parent_of (const subcircuit_pair &subcircuit_pair) const = 0;
|
||||
|
||||
virtual std::pair<circuit_pair, Status> top_circuit_from_index (size_t index) const = 0;
|
||||
virtual std::pair<circuit_pair, Status> child_circuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual std::pair<circuit_pair, Status> circuit_from_index (size_t index) const = 0;
|
||||
virtual std::pair<net_pair, Status> net_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > top_circuit_from_index (size_t index) const = 0;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > child_circuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > circuit_from_index (size_t index) const = 0;
|
||||
virtual std::pair<net_pair, std::pair<Status, std::string> > net_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual const db::Net *second_net_for (const db::Net *first) const = 0;
|
||||
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const = 0;
|
||||
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const = 0;
|
||||
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const = 0;
|
||||
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const = 0;
|
||||
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const = 0;
|
||||
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual std::pair<pin_pair, Status> pin_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual std::pair<subcircuit_pair, Status> subcircuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual std::pair<device_pair, std::pair<Status, std::string> > device_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual std::pair<pin_pair, std::pair<Status, std::string> > pin_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
virtual std::pair<subcircuit_pair, std::pair<Status, std::string> > subcircuit_from_index (const circuit_pair &circuits, size_t index) const = 0;
|
||||
|
||||
virtual std::string top_circuit_status_hint (size_t /*index*/) const { return std::string (); }
|
||||
virtual std::string circuit_status_hint (size_t /*index*/) const { return std::string (); }
|
||||
virtual std::string child_circuit_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
|
||||
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, Status> & /*cp*/) const { return std::string (); }
|
||||
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, std::pair<Status, std::string> > & /*cp*/) const { return std::string (); }
|
||||
virtual std::string net_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
|
||||
virtual std::string device_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
|
||||
virtual std::string pin_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); }
|
||||
|
|
@ -159,19 +159,19 @@ public:
|
|||
virtual circuit_pair parent_of (const device_pair &devices) const;
|
||||
virtual circuit_pair parent_of (const subcircuit_pair &subcircuits) const;
|
||||
|
||||
virtual std::pair<circuit_pair, Status> top_circuit_from_index (size_t index) const;
|
||||
virtual std::pair<circuit_pair, Status> circuit_from_index (size_t index) const;
|
||||
virtual std::pair<circuit_pair, Status> child_circuit_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<net_pair, Status> net_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > top_circuit_from_index (size_t index) const;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > circuit_from_index (size_t index) const;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > child_circuit_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<net_pair, std::pair<Status, std::string> > net_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual const db::Net *second_net_for (const db::Net *first) const;
|
||||
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const;
|
||||
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const;
|
||||
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<pin_pair, Status> pin_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<subcircuit_pair, Status> subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<device_pair, std::pair<Status, std::string> > device_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<pin_pair, std::pair<Status, std::string> > pin_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<subcircuit_pair, std::pair<Status, std::string> > subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
|
||||
virtual size_t circuit_index (const circuit_pair &circuits) const;
|
||||
virtual size_t net_index (const net_pair &nets) const;
|
||||
|
|
|
|||
|
|
@ -204,10 +204,10 @@ LayerControlPanel::LayerControlPanel (lay::LayoutView *view, db::Manager *manage
|
|||
mp_view (view),
|
||||
m_needs_update (true),
|
||||
m_tabs_need_update (true),
|
||||
m_hidden_flags_need_update (true),
|
||||
m_in_update (false),
|
||||
m_phase (0),
|
||||
m_do_update_content_dm (this, &LayerControlPanel::do_update_content),
|
||||
m_do_update_hidden_flags_dm (this, &LayerControlPanel::do_update_hidden_flags),
|
||||
m_no_stipples (false)
|
||||
{
|
||||
setObjectName (QString::fromUtf8 (name));
|
||||
|
|
@ -1661,7 +1661,8 @@ LayerControlPanel::set_text_color (QColor c)
|
|||
void
|
||||
LayerControlPanel::update_hidden_flags ()
|
||||
{
|
||||
m_do_update_hidden_flags_dm ();
|
||||
m_hidden_flags_need_update = true;
|
||||
m_do_update_content_dm ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1688,6 +1689,7 @@ LayerControlPanel::begin_updates ()
|
|||
if (! m_in_update) {
|
||||
|
||||
m_in_update = true;
|
||||
m_hidden_flags_need_update = true;
|
||||
|
||||
mp_model->signal_begin_layer_changed (); // this makes the view redraw the data
|
||||
|
||||
|
|
@ -1718,6 +1720,7 @@ LayerControlPanel::cancel_updates ()
|
|||
{
|
||||
m_in_update = false;
|
||||
m_needs_update = false;
|
||||
m_hidden_flags_need_update = false;
|
||||
m_tabs_need_update = false;
|
||||
}
|
||||
|
||||
|
|
@ -1833,7 +1836,7 @@ LayerControlPanel::do_update_content ()
|
|||
mp_layer_list->setCurrentIndex(QModelIndex());
|
||||
|
||||
// this makes the view redraw the data and establishes a valid selection scheme
|
||||
mp_model->signal_layer_changed ();
|
||||
mp_model->signal_layers_changed ();
|
||||
|
||||
// now realize the selection if required
|
||||
if (! m_new_sel.empty ()) {
|
||||
|
|
@ -1875,6 +1878,14 @@ LayerControlPanel::do_update_content ()
|
|||
} else {
|
||||
mp_model->signal_data_changed (); // this makes the view redraw the data
|
||||
}
|
||||
|
||||
if (m_hidden_flags_need_update) {
|
||||
|
||||
do_update_hidden_flags ();
|
||||
|
||||
m_hidden_flags_need_update = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2007,7 +2018,7 @@ LayerControlPanel::update_required (int f)
|
|||
}
|
||||
|
||||
if ((f & 3) != 0) {
|
||||
m_do_update_hidden_flags_dm ();
|
||||
m_hidden_flags_need_update = true;
|
||||
}
|
||||
|
||||
m_do_update_content_dm ();
|
||||
|
|
|
|||
|
|
@ -341,10 +341,11 @@ private:
|
|||
lay::LayoutView *mp_view;
|
||||
bool m_needs_update;
|
||||
bool m_tabs_need_update;
|
||||
bool m_hidden_flags_need_update;
|
||||
bool m_in_update;
|
||||
std::vector<size_t> m_new_sel;
|
||||
int m_phase;
|
||||
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm, m_do_update_hidden_flags_dm;
|
||||
tl::DeferredMethod<LayerControlPanel> m_do_update_content_dm;
|
||||
std::set<unsigned int> m_expanded;
|
||||
bool m_no_stipples;
|
||||
QLabel *m_no_stipples_label;
|
||||
|
|
|
|||
|
|
@ -421,9 +421,9 @@ LayerTreeModel::signal_begin_layer_changed ()
|
|||
}
|
||||
|
||||
void
|
||||
LayerTreeModel::signal_layer_changed ()
|
||||
LayerTreeModel::signal_layers_changed ()
|
||||
{
|
||||
// establish a new range of valid iterator indices
|
||||
// establish a new range of valid iterator indices
|
||||
m_id_start = m_id_end;
|
||||
|
||||
// TODO: is there a more efficient way to compute that?
|
||||
|
|
@ -433,6 +433,21 @@ LayerTreeModel::signal_layer_changed ()
|
|||
}
|
||||
m_id_end += max_id + 1;
|
||||
|
||||
// update the persistent indexes
|
||||
|
||||
QModelIndexList indexes = persistentIndexList ();
|
||||
QModelIndexList new_indexes;
|
||||
for (QModelIndexList::const_iterator i = indexes.begin (); i != indexes.end (); ++i) {
|
||||
lay::LayerPropertiesConstIterator li = iterator (*i);
|
||||
if (! li.at_end ()) {
|
||||
new_indexes.push_back (createIndex (li.child_index (), i->column (), (void *) (li.uint () + m_id_start)));
|
||||
} else {
|
||||
new_indexes.push_back (QModelIndex ());
|
||||
}
|
||||
}
|
||||
|
||||
changePersistentIndexList (indexes, new_indexes);
|
||||
|
||||
m_test_shapes_cache.clear ();
|
||||
emit layoutChanged ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,11 +235,12 @@ public:
|
|||
/**
|
||||
* @brief emit a layoutChanged signal
|
||||
*/
|
||||
void signal_layer_changed ();
|
||||
void signal_layers_changed ();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief This signal is emitted to indicate
|
||||
* @brief This signal is emitted to indicate the hidden flags need update by the client
|
||||
* Note this is neither done by the view nor the model. It needs to be implemented elsewhere.
|
||||
*/
|
||||
void hidden_flags_need_update ();
|
||||
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ LayoutView::LayoutView (db::Manager *manager, bool editable, lay::Plugin *plugin
|
|||
// ensures the deferred method scheduler is present
|
||||
tl::DeferredMethodScheduler::instance ();
|
||||
|
||||
setObjectName (QString::fromUtf8 (name));
|
||||
setObjectName (QString::fromUtf8(name));
|
||||
init (manager, parent);
|
||||
}
|
||||
|
||||
|
|
@ -2859,6 +2859,8 @@ LayoutView::add_new_layers (const std::vector <unsigned int> &layer_ids, int cv_
|
|||
// create the layers and do a basic recoloring ..
|
||||
lay::LayerPropertiesList new_props (get_properties ());
|
||||
|
||||
bool was_empty = new_props.begin_const_recursive ().at_end ();
|
||||
|
||||
// don't create new layers for those, for which there are layers already: compute a
|
||||
// set of layers already present
|
||||
std::set <db::LayerProperties, db::LPLogicalLessFunc> present_layers;
|
||||
|
|
@ -2890,6 +2892,10 @@ LayoutView::add_new_layers (const std::vector <unsigned int> &layer_ids, int cv_
|
|||
|
||||
set_properties (new_props);
|
||||
|
||||
if (was_empty) {
|
||||
set_current_layer (new_props.begin_const_recursive ());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3291,6 +3297,18 @@ LayoutView::add_layout (lay::LayoutHandle *layout_handle, bool add_cellview, boo
|
|||
|
||||
}
|
||||
|
||||
// select the first layer if nothing else is selected
|
||||
if (cv_index == 0 && ! mp_control_panel->has_selection ()) {
|
||||
const lay::LayerPropertiesList &lp = get_properties ();
|
||||
lay::LayerPropertiesConstIterator li = lp.begin_const_recursive ();
|
||||
while (! li.at_end () && li->has_children ()) {
|
||||
++li;
|
||||
}
|
||||
if (! li.at_end ()) {
|
||||
mp_control_panel->set_current_layer (li);
|
||||
}
|
||||
}
|
||||
|
||||
// signal to any observers
|
||||
file_open_event ();
|
||||
|
||||
|
|
@ -3456,6 +3474,18 @@ LayoutView::load_layout (const std::string &filename, const db::LoadLayoutOption
|
|||
// create the initial layer properties
|
||||
create_initial_layer_props (cv_index, lyp_file, add_other_layers);
|
||||
|
||||
// select the first layer if nothing else is selected
|
||||
if (cv_index == 0 && ! mp_control_panel->has_selection ()) {
|
||||
const lay::LayerPropertiesList &lp = get_properties ();
|
||||
lay::LayerPropertiesConstIterator li = lp.begin_const_recursive ();
|
||||
while (! li.at_end () && li->has_children ()) {
|
||||
++li;
|
||||
}
|
||||
if (! li.at_end ()) {
|
||||
mp_control_panel->set_current_layer (li);
|
||||
}
|
||||
}
|
||||
|
||||
// signal to any observers
|
||||
file_open_event ();
|
||||
|
||||
|
|
@ -3942,6 +3972,8 @@ LayoutView::cancel ()
|
|||
{
|
||||
// cancel all drags and pending edit operations such as move operations.
|
||||
cancel_edits ();
|
||||
// re-enable edit mode
|
||||
enable_edits (true);
|
||||
// and clear the selection
|
||||
clear_selection ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ LibrariesView::LibrariesView (lay::LayoutView *view, QWidget *parent, const char
|
|||
: QFrame (parent),
|
||||
m_enable_cb (true),
|
||||
mp_view (view),
|
||||
m_active_index (-1),
|
||||
m_split_mode (false),
|
||||
m_do_update_content_dm (this, &LibrariesView::do_update_content),
|
||||
m_do_full_update_content_dm (this, &LibrariesView::do_full_update_content)
|
||||
|
|
|
|||
|
|
@ -772,10 +772,7 @@ NetlistBrowserDialog::update_content ()
|
|||
m_reload_action->setEnabled (l2ndb != 0);
|
||||
|
||||
browser_page->enable_updates (false); // Avoid building the internal lists several times ...
|
||||
if (browser_page->db () != l2ndb) {
|
||||
db_changed = true;
|
||||
browser_page->set_db (l2ndb);
|
||||
}
|
||||
db_changed = browser_page->set_db (l2ndb);
|
||||
browser_page->set_max_shape_count (m_max_shape_count);
|
||||
browser_page->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0);
|
||||
browser_page->set_window (m_window, m_window_dim);
|
||||
|
|
|
|||
|
|
@ -1598,7 +1598,7 @@ db::NetlistCrossReference::Status
|
|||
CircuitItemData::status (NetlistBrowserModel *model)
|
||||
{
|
||||
size_t index = model->indexer ()->circuit_index (m_cp);
|
||||
return model->indexer ()->circuit_from_index (index).second;
|
||||
return model->indexer ()->circuit_from_index (index).second.first;
|
||||
}
|
||||
|
||||
CircuitNetItemData *
|
||||
|
|
@ -1938,7 +1938,7 @@ CircuitNetItemData::status (NetlistBrowserModel *model)
|
|||
{
|
||||
if (m_np.first || m_np.second) {
|
||||
size_t index = model->indexer ()->net_index (m_np);
|
||||
return model->indexer ()->net_from_index (circuits (), index).second;
|
||||
return model->indexer ()->net_from_index (circuits (), index).second.first;
|
||||
} else {
|
||||
return db::NetlistCrossReference::None;
|
||||
}
|
||||
|
|
@ -2016,7 +2016,7 @@ CircuitNetDeviceTerminalItemData::tooltip (NetlistBrowserModel *model)
|
|||
db::NetlistCrossReference::Status
|
||||
CircuitNetDeviceTerminalItemData::status (NetlistBrowserModel *model)
|
||||
{
|
||||
return model->indexer ()->device_from_index (circuits (), model->indexer ()->device_index (dp ())).second;
|
||||
return model->indexer ()->device_from_index (circuits (), model->indexer ()->device_index (dp ())).second.first;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
|
@ -2113,7 +2113,7 @@ CircuitNetSubCircuitPinItemData::tooltip (NetlistBrowserModel *model)
|
|||
db::NetlistCrossReference::Status
|
||||
CircuitNetSubCircuitPinItemData::status (NetlistBrowserModel *model)
|
||||
{
|
||||
return model->indexer ()->subcircuit_from_index (parent ()->circuits (), model->indexer ()->subcircuit_index (subcircuits ())).second;
|
||||
return model->indexer ()->subcircuit_from_index (parent ()->circuits (), model->indexer ()->subcircuit_index (subcircuits ())).second.first;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
|
@ -2272,7 +2272,7 @@ db::NetlistCrossReference::Status
|
|||
CircuitSubCircuitItemData::status (NetlistBrowserModel *model)
|
||||
{
|
||||
size_t index = model->indexer ()->subcircuit_index (sp ());
|
||||
return model->indexer ()->subcircuit_from_index (circuits (), index).second;
|
||||
return model->indexer ()->subcircuit_from_index (circuits (), index).second.first;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
|
@ -2371,7 +2371,7 @@ db::NetlistCrossReference::Status
|
|||
CircuitDeviceItemData::status (NetlistBrowserModel *model)
|
||||
{
|
||||
size_t index = model->indexer ()->device_index (m_dp);
|
||||
return model->indexer ()->device_from_index (circuits (), index).second;
|
||||
return model->indexer ()->device_from_index (circuits (), index).second.first;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/)
|
|||
mp_view (0),
|
||||
m_cv_index (0),
|
||||
mp_plugin_root (0),
|
||||
mp_last_db (0),
|
||||
m_history_ptr (0),
|
||||
m_signals_enabled (true),
|
||||
m_enable_updates (true),
|
||||
|
|
@ -606,7 +607,7 @@ NetlistBrowserPage::rerun_macro ()
|
|||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
if (! mp_database->generator ().empty ()) {
|
||||
if (mp_database.get () && ! mp_database->generator ().empty ()) {
|
||||
|
||||
std::map<std::string, tl::Variant> add_pars;
|
||||
|
||||
|
|
@ -764,12 +765,14 @@ NetlistBrowserPage::show_all (bool f)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
|
||||
{
|
||||
if (l2ndb == mp_database.get ()) {
|
||||
// NOTE: mp_last_db mirrors mp_database, but does not automatically fall back to 0 when the DB is deleted. This way we can call
|
||||
// set_db(0) with the correct behavior after the DB has been destroyed.
|
||||
if (l2ndb == mp_last_db) {
|
||||
// not change
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mp_info_dialog) {
|
||||
|
|
@ -779,6 +782,7 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
|
|||
|
||||
db::LayoutVsSchematic *lvsdb = dynamic_cast<db::LayoutVsSchematic *> (l2ndb);
|
||||
mp_database.reset (l2ndb);
|
||||
mp_last_db = l2ndb;
|
||||
|
||||
rerun_button->setEnabled (mp_database.get () && ! mp_database->generator ().empty ());
|
||||
if (rerun_button->isEnabled ()) {
|
||||
|
|
@ -800,13 +804,15 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb)
|
|||
show_xref->setChecked (lvsdb != 0);
|
||||
m_signals_enabled = se;
|
||||
|
||||
clear_markers ();
|
||||
clear_highlights ();
|
||||
|
||||
m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0);
|
||||
|
||||
setup_trees ();
|
||||
|
||||
selection_changed_event ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -892,6 +898,15 @@ NetlistBrowserPage::setup_trees ()
|
|||
find_text->setText (QString ());
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::clear_highlights ()
|
||||
{
|
||||
m_current_path = lay::NetlistObjectsPath ();
|
||||
m_selected_paths.clear ();
|
||||
|
||||
update_highlights ();
|
||||
}
|
||||
|
||||
void
|
||||
NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std::vector<NetlistObjectsPath> &selected_paths)
|
||||
{
|
||||
|
|
@ -900,9 +915,8 @@ NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std
|
|||
m_current_path = current_path;
|
||||
m_selected_paths = selected_paths;
|
||||
|
||||
clear_markers ();
|
||||
adjust_view ();
|
||||
update_highlights ();
|
||||
adjust_view ();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public:
|
|||
/**
|
||||
* @brief Attaches the page to a L2N DB
|
||||
*/
|
||||
void set_db (db::LayoutToNetlist *database);
|
||||
bool set_db(db::LayoutToNetlist *database);
|
||||
|
||||
/**
|
||||
* @brief Gets the database the page is connected to
|
||||
|
|
@ -228,6 +228,7 @@ private:
|
|||
unsigned int m_cv_index;
|
||||
lay::Dispatcher *mp_plugin_root;
|
||||
tl::weak_ptr<db::LayoutToNetlist> mp_database;
|
||||
db::LayoutToNetlist *mp_last_db;
|
||||
std::vector<QModelIndex> m_history;
|
||||
size_t m_history_ptr;
|
||||
bool m_signals_enabled;
|
||||
|
|
@ -247,6 +248,7 @@ private:
|
|||
void adjust_view ();
|
||||
void clear_markers ();
|
||||
void highlight (const NetlistObjectsPath ¤t_path, const std::vector<NetlistObjectsPath> &selected_paths);
|
||||
void clear_highlights ();
|
||||
std::vector<const db::Net *> selected_nets ();
|
||||
std::vector<const db::Device *> selected_devices ();
|
||||
std::vector<const db::SubCircuit *> selected_subcircuits ();
|
||||
|
|
|
|||
|
|
@ -204,10 +204,10 @@ NetlistBrowserTreeModel::search_text (const QModelIndex &index) const
|
|||
return tl::to_qstring (search_string_from_names (circuits));
|
||||
}
|
||||
|
||||
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status>
|
||||
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> >
|
||||
NetlistBrowserTreeModel::cp_status_from_index (const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const
|
||||
{
|
||||
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status> cp_status;
|
||||
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp_status;
|
||||
|
||||
void *id = index.internalPointer ();
|
||||
tl_assert (id != 0);
|
||||
|
|
@ -251,7 +251,7 @@ NetlistBrowserTreeModel::build_circuits_to_index (size_t nprod, const std::pair<
|
|||
size_t child_nprod = nprod * (count + 1);
|
||||
|
||||
for (size_t n = count; n > 0; ) {
|
||||
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, IndexedNetlistModel::Status> cp = mp_indexer->child_circuit_from_index (circuits, n - 1);
|
||||
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp = mp_indexer->child_circuit_from_index (circuits, n - 1);
|
||||
QModelIndex child_index = createIndex (int (n - 1), 0, reinterpret_cast<void *> (size_t (index.internalPointer ()) + nprod * n));
|
||||
build_circuits_to_index (child_nprod, cp.first, model, child_index, map);
|
||||
--n;
|
||||
|
|
@ -304,7 +304,7 @@ NetlistBrowserTreeModel::index_from_circuits (const std::pair<const db::Circuit
|
|||
|
||||
size_t count = mp_indexer->top_circuit_count ();
|
||||
for (size_t n = count; n > 0; ) {
|
||||
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, IndexedNetlistModel::Status> cp = mp_indexer->top_circuit_from_index (n - 1);
|
||||
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp = mp_indexer->top_circuit_from_index (n - 1);
|
||||
build_circuits_to_index (count + 1, cp.first, mp_indexer.get (), createIndex (int (n - 1), 0, reinterpret_cast<void *> (n)), m_circuits_to_index);
|
||||
--n;
|
||||
}
|
||||
|
|
@ -324,13 +324,13 @@ db::NetlistCrossReference::Status
|
|||
NetlistBrowserTreeModel::status (const QModelIndex &index) const
|
||||
{
|
||||
size_t nprod = 0, nlast = 0, nnlast = 0;
|
||||
return cp_status_from_index (index, nprod, nlast, nnlast).second;
|
||||
return cp_status_from_index (index, nprod, nlast, nnlast).second.first;
|
||||
}
|
||||
|
||||
QVariant
|
||||
NetlistBrowserTreeModel::tooltip (const QModelIndex &index) const
|
||||
{
|
||||
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status> cp_status;
|
||||
typedef std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp_status;
|
||||
size_t nlast = 0;
|
||||
std::string hint;
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ private:
|
|||
QVariant tooltip (const QModelIndex &index) const;
|
||||
QString search_text (const QModelIndex &index) const;
|
||||
db::NetlistCrossReference::Status status (const QModelIndex &index) const;
|
||||
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, db::NetlistCrossReference::Status> cp_status_from_index (const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const;
|
||||
std::pair<std::pair<const db::Circuit *, const db::Circuit *>, std::pair<db::NetlistCrossReference::Status, std::string> > cp_status_from_index(const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const;
|
||||
void build_circuits_to_index (size_t nprod, const std::pair<const db::Circuit *, const db::Circuit *> &circuits, IndexedNetlistModel *model, const QModelIndex &index, std::map<std::pair<const db::Circuit *, const db::Circuit *>, QModelIndex> &map) const;
|
||||
|
||||
db::LayoutToNetlist *mp_l2ndb;
|
||||
|
|
|
|||
|
|
@ -263,39 +263,39 @@ IndexedNetlistModel::circuit_pair NetlistCrossReferenceModel::parent_of (const I
|
|||
return get_parent_of (subcircuit_pair, mp_cross_ref.get (), m_parents_of_subcircuits);
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::top_circuit_from_index (size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::top_circuit_from_index (size_t index) const
|
||||
{
|
||||
build_top_circuit_list (mp_cross_ref.get (), m_top_level_circuits);
|
||||
|
||||
IndexedNetlistModel::circuit_pair cp = m_top_level_circuits [index];
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (cp, data->status);
|
||||
return std::make_pair (cp, std::make_pair (data->status, data->msg));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
build_child_circuit_map (mp_cross_ref.get (), m_child_circuits);
|
||||
|
||||
IndexedNetlistModel::circuit_pair cp = m_child_circuits [circuits][index];
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (cp, data->status);
|
||||
return std::make_pair (cp, std::make_pair (data->status, data->msg));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::circuit_from_index (size_t index) const
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::circuit_from_index (size_t index) const
|
||||
{
|
||||
IndexedNetlistModel::circuit_pair cp = mp_cross_ref->begin_circuits () [index];
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (cp, data->status);
|
||||
return std::make_pair (cp, std::make_pair (data->status, data->msg));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::net_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::net_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::net_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::net_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (data->nets [index].pair, data->nets [index].status);
|
||||
return std::make_pair (data->nets [index].pair, std::make_pair (data->nets [index].status, data->nets [index].msg));
|
||||
}
|
||||
|
||||
const db::Net *NetlistCrossReferenceModel::second_net_for (const db::Net *first) const
|
||||
|
|
@ -484,25 +484,25 @@ IndexedNetlistModel::net_pin_pair NetlistCrossReferenceModel::net_pinref_from_in
|
|||
return data->pins [index];
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::device_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::device_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::device_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::device_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (data->devices [index].pair, data->devices [index].status);
|
||||
return std::make_pair (data->devices [index].pair, std::make_pair (data->devices [index].status, data->devices [index].msg));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::pin_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::pin_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::pin_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::pin_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (data->pins [index].pair, data->pins [index].status);
|
||||
return std::make_pair (data->pins [index].pair, std::make_pair (data->pins [index].status, data->pins [index].msg));
|
||||
}
|
||||
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, NetlistCrossReferenceModel::Status> NetlistCrossReferenceModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > NetlistCrossReferenceModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits);
|
||||
tl_assert (data != 0);
|
||||
return std::make_pair (data->subcircuits [index].pair, data->subcircuits [index].status);
|
||||
return std::make_pair (data->subcircuits [index].pair, std::make_pair (data->subcircuits [index].status, data->subcircuits [index].msg));
|
||||
}
|
||||
|
||||
template <class Pair, class Iter>
|
||||
|
|
@ -609,27 +609,37 @@ size_t NetlistCrossReferenceModel::subcircuit_index (const subcircuit_pair &subc
|
|||
return get_index_of (subcircuits, org_data->subcircuits.begin (), org_data->subcircuits.end (), data->index_of_subcircuits);
|
||||
}
|
||||
|
||||
std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> &cps) const
|
||||
std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > &cps) const
|
||||
{
|
||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||
std::string msg;
|
||||
|
||||
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
|
||||
if (! cps.first.first || ! cps.first.second) {
|
||||
return tl::to_string (tr ("No matching circuit found in the other netlist.\n"
|
||||
"By default, circuits are identified by their name.\n"
|
||||
"A missing circuit probably means there is no circuit in the other netlist with this name.\n"
|
||||
"If circuits with different names need to be associated, use 'same_circuits' in the\n"
|
||||
"LVS script to establish such an association."));
|
||||
msg = tl::to_string (tr ("No matching circuit found in the other netlist.\n"
|
||||
"By default, circuits are identified by their name.\n"
|
||||
"A missing circuit probably means there is no circuit in the other netlist with this name.\n"
|
||||
"If circuits with different names need to be associated, use 'same_circuits' in the\n"
|
||||
"LVS script to establish such an association."));
|
||||
} else {
|
||||
return tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n"
|
||||
"Browse the circuit's component list to identify the mismatching elements."));
|
||||
msg = tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n"
|
||||
"Browse the circuit's component list to identify the mismatching elements."));
|
||||
}
|
||||
} else if (cps.second == db::NetlistCrossReference::Skipped) {
|
||||
return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n"
|
||||
"pin-to-pin correspondence could be established for each child circuit.\n"
|
||||
"This is not the case here. Browse the child circuits to identify the blockers.\n"
|
||||
"Potential blockers are subcircuits without a corresponding other circuit or circuits\n"
|
||||
"where some pins could not be mapped to pins from the corresponding other circuit."));
|
||||
} else if (cps.second.first == db::NetlistCrossReference::Skipped) {
|
||||
msg = tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n"
|
||||
"pin-to-pin correspondence could be established for each child circuit.\n"
|
||||
"This is not the case here. Browse the child circuits to identify the blockers.\n"
|
||||
"Potential blockers are subcircuits without a corresponding other circuit or circuits\n"
|
||||
"where some pins could not be mapped to pins from the corresponding other circuit."));
|
||||
}
|
||||
return std::string ();
|
||||
|
||||
if (! cps.second.second.empty ()) {
|
||||
if (! msg.empty ()) {
|
||||
msg += "\n\n";
|
||||
}
|
||||
msg += cps.second.second;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string NetlistCrossReferenceModel::top_circuit_status_hint (size_t index) const
|
||||
|
|
@ -644,94 +654,149 @@ std::string NetlistCrossReferenceModel::circuit_status_hint (size_t index) const
|
|||
|
||||
std::string NetlistCrossReferenceModel::child_circuit_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
std::pair<IndexedNetlistModel::circuit_pair, NetlistCrossReferenceModel::Status> cps = child_circuit_from_index (circuits, index);
|
||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::circuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = child_circuit_from_index (circuits, index);
|
||||
|
||||
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
|
||||
if (!cps.first.first || !cps.first.second) {
|
||||
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin\n"
|
||||
"assignment could not be derived from the nets connected to the pins.\n"
|
||||
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
|
||||
"'equivalent_pins' in the LVS script."));
|
||||
msg = tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin\n"
|
||||
"assignment could not be derived from the nets connected to the pins.\n"
|
||||
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
|
||||
"'equivalent_pins' in the LVS script."));
|
||||
} else {
|
||||
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n"
|
||||
"originating from equivalent circuits.\n"
|
||||
"If the circuits behind the subcircuits are identical, using 'same_circuits'\n"
|
||||
"in the LVS script will associate them."));
|
||||
msg = tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n"
|
||||
"originating from equivalent circuits.\n"
|
||||
"If the circuits behind the subcircuits are identical, using 'same_circuits'\n"
|
||||
"in the LVS script will associate them."));
|
||||
}
|
||||
}
|
||||
return std::string ();
|
||||
|
||||
if (! cps.second.second.empty ()) {
|
||||
if (! msg.empty ()) {
|
||||
msg += "\n\n";
|
||||
}
|
||||
msg += cps.second.second;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string NetlistCrossReferenceModel::net_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
std::pair<IndexedNetlistModel::net_pair, NetlistCrossReferenceModel::Status> cps = net_from_index (circuits, index);
|
||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||
return tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n"
|
||||
"counterpart in the other netlist (component-wise and pin/terminal-wise).\n"
|
||||
"If there already is a net candidate from the other netlist, scan the net members for\n"
|
||||
"mismatching items (with errors or warnings) and fix these issues.\n"
|
||||
"Otherwise, look for the corresponding other net.\n"
|
||||
"Net items not found in the reference netlist indicate additional connections.\n"
|
||||
"Net items only found in the reference netlist indicate missing connections."));
|
||||
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) {
|
||||
return tl::to_string (tr ("Nets match, but the choice was ambiguous. This may lead to mismatching nets in other places.\n"));
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::net_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = net_from_index (circuits, index);
|
||||
|
||||
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
|
||||
msg = tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n"
|
||||
"counterpart in the other netlist (component-wise and pin/terminal-wise).\n"
|
||||
"If there already is a net candidate from the other netlist, scan the net members for\n"
|
||||
"mismatching items (with errors or warnings) and fix these issues.\n"
|
||||
"Otherwise, look for the corresponding other net.\n"
|
||||
"Net items not found in the reference netlist indicate additional connections.\n"
|
||||
"Net items only found in the reference netlist indicate missing connections."));
|
||||
} else if (cps.second.first == db::NetlistCrossReference::MatchWithWarning) {
|
||||
msg = tl::to_string (tr ("Nets match, but the choice was ambiguous. This may lead to mismatching nets in other places.\n"));
|
||||
}
|
||||
return std::string ();
|
||||
|
||||
if (! cps.second.second.empty ()) {
|
||||
if (! msg.empty ()) {
|
||||
msg += "\n\n";
|
||||
}
|
||||
msg += cps.second.second;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
std::pair<IndexedNetlistModel::device_pair, NetlistCrossReferenceModel::Status> cps = device_from_index (circuits, index);
|
||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::device_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = device_from_index (circuits, index);
|
||||
|
||||
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
|
||||
if (!cps.first.first || !cps.first.second) {
|
||||
return tl::to_string (tr ("No matching device was found in the other netlist.\n"
|
||||
"Devices are identified by the nets they are attached to. Unmatched devices mean that\n"
|
||||
"at least one terminal net isn't matched with a corresponding net from the other netlist.\n"
|
||||
"Make all terminal nets match and the devices will match too."));
|
||||
msg = tl::to_string (tr ("No matching device was found in the other netlist.\n"
|
||||
"Devices are identified by the nets they are attached to. Unmatched devices mean that\n"
|
||||
"at least one terminal net isn't matched with a corresponding net from the other netlist.\n"
|
||||
"Make all terminal nets match and the devices will match too."));
|
||||
} else {
|
||||
return tl::to_string (tr ("Devices don't match topologically.\n"
|
||||
"Check the terminal connections to identify the terminals not being connected to\n"
|
||||
"corresponding nets. Either the devices are not connected correctly or the nets\n"
|
||||
"need to be fixed before the devices will match too."));
|
||||
msg = tl::to_string (tr ("Devices don't match topologically.\n"
|
||||
"Check the terminal connections to identify the terminals not being connected to\n"
|
||||
"corresponding nets. Either the devices are not connected correctly or the nets\n"
|
||||
"need to be fixed before the devices will match too."));
|
||||
}
|
||||
} else if (cps.second == db::NetlistCrossReference::MatchWithWarning) {
|
||||
return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n"
|
||||
"device classes don't match.\n"
|
||||
"If the device class is different but should be considered the same, using\n"
|
||||
"'same_device_classed' in the LVS script will solve this issue."));
|
||||
} else if (cps.second.first == db::NetlistCrossReference::MatchWithWarning) {
|
||||
msg = tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n"
|
||||
"device classes don't match.\n"
|
||||
"If the device class is different but should be considered the same, using\n"
|
||||
"'same_device_classed' in the LVS script will solve this issue."));
|
||||
}
|
||||
return std::string ();
|
||||
|
||||
if (! cps.second.second.empty ()) {
|
||||
if (! msg.empty ()) {
|
||||
msg += "\n\n";
|
||||
}
|
||||
msg += cps.second.second;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string NetlistCrossReferenceModel::pin_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
std::pair<IndexedNetlistModel::pin_pair, NetlistCrossReferenceModel::Status> cps = pin_from_index (circuits, index);
|
||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::pin_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = pin_from_index (circuits, index);
|
||||
|
||||
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
|
||||
if (!cps.first.first || !cps.first.second) {
|
||||
return tl::to_string (tr ("No matching pin was found in the other netlist.\n"
|
||||
"Pins are identified by the nets they are attached to - pins on equivalent nets are also\n"
|
||||
"equivalent. Making the nets match will make the pins match too."));
|
||||
msg = tl::to_string (tr ("No matching pin was found in the other netlist.\n"
|
||||
"Pins are identified by the nets they are attached to - pins on equivalent nets are also\n"
|
||||
"equivalent. Making the nets match will make the pins match too."));
|
||||
}
|
||||
}
|
||||
return std::string ();
|
||||
|
||||
if (! cps.second.second.empty ()) {
|
||||
if (! msg.empty ()) {
|
||||
msg += "\n\n";
|
||||
}
|
||||
msg += cps.second.second;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::string NetlistCrossReferenceModel::subcircuit_status_hint (const circuit_pair &circuits, size_t index) const
|
||||
{
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, NetlistCrossReferenceModel::Status> cps = subcircuit_from_index (circuits, index);
|
||||
if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) {
|
||||
std::string msg;
|
||||
|
||||
std::pair<IndexedNetlistModel::subcircuit_pair, std::pair<NetlistCrossReferenceModel::Status, std::string> > cps = subcircuit_from_index (circuits, index);
|
||||
|
||||
if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) {
|
||||
if (!cps.first.first || !cps.first.second) {
|
||||
return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment\n"
|
||||
"could not be derived from the nets connected to the pins.\n"
|
||||
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
|
||||
"'equivalent_pins' in the LVS script."));
|
||||
msg = tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment\n"
|
||||
"could not be derived from the nets connected to the pins.\n"
|
||||
"Check, if the pins are attached properly. If pins need to be swappable, consider using\n"
|
||||
"'equivalent_pins' in the LVS script."));
|
||||
} else {
|
||||
return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n"
|
||||
"equivalent circuits.\n"
|
||||
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n"
|
||||
"will associate them."));
|
||||
msg = tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n"
|
||||
"equivalent circuits.\n"
|
||||
"If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n"
|
||||
"will associate them."));
|
||||
}
|
||||
}
|
||||
return std::string ();
|
||||
|
||||
if (! cps.second.second.empty ()) {
|
||||
if (! msg.empty ()) {
|
||||
msg += "\n\n";
|
||||
}
|
||||
msg += cps.second.second;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,24 +59,24 @@ public:
|
|||
virtual circuit_pair parent_of (const device_pair &device_pair) const;
|
||||
virtual circuit_pair parent_of (const subcircuit_pair &subcircuit_pair) const;
|
||||
|
||||
virtual std::pair<circuit_pair, Status> top_circuit_from_index (size_t index) const;
|
||||
virtual std::pair<circuit_pair, Status> circuit_from_index (size_t index) const;
|
||||
virtual std::pair<circuit_pair, Status> child_circuit_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<net_pair, Status> net_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > top_circuit_from_index(size_t index) const;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > circuit_from_index (size_t index) const;
|
||||
virtual std::pair<circuit_pair, std::pair<Status, std::string> > child_circuit_from_index(const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<net_pair, std::pair<Status, std::string> > net_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual const db::Net *second_net_for (const db::Net *first) const;
|
||||
virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const;
|
||||
virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &nets, size_t index) const;
|
||||
virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const;
|
||||
virtual std::pair<device_pair, Status> device_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<pin_pair, Status> pin_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<subcircuit_pair, Status> subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<device_pair, std::pair<Status, std::string> > device_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<pin_pair, std::pair<Status, std::string> > pin_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::pair<subcircuit_pair, std::pair<Status, std::string> > subcircuit_from_index (const circuit_pair &circuits, size_t index) const;
|
||||
|
||||
virtual std::string top_circuit_status_hint (size_t index) const;
|
||||
virtual std::string circuit_status_hint (size_t index) const;
|
||||
virtual std::string child_circuit_status_hint (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, Status> &cp) const;
|
||||
virtual std::string circuit_pair_status_hint (const std::pair<circuit_pair, std::pair<Status, std::string> > &cp) const;
|
||||
virtual std::string net_status_hint (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::string device_status_hint (const circuit_pair &circuits, size_t index) const;
|
||||
virtual std::string pin_status_hint (const circuit_pair &circuits, size_t index) const;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
|
||||
#include "layProperties.h"
|
||||
#include "layEditable.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#define HDR_layProperties
|
||||
|
||||
#include "laybasicCommon.h"
|
||||
#include "layEditable.h"
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
|
|
@ -209,7 +210,7 @@ public:
|
|||
*/
|
||||
lay::Editable *editable ()
|
||||
{
|
||||
return mp_editable;
|
||||
return mp_editable.get ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -229,7 +230,7 @@ signals:
|
|||
|
||||
private:
|
||||
db::Manager *mp_manager;
|
||||
lay::Editable *mp_editable;
|
||||
tl::weak_ptr<lay::Editable> mp_editable;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,39 +17,52 @@
|
|||
<text>
|
||||
module LVS
|
||||
|
||||
def self.execute_lvs(macro, generator, l2ndb_index = nil)
|
||||
class LVSExecutable < RBA::Executable
|
||||
|
||||
timer = RBA::Timer::new
|
||||
timer.start
|
||||
lvs = LVSEngine::new
|
||||
lvs._l2ndb_index = l2ndb_index
|
||||
lvs._generator = generator
|
||||
def initialize(macro, generator, l2ndb_index = nil)
|
||||
|
||||
begin
|
||||
@lvs = LVSEngine::new
|
||||
@lvs._l2ndb_index = l2ndb_index
|
||||
@lvs._generator = generator
|
||||
|
||||
# Set a debugger scope so that our errors end up with the debugger set to the LVS's line
|
||||
RBA::MacroExecutionContext::set_debugger_scope(macro.path)
|
||||
# No verbosity set in lvs engine - we cannot use the engine's logger
|
||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{macro.path}")
|
||||
lvs.instance_eval(macro.text, macro.path)
|
||||
# Remove the debugger scope
|
||||
RBA::MacroExecutionContext::remove_debugger_scope
|
||||
|
||||
rescue => ex
|
||||
|
||||
lvs.error("In #{macro.path}: #{ex.to_s}")
|
||||
RBA::MacroExecutionContext::ignore_next_exception
|
||||
raise ex
|
||||
|
||||
ensure
|
||||
|
||||
# cleans up and creates layout and report views
|
||||
lvs._finish
|
||||
@macro = macro
|
||||
|
||||
end
|
||||
|
||||
timer.stop
|
||||
lvs.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s")
|
||||
def execute
|
||||
|
||||
@lvs._start("LVS: " + @macro.path)
|
||||
|
||||
# Set a debugger scope so that our errors end up with the debugger set to the LVS's line
|
||||
RBA::MacroExecutionContext::set_debugger_scope(@macro.path)
|
||||
|
||||
begin
|
||||
|
||||
# No verbosity set in lvs engine - we cannot use the engine's logger
|
||||
RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}")
|
||||
@lvs.instance_eval(@macro.text, @macro.path)
|
||||
|
||||
rescue => ex
|
||||
|
||||
@lvs.error("In #{@macro.path}: #{ex.to_s}")
|
||||
RBA::MacroExecutionContext::ignore_next_exception
|
||||
raise ex
|
||||
|
||||
end
|
||||
|
||||
nil
|
||||
|
||||
end
|
||||
|
||||
def cleanup
|
||||
|
||||
# Remove the debugger scope
|
||||
RBA::MacroExecutionContext::remove_debugger_scope
|
||||
|
||||
# cleans up and creates layout and report views
|
||||
@lvs._finish
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -83,8 +96,8 @@ module LVS
|
|||
end
|
||||
|
||||
# Implements the execute method
|
||||
def execute(macro)
|
||||
LVS::execute_lvs(macro, @recipe.generator("script" => macro.path))
|
||||
def executable(macro)
|
||||
LVSExecutable::new(macro, @recipe.generator("script" => macro.path))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -110,8 +123,8 @@ module LVS
|
|||
end
|
||||
|
||||
# Implements the execute method
|
||||
def execute(macro)
|
||||
LVS::execute_lvs(macro, @recipe.generator("script" => macro.path))
|
||||
def executable(macro)
|
||||
LVSExecutable::new(macro, @recipe.generator("script" => macro.path))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -123,7 +136,7 @@ module LVS
|
|||
super("lvs", "LVS recipe")
|
||||
end
|
||||
|
||||
def execute(params)
|
||||
def executable(params)
|
||||
|
||||
script = params["script"]
|
||||
if ! script
|
||||
|
|
@ -133,7 +146,7 @@ module LVS
|
|||
macro = RBA::Macro::macro_by_path(script)
|
||||
macro || raise("Can't find LVS script #{script} - unable to re-run")
|
||||
|
||||
LVS::execute_lvs(macro, self.generator("script" => script), params["l2ndb_index"])
|
||||
LVSExecutable::new(macro, self.generator("script" => script), params["l2ndb_index"])
|
||||
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
#include "lymMacro.h"
|
||||
#include "tlFileUtils.h"
|
||||
|
||||
void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string &au_netlist, const std::string &layout, bool priv = false)
|
||||
void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string &au_netlist, const std::string &layout, bool priv = false, const std::string &au_lvsdb_name = std::string ())
|
||||
{
|
||||
std::string testsrc = priv ? tl::testsrc_private () : tl::testsrc ();
|
||||
testsrc = tl::combine_path (tl::combine_path (testsrc, "testdata"), "lvs");
|
||||
|
|
@ -88,6 +88,11 @@ void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string
|
|||
tl::info << " golden: " << au_cir;
|
||||
}
|
||||
EXPECT_EQ (res, true);
|
||||
|
||||
if (! au_lvsdb_name.empty ()) {
|
||||
std::string au_lvsdb = tl::combine_path (testsrc, au_lvsdb_name);
|
||||
_this->compare_text_files (output_lvsdb, au_lvsdb);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(1_full)
|
||||
|
|
@ -143,3 +148,9 @@ TEST(16_private)
|
|||
// test_is_long_runner ();
|
||||
run_test (_this, "test_16.lvs", "test_16.cir.gz", "test_16.gds.gz", true);
|
||||
}
|
||||
|
||||
TEST(17_private)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
run_test (_this, "test_17.lylvs", "test_17.cir.gz", "test_17.gds.gz", true, "test_17.lvsdb");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,10 +142,12 @@ public:
|
|||
m_name = name;
|
||||
}
|
||||
|
||||
virtual void execute (const lym::Macro *macro) const
|
||||
virtual tl::Executable *executable (const lym::Macro *macro) const
|
||||
{
|
||||
if (f_execute.can_issue ()) {
|
||||
f_execute.issue<MacroInterpreter, const lym::Macro *> (&MacroInterpreter::execute, macro);
|
||||
if (f_executable.can_issue ()) {
|
||||
return f_executable.issue<MacroInterpreter, tl::Executable *, const lym::Macro *> (&MacroInterpreter::executable, macro);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -240,7 +242,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
gsi::Callback f_execute;
|
||||
gsi::Callback f_executable;
|
||||
|
||||
private:
|
||||
tl::RegisteredClass <lym::MacroInterpreter> *mp_registration;
|
||||
|
|
@ -307,7 +309,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
|
|||
) +
|
||||
gsi::method ("create_template", &MacroInterpreter::create_template, gsi::arg ("url"),
|
||||
"@brief Creates a new macro template\n"
|
||||
"@url The template will be initialized from that URL.\n"
|
||||
"@param url The template will be initialized from that URL.\n"
|
||||
"\n"
|
||||
"This method will create a register a new macro template. It returns a \\Macro object which "
|
||||
"can be modified in order to adjust the template (for example to set description, add a content, "
|
||||
|
|
@ -378,13 +380,15 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
|
|||
"Before version 0.25 this attribute was a reimplementable method. It has been turned into an attribute for "
|
||||
"performance reasons in version 0.25.\n"
|
||||
) +
|
||||
gsi::callback ("execute", &gsi::MacroInterpreter::execute, &gsi::MacroInterpreter::f_execute, gsi::arg ("macro"),
|
||||
"@brief Gets called to execute a macro\n"
|
||||
"This method must be reimplemented to execute the macro. "
|
||||
"The system will call this script when a macro with interpreter type 'dsl' and the "
|
||||
"name of this interpreter is run."
|
||||
gsi::callback ("executable", &gsi::MacroInterpreter::executable, &gsi::MacroInterpreter::f_executable, gsi::arg ("macro"),
|
||||
"@brief Returns the executable object which implements the macro execution\n"
|
||||
"This method must be reimplemented to return an \\Executable object for the actual implementation. "
|
||||
"The system will use this function to execute the script when a macro with interpreter type 'dsl' and the "
|
||||
"name of this interpreter is run.\n"
|
||||
"\n"
|
||||
"@param macro The macro to execute\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27 and replaces the 'execute' method.\n"
|
||||
),
|
||||
"@brief A custom interpreter for a DSL (domain specific language)\n"
|
||||
"\n"
|
||||
|
|
@ -413,6 +417,21 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
|
|||
"just evaluates the script text:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"class SimpleExecutable < RBA::Excutable\n"
|
||||
"\n"
|
||||
" # Constructor\n"
|
||||
" def initialize(macro)\n"
|
||||
" \\@macro = macro\n"
|
||||
" end\n"
|
||||
" \n"
|
||||
" # Implements the execute method\n"
|
||||
" def execute\n"
|
||||
" eval(\\@macro.text, nil, \\@macro.path)\n"
|
||||
" nil\n"
|
||||
" end\n"
|
||||
"\n"
|
||||
"end\n"
|
||||
"\n"
|
||||
"class SimpleInterpreter < RBA::MacroInterpreter\n"
|
||||
"\n"
|
||||
" # Constructor\n"
|
||||
|
|
@ -427,9 +446,9 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
|
|||
" mt.description = \"Special;;Simple interpreter macro\"\n"
|
||||
" end\n"
|
||||
" \n"
|
||||
" # Implements the execute method\n"
|
||||
" def execute(macro)\n"
|
||||
" eval(macro.text, nil, macro.path)\n"
|
||||
" # Creates the executable delegate\n"
|
||||
" def executable(macro)\n"
|
||||
" SimpleExecutable::new(macro)\n"
|
||||
" end\n"
|
||||
"\n"
|
||||
"end\n"
|
||||
|
|
@ -447,7 +466,7 @@ Class<gsi::MacroInterpreter> decl_MacroInterpreter ("lay", "MacroInterpreter",
|
|||
"\n"
|
||||
"In order to make the above code effective, store the code in an macro, set \"early auto-run\" and restart KLayout.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.23.\n"
|
||||
"This class has been introduced in version 0.23 and modified in 0.27.\n"
|
||||
);
|
||||
|
||||
static lym::Macro *macro_by_path (const std::string &path)
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@
|
|||
namespace lym
|
||||
{
|
||||
|
||||
void
|
||||
MacroInterpreter::execute (const lym::Macro *) const
|
||||
tl::Executable *
|
||||
MacroInterpreter::executable (const lym::Macro *) const
|
||||
{
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("execute() implementation missing for DSL interpreter")));
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("executable() implementation missing for DSL interpreter")));
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -107,7 +107,10 @@ MacroInterpreter::execute_macro (const lym::Macro *macro)
|
|||
std::pair<std::string, std::string> et = cls->include_expansion (macro);
|
||||
if (et.first.empty () || et.first == macro->path ()) {
|
||||
|
||||
cls->execute (macro);
|
||||
std::unique_ptr<tl::Executable> eo (cls->executable (macro));
|
||||
if (eo.get ()) {
|
||||
eo->do_execute ();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -116,7 +119,10 @@ MacroInterpreter::execute_macro (const lym::Macro *macro)
|
|||
tmp_macro.assign (*macro);
|
||||
tmp_macro.set_text (et.second);
|
||||
tmp_macro.set_file_path (et.first);
|
||||
cls->execute (&tmp_macro);
|
||||
std::unique_ptr<tl::Executable> eo (cls->executable (&tmp_macro));
|
||||
if (eo.get ()) {
|
||||
eo->do_execute ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "lymCommon.h"
|
||||
|
||||
#include "tlRecipe.h"
|
||||
#include "gsiObject.h"
|
||||
#include "tlClassRegistry.h"
|
||||
|
||||
|
|
@ -63,11 +64,11 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Executes the macro
|
||||
* @brief Creates the executable for a macro
|
||||
*
|
||||
* This method must be reimplemented to provide the actual execution of the macro.
|
||||
* The caller will delete the returned object.
|
||||
*/
|
||||
virtual void execute (const lym::Macro *macro) const;
|
||||
virtual tl::Executable *executable (const lym::Macro *macro) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the storage scheme
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ public:
|
|||
m_cell_stack.pop_back ();
|
||||
}
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
|
||||
{
|
||||
db::cell_index_type ci = inst.object ().cell_index ();
|
||||
if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) {
|
||||
|
|
@ -156,7 +156,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
tl_assert (! m_cell_stack.empty ());
|
||||
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape);
|
||||
|
|
@ -209,9 +209,9 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void shape (const db::RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * iter->trans (), shape);
|
||||
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * trans, shape);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -49,7 +49,11 @@ ProgressAdaptor::~ProgressAdaptor ()
|
|||
void
|
||||
ProgressAdaptor::register_object (Progress *progress)
|
||||
{
|
||||
bool cancelled = ! mp_objects.empty () && mp_objects.first ()->break_scheduled ();
|
||||
mp_objects.push_back (progress); // this keeps the outmost one visible. push_front would make the latest one visible.
|
||||
if (cancelled) {
|
||||
progress->signal_break ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -130,17 +134,19 @@ ProgressGarbageCollector::~ProgressGarbageCollector ()
|
|||
// store a pointer but a pointer to a pointer.
|
||||
static tl::ThreadStorage<ProgressAdaptor **> s_thread_data;
|
||||
|
||||
Progress::Progress (const std::string &desc, size_t yield_interval)
|
||||
: m_desc (desc),
|
||||
m_final (false),
|
||||
m_title (desc),
|
||||
const double yield_timeout = 0.3;
|
||||
const size_t default_yield_interval = 1000;
|
||||
|
||||
Progress::Progress (const std::string &desc, size_t yield_interval, bool can_cancel)
|
||||
: m_desc (desc), m_title (desc),
|
||||
m_interval_count (0),
|
||||
m_yield_interval (yield_interval),
|
||||
m_yield_interval (yield_interval == 0 ? default_yield_interval : yield_interval),
|
||||
m_last_value (-1.0),
|
||||
m_can_cancel (true),
|
||||
m_cancelled (false)
|
||||
m_can_cancel (can_cancel),
|
||||
m_cancelled (false),
|
||||
m_registered (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
m_last_yield = tl::Clock::current ();
|
||||
}
|
||||
|
||||
Progress::~Progress ()
|
||||
|
|
@ -151,9 +157,19 @@ Progress::~Progress ()
|
|||
void
|
||||
Progress::initialize ()
|
||||
{
|
||||
// The abstract progress does not get test() calls so we need to register it now.
|
||||
ProgressAdaptor *a = adaptor ();
|
||||
if (a) {
|
||||
|
||||
a->register_object (this);
|
||||
m_registered = true;
|
||||
|
||||
// A pending cancel request may immediately kill the operation - "register_object" will set the cancelled flag then.
|
||||
if (m_cancelled) {
|
||||
m_cancelled = false;
|
||||
throw tl::BreakException ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +177,7 @@ void
|
|||
Progress::shutdown ()
|
||||
{
|
||||
ProgressAdaptor *a = adaptor ();
|
||||
if (a) {
|
||||
if (a && m_registered) {
|
||||
a->unregister_object (this);
|
||||
}
|
||||
}
|
||||
|
|
@ -194,29 +210,27 @@ Progress::adaptor ()
|
|||
void
|
||||
Progress::signal_break ()
|
||||
{
|
||||
m_cancelled = true;
|
||||
if (m_can_cancel) {
|
||||
m_cancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Progress::set_desc (const std::string &d)
|
||||
{
|
||||
ProgressAdaptor *a = adaptor ();
|
||||
if (a && d != m_desc) {
|
||||
|
||||
if (d != m_desc) {
|
||||
m_desc = d;
|
||||
a->trigger (this);
|
||||
a->yield (this);
|
||||
|
||||
if (m_cancelled) {
|
||||
m_cancelled = false;
|
||||
throw tl::BreakException ();
|
||||
}
|
||||
|
||||
test (true);
|
||||
}
|
||||
}
|
||||
|
||||
bool Progress::test(bool force_yield)
|
||||
bool Progress::test (bool force_yield)
|
||||
{
|
||||
if (m_cancelled) {
|
||||
m_cancelled = false;
|
||||
throw tl::BreakException ();
|
||||
}
|
||||
|
||||
if (++m_interval_count >= m_yield_interval || force_yield) {
|
||||
|
||||
ProgressAdaptor *a = adaptor ();
|
||||
|
|
@ -228,22 +242,28 @@ bool Progress::test(bool force_yield)
|
|||
needs_trigger = true;
|
||||
}
|
||||
|
||||
if (m_desc != m_last_desc) {
|
||||
m_last_desc = m_desc;
|
||||
needs_trigger = true;
|
||||
}
|
||||
|
||||
m_interval_count = 0;
|
||||
|
||||
if (a) {
|
||||
|
||||
tl::Clock now = tl::Clock::current ();
|
||||
if ((now - m_last_yield).seconds () > 0.1) {
|
||||
if ((now - m_last_yield).seconds () > yield_timeout) {
|
||||
|
||||
m_last_yield = now;
|
||||
|
||||
if (needs_trigger) {
|
||||
a->trigger (this);
|
||||
}
|
||||
a->yield (this);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_cancelled) {
|
||||
m_cancelled = false;
|
||||
throw tl::BreakException ();
|
||||
a->yield (this);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -270,8 +290,8 @@ AbstractProgress::~AbstractProgress ()
|
|||
// ---------------------------------------------------------------------------------------------
|
||||
// RelativeProgress implementation
|
||||
|
||||
RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval)
|
||||
: Progress (desc, yield_interval)
|
||||
RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval, bool can_cancel)
|
||||
: Progress (desc, yield_interval, can_cancel)
|
||||
{
|
||||
m_format = "%.0f%%";
|
||||
m_unit = double (max_count) / 100.0;
|
||||
|
|
@ -315,8 +335,8 @@ RelativeProgress::set (size_t count, bool force_yield)
|
|||
// ---------------------------------------------------------------------------------------------
|
||||
// Progress implementation
|
||||
|
||||
AbsoluteProgress::AbsoluteProgress (const std::string &desc, size_t yield_interval)
|
||||
: Progress (desc, yield_interval)
|
||||
AbsoluteProgress::AbsoluteProgress (const std::string &desc, size_t yield_interval, bool can_cancel)
|
||||
: Progress (desc, yield_interval, can_cancel)
|
||||
{
|
||||
m_format = "%.0f";
|
||||
m_unit = 1.0;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue