|
|
@ -12,6 +12,7 @@ recursive-include src/pymod *.cc *.h
|
|||
recursive-include src/rbastub *.cc *.h
|
||||
recursive-include src/rdb/rdb *.cc *.h
|
||||
recursive-include src/tl/tl *.cc *.h
|
||||
recursive-include src/pymod *.pyi
|
||||
include src/plugins/*/db_plugin/*.cc
|
||||
include src/plugins/*/*/db_plugin/*.cc
|
||||
include src/plugins/*/db_plugin/*.h
|
||||
|
|
|
|||
|
|
@ -600,6 +600,32 @@ run_demo gen, "input1.edges.not(input2)", "drc_not3.png"
|
|||
run_demo gen, "input1.edges.inside_part(input2)", "drc_inside_part.png"
|
||||
run_demo gen, "input1.edges.outside_part(input2)", "drc_outside_part.png"
|
||||
|
||||
class Gen
|
||||
def produce(s1, s2)
|
||||
pts = [
|
||||
RBA::Point::new(0 , 0 ),
|
||||
RBA::Point::new(0 , 3000),
|
||||
RBA::Point::new(2000, 3000),
|
||||
RBA::Point::new(2000, 5000),
|
||||
RBA::Point::new(6000, 5000),
|
||||
RBA::Point::new(6000, 0 )
|
||||
];
|
||||
s1.insert(RBA::Polygon::new(pts))
|
||||
s2.insert(RBA::Box::new(0, 0, 4000, 6000))
|
||||
end
|
||||
end
|
||||
|
||||
gen = Gen::new
|
||||
|
||||
run_demo gen, "input1.edges.inside(input2)", "drc_inside_ep.png"
|
||||
run_demo gen, "input1.edges.inside(input2.edges)", "drc_inside_ee.png"
|
||||
run_demo gen, "input1.edges.not_inside(input2)", "drc_not_inside_ep.png"
|
||||
run_demo gen, "input1.edges.not_inside(input2.edges)", "drc_not_inside_ee.png"
|
||||
run_demo gen, "input1.edges.outside(input2)", "drc_outside_ep.png"
|
||||
run_demo gen, "input1.edges.outside(input2.edges)", "drc_outside_ee.png"
|
||||
run_demo gen, "input1.edges.not_outside(input2)", "drc_not_outside_ep.png"
|
||||
run_demo gen, "input1.edges.not_outside(input2.edges)", "drc_not_outside_ee.png"
|
||||
|
||||
class Gen
|
||||
def produce(s1, s2)
|
||||
s1.insert(RBA::Box::new(-1000, 0, 1000, 2000))
|
||||
|
|
|
|||
2
setup.py
|
|
@ -759,4 +759,6 @@ if __name__ == '__main__':
|
|||
url='https://github.com/klayout/klayout',
|
||||
packages=find_packages('src/pymod/distutils_src'),
|
||||
package_dir={'': 'src/pymod/distutils_src'}, # https://github.com/pypa/setuptools/issues/230
|
||||
package_data={config.root: ["src/pymod/distutils_src/klayout/*.pyi"]},
|
||||
include_package_data=True,
|
||||
ext_modules=[_tl, _gsi, _pya, _rba, _db, _lib, _rdb, _lym, _laybasic, _layview, _ant, _edt, _img] + db_plugins + [tl, db, lib, rdb, lay])
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ PluginDeclaration::get_options (std::vector < std::pair<std::string, std::string
|
|||
options.push_back (std::pair<std::string, std::string> (cfg_ruler_snap_mode, ACConverter ().to_string (lay::AC_Any)));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_ruler_obj_snap, tl::to_string (true)));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_ruler_grid_snap, tl::to_string (false)));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_ruler_templates, ant::TemplatesConverter ().to_string (make_standard_templates ())));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_ruler_templates, std::string ()));
|
||||
options.push_back (std::pair<std::string, std::string> (cfg_current_ruler_template, "0"));
|
||||
// grid-micron is not configured here since some other entity is supposed to do this.
|
||||
}
|
||||
|
|
@ -183,13 +183,10 @@ PluginDeclaration::config_finalize ()
|
|||
if (m_templates_updated) {
|
||||
|
||||
update_menu ();
|
||||
m_templates_updated = false;
|
||||
m_current_template_updated = false;
|
||||
|
||||
} else if (m_current_template_updated) {
|
||||
|
||||
update_current_template ();
|
||||
m_current_template_updated = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -198,21 +195,16 @@ void
|
|||
PluginDeclaration::initialized (lay::Dispatcher *root)
|
||||
{
|
||||
// Check if we already have templates (initial setup)
|
||||
// NOTE: this is not done by using a default value for the configuration item but dynamically.
|
||||
// This provides a migration path from earlier versions (not having templates) to recent ones.
|
||||
bool any_templates = false;
|
||||
for (std::vector<ant::Template>::iterator i = m_templates.begin (); ! any_templates && i != m_templates.end (); ++i) {
|
||||
any_templates = ! i->category ().empty ();
|
||||
}
|
||||
|
||||
if (! any_templates) {
|
||||
|
||||
// This is the migration path from <= 0.24 to 0.25: clear all templates unless we
|
||||
// have categorized ones there. Those can't be deleted, so we know we have a 0.25
|
||||
// setup if there are some
|
||||
m_templates = make_standard_templates ();
|
||||
|
||||
root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (m_templates));
|
||||
root->config_set (cfg_ruler_templates, ant::TemplatesConverter ().to_string (make_standard_templates ()));
|
||||
root->config_end ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -250,6 +242,8 @@ PluginDeclaration::update_current_template ()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
m_current_template_updated = false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -294,6 +288,9 @@ PluginDeclaration::update_menu ()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_templates_updated = false;
|
||||
m_current_template_updated = false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -95,11 +95,11 @@ AsIfFlatEdges::to_string (size_t nmax) const
|
|||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse) const
|
||||
AsIfFlatEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse) const
|
||||
{
|
||||
// shortcuts
|
||||
if (other.empty () || empty ()) {
|
||||
return new EmptyEdges ();
|
||||
return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
|
@ -110,7 +110,7 @@ AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse)
|
|||
scanner.insert1 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressablePolygonDelivery p = other.addressable_polygons ();
|
||||
AddressablePolygonDelivery p = (mode == EdgesInside ? other.addressable_merged_polygons () : other.addressable_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert2 (p.operator-> (), 1);
|
||||
|
|
@ -120,17 +120,17 @@ AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse)
|
|||
|
||||
if (! inverse) {
|
||||
|
||||
edge_to_region_interaction_filter<FlatEdges> filter (*output);
|
||||
edge_to_region_interaction_filter<FlatEdges> filter (output.get (), mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
} else {
|
||||
|
||||
std::set<db::Edge> interacting;
|
||||
edge_to_region_interaction_filter<std::set<db::Edge> > filter (interacting);
|
||||
std::set<db::Edge> result;
|
||||
edge_to_region_interaction_filter<std::set<db::Edge> > filter (&result, mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
|
||||
if (interacting.find (*o) == interacting.end ()) {
|
||||
if (result.find (*o) == result.end ()) {
|
||||
output->insert (*o);
|
||||
}
|
||||
}
|
||||
|
|
@ -141,8 +141,13 @@ AsIfFlatEdges::selected_interacting_generic (const Region &other, bool inverse)
|
|||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) const
|
||||
AsIfFlatEdges::selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const
|
||||
{
|
||||
// shortcuts
|
||||
if (edges.empty () || empty ()) {
|
||||
return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone ();
|
||||
}
|
||||
|
||||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
|
||||
|
|
@ -151,7 +156,8 @@ AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) c
|
|||
scanner.insert (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressableEdgeDelivery ee = edges.addressable_edges ();
|
||||
// NOTE: "inside" needs merged edges for the other edges as the algorithm works edge by edge
|
||||
AddressableEdgeDelivery ee = (mode == EdgesInside ? edges.addressable_merged_edges () : edges.addressable_edges ());
|
||||
|
||||
for ( ; ! ee.at_end (); ++ee) {
|
||||
scanner.insert (ee.operator-> (), 1);
|
||||
|
|
@ -161,17 +167,17 @@ AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) c
|
|||
|
||||
if (! inverse) {
|
||||
|
||||
edge_interaction_filter<FlatEdges> filter (*output);
|
||||
edge_interaction_filter<FlatEdges> filter (*output, mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
} else {
|
||||
|
||||
std::set<db::Edge> interacting;
|
||||
edge_interaction_filter<std::set<db::Edge> > filter (interacting);
|
||||
std::set<db::Edge> result;
|
||||
edge_interaction_filter<std::set<db::Edge> > filter (result, mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
|
||||
if (interacting.find (*o) == interacting.end ()) {
|
||||
if (result.find (*o) == result.end ()) {
|
||||
output->insert (*o);
|
||||
}
|
||||
}
|
||||
|
|
@ -181,6 +187,95 @@ AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) c
|
|||
return output.release ();
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode) const
|
||||
{
|
||||
// shortcuts
|
||||
if (region.empty () || empty ()) {
|
||||
if (mode != EdgesOutside) {
|
||||
return std::make_pair (new EmptyEdges (), clone ());
|
||||
} else {
|
||||
return std::make_pair (clone (), new EmptyEdges ());
|
||||
}
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert1 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressablePolygonDelivery p = region.addressable_merged_polygons ();
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert2 (p.operator-> (), 1);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
|
||||
std::unique_ptr<FlatEdges> output2 (new FlatEdges (true));
|
||||
|
||||
std::set<db::Edge> result;
|
||||
edge_to_region_interaction_filter<std::set<db::Edge> > filter (&result, mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
|
||||
if (result.find (*o) == result.end ()) {
|
||||
output2->insert (*o);
|
||||
} else {
|
||||
output->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair (output.release (), output2.release ());
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode) const
|
||||
{
|
||||
// shortcuts
|
||||
if (other.empty () || empty ()) {
|
||||
if (mode != EdgesOutside) {
|
||||
return std::make_pair (new EmptyEdges (), clone ());
|
||||
} else {
|
||||
return std::make_pair (clone (), new EmptyEdges ());
|
||||
}
|
||||
}
|
||||
|
||||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressableEdgeDelivery ee = other.addressable_merged_edges ();
|
||||
|
||||
for ( ; ! ee.at_end (); ++ee) {
|
||||
scanner.insert (ee.operator-> (), 1);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
|
||||
std::unique_ptr<FlatEdges> output2 (new FlatEdges (true));
|
||||
|
||||
std::set<db::Edge> results;
|
||||
edge_interaction_filter<std::set<db::Edge> > filter (results, mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
|
||||
if (results.find (*o) == results.end ()) {
|
||||
output2->insert (*o);
|
||||
} else {
|
||||
output->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair (output.release (), output2.release ());
|
||||
}
|
||||
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::pull_generic (const Edges &edges) const
|
||||
{
|
||||
|
|
@ -199,7 +294,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const
|
|||
}
|
||||
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
|
||||
edge_interaction_filter<FlatEdges> filter (*output);
|
||||
edge_interaction_filter<FlatEdges> filter (*output, EdgesInteract);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
return output.release ();
|
||||
|
|
@ -229,7 +324,7 @@ AsIfFlatEdges::pull_generic (const Region &other) const
|
|||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (true));
|
||||
|
||||
edge_to_region_interaction_filter<FlatRegion> filter (*output);
|
||||
edge_to_region_interaction_filter<FlatRegion> filter (output.get (), EdgesInteract);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
return output.release ();
|
||||
|
|
@ -250,27 +345,112 @@ AsIfFlatEdges::pull_interacting (const Region &other) const
|
|||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_interacting (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, false);
|
||||
return selected_interacting_generic (other, EdgesInteract, false);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_not_interacting (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, true);
|
||||
return selected_interacting_generic (other, EdgesInteract, true);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_interacting (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, false);
|
||||
return selected_interacting_generic (other, EdgesInteract, false);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_not_interacting (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, true);
|
||||
return selected_interacting_generic (other, EdgesInteract, true);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::selected_interacting_pair (const Region &other) const
|
||||
{
|
||||
return selected_interacting_pair_generic (other, EdgesInteract);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::selected_interacting_pair (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_pair_generic (other, EdgesInteract);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_outside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, EdgesOutside, false);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_not_outside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, EdgesOutside, true);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::selected_outside_pair (const Region &other) const
|
||||
{
|
||||
return selected_interacting_pair_generic (other, EdgesOutside);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_inside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, EdgesInside, false);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_not_inside (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, EdgesInside, true);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::selected_inside_pair (const Region &other) const
|
||||
{
|
||||
return selected_interacting_pair_generic (other, EdgesInside);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_outside (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, EdgesOutside, false);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_not_outside (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, EdgesOutside, true);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::selected_outside_pair (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_pair_generic (other, EdgesOutside);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_inside (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, EdgesInside, false);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_not_inside (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, EdgesInside, true);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::selected_inside_pair (const Edges &other) const
|
||||
{
|
||||
return selected_interacting_pair_generic (other, EdgesInside);
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
|
@ -584,18 +764,52 @@ AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
|
|||
return output.release ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::edge_region_op (const Region &other, bool outside, bool include_borders) const
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::boolean_andnot (const Edges *other) const
|
||||
{
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
|
||||
std::unique_ptr<FlatEdges> output2 (new FlatEdges (true));
|
||||
EdgeBooleanClusterCollectorToShapes cluster_collector (&output->raw_edges (), EdgeAndNot, &output2->raw_edges ());
|
||||
|
||||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve (count () + (other ? other->count () : 0));
|
||||
|
||||
AddressableEdgeDelivery e (begin (), has_valid_edges ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
if (! e->is_degenerate ()) {
|
||||
scanner.insert (e.operator-> (), 0);
|
||||
}
|
||||
}
|
||||
|
||||
AddressableEdgeDelivery ee;
|
||||
|
||||
if (other) {
|
||||
ee = other->addressable_edges ();
|
||||
for ( ; ! ee.at_end (); ++ee) {
|
||||
if (! ee->is_degenerate ()) {
|
||||
scanner.insert (ee.operator-> (), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
return std::make_pair (output.release (), output2.release ());
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::edge_region_op (const Region &other, db::EdgePolygonOp::mode_t mode, bool include_borders) const
|
||||
{
|
||||
// shortcuts
|
||||
if (other.empty ()) {
|
||||
if (! outside) {
|
||||
return new EmptyEdges ();
|
||||
if (other.empty () || empty ()) {
|
||||
if (mode == db::EdgePolygonOp::Both) {
|
||||
return std::make_pair (new EmptyEdges (), clone ());
|
||||
} else if (mode == db::EdgePolygonOp::Inside) {
|
||||
return std::make_pair (new EmptyEdges (), (EdgesDelegate *) 0);
|
||||
} else {
|
||||
return clone ();
|
||||
return std::make_pair (clone (), (EdgesDelegate *) 0);
|
||||
}
|
||||
} else if (empty ()) {
|
||||
return new EmptyEdges ();
|
||||
}
|
||||
|
||||
db::EdgeProcessor ep (report_progress (), progress_desc ());
|
||||
|
|
@ -610,12 +824,19 @@ AsIfFlatEdges::edge_region_op (const Region &other, bool outside, bool include_b
|
|||
ep.insert (*e, 1);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatEdges> output_second;
|
||||
std::unique_ptr<db::EdgeShapeGenerator> cc_second;
|
||||
if (mode == db::EdgePolygonOp::Both) {
|
||||
output_second.reset (new FlatEdges (false));
|
||||
cc_second.reset (new db::EdgeShapeGenerator (output_second->raw_edges (), true /*clear*/, 2 /*second tag*/));
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges (false));
|
||||
db::EdgeShapeGenerator cc (output->raw_edges (), true /*clear*/);
|
||||
db::EdgePolygonOp op (outside, include_borders);
|
||||
db::EdgeShapeGenerator cc (output->raw_edges (), true /*clear*/, 1 /*tag*/, cc_second.get ());
|
||||
db::EdgePolygonOp op (mode, include_borders);
|
||||
ep.process (cc, op);
|
||||
|
||||
return output.release ();
|
||||
return std::make_pair (output.release (), output_second.release ());
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include "dbBoxScanner.h"
|
||||
#include "dbEdgesDelegate.h"
|
||||
#include "dbEdgeBoolean.h"
|
||||
#include "dbEdgeProcessor.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbPolygonTools.h"
|
||||
|
||||
|
|
@ -115,19 +117,29 @@ public:
|
|||
return boolean (&other, EdgeAnd);
|
||||
}
|
||||
|
||||
virtual EdgesDelegate *and_with (const Region &other) const
|
||||
{
|
||||
return edge_region_op (other, false /*inside*/, true /*include borders*/);
|
||||
}
|
||||
|
||||
virtual EdgesDelegate *not_with (const Edges &other) const
|
||||
{
|
||||
return boolean (&other, EdgeNot);
|
||||
}
|
||||
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &other) const
|
||||
{
|
||||
return boolean_andnot (&other);
|
||||
}
|
||||
|
||||
virtual EdgesDelegate *and_with (const Region &other) const
|
||||
{
|
||||
return edge_region_op (other, db::EdgePolygonOp::Inside, true /*include borders*/).first;
|
||||
}
|
||||
|
||||
virtual EdgesDelegate *not_with (const Region &other) const
|
||||
{
|
||||
return edge_region_op (other, true /*outside*/, true /*include borders*/);
|
||||
return edge_region_op (other, db::EdgePolygonOp::Outside, true /*include borders*/).first;
|
||||
}
|
||||
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &other) const
|
||||
{
|
||||
return edge_region_op (other, db::EdgePolygonOp::Both, true /*include borders*/);
|
||||
}
|
||||
|
||||
virtual EdgesDelegate *xor_with (const Edges &other) const
|
||||
|
|
@ -154,12 +166,17 @@ public:
|
|||
|
||||
virtual EdgesDelegate *inside_part (const Region &other) const
|
||||
{
|
||||
return edge_region_op (other, false /*inside*/, false /*don't include borders*/);
|
||||
return edge_region_op (other, db::EdgePolygonOp::Inside, false /*don't include borders*/).first;
|
||||
}
|
||||
|
||||
virtual EdgesDelegate *outside_part (const Region &other) const
|
||||
{
|
||||
return edge_region_op (other, true /*outside*/, false /*don't include borders*/);
|
||||
return edge_region_op (other, db::EdgePolygonOp::Outside, false /*don't include borders*/).first;
|
||||
}
|
||||
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> inside_outside_part_pair (const Region &other) const
|
||||
{
|
||||
return edge_region_op (other, db::EdgePolygonOp::Both, false /*don't include borders*/);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const;
|
||||
|
|
@ -170,6 +187,21 @@ public:
|
|||
virtual EdgesDelegate *selected_not_interacting (const Edges &) const;
|
||||
virtual EdgesDelegate *selected_interacting (const Region &) const;
|
||||
virtual EdgesDelegate *selected_not_interacting (const Region &) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &other) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &other) const;
|
||||
|
||||
virtual EdgesDelegate *selected_outside (const Edges &other) const;
|
||||
virtual EdgesDelegate *selected_not_outside (const Edges &other) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_outside_pair (const Edges &other) const;
|
||||
virtual EdgesDelegate *selected_inside (const Edges &other) const;
|
||||
virtual EdgesDelegate *selected_not_inside (const Edges &other) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Edges &other) const;
|
||||
virtual EdgesDelegate *selected_outside (const Region &other) const;
|
||||
virtual EdgesDelegate *selected_not_outside (const Region &other) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_outside_pair (const Region &other) const;
|
||||
virtual EdgesDelegate *selected_inside (const Region &other) const;
|
||||
virtual EdgesDelegate *selected_not_inside (const Region &other) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Region &other) const;
|
||||
|
||||
virtual EdgesDelegate *in (const Edges &, bool) const;
|
||||
|
||||
|
|
@ -184,8 +216,10 @@ protected:
|
|||
EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const EdgesCheckOptions &options) const;
|
||||
virtual EdgesDelegate *pull_generic (const Edges &edges) const;
|
||||
virtual RegionDelegate *pull_generic (const Region ®ion) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool inverse) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode) const;
|
||||
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
|
||||
AsIfFlatEdges (const AsIfFlatEdges &other);
|
||||
|
||||
|
|
@ -195,7 +229,8 @@ private:
|
|||
|
||||
virtual db::Box compute_bbox () const;
|
||||
EdgesDelegate *boolean (const Edges *other, EdgeBoolOp op) const;
|
||||
EdgesDelegate *edge_region_op (const Region &other, bool outside, bool include_borders) const;
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *> boolean_andnot (const Edges *other) const;
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *> edge_region_op(const Region &other, db::EdgePolygonOp::mode_t mode, bool include_borders) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ DeepEdges::has_valid_edges () const
|
|||
bool
|
||||
DeepEdges::has_valid_merged_edges () const
|
||||
{
|
||||
return merged_semantics ();
|
||||
return false;
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator *
|
||||
|
|
@ -797,12 +797,21 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
|
|||
return dl_out;
|
||||
}
|
||||
|
||||
DeepLayer
|
||||
DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const
|
||||
std::pair<DeepLayer, DeepLayer>
|
||||
DeepEdges::edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t mode, bool include_borders) const
|
||||
{
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
std::vector<unsigned int> output_layers;
|
||||
|
||||
db::EdgeToPolygonLocalOperation op (outside, include_borders);
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
output_layers.push_back (dl_out.layer ());
|
||||
|
||||
DeepLayer dl_out2;
|
||||
if (mode == EdgePolygonOp::Both) {
|
||||
dl_out2 = DeepLayer (deep_layer ().derived ());
|
||||
output_layers.push_back (dl_out2.layer ());
|
||||
}
|
||||
|
||||
db::EdgeToPolygonLocalOperation op (mode, include_borders);
|
||||
|
||||
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
|
|
@ -810,9 +819,9 @@ DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_b
|
|||
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
|
||||
|
||||
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), output_layers);
|
||||
|
||||
return dl_out;
|
||||
return std::make_pair (dl_out, dl_out2);
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::intersections (const Edges &other) const
|
||||
|
|
@ -821,8 +830,7 @@ EdgesDelegate *DeepEdges::intersections (const Edges &other) const
|
|||
|
||||
if (empty () || other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return new EmptyEdges ();
|
||||
return clone ();
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
|
|
@ -839,10 +847,14 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const
|
|||
{
|
||||
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
|
||||
|
||||
if (empty () || other.empty ()) {
|
||||
if (empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return new EmptyEdges ();
|
||||
return clone ();
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// NOTE: we do not use "EmptyEdges" as we want to maintain
|
||||
return new DeepEdges (deep_layer ().derived ());
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
|
|
@ -855,43 +867,12 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const
|
|||
}
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::and_with (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
|
||||
if (empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return new EmptyEdges ();
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return clone ();
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
return AsIfFlatEdges::not_with (other);
|
||||
|
||||
} else {
|
||||
|
||||
return new DeepEdges (edge_region_op (other_deep, false /*outside*/, true /*include borders*/));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::not_with (const Edges &other) const
|
||||
{
|
||||
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
|
||||
|
||||
if (empty ()) {
|
||||
if (empty () || other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return new EmptyEdges ();
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return clone ();
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
|
@ -905,18 +886,61 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const
|
|||
}
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::not_with (const Region &other) const
|
||||
EdgesDelegate *DeepEdges::and_with (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
|
||||
if (empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return new EmptyEdges ();
|
||||
return clone ();
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
// NOTE: we do not use "EmptyEdges" as we want to maintain
|
||||
return new DeepEdges (deep_layer ().derived ());
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
return AsIfFlatEdges::and_with (other);
|
||||
|
||||
} else {
|
||||
|
||||
return new DeepEdges (edge_region_op (other_deep, EdgePolygonOp::Inside, true /*include borders*/).first);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *> DeepEdges::andnot_with (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
|
||||
if (empty ()) {
|
||||
|
||||
return std::make_pair (clone (), clone ());
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// NOTE: we do not use "EmptyEdges" as we want to maintain "deepness"
|
||||
return std::make_pair (new DeepEdges (deep_layer ().derived ()), clone ());
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
return AsIfFlatEdges::andnot_with (other);
|
||||
|
||||
} else {
|
||||
|
||||
auto res = edge_region_op (other_deep, EdgePolygonOp::Both, true /*include borders*/);
|
||||
return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::not_with (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
|
||||
if (empty () || other.empty ()) {
|
||||
|
||||
return clone ();
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
|
@ -925,7 +949,33 @@ EdgesDelegate *DeepEdges::not_with (const Region &other) const
|
|||
|
||||
} else {
|
||||
|
||||
return new DeepEdges (edge_region_op (other_deep, true /*outside*/, true /*include borders*/));
|
||||
return new DeepEdges (edge_region_op (other_deep, EdgePolygonOp::Outside, true /*include borders*/).first);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
DeepEdges::andnot_with (const Edges &other) const
|
||||
{
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
|
||||
if (empty ()) {
|
||||
|
||||
return std::make_pair (clone (), clone ());
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// NOTE: we do not use "EmptyEdges" as we want to maintain
|
||||
return std::make_pair (new DeepEdges (deep_layer ().derived ()), clone ());
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
return AsIfFlatEdges::andnot_with (other);
|
||||
|
||||
} else {
|
||||
|
||||
auto res = edge_region_op (other_deep, EdgePolygonOp::Both, true /*include borders*/);
|
||||
return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -936,12 +986,10 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const
|
|||
|
||||
if (empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return other.delegate ()->clone ();
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return clone ();
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
|
@ -1013,21 +1061,20 @@ EdgesDelegate *DeepEdges::inside_part (const Region &other) const
|
|||
|
||||
if (empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return new EmptyEdges ();
|
||||
return clone ();
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return clone ();
|
||||
// NOTE: we do not use "EmptyEdges" as we want to maintain
|
||||
return new DeepEdges (deep_layer ().derived ());
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
return AsIfFlatEdges::not_with (other);
|
||||
return AsIfFlatEdges::inside_part (other);
|
||||
|
||||
} else {
|
||||
|
||||
return new DeepEdges (edge_region_op (other_deep, false /*outside*/, false /*include borders*/));
|
||||
return new DeepEdges (edge_region_op (other_deep, db::EdgePolygonOp::Inside, false /*include borders*/).first);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1036,23 +1083,42 @@ EdgesDelegate *DeepEdges::outside_part (const Region &other) const
|
|||
{
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
|
||||
if (empty ()) {
|
||||
if (empty () || other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return new EmptyEdges ();
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// Nothing to do
|
||||
return clone ();
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
return AsIfFlatEdges::not_with (other);
|
||||
return AsIfFlatEdges::outside_part (other);
|
||||
|
||||
} else {
|
||||
|
||||
return new DeepEdges (edge_region_op (other_deep, true /*outside*/, false /*include borders*/));
|
||||
return new DeepEdges (edge_region_op (other_deep, db::EdgePolygonOp::Outside, false /*include borders*/).first);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *> DeepEdges::inside_outside_part_pair (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
|
||||
|
||||
if (empty ()) {
|
||||
|
||||
return std::make_pair (clone (), clone ());
|
||||
|
||||
} else if (other.empty ()) {
|
||||
|
||||
// NOTE: we do not use "EmptyEdges" as we want to maintain "deepness"
|
||||
return std::make_pair (new DeepEdges (deep_layer ().derived ()), clone ());
|
||||
|
||||
} else if (! other_deep) {
|
||||
|
||||
return AsIfFlatEdges::inside_outside_part_pair (other);
|
||||
|
||||
} else {
|
||||
|
||||
auto res = edge_region_op (other_deep, EdgePolygonOp::Both, false /*include borders*/);
|
||||
return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1157,8 +1223,10 @@ class Edge2EdgeInteractingLocalOperation
|
|||
: public local_operation<db::Edge, db::Edge, db::Edge>
|
||||
{
|
||||
public:
|
||||
Edge2EdgeInteractingLocalOperation (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
enum output_mode_t { Normal, Inverse, Both };
|
||||
|
||||
Edge2EdgeInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode)
|
||||
: m_mode (mode), m_output_mode (output_mode)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -1171,9 +1239,15 @@ public:
|
|||
|
||||
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
tl_assert (results.size () == 1);
|
||||
tl_assert (results.size () == (m_output_mode == Both ? 2 : 1));
|
||||
|
||||
std::unordered_set<db::Edge> &result = results.front ();
|
||||
|
||||
std::unordered_set<db::Edge> *result2 = 0;
|
||||
if (m_output_mode == Both) {
|
||||
result2 = &results[1];
|
||||
}
|
||||
|
||||
db::box_scanner<db::Edge, size_t> scanner;
|
||||
|
||||
std::set<db::Edge> others;
|
||||
|
|
@ -1192,22 +1266,30 @@ public:
|
|||
scanner.insert (o.operator-> (), 1);
|
||||
}
|
||||
|
||||
if (m_inverse) {
|
||||
if (m_output_mode == Inverse || m_output_mode == Both) {
|
||||
|
||||
std::unordered_set<db::Edge> interacting;
|
||||
edge_interaction_filter<std::unordered_set<db::Edge> > filter (interacting);
|
||||
edge_interaction_filter<std::unordered_set<db::Edge> > filter (interacting, m_mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const db::Edge &subject = interactions.subject_shape (i->first);
|
||||
if (interacting.find (subject) == interacting.end ()) {
|
||||
if (m_output_mode != Both) {
|
||||
result.insert (subject);
|
||||
} else {
|
||||
result2->insert (subject);
|
||||
}
|
||||
} else if (m_output_mode == Both) {
|
||||
result.insert (subject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result);
|
||||
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result, m_mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
}
|
||||
|
|
@ -1216,10 +1298,10 @@ public:
|
|||
|
||||
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
|
||||
{
|
||||
if (m_inverse) {
|
||||
return Copy;
|
||||
if (m_mode == EdgesOutside) {
|
||||
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
|
||||
} else {
|
||||
return Drop;
|
||||
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1229,7 +1311,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
EdgeInteractionMode m_mode;
|
||||
output_mode_t m_output_mode;
|
||||
};
|
||||
|
||||
class Edge2EdgePullLocalOperation
|
||||
|
|
@ -1270,7 +1353,7 @@ public:
|
|||
scanner.insert (o.operator-> (), 0);
|
||||
}
|
||||
|
||||
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result);
|
||||
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result, EdgesInteract);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> ());
|
||||
|
||||
}
|
||||
|
|
@ -1290,8 +1373,10 @@ class Edge2PolygonInteractingLocalOperation
|
|||
: public local_operation<db::Edge, db::PolygonRef, db::Edge>
|
||||
{
|
||||
public:
|
||||
Edge2PolygonInteractingLocalOperation (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
enum output_mode_t { Normal, Inverse, Both };
|
||||
|
||||
Edge2PolygonInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode)
|
||||
: m_mode (mode), m_output_mode (output_mode)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -1304,9 +1389,15 @@ public:
|
|||
|
||||
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
tl_assert (results.size () == 1);
|
||||
tl_assert (results.size () == size_t (m_output_mode == Both ? 2 : 1));
|
||||
|
||||
std::unordered_set<db::Edge> &result = results.front ();
|
||||
|
||||
std::unordered_set<db::Edge> *result2 = 0;
|
||||
if (m_output_mode == Both) {
|
||||
result2 = &results[1];
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
|
|
@ -1327,22 +1418,31 @@ public:
|
|||
scanner.insert2 (& heap.back (), 1);
|
||||
}
|
||||
|
||||
if (m_inverse) {
|
||||
if (m_output_mode == Inverse || m_output_mode == Both) {
|
||||
|
||||
std::unordered_set<db::Edge> interacting;
|
||||
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (interacting);
|
||||
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (&interacting, m_mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const db::Edge &subject = interactions.subject_shape (i->first);
|
||||
|
||||
if (interacting.find (subject) == interacting.end ()) {
|
||||
if (m_output_mode != Both) {
|
||||
result.insert (subject);
|
||||
} else {
|
||||
result2->insert (subject);
|
||||
}
|
||||
} else if (m_output_mode == Both) {
|
||||
result.insert (subject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (result);
|
||||
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (&result, m_mode);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
}
|
||||
|
|
@ -1350,20 +1450,46 @@ public:
|
|||
|
||||
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
|
||||
{
|
||||
if (m_inverse) {
|
||||
return Copy;
|
||||
if (m_mode == EdgesOutside) {
|
||||
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
|
||||
} else {
|
||||
return Drop;
|
||||
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select interacting edges"));
|
||||
if (m_mode == EdgesInteract) {
|
||||
if (m_output_mode == Inverse) {
|
||||
return tl::to_string (tr ("Select non-interacting edges"));
|
||||
} else if (m_output_mode == Normal) {
|
||||
return tl::to_string (tr ("Select interacting edges"));
|
||||
} else {
|
||||
return tl::to_string (tr ("Select interacting and non-interacting edges"));
|
||||
}
|
||||
} else if (m_mode == EdgesInside) {
|
||||
if (m_output_mode == Inverse) {
|
||||
return tl::to_string (tr ("Select non-inside edges"));
|
||||
} else if (m_output_mode == Normal) {
|
||||
return tl::to_string (tr ("Select inside edges"));
|
||||
} else {
|
||||
return tl::to_string (tr ("Select inside and non-inside edges"));
|
||||
}
|
||||
} else if (m_mode == EdgesOutside) {
|
||||
if (m_output_mode == Inverse) {
|
||||
return tl::to_string (tr ("Select non-outside edges"));
|
||||
} else if (m_output_mode == Normal) {
|
||||
return tl::to_string (tr ("Select outside edges"));
|
||||
} else {
|
||||
return tl::to_string (tr ("Select outside and non-outside edges"));
|
||||
}
|
||||
}
|
||||
return std::string ();
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
EdgeInteractionMode m_mode;
|
||||
output_mode_t m_output_mode;
|
||||
};
|
||||
|
||||
struct ResultInserter
|
||||
|
|
@ -1427,7 +1553,7 @@ public:
|
|||
}
|
||||
|
||||
ResultInserter inserter (layout, result);
|
||||
edge_to_region_interaction_filter<ResultInserter> filter (inserter);
|
||||
edge_to_region_interaction_filter<ResultInserter> filter (&inserter, EdgesInteract);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
}
|
||||
|
||||
|
|
@ -1445,7 +1571,7 @@ public:
|
|||
}
|
||||
|
||||
EdgesDelegate *
|
||||
DeepEdges::selected_interacting_generic (const Region &other, bool inverse) const
|
||||
DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse) const
|
||||
{
|
||||
std::unique_ptr<db::DeepRegion> dr_holder;
|
||||
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
|
||||
|
|
@ -1459,19 +1585,51 @@ DeepEdges::selected_interacting_generic (const Region &other, bool inverse) cons
|
|||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
|
||||
db::Edge2PolygonInteractingLocalOperation op (inverse);
|
||||
db::Edge2PolygonInteractingLocalOperation op (mode, inverse ? db::Edge2PolygonInteractingLocalOperation::Inverse : db::Edge2PolygonInteractingLocalOperation::Normal);
|
||||
|
||||
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (edges.store ()->threads ());
|
||||
|
||||
proc.run (&op, edges.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&op, edges.layer (), (mode == EdgesInside ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
|
||||
|
||||
return new db::DeepEdges (dl_out);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteractionMode mode) const
|
||||
{
|
||||
std::unique_ptr<db::DeepRegion> dr_holder;
|
||||
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchization
|
||||
dr_holder.reset (new db::DeepRegion (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
DeepLayer dl_out2 (edges.derived ());
|
||||
|
||||
std::vector<unsigned int> output_layers;
|
||||
output_layers.reserve (2);
|
||||
output_layers.push_back (dl_out.layer ());
|
||||
output_layers.push_back (dl_out2.layer ());
|
||||
|
||||
db::Edge2PolygonInteractingLocalOperation op (mode, db::Edge2PolygonInteractingLocalOperation::Both);
|
||||
|
||||
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (edges.store ()->threads ());
|
||||
|
||||
proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers);
|
||||
|
||||
return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2));
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
DeepEdges::selected_interacting_generic (const Edges &other, bool inverse) const
|
||||
DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode mode, bool inverse) const
|
||||
{
|
||||
std::unique_ptr<db::DeepEdges> dr_holder;
|
||||
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
|
||||
|
|
@ -1485,17 +1643,49 @@ DeepEdges::selected_interacting_generic (const Edges &other, bool inverse) const
|
|||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
|
||||
db::Edge2EdgeInteractingLocalOperation op (inverse);
|
||||
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal);
|
||||
|
||||
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (edges.store ()->threads ());
|
||||
|
||||
proc.run (&op, edges.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&op, edges.layer (), (mode == EdgesInside ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
|
||||
|
||||
return new db::DeepEdges (dl_out);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode) const
|
||||
{
|
||||
std::unique_ptr<db::DeepEdges> dr_holder;
|
||||
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other edge collection isn't deep, turn into a top-level only deep edge collection to facilitate re-hierarchization
|
||||
dr_holder.reset (new db::DeepEdges (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
DeepLayer dl_out2 (edges.derived ());
|
||||
|
||||
std::vector<unsigned int> output_layers;
|
||||
output_layers.reserve (2);
|
||||
output_layers.push_back (dl_out.layer ());
|
||||
output_layers.push_back (dl_out2.layer ());
|
||||
|
||||
db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both);
|
||||
|
||||
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (edges.store ()->threads ());
|
||||
|
||||
proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers);
|
||||
|
||||
return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2));
|
||||
}
|
||||
|
||||
RegionDelegate *DeepEdges::pull_generic (const Region &other) const
|
||||
{
|
||||
std::unique_ptr<db::DeepRegion> dr_holder;
|
||||
|
|
|
|||
|
|
@ -133,10 +133,12 @@ public:
|
|||
virtual EdgesDelegate *merged () const;
|
||||
|
||||
virtual EdgesDelegate *and_with (const Edges &other) const;
|
||||
virtual EdgesDelegate *and_with (const Region &other) const;
|
||||
|
||||
virtual EdgesDelegate *not_with (const Edges &other) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &) const;
|
||||
|
||||
virtual EdgesDelegate *and_with (const Region &other) const;
|
||||
virtual EdgesDelegate *not_with (const Region &other) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &) const;
|
||||
|
||||
virtual EdgesDelegate *xor_with (const Edges &other) const;
|
||||
|
||||
|
|
@ -149,6 +151,7 @@ public:
|
|||
|
||||
virtual EdgesDelegate *inside_part (const Region &other) const;
|
||||
virtual EdgesDelegate *outside_part (const Region &other) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> inside_outside_part_pair (const Region &) const;
|
||||
|
||||
virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const;
|
||||
|
||||
|
|
@ -179,12 +182,14 @@ private:
|
|||
void ensure_merged_edges_valid () const;
|
||||
const DeepLayer &merged_deep_layer () const;
|
||||
DeepLayer and_or_not_with(const DeepEdges *other, EdgeBoolOp op) const;
|
||||
DeepLayer edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const;
|
||||
std::pair<DeepLayer, DeepLayer> edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t op, bool include_borders) const;
|
||||
EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const db::EdgesCheckOptions &options) const;
|
||||
virtual EdgesDelegate *pull_generic (const Edges &edges) const;
|
||||
virtual RegionDelegate *pull_generic (const Region ®ion) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool invert) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode) const;
|
||||
DeepEdges *apply_filter (const EdgeFilterBase &filter) const;
|
||||
|
||||
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace db
|
|||
/**
|
||||
* @brief A common definition for the boolean operations available on edges
|
||||
*/
|
||||
enum EdgeBoolOp { EdgeOr, EdgeNot, EdgeXor, EdgeAnd, EdgeIntersections };
|
||||
enum EdgeBoolOp { EdgeOr, EdgeNot, EdgeXor, EdgeAnd, EdgeIntersections, EdgeAndNot /*not always supported*/ };
|
||||
|
||||
struct OrJoinOp
|
||||
{
|
||||
|
|
@ -87,7 +87,13 @@ struct EdgeBooleanCluster
|
|||
typedef db::Edge::coord_type coord_type;
|
||||
|
||||
EdgeBooleanCluster (OutputContainer *output, EdgeBoolOp op)
|
||||
: mp_output (output), m_op (op)
|
||||
: mp_output (output), mp_output2 (0), m_op (op)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EdgeBooleanCluster (OutputContainer *output, OutputContainer *output2, EdgeBoolOp op)
|
||||
: mp_output (output), mp_output2 (output2), m_op (op)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -99,11 +105,13 @@ struct EdgeBooleanCluster
|
|||
// shortcut for single edge
|
||||
if (begin () + 1 == end ()) {
|
||||
if (begin ()->second == 0) {
|
||||
if (m_op != EdgeAnd) {
|
||||
if (m_op == EdgeAndNot) {
|
||||
mp_output2->insert (*(begin ()->first));
|
||||
} else if (m_op != EdgeAnd) {
|
||||
mp_output->insert (*(begin ()->first));
|
||||
}
|
||||
} else {
|
||||
if (m_op != EdgeAnd && m_op != EdgeNot) {
|
||||
if (m_op != EdgeAnd && m_op != EdgeNot && m_op != EdgeAndNot) {
|
||||
mp_output->insert (*(begin ()->first));
|
||||
}
|
||||
}
|
||||
|
|
@ -174,19 +182,34 @@ struct EdgeBooleanCluster
|
|||
if (b.begin () == b.end ()) {
|
||||
|
||||
// optimize for empty b
|
||||
if (m_op != EdgeAnd) {
|
||||
OutputContainer *oc = 0;
|
||||
if (m_op == EdgeAndNot) {
|
||||
oc = mp_output;
|
||||
} else if (m_op != EdgeAnd) {
|
||||
oc = mp_output;
|
||||
}
|
||||
|
||||
if (oc) {
|
||||
for (tl::interval_map<db::Coord, int>::const_iterator ib = b.begin (); ib != b.end (); ++ib) {
|
||||
if (ib->second > 0) {
|
||||
mp_output->insert (db::Edge (p1 + db::Vector (d * (ib->first.first * n)), p1 + db::Vector (d * (ib->first.second * n))));
|
||||
oc->insert (db::Edge (p1 + db::Vector (d * (ib->first.first * n)), p1 + db::Vector (d * (ib->first.second * n))));
|
||||
} else if (ib->second < 0) {
|
||||
mp_output->insert (db::Edge (p1 + db::Vector (d * (ib->first.second * n)), p1 + db::Vector (d * (ib->first.first * n))));
|
||||
oc->insert (db::Edge (p1 + db::Vector (d * (ib->first.second * n)), p1 + db::Vector (d * (ib->first.first * n))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (m_op == EdgeAnd) {
|
||||
tl::interval_map<db::Coord, int> q2;
|
||||
|
||||
if (m_op == EdgeAnd || m_op == EdgeAndNot) {
|
||||
if (m_op == EdgeAndNot) {
|
||||
q2 = q;
|
||||
for (tl::interval_map<db::Coord, int>::const_iterator ib = b.begin (); ib != b.end (); ++ib) {
|
||||
q2.add (ib->first.first, ib->first.second, ib->second, not_jop);
|
||||
}
|
||||
}
|
||||
for (tl::interval_map<db::Coord, int>::const_iterator ib = b.begin (); ib != b.end (); ++ib) {
|
||||
q.add (ib->first.first, ib->first.second, ib->second, and_jop);
|
||||
}
|
||||
|
|
@ -208,12 +231,20 @@ struct EdgeBooleanCluster
|
|||
}
|
||||
}
|
||||
|
||||
for (tl::interval_map<db::Coord, int>::const_iterator iq = q2.begin (); iq != q2.end (); ++iq) {
|
||||
if (iq->second > 0) {
|
||||
mp_output2->insert (db::Edge (p1 + db::Vector (d * (iq->first.first * n)), p1 + db::Vector (d * (iq->first.second * n))));
|
||||
} else if (iq->second < 0) {
|
||||
mp_output2->insert (db::Edge (p1 + db::Vector (d * (iq->first.second * n)), p1 + db::Vector (d * (iq->first.first * n))));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
OutputContainer *mp_output, *mp_output2;
|
||||
db::EdgeBoolOp m_op;
|
||||
};
|
||||
|
||||
|
|
@ -221,8 +252,8 @@ template <class OutputContainer>
|
|||
struct EdgeBooleanClusterCollector
|
||||
: public db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> >
|
||||
{
|
||||
EdgeBooleanClusterCollector (OutputContainer *output, EdgeBoolOp op)
|
||||
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, op == EdgeIntersections ? EdgeAnd : op), op != EdgeAnd && op != EdgeIntersections /*report single*/),
|
||||
EdgeBooleanClusterCollector (OutputContainer *output, EdgeBoolOp op, OutputContainer *output2 = 0)
|
||||
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, output2, op == EdgeIntersections ? EdgeAnd : op), op != EdgeAnd && op != EdgeIntersections /*report single*/),
|
||||
mp_output (output), mp_intersections (op == EdgeIntersections ? output : 0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
|
|
@ -377,6 +408,12 @@ public:
|
|||
|
||||
typedef Iterator const_iterator;
|
||||
|
||||
ShapesToOutputContainerAdaptor ()
|
||||
: mp_shapes (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
ShapesToOutputContainerAdaptor (db::Shapes &shapes)
|
||||
: mp_shapes (&shapes)
|
||||
{
|
||||
|
|
@ -413,8 +450,14 @@ struct DB_PUBLIC EdgeBooleanClusterCollectorToShapes
|
|||
{
|
||||
}
|
||||
|
||||
EdgeBooleanClusterCollectorToShapes (db::Shapes *output, EdgeBoolOp op, db::Shapes *output2)
|
||||
: EdgeBooleanClusterCollector<ShapesToOutputContainerAdaptor> (&m_adaptor, op, &m_adaptor2), m_adaptor (*output), m_adaptor2 (*output2)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
ShapesToOutputContainerAdaptor m_adaptor;
|
||||
ShapesToOutputContainerAdaptor m_adaptor2;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -560,8 +560,8 @@ private:
|
|||
// -------------------------------------------------------------------------------
|
||||
// EdgePolygonOp implementation
|
||||
|
||||
EdgePolygonOp::EdgePolygonOp (bool outside, bool include_touching, int polygon_mode)
|
||||
: m_outside (outside), m_include_touching (include_touching),
|
||||
EdgePolygonOp::EdgePolygonOp (EdgePolygonOp::mode_t mode, bool include_touching, int polygon_mode)
|
||||
: m_mode (mode), m_include_touching (include_touching),
|
||||
m_function (polygon_mode),
|
||||
m_wcp_n (0), m_wcp_s (0)
|
||||
{
|
||||
|
|
@ -572,27 +572,30 @@ void EdgePolygonOp::reset ()
|
|||
m_wcp_n = m_wcp_s = 0;
|
||||
}
|
||||
|
||||
bool EdgePolygonOp::select_edge (bool horizontal, property_type p)
|
||||
int EdgePolygonOp::select_edge (bool horizontal, property_type p)
|
||||
{
|
||||
if (p == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
bool inside;
|
||||
|
||||
} else if (horizontal) {
|
||||
|
||||
bool res;
|
||||
if (horizontal) {
|
||||
if (m_include_touching) {
|
||||
res = (m_function (m_wcp_n) || m_function (m_wcp_s));
|
||||
inside = (m_function (m_wcp_n) || m_function (m_wcp_s));
|
||||
} else {
|
||||
res = (m_function (m_wcp_n) && m_function (m_wcp_s));
|
||||
inside = (m_function (m_wcp_n) && m_function (m_wcp_s));
|
||||
}
|
||||
|
||||
return m_outside ? !res : res;
|
||||
|
||||
} else {
|
||||
inside = m_function (m_wcp_n);
|
||||
}
|
||||
|
||||
return m_outside ? !m_function (m_wcp_n) : m_function (m_wcp_n);
|
||||
|
||||
if (m_mode == Inside) {
|
||||
return inside ? 1 : 0;
|
||||
} else if (m_mode == Outside) {
|
||||
return inside ? 0 : 1;
|
||||
} else {
|
||||
return inside ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1626,6 +1629,7 @@ public:
|
|||
|
||||
void reset ()
|
||||
{
|
||||
mp_es->reset_stop ();
|
||||
mp_op->reset ();
|
||||
}
|
||||
|
||||
|
|
@ -1634,6 +1638,11 @@ public:
|
|||
return mp_op->is_reset ();
|
||||
}
|
||||
|
||||
bool can_stop ()
|
||||
{
|
||||
return mp_es->can_stop ();
|
||||
}
|
||||
|
||||
void reserve (size_t n)
|
||||
{
|
||||
mp_op->reserve (n);
|
||||
|
|
@ -1705,10 +1714,11 @@ public:
|
|||
|
||||
void select_edge (const WorkEdge &e)
|
||||
{
|
||||
if (mp_op->select_edge (e.dy () == 0, e.prop)) {
|
||||
mp_es->put (e);
|
||||
int tag = mp_op->select_edge (e.dy () == 0, e.prop);
|
||||
if (tag > 0) {
|
||||
mp_es->put (e, (unsigned int) tag);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("put(%s)\n", e.to_string().c_str());
|
||||
printf ("put(%s, %d)\n", e.to_string().c_str(), tag);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -1937,6 +1947,19 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the generator wants to stop
|
||||
*/
|
||||
bool can_stop ()
|
||||
{
|
||||
for (std::vector<EdgeProcessorState>::iterator s = m_states.begin (); s != m_states.end (); ++s) {
|
||||
if (s->can_stop ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserve memory n edges
|
||||
*/
|
||||
|
|
@ -2410,7 +2433,7 @@ EdgeProcessor::redo_or_process (const std::vector<std::pair<db::EdgeSink *, db::
|
|||
y = edge_ymin ((*mp_work_edges) [0]);
|
||||
|
||||
future = mp_work_edges->begin ();
|
||||
for (std::vector <WorkEdge>::iterator current = mp_work_edges->begin (); current != mp_work_edges->end (); ) {
|
||||
for (std::vector <WorkEdge>::iterator current = mp_work_edges->begin (); current != mp_work_edges->end () && ! gs.can_stop (); ) {
|
||||
|
||||
if (m_report_progress) {
|
||||
double p = double (std::distance (mp_work_edges->begin (), current)) / double (mp_work_edges->size ());
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public:
|
|||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
EdgeSink () { }
|
||||
EdgeSink () : m_can_stop (false) { }
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
|
|
@ -87,6 +87,15 @@ public:
|
|||
*/
|
||||
virtual void put (const db::Edge &) { }
|
||||
|
||||
/**
|
||||
* @brief Deliver a tagged edge
|
||||
*
|
||||
* This method delivers an edge that ends or starts at the current scanline.
|
||||
* This version includes a tag which is generated when using "select_edge".
|
||||
* A tag is a value > 0 returned by "select_edge".
|
||||
*/
|
||||
virtual void put (const db::Edge &, int /*tag*/) { }
|
||||
|
||||
/**
|
||||
* @brief Deliver an edge that crosses the scanline
|
||||
*
|
||||
|
|
@ -114,6 +123,38 @@ public:
|
|||
* @brief Signal the end of a scanline at the given y coordinate
|
||||
*/
|
||||
virtual void end_scanline (db::Coord /*y*/) { }
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating that the generator wants to stop
|
||||
*/
|
||||
bool can_stop () const
|
||||
{
|
||||
return m_can_stop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the stop request
|
||||
*/
|
||||
void reset_stop ()
|
||||
{
|
||||
m_can_stop = false;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Sets the stop request
|
||||
*
|
||||
* The scanner can choose to stop once the request is set.
|
||||
* This is useful for implementing receivers that can stop once a
|
||||
* specific condition is found.
|
||||
*/
|
||||
void request_stop ()
|
||||
{
|
||||
m_can_stop = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_can_stop;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -130,15 +171,15 @@ public:
|
|||
/**
|
||||
* @brief Constructor connecting this receiver to an external edge vector
|
||||
*/
|
||||
EdgeContainer (std::vector<db::Edge> &edges, bool clear = false)
|
||||
: EdgeSink (), mp_edges (&edges), m_clear (clear)
|
||||
EdgeContainer (std::vector<db::Edge> &edges, bool clear = false, int tag = 0, EdgeContainer *chained = 0)
|
||||
: EdgeSink (), mp_edges (&edges), m_clear (clear), m_tag (tag), mp_chained (chained)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* @brief Constructor using an internal edge vector
|
||||
*/
|
||||
EdgeContainer ()
|
||||
: EdgeSink (), mp_edges (&m_edges), m_clear (false)
|
||||
EdgeContainer (int tag = 0, EdgeContainer *chained = 0)
|
||||
: EdgeSink (), mp_edges (&m_edges), m_clear (false), m_tag (tag), mp_chained (chained)
|
||||
{ }
|
||||
|
||||
/**
|
||||
|
|
@ -167,6 +208,9 @@ public:
|
|||
// The single-shot scheme is a easy way to overcome problems with multiple start/flush brackets (i.e. on size filter)
|
||||
m_clear = false;
|
||||
}
|
||||
if (mp_chained) {
|
||||
mp_chained->start ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -175,12 +219,30 @@ public:
|
|||
virtual void put (const db::Edge &e)
|
||||
{
|
||||
mp_edges->push_back (e);
|
||||
if (mp_chained) {
|
||||
mp_chained->put (e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implementation of the EdgeSink interface
|
||||
*/
|
||||
virtual void put (const db::Edge &e, int tag)
|
||||
{
|
||||
if (m_tag == 0 || tag == m_tag) {
|
||||
mp_edges->push_back (e);
|
||||
}
|
||||
if (mp_chained) {
|
||||
mp_chained->put (e, tag);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<db::Edge> m_edges;
|
||||
std::vector<db::Edge> *mp_edges;
|
||||
bool m_clear;
|
||||
int m_tag;
|
||||
EdgeContainer *mp_chained;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -204,7 +266,7 @@ public:
|
|||
virtual void reset () { }
|
||||
virtual void reserve (size_t /*n*/) { }
|
||||
virtual int edge (bool /*north*/, bool /*enter*/, property_type /*p*/) { return 0; }
|
||||
virtual bool select_edge (bool /*horizontal*/, property_type /*p*/) { return false; }
|
||||
virtual int select_edge (bool /*horizontal*/, property_type /*p*/) { return 0; }
|
||||
virtual int compare_ns () const { return 0; }
|
||||
virtual bool is_reset () const { return false; }
|
||||
virtual bool prefer_touch () const { return false; }
|
||||
|
|
@ -215,8 +277,8 @@ public:
|
|||
* @brief An intersection detector
|
||||
*
|
||||
* This edge evaluator will not produce output edges but rather record the
|
||||
* property pairs of polygons intersecting. Only intersections (overlaps)
|
||||
* are recorded. Touching contacts are not recorded.
|
||||
* property pairs of polygons intersecting or interacting in the specified
|
||||
* way.
|
||||
*
|
||||
* It will build a set of property pairs, where the lower property value
|
||||
* is the first one of the pairs.
|
||||
|
|
@ -491,6 +553,15 @@ class DB_PUBLIC EdgePolygonOp
|
|||
: public db::EdgeEvaluatorBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief The operation mode
|
||||
*/
|
||||
enum mode_t {
|
||||
Inside = 0, // Selects inside edges
|
||||
Outside = 1, // Selects outside edges
|
||||
Both = 2 // Selects both (inside -> tag #1, outside -> tag #2)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
|
|
@ -498,17 +569,18 @@ public:
|
|||
* @param include_touching If true, edges on the polygon's border will be considered "inside" of polygons
|
||||
* @param polygon_mode Determines how the polygon edges on property 0 are interpreted (see merge operators)
|
||||
*/
|
||||
EdgePolygonOp (bool outside = false, bool include_touching = true, int polygon_mode = -1);
|
||||
EdgePolygonOp (mode_t mode = Inside, bool include_touching = true, int polygon_mode = -1);
|
||||
|
||||
virtual void reset ();
|
||||
virtual bool select_edge (bool horizontal, property_type p);
|
||||
virtual int select_edge (bool horizontal, property_type p);
|
||||
virtual int edge (bool north, bool enter, property_type p);
|
||||
virtual bool is_reset () const;
|
||||
virtual bool prefer_touch () const;
|
||||
virtual bool selects_edges () const;
|
||||
|
||||
private:
|
||||
bool m_outside, m_include_touching;
|
||||
mode_t m_mode;
|
||||
bool m_include_touching;
|
||||
db::ParametrizedInsideFunc m_function;
|
||||
int m_wcp_n, m_wcp_s;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -274,6 +274,16 @@ public:
|
|||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Takes the underlying delegate object
|
||||
*/
|
||||
EdgesDelegate *take_delegate ()
|
||||
{
|
||||
EdgesDelegate *delegate = mp_delegate;
|
||||
mp_delegate = 0;
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the base verbosity
|
||||
*
|
||||
|
|
@ -794,6 +804,24 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Boolean AND/NOT operator in the same operation
|
||||
*/
|
||||
std::pair<Edges, Edges> andnot (const Edges &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->andnot_with (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Boolean AND/NOT operator with a region in the same operation
|
||||
*/
|
||||
std::pair<Edges, Edges> andnot (const Region &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->andnot_with (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Boolean XOR operator
|
||||
*/
|
||||
|
|
@ -974,6 +1002,17 @@ public:
|
|||
return Edges (mp_delegate->outside_part (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the eges inside the given region and the ones outside the region.
|
||||
*
|
||||
* This method combined both inside_part and outside_part.
|
||||
*/
|
||||
std::pair<Edges, Edges> inside_outside_part (const Region &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->inside_outside_part_pair (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of the other region set which overlap or touch edges from this edge set
|
||||
*
|
||||
|
|
@ -1037,6 +1076,251 @@ public:
|
|||
return Edges (mp_delegate->selected_not_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this edge set which do not overlap or touch with polygons from the region together with the ones that do not
|
||||
*/
|
||||
std::pair<Edges, Edges> selected_interacting_differential (const Region &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge collection which are completely outside polygons from the region
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges &select_outside (const Region &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_outside (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge collection which are not completely outside polygons from the region
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges &select_not_outside (const Region &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_not_outside (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this edge collection which are completely outside polygons from the region
|
||||
*
|
||||
* This method is an out-of-place version of select_outside.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges selected_outside (const Region &other) const
|
||||
{
|
||||
return Edges (mp_delegate->selected_outside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this edge collection which are not completely outside polygons from the region
|
||||
*
|
||||
* This method is an out-of-place version of select_not_outside.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges selected_not_outside (const Region &other) const
|
||||
{
|
||||
return Edges (mp_delegate->selected_not_outside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this which are completely outside polygons from the 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<Edges, Edges> selected_outside_differential (const Region &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_outside_pair (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge collection which are completely inside polygons from the region
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges &select_inside (const Region &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_inside (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge collection which are not completely inside polygons from the region
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges &select_not_inside (const Region &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_not_inside (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this which are completely inside polygons from the region
|
||||
*
|
||||
* This method is an out-of-place version of select_inside.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges selected_inside (const Region &other) const
|
||||
{
|
||||
return Edges (mp_delegate->selected_inside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this which are not completely inside polygons from the region
|
||||
*
|
||||
* This method is an out-of-place version of select_not_inside.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges selected_not_inside (const Region &other) const
|
||||
{
|
||||
return Edges (mp_delegate->selected_not_inside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this which are completely inside polygons from the 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<Edges, Edges> selected_inside_differential (const Region &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_inside_pair (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge collection which are completely outside edges from the other edge collection
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges &select_outside (const Edges &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_outside (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge collection which are not completely outside edges from the other edge collection
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges &select_not_outside (const Edges &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_not_outside (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this edge collection which are completely outside edges from the other edge collection
|
||||
*
|
||||
* This method is an out-of-place version of select_outside.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges selected_outside (const Edges &other) const
|
||||
{
|
||||
return Edges (mp_delegate->selected_outside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this edge collection which are not completely outside edges from the other edge collection
|
||||
*
|
||||
* This method is an out-of-place version of select_not_outside.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges selected_not_outside (const Edges &other) const
|
||||
{
|
||||
return Edges (mp_delegate->selected_not_outside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this which are completely outside edges from the other edge collection 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<Edges, Edges> selected_outside_differential (const Edges &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_outside_pair (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge collection which are completely inside edges from the other edge collection
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges &select_inside (const Edges &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_inside (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge collection which are not completely inside edges from the other edge collection
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges &select_not_inside (const Edges &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_not_inside (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this which are completely inside edgess from the other edge collection
|
||||
*
|
||||
* This method is an out-of-place version of select_inside.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges selected_inside (const Edges &other) const
|
||||
{
|
||||
return Edges (mp_delegate->selected_inside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this which are not completely inside edges from the other edge collection
|
||||
*
|
||||
* This method is an out-of-place version of select_not_inside.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges selected_not_inside (const Edges &other) const
|
||||
{
|
||||
return Edges (mp_delegate->selected_not_inside (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this which are completely inside edges from the other edge collection 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<Edges, Edges> selected_inside_differential (const Edges &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_inside_pair (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge set which overlap or touch with edges from the other edge set
|
||||
*
|
||||
|
|
@ -1059,6 +1343,15 @@ public:
|
|||
return Edges (mp_delegate->selected_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges of this edge set which do not overlap or touch with edges from the other edge set together with the ones that do not
|
||||
*/
|
||||
std::pair<Edges, Edges> selected_interacting_differential (const Edges &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all edges of this edge set which do not overlap or touch with edges from the other edge set
|
||||
*
|
||||
|
|
|
|||
|
|
@ -294,9 +294,11 @@ public:
|
|||
virtual EdgesDelegate *merged () const = 0;
|
||||
|
||||
virtual EdgesDelegate *and_with (const Edges &other) const = 0;
|
||||
virtual EdgesDelegate *and_with (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *not_with (const Edges &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &) const = 0;
|
||||
virtual EdgesDelegate *and_with (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *not_with (const Region &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &) const = 0;
|
||||
virtual EdgesDelegate *xor_with (const Edges &other) const = 0;
|
||||
virtual EdgesDelegate *or_with (const Edges &other) const = 0;
|
||||
virtual EdgesDelegate *add_in_place (const Edges &other) = 0;
|
||||
|
|
@ -307,12 +309,28 @@ public:
|
|||
|
||||
virtual EdgesDelegate *inside_part (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *outside_part (const Region &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> inside_outside_part_pair (const Region &other) const = 0;
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const = 0;
|
||||
virtual EdgesDelegate *pull_interacting (const Edges &) const = 0;
|
||||
virtual EdgesDelegate *selected_interacting (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *selected_not_interacting (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *selected_interacting (const Edges &other) const = 0;
|
||||
virtual EdgesDelegate *selected_not_interacting (const Edges &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &other) const = 0;
|
||||
|
||||
virtual EdgesDelegate *selected_outside (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *selected_not_outside (const Region &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_outside_pair (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *selected_inside (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *selected_not_inside (const Region &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *selected_outside (const Edges &other) const = 0;
|
||||
virtual EdgesDelegate *selected_not_outside (const Edges &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_outside_pair (const Edges &other) const = 0;
|
||||
virtual EdgesDelegate *selected_inside (const Edges &other) const = 0;
|
||||
virtual EdgesDelegate *selected_not_inside (const Edges &other) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Edges &other) const = 0;
|
||||
|
||||
virtual EdgesDelegate *in (const Edges &other, bool invert) const = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ extended_edge (const db::Edge &edge, db::Coord ext_b, db::Coord ext_e, db::Coord
|
|||
// -------------------------------------------------------------------------------------------------------------
|
||||
// EdgeSegmentSelector processor
|
||||
|
||||
EdgeSegmentSelector::EdgeSegmentSelector (int mode, db::Edges::length_type length, double fraction)
|
||||
EdgeSegmentSelector::EdgeSegmentSelector (int mode, Edge::distance_type length, double fraction)
|
||||
: m_mode (mode), m_length (length), m_fraction (fraction)
|
||||
{ }
|
||||
|
||||
|
|
@ -274,4 +274,96 @@ EdgeOrientationFilter::selected (const db::Edge &edge) const
|
|||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Edge to Edge relation implementation
|
||||
|
||||
bool edge_interacts (const db::Edge &a, const db::Edge &b)
|
||||
{
|
||||
return a.intersect (b);
|
||||
}
|
||||
|
||||
bool edge_is_inside (const db::Edge &a, const db::Edge &b)
|
||||
{
|
||||
return b.contains (a.p1 ()) && b.contains (a.p2 ());
|
||||
}
|
||||
|
||||
bool edge_is_outside (const db::Edge &a, const db::Edge &b)
|
||||
{
|
||||
if (a.parallel (b)) {
|
||||
return ! a.coincident (b);
|
||||
} else {
|
||||
auto pt = a.intersect_point (b);
|
||||
if (! pt.first) {
|
||||
// no intersection -> outside
|
||||
return true;
|
||||
}
|
||||
return ! b.contains_excl (pt.second) || ! a.contains_excl (pt.second);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Edge to Polygon relation implementation
|
||||
|
||||
bool edge_interacts (const db::Edge &a, const db::Polygon &b)
|
||||
{
|
||||
return db::interact (b, a);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct DetectTagEdgeSink
|
||||
: public db::EdgeSink
|
||||
{
|
||||
DetectTagEdgeSink (int tag)
|
||||
: fail_tag (tag), result (true) { }
|
||||
|
||||
virtual void put (const db::Edge &, int tag)
|
||||
{
|
||||
if (tag == fail_tag) {
|
||||
result = false;
|
||||
request_stop ();
|
||||
}
|
||||
}
|
||||
|
||||
int fail_tag;
|
||||
bool result;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
static bool
|
||||
edge_is_inside_or_outside (bool outside, const db::Edge &a, const db::Polygon &b)
|
||||
{
|
||||
db::EdgeProcessor ep;
|
||||
ep.insert (b, 0);
|
||||
|
||||
ep.insert (a, 1);
|
||||
|
||||
DetectTagEdgeSink es (outside ? 1 : 2); // 2 is the "outside" tag in "Both" mode -> this makes inside fail
|
||||
db::EdgePolygonOp op (db::EdgePolygonOp::Both, true /*include borders*/);
|
||||
ep.process (es, op);
|
||||
|
||||
return es.result;
|
||||
}
|
||||
|
||||
bool edge_is_inside (const db::Edge &a, const db::Polygon &b)
|
||||
{
|
||||
// shortcuts
|
||||
if (!a.bbox ().inside (b.box ())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return edge_is_inside_or_outside (false, a, b);
|
||||
}
|
||||
|
||||
bool edge_is_outside (const db::Edge &a, const db::Polygon &b)
|
||||
{
|
||||
// shortcuts
|
||||
if (! a.bbox ().overlaps (b.box ())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return edge_is_inside_or_outside (true, a, b);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@
|
|||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief The operation mode for the interaction filters
|
||||
*/
|
||||
enum EdgeInteractionMode { EdgesInteract, EdgesInside, EdgesOutside };
|
||||
|
||||
class PolygonSink;
|
||||
|
||||
/**
|
||||
|
|
@ -241,6 +246,21 @@ private:
|
|||
EdgeAngleChecker m_checker;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A predicate defining edge a interacts with b
|
||||
*/
|
||||
DB_PUBLIC bool edge_interacts (const db::Edge &a, const db::Edge &b);
|
||||
|
||||
/**
|
||||
* @brief A predicate defining edge a is "inside" b
|
||||
*/
|
||||
DB_PUBLIC bool edge_is_inside (const db::Edge &a, const db::Edge &b);
|
||||
|
||||
/**
|
||||
* @brief A predicate defining edge a is "outside" b
|
||||
*/
|
||||
DB_PUBLIC bool edge_is_outside (const db::Edge &a, const db::Edge &b);
|
||||
|
||||
/**
|
||||
* @brief A helper class for the edge interaction functionality which acts as an edge pair receiver
|
||||
*/
|
||||
|
|
@ -249,31 +269,65 @@ class edge_interaction_filter
|
|||
: public db::box_scanner_receiver<db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
edge_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output)
|
||||
edge_interaction_filter (OutputContainer &output, EdgeInteractionMode mode)
|
||||
: mp_output (&output), m_mode (mode)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void finish (const db::Edge *o, size_t p)
|
||||
{
|
||||
if (p == 0 && m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
|
||||
mp_output->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
|
||||
{
|
||||
// Select the edges which intersect
|
||||
if (p1 != p2) {
|
||||
|
||||
const db::Edge *o = p1 > p2 ? o2 : o1;
|
||||
const db::Edge *oo = p1 > p2 ? o1 : o2;
|
||||
if (o->intersect (*oo)) {
|
||||
|
||||
if ((m_mode == EdgesInteract && db::edge_interacts (*o, *oo)) ||
|
||||
(m_mode == EdgesInside && db::edge_is_inside (*o, *oo))) {
|
||||
|
||||
if (m_seen.insert (o).second) {
|
||||
mp_output->insert (*o);
|
||||
}
|
||||
|
||||
} else if (m_mode == EdgesOutside && ! db::edge_is_outside (*o, *oo)) {
|
||||
|
||||
// In this case we need to collect edges which are outside always - we report those on "finished".
|
||||
m_seen.insert (o);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const db::Edge *> m_seen;
|
||||
EdgeInteractionMode m_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A predicate defining edge a interacts with polygon b
|
||||
*/
|
||||
DB_PUBLIC bool edge_interacts (const db::Edge &a, const db::Polygon &b);
|
||||
|
||||
/**
|
||||
* @brief A predicate defining edge a is "inside" polygon b
|
||||
*/
|
||||
DB_PUBLIC bool edge_is_inside (const db::Edge &a, const db::Polygon &b);
|
||||
|
||||
/**
|
||||
* @brief A predicate defining edge a is "outside" polygon b
|
||||
*/
|
||||
DB_PUBLIC bool edge_is_outside (const db::Edge &a, const db::Polygon &b);
|
||||
|
||||
/**
|
||||
* @brief A helper class for the edge to region interaction functionality which acts as an edge pair receiver
|
||||
*
|
||||
|
|
@ -288,28 +342,64 @@ class edge_to_region_interaction_filter
|
|||
: public db::box_scanner_receiver2<db::Edge, size_t, db::Polygon, size_t>
|
||||
{
|
||||
public:
|
||||
edge_to_region_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output)
|
||||
edge_to_region_interaction_filter (OutputContainer *output, EdgeInteractionMode mode)
|
||||
: mp_output (output), m_mode (mode)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void finish (const OutputType *o)
|
||||
{
|
||||
if (m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
|
||||
mp_output->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
void finish1 (const db::Edge *o, size_t /*p*/)
|
||||
{
|
||||
const OutputType *ep = 0;
|
||||
tl::select (ep, o, (const db::Polygon *) 0);
|
||||
if (ep) {
|
||||
finish (ep);
|
||||
}
|
||||
}
|
||||
|
||||
void finish2 (const db::Polygon *o, size_t /*p*/)
|
||||
{
|
||||
const OutputType *ep = 0;
|
||||
tl::select (ep, (const db::Edge *) 0, o);
|
||||
if (ep) {
|
||||
finish (ep);
|
||||
}
|
||||
}
|
||||
|
||||
void add (const db::Edge *e, size_t, const db::Polygon *p, size_t)
|
||||
{
|
||||
const OutputType *ep = 0;
|
||||
tl::select (ep, e, p);
|
||||
|
||||
if (m_seen.find (ep) == m_seen.end ()) {
|
||||
if (db::interact (*p, *e)) {
|
||||
|
||||
if ((m_mode == EdgesInteract && db::edge_interacts (*e, *p)) ||
|
||||
(m_mode == EdgesInside && db::edge_is_inside (*e, *p))) {
|
||||
|
||||
m_seen.insert (ep);
|
||||
mp_output->insert (*ep);
|
||||
|
||||
} else if (m_mode == EdgesOutside && ! db::edge_is_outside (*e, *p)) {
|
||||
|
||||
// In this case we need to collect edges which are outside always - we report those on "finished".
|
||||
m_seen.insert (ep);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const OutputType *> m_seen;
|
||||
EdgeInteractionMode m_mode;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -407,7 +497,7 @@ class DB_PUBLIC EdgeSegmentSelector
|
|||
: public EdgeProcessorBase
|
||||
{
|
||||
public:
|
||||
EdgeSegmentSelector (int mode, db::Edges::length_type length, double fraction);
|
||||
EdgeSegmentSelector (int mode, Edge::distance_type length, double fraction);
|
||||
~EdgeSegmentSelector ();
|
||||
|
||||
virtual void process (const db::Edge &edge, std::vector<db::Edge> &res) const;
|
||||
|
|
@ -420,7 +510,7 @@ public:
|
|||
|
||||
private:
|
||||
int m_mode;
|
||||
db::Edges::length_type m_length;
|
||||
db::Edge::distance_type m_length;
|
||||
double m_fraction;
|
||||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -75,9 +75,11 @@ public:
|
|||
virtual EdgesDelegate *merged () const { return new EmptyEdges (); }
|
||||
|
||||
virtual EdgesDelegate *and_with (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *and_with (const Region &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *not_with (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
virtual EdgesDelegate *and_with (const Region &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *not_with (const Region &) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
virtual EdgesDelegate *xor_with (const Edges &other) const;
|
||||
virtual EdgesDelegate *or_with (const Edges &other) const;
|
||||
virtual EdgesDelegate *add_in_place (const Edges &other);
|
||||
|
|
@ -88,12 +90,29 @@ public:
|
|||
|
||||
virtual EdgesDelegate *inside_part (const Region &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *outside_part (const Region &) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> inside_outside_part_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const;
|
||||
virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *selected_interacting (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *selected_not_interacting (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *selected_interacting (const Region &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *selected_not_interacting (const Region &) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
|
||||
virtual EdgesDelegate *selected_outside (const Region &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *selected_not_outside (const Region &) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_outside_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
virtual EdgesDelegate *selected_inside (const Region &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *selected_not_inside (const Region &) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Region &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
virtual EdgesDelegate *selected_outside (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *selected_not_outside (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_outside_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
virtual EdgesDelegate *selected_inside (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *selected_not_inside (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
|
||||
virtual EdgesDelegate *in (const Edges &, bool) const { return new EmptyEdges (); }
|
||||
|
||||
|
|
|
|||
|
|
@ -152,30 +152,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
size_t filled_pixels () const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (std::vector<db::AreaMap>::const_iterator a = m_area_maps.begin (); a != m_area_maps.end (); ++a) {
|
||||
|
||||
db::Coord nx = db::Coord (a->nx ());
|
||||
db::Coord ny = db::Coord (a->ny ());
|
||||
db::AreaMap::area_type amax = a->pixel_area ();
|
||||
|
||||
double n = 0;
|
||||
for (size_t i = 0; i < size_t (nx); ++i) {
|
||||
for (size_t j = 0; j < size_t (ny); ++j) {
|
||||
if (a->get (i, j) >= amax) {
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
const db::Point &p0 () const { return m_origin; }
|
||||
|
||||
unsigned int row_steps () const { return m_row_steps; }
|
||||
|
|
|
|||
|
|
@ -20,12 +20,11 @@
|
|||
|
||||
*/
|
||||
|
||||
|
||||
#include "dbLocalOperation.h"
|
||||
#include "dbHierProcessor.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbBoxConvert.h"
|
||||
#include "dbEdgeProcessor.h"
|
||||
#include "dbPolygonGenerators.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "dbLocalOperationUtils.h"
|
||||
|
|
@ -366,10 +365,16 @@ EdgeBoolAndOrNotLocalOperation::description () const
|
|||
void
|
||||
EdgeBoolAndOrNotLocalOperation::do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
tl_assert (results.size () == 1);
|
||||
tl_assert (results.size () == size_t (m_op == EdgeAndNot ? 2 : 1));
|
||||
|
||||
std::unordered_set<db::Edge> &result = results.front ();
|
||||
|
||||
EdgeBooleanClusterCollector<std::unordered_set<db::Edge> > cluster_collector (&result, m_op);
|
||||
std::unordered_set<db::Edge> *result2 = 0;
|
||||
if (results.size () > 1) {
|
||||
result2 = &results[1];
|
||||
}
|
||||
|
||||
EdgeBooleanClusterCollector<std::unordered_set<db::Edge> > cluster_collector (&result, m_op, result2);
|
||||
|
||||
db::box_scanner<db::Edge, size_t> scanner;
|
||||
|
||||
|
|
@ -381,7 +386,7 @@ EdgeBoolAndOrNotLocalOperation::do_compute_local (db::Layout * /*layout*/, const
|
|||
}
|
||||
|
||||
bool any_subject = false;
|
||||
bool is_and = (m_op == EdgeAnd || m_op == EdgeIntersections);
|
||||
bool is_and = (m_op == EdgeAnd || m_op == EdgeAndNot || m_op == EdgeIntersections);
|
||||
|
||||
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
|
|
@ -416,8 +421,8 @@ EdgeBoolAndOrNotLocalOperation::do_compute_local (db::Layout * /*layout*/, const
|
|||
// ---------------------------------------------------------------------------------------------
|
||||
// EdgeToPolygonLocalOperation implementation
|
||||
|
||||
EdgeToPolygonLocalOperation::EdgeToPolygonLocalOperation (bool outside, bool include_borders)
|
||||
: m_outside (outside), m_include_borders (include_borders)
|
||||
EdgeToPolygonLocalOperation::EdgeToPolygonLocalOperation (EdgePolygonOp::mode_t op, bool include_borders)
|
||||
: m_op (op), m_include_borders (include_borders)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -425,21 +430,33 @@ EdgeToPolygonLocalOperation::EdgeToPolygonLocalOperation (bool outside, bool inc
|
|||
OnEmptyIntruderHint
|
||||
EdgeToPolygonLocalOperation::on_empty_intruder_hint () const
|
||||
{
|
||||
return m_outside ? Copy : Drop;
|
||||
return m_op == EdgePolygonOp::Inside ? Drop : (m_op == EdgePolygonOp::Outside ? Copy : CopyToSecond);
|
||||
}
|
||||
|
||||
std::string
|
||||
EdgeToPolygonLocalOperation::description () const
|
||||
{
|
||||
return tl::to_string (m_outside ? tr ("Edge to polygon AND/INSIDE") : tr ("Edge to polygons NOT/OUTSIDE"));
|
||||
if (m_op == EdgePolygonOp::Inside) {
|
||||
return tl::to_string (tr ("Edge to polygon AND/INSIDE"));
|
||||
} else if (m_op == EdgePolygonOp::Outside) {
|
||||
return tl::to_string (tr ("Edge to polygon NOT/OUTSIDE"));
|
||||
} else {
|
||||
return tl::to_string (tr ("Edge to polygon ANDNOT/INOUTSIDE"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EdgeToPolygonLocalOperation::do_compute_local (db::Layout * /*layout*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
tl_assert (results.size () == 1);
|
||||
tl_assert (results.size () == size_t (m_op == EdgePolygonOp::Both ? 2 : 1));
|
||||
|
||||
std::unordered_set<db::Edge> &result = results.front ();
|
||||
|
||||
std::unordered_set<db::Edge> *result2 = 0;
|
||||
if (results.size () > 1) {
|
||||
result2 = &results[1];
|
||||
}
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
|
|
@ -456,8 +473,10 @@ EdgeToPolygonLocalOperation::do_compute_local (db::Layout * /*layout*/, const sh
|
|||
const db::Edge &subject = interactions.subject_shape (i->first);
|
||||
if (i->second.empty ()) {
|
||||
// shortcut (outside: keep, otherwise: drop)
|
||||
if (m_outside) {
|
||||
if (m_op == db::EdgePolygonOp::Outside) {
|
||||
result.insert (subject);
|
||||
} else if (m_op == db::EdgePolygonOp::Both) {
|
||||
result2->insert (subject);
|
||||
}
|
||||
} else {
|
||||
ep.insert (subject, 1);
|
||||
|
|
@ -474,8 +493,13 @@ EdgeToPolygonLocalOperation::do_compute_local (db::Layout * /*layout*/, const sh
|
|||
}
|
||||
}
|
||||
|
||||
db::EdgeToEdgeSetGenerator cc (result);
|
||||
db::EdgePolygonOp op (m_outside, m_include_borders);
|
||||
std::unique_ptr<db::EdgeToEdgeSetGenerator> cc_second;
|
||||
if (result2) {
|
||||
cc_second.reset (new db::EdgeToEdgeSetGenerator (*result2, 2 /*second tag*/));
|
||||
}
|
||||
|
||||
db::EdgeToEdgeSetGenerator cc (result, 1 /*first tag*/, cc_second.get ());
|
||||
db::EdgePolygonOp op (m_op, m_include_borders);
|
||||
ep.process (cc, op);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "dbLayout.h"
|
||||
#include "dbEdgeBoolean.h"
|
||||
#include "dbEdgeProcessor.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
|
@ -187,7 +188,7 @@ class DB_PUBLIC EdgeBoolAndOrNotLocalOperation
|
|||
: public local_operation<db::Edge, db::Edge, db::Edge>
|
||||
{
|
||||
public:
|
||||
EdgeBoolAndOrNotLocalOperation (EdgeBoolOp op);
|
||||
EdgeBoolAndOrNotLocalOperation (db::EdgeBoolOp op);
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &result, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
|
||||
|
|
@ -197,7 +198,7 @@ public:
|
|||
virtual db::Coord dist () const { return 1; }
|
||||
|
||||
private:
|
||||
EdgeBoolOp m_op;
|
||||
db::EdgeBoolOp m_op;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -210,7 +211,7 @@ class DB_PUBLIC EdgeToPolygonLocalOperation
|
|||
: public local_operation<db::Edge, db::PolygonRef, db::Edge>
|
||||
{
|
||||
public:
|
||||
EdgeToPolygonLocalOperation (bool outside, bool include_borders);
|
||||
EdgeToPolygonLocalOperation (EdgePolygonOp::mode_t op, bool include_borders);
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &result, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
|
||||
|
|
@ -220,7 +221,7 @@ public:
|
|||
virtual db::Coord dist () const { return m_include_borders ? 1 : 0; }
|
||||
|
||||
private:
|
||||
bool m_outside;
|
||||
db::EdgePolygonOp::mode_t m_op;
|
||||
bool m_include_borders;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ namespace db
|
|||
// -----------------------------------------------------------------------------------------------
|
||||
// class EdgeToEdgeSetGenerator
|
||||
|
||||
EdgeToEdgeSetGenerator::EdgeToEdgeSetGenerator (std::unordered_set<db::Edge> &edges)
|
||||
: mp_edges (&edges)
|
||||
EdgeToEdgeSetGenerator::EdgeToEdgeSetGenerator (std::unordered_set<db::Edge> &edges, int tag, EdgeToEdgeSetGenerator *chained)
|
||||
: mp_edges (&edges), m_tag (tag), mp_chained (chained)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -39,6 +39,19 @@ EdgeToEdgeSetGenerator::EdgeToEdgeSetGenerator (std::unordered_set<db::Edge> &ed
|
|||
void EdgeToEdgeSetGenerator::put (const db::Edge &edge)
|
||||
{
|
||||
mp_edges->insert (edge);
|
||||
if (mp_chained) {
|
||||
mp_chained->put (edge);
|
||||
}
|
||||
}
|
||||
|
||||
void EdgeToEdgeSetGenerator::put (const db::Edge &edge, int tag)
|
||||
{
|
||||
if (m_tag == 0 || m_tag == tag) {
|
||||
mp_edges->insert (edge);
|
||||
}
|
||||
if (mp_chained) {
|
||||
mp_chained->put (edge, tag);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -130,15 +130,22 @@ public:
|
|||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
EdgeToEdgeSetGenerator (std::unordered_set<db::Edge> &edges);
|
||||
EdgeToEdgeSetGenerator (std::unordered_set<db::Edge> &edges, int tag = 0, EdgeToEdgeSetGenerator *chained = 0);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the PolygonSink interface
|
||||
*/
|
||||
virtual void put (const db::Edge &edge);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the PolygonSink interface
|
||||
*/
|
||||
virtual void put (const db::Edge &edge, int tag);
|
||||
|
||||
private:
|
||||
std::unordered_set<db::Edge> *mp_edges;
|
||||
int m_tag;
|
||||
EdgeToEdgeSetGenerator *mp_chained;
|
||||
};
|
||||
|
||||
class DB_PUBLIC PolygonRefToShapesGenerator
|
||||
|
|
|
|||
|
|
@ -1181,7 +1181,7 @@ NetlistCompareCore::derive_node_identities_from_singular_match (const NetGraphNo
|
|||
}
|
||||
return tentative ? failed_match : 0;
|
||||
|
||||
} else if ((! n->has_any_other () && ! n_other->has_any_other ()) || (n->has_unknown_other () && n_other->has_unknown_other ())) { // @@@
|
||||
} else if ((! n->has_any_other () && ! n_other->has_any_other ()) || (n->has_unknown_other () && n_other->has_unknown_other ())) {
|
||||
|
||||
// in tentative mode, reject this choice if both nets are named and
|
||||
// their names differ -> this favors net matching by name
|
||||
|
|
|
|||
|
|
@ -220,14 +220,6 @@ public:
|
|||
*/
|
||||
~NetlistDeviceExtractor ();
|
||||
|
||||
/**
|
||||
* @brief Gets the name of the extractor and the device class
|
||||
*/
|
||||
const std::string &name ()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the property name for the device terminal annotation
|
||||
* This name is used to attach the terminal ID to terminal shapes.
|
||||
|
|
@ -321,6 +313,14 @@ public:
|
|||
m_name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the name of the device class and the device extractor
|
||||
*/
|
||||
const std::string &name () const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets up the extractor
|
||||
*
|
||||
|
|
|
|||
|
|
@ -97,7 +97,13 @@ Reader::Reader (tl::InputStream &stream)
|
|||
}
|
||||
|
||||
if (! mp_actual_reader) {
|
||||
throw db::ReaderException (tl::to_string (tr ("Stream has unknown format: ")) + stream.source ());
|
||||
|
||||
m_stream.reset ();
|
||||
std::string head = m_stream.read_all (4000);
|
||||
bool has_more (m_stream.get (1) != 0);
|
||||
|
||||
throw db::ReaderUnknownFormatException (tl::to_string (tr ("Stream has unknown format: ")) + stream.source (), head, has_more);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,35 @@ public:
|
|||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class representing the "unknown format" reader error
|
||||
*
|
||||
* The purpose of this class is supply the header bytes of the
|
||||
* data stream for analysis.
|
||||
*/
|
||||
class DB_PUBLIC ReaderUnknownFormatException
|
||||
: public ReaderException
|
||||
{
|
||||
public:
|
||||
ReaderUnknownFormatException (const std::string &msg, const std::string &data, bool has_more)
|
||||
: ReaderException (msg), m_data (data), m_has_more (has_more)
|
||||
{ }
|
||||
|
||||
const std::string &data () const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
bool has_more () const
|
||||
{
|
||||
return m_has_more;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_data;
|
||||
bool m_has_more;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Joins layer names into a single, combined layer
|
||||
* @param s The first layer name and output
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ public:
|
|||
*
|
||||
* @param clear_shapes If true, the shapes container is cleared on the start event.
|
||||
*/
|
||||
EdgeShapeGenerator (db::Shapes &shapes, bool clear_shapes = false)
|
||||
: EdgeSink (), mp_shapes (&shapes), m_clear_shapes (clear_shapes)
|
||||
EdgeShapeGenerator (db::Shapes &shapes, bool clear_shapes = false, int tag = 0, EdgeShapeGenerator *chained = 0)
|
||||
: EdgeSink (), mp_shapes (&shapes), m_clear_shapes (clear_shapes), m_tag (tag), mp_chained (chained)
|
||||
{ }
|
||||
|
||||
/**
|
||||
|
|
@ -115,6 +115,22 @@ public:
|
|||
virtual void put (const db::Edge &edge)
|
||||
{
|
||||
mp_shapes->insert (edge);
|
||||
if (mp_chained) {
|
||||
mp_chained->put (edge);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Implementation of the EdgeSink interface
|
||||
*/
|
||||
virtual void put (const db::Edge &edge, int tag)
|
||||
{
|
||||
if (m_tag == 0 || m_tag == tag) {
|
||||
mp_shapes->insert (edge);
|
||||
}
|
||||
if (mp_chained) {
|
||||
mp_chained->put (edge, tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -127,11 +143,16 @@ public:
|
|||
// The single-shot scheme is a easy way to overcome problems with multiple start/flush brackets (i.e. on size filter)
|
||||
m_clear_shapes = false;
|
||||
}
|
||||
if (mp_chained) {
|
||||
mp_chained->start ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
db::Shapes *mp_shapes;
|
||||
bool m_clear_shapes;
|
||||
int m_tag;
|
||||
EdgeShapeGenerator *mp_chained;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -38,9 +38,11 @@
|
|||
#include "dbCellMapping.h"
|
||||
#include "dbPCellDeclaration.h"
|
||||
#include "dbSaveLayoutOptions.h"
|
||||
#include "dbLoadLayoutOptions.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbRecursiveInstanceIterator.h"
|
||||
#include "dbWriter.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbHash.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
|
|
@ -1683,6 +1685,39 @@ static const char *cell_name (const db::Cell *cell)
|
|||
}
|
||||
}
|
||||
|
||||
static std::vector<db::cell_index_type>
|
||||
read_options (db::Cell *cell, const std::string &path, const db::LoadLayoutOptions &options)
|
||||
{
|
||||
if (! cell->layout ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout - cannot read such cells")));
|
||||
}
|
||||
|
||||
db::Layout tmp (cell->layout ()->dbu ());
|
||||
|
||||
{
|
||||
tl::InputStream stream (path);
|
||||
db::Reader reader (stream);
|
||||
reader.read (tmp, options);
|
||||
}
|
||||
|
||||
if (tmp.end_top_cells () - tmp.begin_top_down () != 1) {
|
||||
throw tl::Exception (tl::to_string (tr ("Imported layout does not have a single top cell - cannot read such layouts into a cell")));
|
||||
}
|
||||
|
||||
db::CellMapping cm;
|
||||
std::vector<db::cell_index_type> new_cells = cm.create_single_mapping_full (*cell->layout (), cell->cell_index (), tmp, *tmp.begin_top_down ());
|
||||
cell->move_tree_shapes (tmp.cell (*tmp.begin_top_down ()), cm);
|
||||
|
||||
return new_cells;
|
||||
}
|
||||
|
||||
static std::vector<db::cell_index_type>
|
||||
read_simple (db::Cell *cell, const std::string &path)
|
||||
{
|
||||
return read_options (cell, path, db::LoadLayoutOptions ());
|
||||
}
|
||||
|
||||
|
||||
static db::Point default_origin;
|
||||
|
||||
Class<db::Cell> decl_Cell ("db", "Cell",
|
||||
|
|
@ -1761,6 +1796,40 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23.\n"
|
||||
) +
|
||||
gsi::method_ext ("read", &read_options, gsi::arg ("file_name"), gsi::arg ("options"),
|
||||
"@brief Reads a layout file into this cell\n"
|
||||
"\n"
|
||||
"@param file_name The path of the file to read\n"
|
||||
"@param options The reader options to use\n"
|
||||
"@return The indexes of the cells created during the reading (new child cells)\n"
|
||||
"\n"
|
||||
"The format of the file will be determined from the file name. "
|
||||
"The layout will be read into the cell, potentially creating new layers and "
|
||||
"a subhierarchy of cells below this cell.\n"
|
||||
"\n"
|
||||
"This feature is equivalent to the following code:\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"def Cell.read(file_name, options)\n"
|
||||
" layout = RBA::Layout::new\n"
|
||||
" layout.read(file_name, options)\n"
|
||||
" cm = RBA::CellMapping::new\n"
|
||||
" cm.for_single_cell_full(self, layout.top_cell)\n"
|
||||
" self.move_tree_shapes(layout.top_cell)\n"
|
||||
"end\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"See \\move_tree_shapes and \\CellMapping for more details and how to "
|
||||
"implement more elaborate schemes.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::method_ext ("read", &read_simple, gsi::arg ("file_name"),
|
||||
"@brief Reads a layout file into this cell\n"
|
||||
"This version uses the default options for reading the file.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::method_ext ("dup", &dup_cell,
|
||||
"@brief Creates a copy of the cell\n"
|
||||
"\n"
|
||||
|
|
@ -2649,14 +2718,16 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"@return The bounding box of the cell\n"
|
||||
"\n"
|
||||
"The bounding box is computed over all layers. To compute the bounding box over single layers, "
|
||||
"use \\bbox_per_layer.\n"
|
||||
"use \\bbox with a layer index argument.\n"
|
||||
) +
|
||||
gsi::method ("bbox_per_layer", (const db::Cell::box_type &(db::Cell::*) (unsigned int) const) &db::Cell::bbox, gsi::arg ("layer_index"),
|
||||
gsi::method ("bbox|#bbox_per_layer", (const db::Cell::box_type &(db::Cell::*) (unsigned int) const) &db::Cell::bbox, gsi::arg ("layer_index"),
|
||||
"@brief Gets the per-layer bounding box of the cell\n"
|
||||
"\n"
|
||||
"@return The bounding box of the cell considering only the given layer\n"
|
||||
"\n"
|
||||
"The bounding box is the box enclosing all shapes on the given layer.\n"
|
||||
"\n"
|
||||
"'bbox' is the preferred synonym since version 0.28.\n"
|
||||
) +
|
||||
gsi::method_ext ("dbbox", &cell_dbbox,
|
||||
"@brief Gets the bounding box of the cell in micrometer units\n"
|
||||
|
|
@ -2664,18 +2735,19 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"@return The bounding box of the cell\n"
|
||||
"\n"
|
||||
"The bounding box is computed over all layers. To compute the bounding box over single layers, "
|
||||
"use \\dbbox_per_layer.\n"
|
||||
"use \\dbbox with a layer index argument.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method_ext ("dbbox_per_layer", &cell_dbbox_per_layer, gsi::arg ("layer_index"),
|
||||
gsi::method_ext ("dbbox|#dbbox_per_layer", &cell_dbbox_per_layer, gsi::arg ("layer_index"),
|
||||
"@brief Gets the per-layer bounding box of the cell in micrometer units\n"
|
||||
"\n"
|
||||
"@return The bounding box of the cell considering only the given layer\n"
|
||||
"\n"
|
||||
"The bounding box is the box enclosing all shapes on the given layer.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
"This method has been introduced in version 0.25. "
|
||||
"'dbbox' is the preferred synonym since version 0.28.\n"
|
||||
) +
|
||||
gsi::iterator_ext ("each_overlapping_inst", &begin_overlapping_inst, gsi::arg ("b"),
|
||||
"@brief Gets the instances overlapping the given rectangle\n"
|
||||
|
|
@ -3844,22 +3916,22 @@ Class<db::Instance> decl_Instance ("db", "Instance",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
) +
|
||||
gsi::method_ext ("bbox_per_layer", &inst_bbox_per_layer, gsi::arg ("layer_index"),
|
||||
gsi::method_ext ("bbox|#bbox_per_layer", &inst_bbox_per_layer, gsi::arg ("layer_index"),
|
||||
"@brief Gets the bounding box of the instance for a given layer\n"
|
||||
"@param layer_index The index of the layer the bounding box will be computed for.\n"
|
||||
"The bounding box incorporates all instances that the array represents. "
|
||||
"It gives the overall extension of the child cell as seen in the calling cell (or all array members if the instance forms an array) "
|
||||
"for the given layer. If the layer is empty in this cell and all it's children', an empty bounding box will be returned. "
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
"This method has been introduced in version 0.25. 'bbox' is the preferred synonym for it since version 0.28."
|
||||
) +
|
||||
gsi::method_ext ("dbbox_per_layer", &inst_dbbox_per_layer, gsi::arg ("layer_index"),
|
||||
gsi::method_ext ("dbbox|#dbbox_per_layer", &inst_dbbox_per_layer, gsi::arg ("layer_index"),
|
||||
"@brief Gets the bounding box of the instance in micron units\n"
|
||||
"@param layer_index The index of the layer the bounding box will be computed for.\n"
|
||||
"Gets the bounding box (see \\bbox_per_layer) of the instance, but will compute the micrometer unit box by "
|
||||
"multiplying \\bbox_per_layer with the database unit.\n"
|
||||
"Gets the bounding box (see \\bbox) of the instance, but will compute the micrometer unit box by "
|
||||
"multiplying \\bbox with the database unit.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.25."
|
||||
"This method has been introduced in version 0.25. 'dbbox' is the preferred synonym for it since version 0.28."
|
||||
) +
|
||||
gsi::method_ext ("parent_cell", &parent_cell_ptr,
|
||||
"@brief Gets the cell this instance is contained in\n"
|
||||
|
|
@ -4343,10 +4415,12 @@ static db::CellInstArray::box_type cell_inst_array_bbox_per_layer (const db::Cel
|
|||
|
||||
Class<db::CellInstArray> decl_CellInstArray ("db", "CellInstArray",
|
||||
cell_inst_array_defs<db::CellInstArray>::methods (false /*old version*/) +
|
||||
gsi::method_ext ("bbox_per_layer", &cell_inst_array_bbox_per_layer, gsi::arg ("layout"), gsi::arg ("layer_index"),
|
||||
gsi::method_ext ("bbox|#bbox_per_layer", &cell_inst_array_bbox_per_layer, gsi::arg ("layout"), gsi::arg ("layer_index"),
|
||||
"@brief Gets the bounding box of the array with respect to one layer\n"
|
||||
"The bounding box incorporates all instances that the array represents. It needs the layout object to access the "
|
||||
"actual cell from the cell index."
|
||||
"actual cell from the cell index.\n"
|
||||
"\n"
|
||||
"'bbox' is the preferred synonym since version 0.28.\n"
|
||||
) +
|
||||
gsi::method_ext ("bbox", &cell_inst_array_bbox, gsi::arg ("layout"),
|
||||
"@brief Gets the bounding box of the array\n"
|
||||
|
|
@ -4405,10 +4479,12 @@ static db::DBox cell_dinst_array_bbox_per_layer (const db::DCellInstArray *a, co
|
|||
|
||||
Class<db::DCellInstArray> decl_DCellInstArray ("db", "DCellInstArray",
|
||||
cell_inst_array_defs<db::DCellInstArray>::methods (true /*new version*/) +
|
||||
gsi::method_ext ("bbox_per_layer", &cell_dinst_array_bbox_per_layer, gsi::arg ("layout"), gsi::arg ("layer_index"),
|
||||
gsi::method_ext ("bbox|#bbox_per_layer", &cell_dinst_array_bbox_per_layer, gsi::arg ("layout"), gsi::arg ("layer_index"),
|
||||
"@brief Gets the bounding box of the array with respect to one layer\n"
|
||||
"The bounding box incorporates all instances that the array represents. It needs the layout object to access the "
|
||||
"actual cell from the cell index."
|
||||
"actual cell from the cell index.\n"
|
||||
"\n"
|
||||
"'bbox' is the preferred synonym since version 0.28.\n"
|
||||
) +
|
||||
gsi::method_ext ("bbox", &cell_dinst_array_bbox, gsi::arg ("layout"),
|
||||
"@brief Gets the bounding box of the array\n"
|
||||
|
|
|
|||
|
|
@ -36,9 +36,98 @@ static db::cell_index_type drop_cell_const ()
|
|||
return db::DropCell;
|
||||
}
|
||||
|
||||
static void create_single_mapping (db::CellMapping *cm, db::Cell &a, const db::Cell &b)
|
||||
{
|
||||
tl_assert (a.layout () != 0);
|
||||
tl_assert (b.layout () != 0);
|
||||
cm->create_single_mapping (*a.layout (), a.cell_index (), *b.layout(), b.cell_index ());
|
||||
}
|
||||
|
||||
static std::vector<db::cell_index_type> create_single_mapping_full (db::CellMapping *cm, db::Cell &a, const db::Cell &b)
|
||||
{
|
||||
tl_assert (a.layout () != 0);
|
||||
tl_assert (b.layout () != 0);
|
||||
return cm->create_single_mapping_full (*a.layout (), a.cell_index (), *b.layout(), b.cell_index ());
|
||||
}
|
||||
|
||||
static std::vector<db::cell_index_type> create_multi_mapping_gen (db::CellMapping *cm, const std::vector<db::Cell *> &a, const std::vector<const db::Cell *> &b, bool full)
|
||||
{
|
||||
db::Layout *lya = 0;
|
||||
const db::Layout *lyb = 0;
|
||||
std::vector<db::cell_index_type> cia, cib;
|
||||
|
||||
for (auto i = a.begin (); i != a.end (); ++i) {
|
||||
tl_assert (*i != 0);
|
||||
tl_assert ((*i)->layout () != 0);
|
||||
cia.push_back ((*i)->cell_index ());
|
||||
if (lya == 0) {
|
||||
lya = (*i)->layout ();
|
||||
} else if (lya != (*i)->layout ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("First cell array contains cells from different layouts")));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i = b.begin (); i != b.end (); ++i) {
|
||||
tl_assert (*i != 0);
|
||||
tl_assert ((*i)->layout () != 0);
|
||||
cib.push_back ((*i)->cell_index ());
|
||||
if (lyb == 0) {
|
||||
lyb = (*i)->layout ();
|
||||
} else if (lyb != (*i)->layout ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Second cell array contains cells from different layouts")));
|
||||
}
|
||||
}
|
||||
|
||||
if (full) {
|
||||
return cm->create_multi_mapping_full (*lya, cia, *lyb, cib);
|
||||
} else {
|
||||
cm->create_multi_mapping (*lya, cia, *lyb, cib);
|
||||
return std::vector<db::cell_index_type> ();
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<db::cell_index_type> create_multi_mapping_full (db::CellMapping *cm, const std::vector<db::Cell *> &a, const std::vector<const db::Cell *> &b)
|
||||
{
|
||||
return create_multi_mapping_gen (cm, a, b, true);
|
||||
}
|
||||
|
||||
static void create_multi_mapping (db::CellMapping *cm, const std::vector<db::Cell *> &a, const std::vector<const db::Cell *> &b)
|
||||
{
|
||||
create_multi_mapping_gen (cm, a, b, false);
|
||||
}
|
||||
|
||||
static void create_from_geometry (db::CellMapping *cm, db::Cell &a, const db::Cell &b)
|
||||
{
|
||||
tl_assert (a.layout () != 0);
|
||||
tl_assert (b.layout () != 0);
|
||||
return cm->create_from_geometry (*a.layout (), a.cell_index (), *b.layout(), b.cell_index ());
|
||||
}
|
||||
|
||||
static std::vector<db::cell_index_type> create_from_geometry_full (db::CellMapping *cm, db::Cell &a, const db::Cell &b)
|
||||
{
|
||||
tl_assert (a.layout () != 0);
|
||||
tl_assert (b.layout () != 0);
|
||||
return cm->create_from_geometry_full (*a.layout (), a.cell_index (), *b.layout(), b.cell_index ());
|
||||
}
|
||||
|
||||
static void create_from_names (db::CellMapping *cm, db::Cell &a, const db::Cell &b)
|
||||
{
|
||||
tl_assert (a.layout () != 0);
|
||||
tl_assert (b.layout () != 0);
|
||||
return cm->create_from_names (*a.layout (), a.cell_index (), *b.layout(), b.cell_index ());
|
||||
}
|
||||
|
||||
static std::vector<db::cell_index_type> create_from_names_full (db::CellMapping *cm, db::Cell &a, const db::Cell &b)
|
||||
{
|
||||
tl_assert (a.layout () != 0);
|
||||
tl_assert (b.layout () != 0);
|
||||
return cm->create_from_names_full (*a.layout (), a.cell_index (), *b.layout(), b.cell_index ());
|
||||
}
|
||||
|
||||
|
||||
Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
||||
gsi::method ("DropCell", &drop_cell_const,
|
||||
"@brief A constant indicating the reques to drop a cell\n"
|
||||
"@brief A constant indicating the request to drop a cell\n"
|
||||
"\n"
|
||||
"If used as a pseudo-target for the cell mapping, this index indicates "
|
||||
"that the cell shall be dropped rather than created on the target side "
|
||||
|
|
@ -65,9 +154,19 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method ("for_single_cell_full", &db::CellMapping::create_single_mapping_full, gsi::arg ("layout_a"), gsi::arg ("cell_index_a"), gsi::arg ("layout_b"), gsi::arg ("cell_index_b"),
|
||||
gsi::method_ext ("for_single_cell", &create_single_mapping, gsi::arg ("cell_a"), gsi::arg ("cell_b"),
|
||||
"@brief Initializes the cell mapping for top-level identity\n"
|
||||
"\n"
|
||||
"@param cell_a The target cell.\n"
|
||||
"@param cell_b The source cell.\n"
|
||||
"@return A list of indexes of cells created.\n"
|
||||
"\n"
|
||||
"This is a convenience version which uses cell references instead of layout/cell index combinations. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
gsi::method ("for_single_cell_full", &db::CellMapping::create_single_mapping_full, gsi::arg ("layout_a"), gsi::arg ("cell_index_a"), gsi::arg ("layout_b"), gsi::arg ("cell_index_b"),
|
||||
"@brief Initializes the cell mapping for top-level identity in full mapping mode\n"
|
||||
"\n"
|
||||
"@param layout_a The target layout.\n"
|
||||
"@param cell_index_a The index of the target cell.\n"
|
||||
"@param layout_b The source layout.\n"
|
||||
|
|
@ -80,6 +179,16 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method_ext ("for_single_cell_full", &create_single_mapping_full, gsi::arg ("cell_a"), gsi::arg ("cell_b"),
|
||||
"@brief Initializes the cell mapping for top-level identity in full mapping mode\n"
|
||||
"\n"
|
||||
"@param cell_a The target cell.\n"
|
||||
"@param cell_b The source cell.\n"
|
||||
"@return A list of indexes of cells created.\n"
|
||||
"\n"
|
||||
"This is a convenience version which uses cell references instead of layout/cell index combinations. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
gsi::method ("for_multi_cells", &db::CellMapping::create_multi_mapping, gsi::arg ("layout_a"), gsi::arg ("cell_indexes_a"), gsi::arg ("layout_b"), gsi::arg ("cell_indexes_b"),
|
||||
"@brief Initializes the cell mapping for top-level identity\n"
|
||||
"\n"
|
||||
|
|
@ -97,9 +206,19 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method ("for_multi_cells_full", &db::CellMapping::create_multi_mapping_full, gsi::arg ("layout_a"), gsi::arg ("cell_indexes_a"), gsi::arg ("layout_b"), gsi::arg ("cell_indexes_b"),
|
||||
gsi::method_ext ("for_multi_cells", &create_multi_mapping, gsi::arg ("cell_a"), gsi::arg ("cell_b"),
|
||||
"@brief Initializes the cell mapping for top-level identity\n"
|
||||
"\n"
|
||||
"@param cell_a A list of target cells.\n"
|
||||
"@param cell_b A list of source cells.\n"
|
||||
"@return A list of indexes of cells created.\n"
|
||||
"\n"
|
||||
"This is a convenience version which uses cell references instead of layout/cell index combinations. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
gsi::method ("for_multi_cells_full", &db::CellMapping::create_multi_mapping_full, gsi::arg ("layout_a"), gsi::arg ("cell_indexes_a"), gsi::arg ("layout_b"), gsi::arg ("cell_indexes_b"),
|
||||
"@brief Initializes the cell mapping for top-level identity in full mapping mode\n"
|
||||
"\n"
|
||||
"@param layout_a The target layout.\n"
|
||||
"@param cell_indexes_a A list of cell indexes for the target cells.\n"
|
||||
"@param layout_b The source layout.\n"
|
||||
|
|
@ -112,6 +231,16 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method_ext ("for_multi_cells_full", &create_multi_mapping_full, gsi::arg ("cell_a"), gsi::arg ("cell_b"),
|
||||
"@brief Initializes the cell mapping for top-level identity in full mapping mode\n"
|
||||
"\n"
|
||||
"@param cell_a A list of target cells.\n"
|
||||
"@param cell_b A list of source cells.\n"
|
||||
"@return A list of indexes of cells created.\n"
|
||||
"\n"
|
||||
"This is a convenience version which uses cell references instead of layout/cell index combinations. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
gsi::method ("from_geometry_full", &db::CellMapping::create_from_geometry_full, gsi::arg ("layout_a"), gsi::arg ("cell_index_a"), gsi::arg ("layout_b"), gsi::arg ("cell_index_b"),
|
||||
"@brief Initializes the cell mapping using the geometrical identity in full mapping mode\n"
|
||||
"\n"
|
||||
|
|
@ -132,6 +261,16 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method_ext ("from_geometry_full", &create_from_geometry_full, gsi::arg ("cell_a"), gsi::arg ("cell_b"),
|
||||
"@brief Initializes the cell mapping using the geometrical identity in full mapping mode\n"
|
||||
"\n"
|
||||
"@param cell_a The target cell.\n"
|
||||
"@param cell_b The source cell.\n"
|
||||
"@return A list of indexes of cells created.\n"
|
||||
"\n"
|
||||
"This is a convenience version which uses cell references instead of layout/cell index combinations. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
gsi::method ("from_geometry", &db::CellMapping::create_from_geometry, gsi::arg ("layout_a"), gsi::arg ("cell_index_a"), gsi::arg ("layout_b"), gsi::arg ("cell_index_b"),
|
||||
"@brief Initializes the cell mapping using the geometrical identity\n"
|
||||
"\n"
|
||||
|
|
@ -147,6 +286,16 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method_ext ("from_geometry", &create_from_geometry, gsi::arg ("cell_a"), gsi::arg ("cell_b"),
|
||||
"@brief Initializes the cell mapping using the geometrical identity\n"
|
||||
"\n"
|
||||
"@param cell_a The target cell.\n"
|
||||
"@param cell_b The source cell.\n"
|
||||
"@return A list of indexes of cells created.\n"
|
||||
"\n"
|
||||
"This is a convenience version which uses cell references instead of layout/cell index combinations. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
gsi::method ("from_names", &db::CellMapping::create_from_names, gsi::arg ("layout_a"), gsi::arg ("cell_index_a"), gsi::arg ("layout_b"), gsi::arg ("cell_index_b"),
|
||||
"@brief Initializes the cell mapping using the name identity\n"
|
||||
"\n"
|
||||
|
|
@ -161,6 +310,16 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method_ext ("from_names", &create_from_names, gsi::arg ("cell_a"), gsi::arg ("cell_b"),
|
||||
"@brief Initializes the cell mapping using the name identity\n"
|
||||
"\n"
|
||||
"@param cell_a The target cell.\n"
|
||||
"@param cell_b The source cell.\n"
|
||||
"@return A list of indexes of cells created.\n"
|
||||
"\n"
|
||||
"This is a convenience version which uses cell references instead of layout/cell index combinations. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
gsi::method ("from_names_full", &db::CellMapping::create_from_names_full, gsi::arg ("layout_a"), gsi::arg ("cell_index_a"), gsi::arg ("layout_b"), gsi::arg ("cell_index_b"),
|
||||
"@brief Initializes the cell mapping using the name identity in full mapping mode\n"
|
||||
"\n"
|
||||
|
|
@ -180,7 +339,17 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
) +
|
||||
gsi::method ("clear", &db::CellMapping::clear,
|
||||
gsi::method_ext ("from_names_full", &create_from_names_full, gsi::arg ("cell_a"), gsi::arg ("cell_b"),
|
||||
"@brief Initializes the cell mapping using the name identity in full mapping mode\n"
|
||||
"\n"
|
||||
"@param cell_a The target cell.\n"
|
||||
"@param cell_b The source cell.\n"
|
||||
"@return A list of indexes of cells created.\n"
|
||||
"\n"
|
||||
"This is a convenience version which uses cell references instead of layout/cell index combinations. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
gsi::method ("clear", &db::CellMapping::clear,
|
||||
"@brief Clears the mapping.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23."
|
||||
|
|
@ -208,7 +377,6 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
gsi::method ("has_mapping?", &db::CellMapping::has_mapping, gsi::arg ("cell_index_b"),
|
||||
"@brief Returns as value indicating whether a cell of layout_b has a mapping to a layout_a cell.\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"@param cell_index_b The index of the cell in layout_b whose mapping is requested.\n"
|
||||
"@return true, if the cell has a mapping\n"
|
||||
"\n"
|
||||
|
|
@ -231,15 +399,27 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"the mapping of cells of a source layout B to a target layout A. The cell mapping object "
|
||||
"is basically a table associating a cell in layout B with a cell in layout A.\n"
|
||||
"\n"
|
||||
"The cell mapping is of particular interest for providing the cell mapping recipe in "
|
||||
"\\Cell#copy_tree_shapes or \\Cell#move_tree_shapes.\n"
|
||||
"\n"
|
||||
"The mapping object is used to create and hold that table. There are three basic modes in which "
|
||||
"a table can be generated:\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
" @li Top-level identity @/li\n"
|
||||
" @li Geometrical identity @/li\n"
|
||||
" @li Name identity @/li\n"
|
||||
" @li Top-level identity (\\for_single_cell and \\for_single_cell_full) @/li\n"
|
||||
" @li Top-level identify for multiple cells (\\for_multi_cells_full and \\for_multi_cells_full) @/li\n"
|
||||
" @li Geometrical identity (\\from_geometry and \\from_geometry_full)@/li\n"
|
||||
" @li Name identity (\\from_names and \\from_names_full) @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"'full' refers to the way cells are treated which are not mentioned. In the 'full' versions, "
|
||||
"cells for which no mapping is established explicitly - specifically all child cells in top-level identity modes - "
|
||||
"are created in the target layout and instantiated according to their source layout hierarchy. Then, these new "
|
||||
"cells become targets of the respective source cells. "
|
||||
"In the plain version (without 'full' cells), no additional cells are created. For the case of \\Layout#copy_tree_shapes "
|
||||
"cells not explicitly mapped are flattened. Hence for example, \\for_single_cell will flatten all children of the source cell during "
|
||||
"\\Layout#copy_tree_shapes or \\Layout#move_tree_shapes.\n"
|
||||
"\n"
|
||||
"Top-level identity means that only one cell (the top cell) is regarded identical. All child cells are "
|
||||
"not considered identical. In full mode (see below), this will create a new, identical cell tree "
|
||||
"below the top cell in layout A.\n"
|
||||
|
|
@ -264,10 +444,42 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\\from_names_full or \\from_geometry_full. These versions will create new cells and their corresponding "
|
||||
"instances in the target layout if no suitable target cell is found.\n"
|
||||
"\n"
|
||||
"CellMapping objects play a role mainly in the hierarchical copy or move operations of \\Layout. "
|
||||
"However, use is not restricted to these applications.\n"
|
||||
"This is a simple example for a cell mapping preserving the hierarchy of the source cell and creating "
|
||||
"a hierarchy copy in the top cell of the target layout ('hierarchical merge'):\n"
|
||||
"\n"
|
||||
"Here is one example for using \\CellMapping. It extracts cells 'A', 'B' and 'C' from one layout "
|
||||
"@code\n"
|
||||
"cell_names = [ \"A\", \"B\", \"C\" ]\n"
|
||||
"\n"
|
||||
"source = RBA::Layout::new\n"
|
||||
"source.read(\"input.gds\")\n"
|
||||
"\n"
|
||||
"target = RBA::Layout::new\n"
|
||||
"target_top = target.create_cell(\"IMPORTED\")\n"
|
||||
"\n"
|
||||
"cm = RBA::CellMapping::new\n"
|
||||
"# Copies the source layout hierarchy into the target top cell:\n"
|
||||
"cm.for_single_cell_full(target_top, source.top_cell)\n"
|
||||
"target.copy_tree_shapes(source, cm)\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"Without 'full', the effect is move-with-flattening (note we're using 'move' in this example):\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"cell_names = [ \"A\", \"B\", \"C\" ]\n"
|
||||
"\n"
|
||||
"source = RBA::Layout::new\n"
|
||||
"source.read(\"input.gds\")\n"
|
||||
"\n"
|
||||
"target = RBA::Layout::new\n"
|
||||
"target_top = target.create_cell(\"IMPORTED\")\n"
|
||||
"\n"
|
||||
"cm = RBA::CellMapping::new\n"
|
||||
"# Flattens the source layout hierarchy into the target top cell:\n"
|
||||
"cm.for_single_cell(target_top, source.top_cell)\n"
|
||||
"target.move_tree_shapes(source, cm)\n"
|
||||
"@/code\n"
|
||||
"\n"
|
||||
"This is another example for using \\CellMapping in multiple top cell identity mode. It extracts cells 'A', 'B' and 'C' from one layout "
|
||||
"and copies them to another. It will also copy all shapes and all child cells. Child cells which are "
|
||||
"shared between the three initial cells will be shared in the target layout too.\n"
|
||||
"\n"
|
||||
|
|
@ -279,11 +491,11 @@ Class<db::CellMapping> decl_CellMapping ("db", "CellMapping",
|
|||
"\n"
|
||||
"target = RBA::Layout::new\n"
|
||||
"\n"
|
||||
"source_cells = cell_names.collect { |n| source.cell_by_name(n).cell_index }\n"
|
||||
"target_cells = cell_names.collect { |n| target.create_cell(n).cell_index }\n"
|
||||
"source_cells = cell_names.collect { |n| source.cell_by_name(n) }\n"
|
||||
"target_cells = cell_names.collect { |n| target.create_cell(n) }\n"
|
||||
"\n"
|
||||
"cm = RBA::CellMapping::new\n"
|
||||
"cm.for_multi_cells_full(source, source_cells, target, target_cells)\n"
|
||||
"cm.for_multi_cells_full(target_cells, source_cells)\n"
|
||||
"target.copy_tree_shapes(source, cm)\n"
|
||||
"@/code\n"
|
||||
);
|
||||
|
|
|
|||
|
|
@ -711,7 +711,7 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
"This node renders the input if the specified bounding box parameter of the input shape is between pmin and pmax (exclusively). If 'inverse' is set to true, the "
|
||||
"input shape is returned if the parameter is less than pmin (exclusively) or larger than pmax (inclusively)."
|
||||
) +
|
||||
gsi::constructor ("new_ratio_filter", &new_ratio_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0.0), gsi::arg ("pmin_included"), gsi::arg ("pmax", std::numeric_limits<double>::max (), "max"), gsi::arg ("pmax_included", true),
|
||||
gsi::constructor ("new_ratio_filter", &new_ratio_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0.0), gsi::arg ("pmin_included", true), gsi::arg ("pmax", std::numeric_limits<double>::max (), "max"), gsi::arg ("pmax_included", true),
|
||||
"@brief Creates a node filtering the input by ratio parameters.\n"
|
||||
"This node renders the input if the specified ratio parameter of the input shape is between pmin and pmax. If 'pmin_included' is true, the range will include pmin. Same for 'pmax_included' and pmax. "
|
||||
"If 'inverse' is set to true, the input shape is returned if the parameter is not within the specified range."
|
||||
|
|
@ -732,7 +732,7 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
gsi::constructor ("new_edge_length_sum_filter", &new_edge_length_sum_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits<db::Edge::distance_type>::max (), "max"),
|
||||
"@brief Creates a node filtering edges by their length sum (over the local set).\n"
|
||||
) +
|
||||
gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("amin"), gsi::arg ("include_amin"), gsi::arg ("amax"), gsi::arg ("include_amax"),
|
||||
gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse"), gsi::arg ("amin"), gsi::arg ("include_amin"), gsi::arg ("amax"), gsi::arg ("include_amax"),
|
||||
"@brief Creates a node filtering edges by their orientation.\n"
|
||||
) +
|
||||
gsi::constructor ("new_polygons", &new_polygons, gsi::arg ("input"), gsi::arg ("e", 0),
|
||||
|
|
@ -923,4 +923,3 @@ gsi::EnumIn<db::CompoundRegionOperationNode, db::RegionRatioFilter::parameter_ty
|
|||
);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ struct edge_pair_defs
|
|||
return c.release ();
|
||||
}
|
||||
|
||||
static C *new_v ()
|
||||
static C *new_v ()
|
||||
{
|
||||
return new C ();
|
||||
}
|
||||
|
|
@ -67,29 +67,29 @@ struct edge_pair_defs
|
|||
static gsi::Methods methods ()
|
||||
{
|
||||
return
|
||||
constructor ("new", &new_v,
|
||||
constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
"This constructor creates an default edge pair.\n"
|
||||
) +
|
||||
) +
|
||||
constructor ("new", &new_ee, gsi::arg ("first"), gsi::arg ("second"), gsi::arg ("symmetric", false),
|
||||
"@brief Constructor from two edges\n"
|
||||
"\n"
|
||||
"This constructor creates an edge pair from the two edges given.\n"
|
||||
"See \\symmetric? for a description of this attribute."
|
||||
) +
|
||||
method ("first", (const edge_type &(C::*) () const) &C::first,
|
||||
) +
|
||||
method ("first", (const edge_type &(C::*) () const) &C::first,
|
||||
"@brief Gets the first edge\n"
|
||||
) +
|
||||
) +
|
||||
method ("first=", &C::set_first, gsi::arg ("edge"),
|
||||
"@brief Sets the first edge\n"
|
||||
) +
|
||||
method ("second", (const edge_type &(C::*) () const) &C::second,
|
||||
) +
|
||||
method ("second", (const edge_type &(C::*) () const) &C::second,
|
||||
"@brief Gets the second edge\n"
|
||||
) +
|
||||
) +
|
||||
method ("second=", &C::set_second, gsi::arg ("edge"),
|
||||
"@brief Sets the second edge\n"
|
||||
) +
|
||||
) +
|
||||
method ("symmetric?", &C::is_symmetric,
|
||||
"@brief Returns a value indicating whether the edge pair is symmetric\n"
|
||||
"For symmetric edge pairs, the edges are commutable. Specifically, a symmetric edge pair with (e1,e2) is identical to (e2,e1). "
|
||||
|
|
@ -125,8 +125,8 @@ struct edge_pair_defs
|
|||
"Normalization is a first step recommended before converting an edge pair to a polygon, "
|
||||
"because that way the polygons won't be self-overlapping and the enlargement parameter "
|
||||
"is applied properly."
|
||||
) +
|
||||
method ("polygon", &C::to_polygon, gsi::arg ("e The enlargement (set to zero for exact representation)"),
|
||||
) +
|
||||
method ("polygon", &C::to_polygon, gsi::arg ("e"),
|
||||
"@brief Convert an edge pair to a polygon\n"
|
||||
"The polygon is formed by connecting the end and start points of the edges. It is recommended to "
|
||||
"use \\normalized before converting the edge pair to a polygon.\n"
|
||||
|
|
@ -137,8 +137,10 @@ struct edge_pair_defs
|
|||
"edge pairs consisting of two point-like edges.\n"
|
||||
"\n"
|
||||
"Another version for converting edge pairs to simple polygons is \\simple_polygon which renders a \\SimplePolygon object."
|
||||
) +
|
||||
method ("simple_polygon", &C::to_simple_polygon, gsi::arg ("e The enlargement (set to zero for exact representation)"),
|
||||
"\n"
|
||||
"@param e The enlargement (set to zero for exact representation)"
|
||||
) +
|
||||
method ("simple_polygon", &C::to_simple_polygon, gsi::arg ("e"),
|
||||
"@brief Convert an edge pair to a simple polygon\n"
|
||||
"The polygon is formed by connecting the end and start points of the edges. It is recommended to "
|
||||
"use \\normalized before converting the edge pair to a polygon.\n"
|
||||
|
|
@ -149,7 +151,9 @@ struct edge_pair_defs
|
|||
"edge pairs consisting of two point-like edges.\n"
|
||||
"\n"
|
||||
"Another version for converting edge pairs to polygons is \\polygon which renders a \\Polygon object."
|
||||
) +
|
||||
"\n"
|
||||
"@param e The enlargement (set to zero for exact representation)"
|
||||
) +
|
||||
constructor ("from_s", &from_string, gsi::arg ("s"),
|
||||
"@brief Creates an object from a string\n"
|
||||
"Creates the object from a string representation (as returned by \\to_s)\n"
|
||||
|
|
@ -162,7 +166,7 @@ struct edge_pair_defs
|
|||
"\n"
|
||||
"The DBU argument has been added in version 0.27.6.\n"
|
||||
) +
|
||||
method ("bbox", &C::bbox,
|
||||
method ("bbox", &C::bbox,
|
||||
"@brief Gets the bounding box of the edge pair\n"
|
||||
) +
|
||||
method ("<", &C::less, gsi::arg ("box"),
|
||||
|
|
|
|||
|
|
@ -371,6 +371,61 @@ static size_t id (const db::Edges *e)
|
|||
return tl::id_of (e->delegate ());
|
||||
}
|
||||
|
||||
static inline std::vector<db::Edges> as_2edges_vector (const std::pair<db::Edges, db::Edges> &rp)
|
||||
{
|
||||
std::vector<db::Edges> res;
|
||||
res.reserve (2);
|
||||
res.push_back (db::Edges (const_cast<db::Edges &> (rp.first).take_delegate ()));
|
||||
res.push_back (db::Edges (const_cast<db::Edges &> (rp.second).take_delegate ()));
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> andnot_with_edges (const db::Edges *r, const db::Edges &other)
|
||||
{
|
||||
return as_2edges_vector (r->andnot (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> andnot_with_region (const db::Edges *r, const db::Region &other)
|
||||
{
|
||||
return as_2edges_vector (r->andnot (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> inside_outside_part (const db::Edges *r, const db::Region &other)
|
||||
{
|
||||
return as_2edges_vector (r->inside_outside_part (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> split_inside_with_edges (const db::Edges *r, const db::Edges &other)
|
||||
{
|
||||
return as_2edges_vector (r->selected_inside_differential (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> split_inside_with_region (const db::Edges *r, const db::Region &other)
|
||||
{
|
||||
return as_2edges_vector (r->selected_inside_differential (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> split_outside_with_edges (const db::Edges *r, const db::Edges &other)
|
||||
{
|
||||
return as_2edges_vector (r->selected_outside_differential (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> split_outside_with_region (const db::Edges *r, const db::Region &other)
|
||||
{
|
||||
return as_2edges_vector (r->selected_outside_differential (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> split_interacting_with_edges (const db::Edges *r, const db::Edges &other)
|
||||
{
|
||||
return as_2edges_vector (r->selected_interacting_differential (other));
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> split_interacting_with_region (const db::Edges *r, const db::Region &other)
|
||||
{
|
||||
return as_2edges_vector (r->selected_interacting_differential (other));
|
||||
}
|
||||
|
||||
|
||||
extern Class<db::ShapeCollection> decl_dbShapeCollection;
|
||||
|
||||
// NOTE: the Metrics constants are injected into Edges in gsiDeclDbRegion.cc because this is where these constants are instantiated.
|
||||
|
|
@ -774,6 +829,26 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.24."
|
||||
) +
|
||||
method_ext ("andnot", &andnot_with_edges, gsi::arg ("other"),
|
||||
"@brief Returns the boolean AND and NOT between self and the other edge set\n"
|
||||
"\n"
|
||||
"@return A two-element array of edge collections with the first one being the AND result and the second one being the NOT result\n"
|
||||
"\n"
|
||||
"This method will compute the boolean AND and NOT between two edge sets simultaneously. "
|
||||
"Because this requires a single sweep only, using this method is faster than doing AND and NOT separately.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.28.\n"
|
||||
) +
|
||||
method_ext ("andnot", &andnot_with_region, gsi::arg ("other"),
|
||||
"@brief Returns the boolean AND and NOT between self and the region\n"
|
||||
"\n"
|
||||
"@return A two-element array of edge collections with the first one being the AND result and the second one being the NOT result\n"
|
||||
"\n"
|
||||
"This method will compute the boolean AND and NOT simultaneously. "
|
||||
"Because this requires a single sweep only, using this method is faster than doing AND and NOT separately.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.28.\n"
|
||||
) +
|
||||
method ("^", &db::Edges::operator^, gsi::arg ("other"),
|
||||
"@brief Returns the boolean XOR between self and the other edge collection\n"
|
||||
"\n"
|
||||
|
|
@ -828,66 +903,202 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"@brief Returns the edges of this edge collection which overlap or touch edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges overlapping or touching edges from the other edge collection\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the edges of this edge collection which do not overlap or touch edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching edges from the other edge collection\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which overlap or touch edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_not_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which do not overlap or touch edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method_ext ("split_interacting", &split_interacting_with_edges, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which do and do not interact with edges from the other collection\n"
|
||||
"\n"
|
||||
"@return A two-element list of edge collections (first: interacting, second: non-interacting)\n"
|
||||
"\n"
|
||||
"This method provides a faster way to compute both interacting and non-interacting edges compared to using separate methods. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the edges from this edge collection which overlap or touch polygons from the region\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges overlapping or touching polygons from the region\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the edges from this edge collection which do not overlap or touch polygons from the region\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching polygons from the region\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which overlap or touch polygons from the region\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which do not overlap or touch polygons from the region\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method_ext ("split_interacting", &split_interacting_with_region, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which do and do not interact with polygons from the other region\n"
|
||||
"\n"
|
||||
"@return A two-element list of edge collections (first: interacting, second: non-interacting)\n"
|
||||
"\n"
|
||||
"This method provides a faster way to compute both interacting and non-interacting edges compared to using separate methods. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
method ("inside", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_inside, gsi::arg ("other"),
|
||||
"@brief Returns the edges of this edge collection which are inside (completely covered by) edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges overlapping or touching edges from the other edge collection\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("not_inside", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_not_inside, gsi::arg ("other"),
|
||||
"@brief Returns the edges of this edge collection which are not inside (completely covered by) edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching edges from the other edge collection\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("select_inside", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_inside, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are inside (completely covered by) edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("select_not_inside", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_not_inside, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are not inside (completely covered by) edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method_ext ("split_inside", &split_inside_with_edges, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are and are not inside (completely covered by) edges from the other collection\n"
|
||||
"\n"
|
||||
"@return A two-element list of edge collections (first: inside, second: non-inside)\n"
|
||||
"\n"
|
||||
"This method provides a faster way to compute both inside and non-inside edges compared to using separate methods. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
method ("inside", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_inside, gsi::arg ("other"),
|
||||
"@brief Returns the edges from this edge collection which are inside (completely covered by) polygons from the region\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges overlapping or touching polygons from the region\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("not_inside", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_inside, gsi::arg ("other"),
|
||||
"@brief Returns the edges from this edge collection which are not inside (completely covered by) polygons from the region\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching polygons from the region\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("select_inside", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_inside, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are inside (completely covered by) polygons from the region\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("select_not_inside", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_inside, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are not inside (completely covered by) polygons from the region\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method_ext ("split_inside", &split_inside_with_region, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are and are not inside (completely covered by) polygons from the other region\n"
|
||||
"\n"
|
||||
"@return A two-element list of edge collections (first: inside, second: non-inside)\n"
|
||||
"\n"
|
||||
"This method provides a faster way to compute both inside and non-inside edges compared to using separate methods. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
method ("outside", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_outside, gsi::arg ("other"),
|
||||
"@brief Returns the edges of this edge collection which are outside (completely covered by) edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges overlapping or touching edges from the other edge collection\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("not_outside", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_not_outside, gsi::arg ("other"),
|
||||
"@brief Returns the edges of this edge collection which are not outside (completely covered by) edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching edges from the other edge collection\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("select_outside", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_outside, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are outside (completely covered by) edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("select_not_outside", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_not_outside, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are not outside (completely covered by) edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method_ext ("split_outside", &split_outside_with_edges, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are and are not outside (completely covered by) edges from the other collection\n"
|
||||
"\n"
|
||||
"@return A two-element list of edge collections (first: outside, second: non-outside)\n"
|
||||
"\n"
|
||||
"This method provides a faster way to compute both outside and non-outside edges compared to using separate methods. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
method ("outside", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_outside, gsi::arg ("other"),
|
||||
"@brief Returns the edges from this edge collection which are outside (completely covered by) polygons from the region\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges overlapping or touching polygons from the region\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("not_outside", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_outside, gsi::arg ("other"),
|
||||
"@brief Returns the edges from this edge collection which are not outside (completely covered by) polygons from the region\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching polygons from the region\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("select_outside", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_outside, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are outside (completely covered by) polygons from the region\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method ("select_not_outside", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_outside, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are not outside (completely covered by) polygons from the region\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28."
|
||||
) +
|
||||
method_ext ("split_outside", &split_outside_with_region, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this edge collection which are and are not outside (completely covered by) polygons from the other region\n"
|
||||
"\n"
|
||||
"@return A two-element list of edge collections (first: outside, second: non-outside)\n"
|
||||
"\n"
|
||||
"This method provides a faster way to compute both outside and non-outside edges compared to using separate methods. "
|
||||
"It has been introduced in version 0.28."
|
||||
) +
|
||||
method_ext ("pull_interacting", &pull_interacting, gsi::arg ("other"),
|
||||
"@brief Returns all polygons of \"other\" which are interacting with (overlapping, touching) edges of this edge set\n"
|
||||
"The \"pull_...\" methods are similar to \"select_...\" but work the opposite way: they "
|
||||
|
|
@ -966,6 +1177,16 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.24."
|
||||
) +
|
||||
method_ext ("inside_outside_part", &inside_outside_part, gsi::arg ("other"),
|
||||
"@brief Returns the partial edges inside and outside the given region\n"
|
||||
"\n"
|
||||
"@return A two-element array of edge collections with the first one being the \\inside_part result and the second one being the \\outside_part result\n"
|
||||
"\n"
|
||||
"This method will compute the results simultaneously. "
|
||||
"Because this requires a single sweep only, using this method is faster than doing \\inside_part and \\outside_part separately.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.28.\n"
|
||||
) +
|
||||
method ("clear", &db::Edges::clear,
|
||||
"@brief Clears the edge collection\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -266,6 +266,9 @@ Class<db::NetlistDeviceExtractor> decl_dbNetlistDeviceExtractor ("db", "DeviceEx
|
|||
gsi::method ("name", &db::NetlistDeviceExtractor::name,
|
||||
"@brief Gets the name of the device extractor and the device class."
|
||||
) +
|
||||
gsi::method ("name=", &db::NetlistDeviceExtractor::set_name, gsi::arg ("name"),
|
||||
"@brief Sets the name of the device extractor and the device class."
|
||||
) +
|
||||
gsi::method ("device_class", &db::NetlistDeviceExtractor::device_class,
|
||||
"@brief Gets the device class used during extraction\n"
|
||||
"The attribute will hold the actual device class used in the device extraction. It "
|
||||
|
|
@ -293,9 +296,6 @@ Class<db::NetlistDeviceExtractor> decl_dbNetlistDeviceExtractor ("db", "DeviceEx
|
|||
);
|
||||
|
||||
Class<GenericDeviceExtractor> decl_GenericDeviceExtractor (decl_dbNetlistDeviceExtractor, "db", "GenericDeviceExtractor",
|
||||
gsi::method ("name=", &GenericDeviceExtractor::set_name,
|
||||
"@brief Sets the name of the device extractor and the device class."
|
||||
) +
|
||||
gsi::callback ("setup", &GenericDeviceExtractor::setup, &GenericDeviceExtractor::cb_setup,
|
||||
"@brief Sets up the extractor.\n"
|
||||
"This method is supposed to set up the device extractor. This involves three basic steps:\n"
|
||||
|
|
|
|||
|
|
@ -83,9 +83,13 @@ namespace gsi
|
|||
}
|
||||
|
||||
static void
|
||||
lm_map_string (db::LayerMap *layer_map, std::string &s, unsigned int l)
|
||||
lm_map_string (db::LayerMap *layer_map, std::string &s, int l)
|
||||
{
|
||||
layer_map->map_expr (s, l);
|
||||
if (l < 0) {
|
||||
layer_map->map_expr (s, layer_map->next_index ());
|
||||
} else {
|
||||
layer_map->map_expr (s, (unsigned int) l);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -113,9 +117,13 @@ namespace gsi
|
|||
}
|
||||
|
||||
static void
|
||||
lm_mmap_string (db::LayerMap *layer_map, std::string &s, unsigned int l)
|
||||
lm_mmap_string (db::LayerMap *layer_map, std::string &s, int l)
|
||||
{
|
||||
layer_map->mmap_expr (s, l);
|
||||
if (l < 0) {
|
||||
layer_map->mmap_expr (s, layer_map->next_index ());
|
||||
} else {
|
||||
layer_map->mmap_expr (s, (unsigned int) l);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -215,7 +223,7 @@ namespace gsi
|
|||
"\n"
|
||||
"This method has been added in version 0.20.\n"
|
||||
) +
|
||||
gsi::method_ext ("map", &lm_map_string, gsi::arg ("map_expr"), gsi::arg ("log_layer"),
|
||||
gsi::method_ext ("map", &lm_map_string, gsi::arg ("map_expr"), gsi::arg ("log_layer", -1),
|
||||
"@brief Maps a physical layer given by a string to a logical one\n"
|
||||
"@param map_expr The string describing the physical layer to map.\n"
|
||||
"@param log_layer The logical layer to which the physical layers are mapped.\n"
|
||||
|
|
@ -242,7 +250,9 @@ namespace gsi
|
|||
"For example, \"1-10/0: *+1/0\" will add 1 to the original layer number.\n"
|
||||
"\"1-10/0-50: * / *\" will use the original layers.\n"
|
||||
"\n"
|
||||
"Target mapping has been added in version 0.20.\n"
|
||||
"If the logical layer is negative or omitted, the method will select the next available one.\n"
|
||||
"\n"
|
||||
"Target mapping has been added in version 0.20. The logical layer is optional since version 0.28.\n"
|
||||
) +
|
||||
gsi::method_ext ("mmap", &lm_mmap, gsi::arg ("phys_layer"), gsi::arg ("log_layer"),
|
||||
"@brief Maps a physical layer to a logical one and adds to existing mappings\n"
|
||||
|
|
@ -280,14 +290,16 @@ namespace gsi
|
|||
"\n"
|
||||
"Multi-mapping has been added in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("mmap", &lm_mmap_string, gsi::arg ("map_expr"), gsi::arg ("log_layer"),
|
||||
gsi::method_ext ("mmap", &lm_mmap_string, gsi::arg ("map_expr"), gsi::arg ("log_layer", -1),
|
||||
"@brief Maps a physical layer given by an expression to a logical one and adds to existing mappings\n"
|
||||
"\n"
|
||||
"This method acts like the corresponding 'map' method, but adds the logical layer to the receivers of the "
|
||||
"given physical one. Hence this method implements 1:n mapping capabilities.\n"
|
||||
"For backward compatibility, 'map' still substitutes mapping.\n"
|
||||
"\n"
|
||||
"Multi-mapping has been added in version 0.27.\n"
|
||||
"If the logical layer is negative or omitted, the method will select the next available one.\n"
|
||||
"\n"
|
||||
"Multi-mapping has been added in version 0.27. The logical layer is optional since version 0.28.\n"
|
||||
) +
|
||||
gsi::method_ext ("unmap", &lm_unmap, gsi::arg ("phys_layer"),
|
||||
"@brief Unmaps the given layer\n"
|
||||
|
|
@ -347,9 +359,9 @@ namespace gsi
|
|||
"\n"
|
||||
"@code"
|
||||
"lm = RBA::LayerMap::new\n"
|
||||
"lm.map(\"1/0-255 : ONE (1/0)\", 0)\n"
|
||||
"lm.map(\"2/0-255 : TWO (2/0)\", 1)\n"
|
||||
"lm.map(\"3/0-255 : THREE (3/0)\", 2)\n"
|
||||
"lm.map(\"1/0-255 : ONE (1/0)\")\n"
|
||||
"lm.map(\"2/0-255 : TWO (2/0)\")\n"
|
||||
"lm.map(\"3/0-255 : THREE (3/0)\")\n"
|
||||
"\n"
|
||||
"# read the layout using the layer map\n"
|
||||
"lo = RBA::LoadLayoutOptions::new\n"
|
||||
|
|
|
|||
|
|
@ -437,6 +437,15 @@ static void insert_texts_with_dtrans (db::Shapes *sh, const db::Texts &r, const
|
|||
}
|
||||
}
|
||||
|
||||
static db::Layout *layout (db::Shapes *sh)
|
||||
{
|
||||
if (sh->cell ()) {
|
||||
return sh->cell ()->layout ();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int s_all () { return db::ShapeIterator::All; }
|
||||
static unsigned int s_all_with_properties () { return db::ShapeIterator::AllWithProperties; }
|
||||
static unsigned int s_properties () { return db::ShapeIterator::Properties; }
|
||||
|
|
@ -1231,6 +1240,18 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
|
|||
"This method was introduced in version 0.16\n"
|
||||
"@return The number of shapes in this container\n"
|
||||
) +
|
||||
gsi::method ("cell", &db::Shapes::cell,
|
||||
"@brief Gets the cell the shape container belongs to\n"
|
||||
"This method returns nil if the shape container does not belong to a cell.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.28."
|
||||
) +
|
||||
gsi::method_ext ("layout", &layout,
|
||||
"@brief Gets the layout object the shape container belongs to\n"
|
||||
"This method returns nil if the shape container does not belong to a layout.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.28."
|
||||
) +
|
||||
gsi::method ("replace_prop_id", (db::Shape (db::Shapes::*) (const db::Shape &, db::properties_id_type)) &db::Shapes::replace_prop_id, gsi::arg ("shape"), gsi::arg ("property_id"),
|
||||
"@brief Replaces (or install) the properties of a shape\n"
|
||||
"@return A \\Shape object representing the new shape\n"
|
||||
|
|
|
|||
|
|
@ -590,3 +590,595 @@ TEST(10_PullInteracting)
|
|||
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au10.gds");
|
||||
}
|
||||
|
||||
TEST(11_SelectedInsideWithRegion)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Region r;
|
||||
r.insert (db::Box (0, -1000, 2000, 0));
|
||||
r.insert (db::Box (1000, 1000, 2000, 1500));
|
||||
r.insert (db::Box (1000, 1500, 2000, 2000));
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
r.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Region rflat = r;
|
||||
r = db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_inside (db::Region ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (db::Region ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (db::Region ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (db::Region ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_inside (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside_differential (r).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside_differential (r).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside (r), "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside (rflat), "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_inside (r), "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (r), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (rflat), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_not_inside (r), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (r).first, "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (rflat).first, "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_inside_differential (r).first, "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (r).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (rflat).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_inside_differential (r).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
}
|
||||
|
||||
TEST(12_SelectedInsideWithEdges)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Edges ee;
|
||||
for (int i = 0; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, -1000, i, 0));
|
||||
}
|
||||
for (int i = 1000; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, 1000, i, 1500));
|
||||
ee.insert (db::Edge (i, 1500, i, 2000));
|
||||
}
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
ee.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Edges eeflat = ee;
|
||||
ee = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_inside (db::Edges ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (db::Edges ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (db::Edges ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (db::Edges ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_inside (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside_differential (ee).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside_differential (ee).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside (ee), "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside (eeflat), "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_inside (ee), "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (ee), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (eeflat), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_not_inside (ee), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (ee).first, "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (eeflat).first, "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_inside_differential (ee).first, "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (ee).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (eeflat).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_inside_differential (ee).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
}
|
||||
|
||||
TEST(13_SelectedOutsideWithRegion)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Region r;
|
||||
r.insert (db::Box (0, -1000, 2000, 0));
|
||||
r.insert (db::Box (1000, 1000, 2000, 1500));
|
||||
r.insert (db::Box (1000, 1500, 2000, 2000));
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
r.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Region rflat = r;
|
||||
r = db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_outside (db::Region ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (db::Region ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (db::Region ()).first, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (db::Region ()).second, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_outside (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside_differential (r).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside_differential (r).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside (r), "(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside (rflat), "(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_outside (r), "(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (r), "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (rflat), "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_not_outside (r), "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (r).first, "(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (rflat).first, "(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_outside_differential (r).first, "(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (r).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (rflat).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_outside_differential (r).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
}
|
||||
|
||||
TEST(14_SelectedOutsideWithEdges)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Edges ee;
|
||||
for (int i = 0; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, -1000, i, 0));
|
||||
}
|
||||
for (int i = 1000; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, 1000, i, 1500));
|
||||
ee.insert (db::Edge (i, 1500, i, 2000));
|
||||
}
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
ee.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Edges eeflat = ee;
|
||||
ee = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_outside (db::Edges ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (db::Edges ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (db::Edges ()).first, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (db::Edges ()).second, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_outside (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside_differential (ee).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside_differential (ee).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside (ee), "(0,0;0,1000);(100,0;100,3000);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside (eeflat), "(0,0;0,1000);(100,0;100,3000);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_outside (ee), "(0,0;0,1000);(100,0;100,3000);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (ee), "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (eeflat), "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_not_outside (ee), "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (ee).first, "(0,0;0,1000);(100,0;100,3000);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (eeflat).first, "(0,0;0,1000);(100,0;100,3000);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_outside_differential (ee).first, "(0,0;0,1000);(100,0;100,3000);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (ee).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (eeflat).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_outside_differential (ee).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
}
|
||||
|
||||
TEST(15_SelectedInteractingWithRegion)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Region r;
|
||||
r.insert (db::Box (0, -1000, 2000, 0));
|
||||
r.insert (db::Box (1000, 1000, 2000, 1500));
|
||||
r.insert (db::Box (1000, 1500, 2000, 2000));
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
r.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Region rflat = r;
|
||||
r = db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_interacting (db::Region ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_interacting (db::Region ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (db::Region ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (db::Region ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_interacting (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_interacting (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_interacting_differential (r).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_interacting_differential (r).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting (r), "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting (rflat), "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_interacting (r), "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_interacting (r), "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_interacting (rflat), "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_not_interacting (r), "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (r).first, "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (rflat).first, "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_interacting_differential (r).first, "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (r).second, "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (rflat).second, "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_interacting_differential (r).second, "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
}
|
||||
|
||||
TEST(16_SelectedInteractingWithEdges)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Edges ee;
|
||||
for (int i = 0; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, -1000, i, 0));
|
||||
}
|
||||
for (int i = 1000; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, 1000, i, 1500));
|
||||
ee.insert (db::Edge (i, 1500, i, 2000));
|
||||
}
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
ee.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Edges eeflat = ee;
|
||||
ee = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_interacting (db::Edges ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_interacting (db::Edges ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (db::Edges ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (db::Edges ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_interacting (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_interacting (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_interacting_differential (ee).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_interacting_differential (ee).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting (ee), "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting (eeflat), "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_interacting (ee), "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_interacting (ee), "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_interacting (eeflat), "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_not_interacting (ee), "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (ee).first, "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (eeflat).first, "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_interacting_differential (ee).first, "(0,0;0,1000);(1100,-1000;1100,2000);(1300,-800;1300,-200);(1200,-1000;1200,0);(1400,1000;1400,1100);(1600,-800;1600,-200);(100,0;100,3000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (ee).second, "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (eeflat).second, "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.selected_interacting_differential (ee).second, "(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
}
|
||||
|
||||
TEST(17_InsideOutside)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Region r;
|
||||
r.insert (db::Box (0, -1000, 2000, 0));
|
||||
r.insert (db::Box (1000, 1000, 2000, 1500));
|
||||
r.insert (db::Box (1000, 1500, 2000, 2000));
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
r.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Region rflat = r;
|
||||
r = db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e.inside_part (db::Region ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.outside_part (db::Region ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.inside_outside_part (db::Region ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.inside_outside_part (db::Region ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().inside_part (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().outside_part (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().inside_outside_part (r).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().inside_outside_part (r).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.inside_part (r), "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e.inside_part (rflat), "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.inside_part (r), "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e.outside_part (r), "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.outside_part (rflat), "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.outside_part (r), "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.inside_outside_part (r).first, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e.inside_outside_part (rflat).first, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.inside_outside_part (r).first, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e.inside_outside_part (r).second, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.inside_outside_part (rflat).second, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.inside_outside_part (r).second, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
}
|
||||
|
||||
TEST(18_AndNotWithRegion)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Region r;
|
||||
r.insert (db::Box (0, -1000, 2000, 0));
|
||||
r.insert (db::Box (1000, 1000, 2000, 1500));
|
||||
r.insert (db::Box (1000, 1500, 2000, 2000));
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
r.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Region rflat = r;
|
||||
r = db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e & db::Region (), ""), true);
|
||||
EXPECT_EQ (db::compare (e - db::Region (), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (db::Region ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (db::Region ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges () & r, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges () - r, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().andnot (r).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().andnot (r).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e & r, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e & rflat, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (eflat & r, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e - r, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e - rflat, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat - r, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (r).first, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (rflat).first, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.andnot (r).first, "(1500,1500;1500,2000);(1100,1500;1100,2000);(1900,1000;1900,1500);(1900,1500;1900,2000);(1600,-800;1600,-400);(1500,1000;1500,1500);(1100,1000;1100,1500);(1600,-400;1600,-200);(1300,-800;1300,-200);(1700,1500;1650,2000);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (r).second, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (rflat).second, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.andnot (r).second, "(1650,2000;1600,2500);(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
}
|
||||
|
||||
TEST(19_AndNotWithEdges)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Edges ee;
|
||||
for (int i = 0; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, -1000, i, 0));
|
||||
}
|
||||
for (int i = 1000; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, 1000, i, 1500));
|
||||
ee.insert (db::Edge (i, 1500, i, 2000));
|
||||
}
|
||||
|
||||
// make deep
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
db::Layout ly;
|
||||
ly.add_cell ("TOP");
|
||||
unsigned int l1 = ly.insert_layer ();
|
||||
unsigned int l2 = ly.insert_layer ();
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
e.insert_into (&ly, top_cell.cell_index (), l1);
|
||||
db::Edges eflat = e;
|
||||
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
|
||||
ee.insert_into (&ly, top_cell.cell_index (), l2);
|
||||
db::Edges eeflat = ee;
|
||||
ee = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
EXPECT_EQ (db::compare (e & db::Edges (), ""), true);
|
||||
EXPECT_EQ (db::compare (e - db::Edges (), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (db::Edges ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (db::Edges ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges () & ee, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges () - ee, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().andnot (ee).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().andnot (ee).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e & ee, "(1500,1000;1500,2000);(1900,1000;1900,2000);(1600,-800;1600,-200);(1100,1000;1100,2000);(1300,-800;1300,-200);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e & eeflat, "(1500,1000;1500,2000);(1900,1000;1900,2000);(1600,-800;1600,-200);(1100,1000;1100,2000);(1300,-800;1300,-200);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (eflat & ee, "(1500,1000;1500,2000);(1900,1000;1900,2000);(1600,-800;1600,-200);(1100,1000;1100,2000);(1300,-800;1300,-200);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e - ee, "(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1700,1500;1600,2500)"), true);
|
||||
EXPECT_EQ (db::compare (e - eeflat, "(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1700,1500;1600,2500)"), true);
|
||||
EXPECT_EQ (db::compare (eflat - ee, "(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1700,1500;1600,2500)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (ee).first, "(1500,1000;1500,2000);(1900,1000;1900,2000);(1600,-800;1600,-200);(1100,1000;1100,2000);(1300,-800;1300,-200);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (eeflat).first, "(1500,1000;1500,2000);(1900,1000;1900,2000);(1600,-800;1600,-200);(1100,1000;1100,2000);(1300,-800;1300,-200);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.andnot (ee).first, "(1500,1000;1500,2000);(1900,1000;1900,2000);(1600,-800;1600,-200);(1100,1000;1100,2000);(1300,-800;1300,-200);(1100,-1000;1100,0);(1200,-1000;1200,0);(1400,1000;1400,1100)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (ee).second, "(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1700,1500;1600,2500)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot (eeflat).second, "(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1700,1500;1600,2500)"), true);
|
||||
EXPECT_EQ (db::compare (eflat.andnot (ee).second, "(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1700,1500;1600,2500)"), true);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1992,13 +1992,7 @@ TEST(31)
|
|||
|
||||
ep.process (ec, op);
|
||||
|
||||
std::string s;
|
||||
for (size_t i = 0; i < out.size (); ++i) {
|
||||
if (i > 0) {
|
||||
s += ";";
|
||||
}
|
||||
s += out[i].to_string ();
|
||||
}
|
||||
std::string s = tl::join (out.begin (), out.end (), ";");
|
||||
EXPECT_EQ (s, "(0,0;0,400);(0,0;500,0);(500,0;500,300);(0,400;0,417);(400,400;0,400);(394,406;0,417);(0,417;0,500)");
|
||||
|
||||
ep.clear ();
|
||||
|
|
@ -2015,14 +2009,7 @@ TEST(31)
|
|||
|
||||
ep.process (ec, op);
|
||||
|
||||
s.clear ();
|
||||
for (size_t i = 0; i < out.size (); ++i) {
|
||||
if (i > 0) {
|
||||
s += ";";
|
||||
}
|
||||
s += out[i].to_string ();
|
||||
}
|
||||
|
||||
s = tl::join (out.begin (), out.end (), ";");
|
||||
EXPECT_EQ (s, "(400,0;400,400);(0,500;300,500)");
|
||||
}
|
||||
|
||||
|
|
@ -2051,17 +2038,11 @@ TEST(32)
|
|||
|
||||
std::vector<db::Edge> out;
|
||||
db::EdgeContainer ec (out);
|
||||
db::EdgePolygonOp op (false, false /*not including touch*/);
|
||||
db::EdgePolygonOp op (db::EdgePolygonOp::Inside, false /*not including touch*/);
|
||||
|
||||
ep.process (ec, op);
|
||||
|
||||
std::string s;
|
||||
for (size_t i = 0; i < out.size (); ++i) {
|
||||
if (i > 0) {
|
||||
s += ";";
|
||||
}
|
||||
s += out[i].to_string ();
|
||||
}
|
||||
std::string s = tl::join (out.begin (), out.end (), ";");
|
||||
EXPECT_EQ (s, "(400,400;0,400);(394,406;0,417)");
|
||||
|
||||
ep.clear ();
|
||||
|
|
@ -2078,14 +2059,7 @@ TEST(32)
|
|||
|
||||
ep.process (ec, op);
|
||||
|
||||
s.clear ();
|
||||
for (size_t i = 0; i < out.size (); ++i) {
|
||||
if (i > 0) {
|
||||
s += ";";
|
||||
}
|
||||
s += out[i].to_string ();
|
||||
}
|
||||
|
||||
s = tl::join (out.begin (), out.end (), ";");
|
||||
EXPECT_EQ (s, "(400,0;400,400)");
|
||||
}
|
||||
|
||||
|
|
@ -2114,17 +2088,11 @@ TEST(33)
|
|||
|
||||
std::vector<db::Edge> out;
|
||||
db::EdgeContainer ec (out);
|
||||
db::EdgePolygonOp op (true, true /*including touch*/);
|
||||
db::EdgePolygonOp op (db::EdgePolygonOp::Outside, true /*including touch*/);
|
||||
|
||||
ep.process (ec, op);
|
||||
|
||||
std::string s;
|
||||
for (size_t i = 0; i < out.size (); ++i) {
|
||||
if (i > 0) {
|
||||
s += ";";
|
||||
}
|
||||
s += out[i].to_string ();
|
||||
}
|
||||
std::string s = tl::join (out.begin (), out.end (), ";");
|
||||
EXPECT_EQ (s, "(0,-100;0,0);(500,-100;500,0);(-100,0;0,0);(500,0;600,0);(500,300;500,400);"
|
||||
"(0,400;-100,400);(500,400;400,400);(500,400;500,403);(600,400;500,400);"
|
||||
"(600,400;500,403);(500,403;394,406);(500,403;500,600);(0,417;-100,420);"
|
||||
|
|
@ -2144,19 +2112,76 @@ TEST(33)
|
|||
|
||||
ep.process (ec, op);
|
||||
|
||||
s.clear ();
|
||||
for (size_t i = 0; i < out.size (); ++i) {
|
||||
if (i > 0) {
|
||||
s += ";";
|
||||
}
|
||||
s += out[i].to_string ();
|
||||
}
|
||||
|
||||
s = tl::join (out.begin (), out.end (), ";");
|
||||
EXPECT_EQ (s, "(-100,-100;-100,500);(-100,-100;400,-100);(400,-100;400,0);(400,-100;600,-100);"
|
||||
"(600,-100;600,500);(400,400;400,500);(-100,500;-100,600);(-100,500;0,500);"
|
||||
"(300,500;400,500);(400,500;400,600);(400,500;600,500);(600,500;600,600)");
|
||||
}
|
||||
|
||||
TEST(34)
|
||||
{
|
||||
std::vector<db::Polygon> a;
|
||||
db::Point a1[] = {
|
||||
db::Point (0, 0),
|
||||
db::Point (0, 500),
|
||||
db::Point (300, 500),
|
||||
db::Point (500, 300),
|
||||
db::Point (500, 0)
|
||||
};
|
||||
a.push_back (db::Polygon ());
|
||||
a.back ().assign_hull (a1 + 0, a1 + sizeof (a1) / sizeof (a1[0]));
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
|
||||
ep.insert (*i, 0);
|
||||
}
|
||||
ep.insert (db::Edge (600, 400, -100, 420), 1);
|
||||
ep.insert (db::Edge (600, 400, -100, 400), 1);
|
||||
ep.insert (db::Edge (-100, 0, 600, 0), 1);
|
||||
ep.insert (db::Edge (0, -100, 0, 600), 1);
|
||||
ep.insert (db::Edge (500, -100, 500, 600), 1);
|
||||
|
||||
std::vector<db::Edge> out2;
|
||||
db::EdgeContainer ec2 (out2, false, 2);
|
||||
std::vector<db::Edge> out;
|
||||
db::EdgeContainer ec (out, false, 1, &ec2);
|
||||
db::EdgePolygonOp op (db::EdgePolygonOp::Both, true /*not including touch*/);
|
||||
|
||||
ep.process (ec, op);
|
||||
|
||||
std::string s = tl::join (out2.begin (), out2.end (), ";");
|
||||
EXPECT_EQ (s, "(0,-100;0,0);(500,-100;500,0);(-100,0;0,0);(500,0;600,0);(500,300;500,400);"
|
||||
"(0,400;-100,400);(500,400;400,400);(500,400;500,403);(600,400;500,400);"
|
||||
"(600,400;500,403);(500,403;394,406);(500,403;500,600);(0,417;-100,420);"
|
||||
"(0,500;0,600)");
|
||||
|
||||
s = tl::join (out.begin (), out.end (), ";");
|
||||
EXPECT_EQ (s, "(0,0;0,400);(0,0;500,0);(500,0;500,300);(0,400;0,417);(400,400;0,400);(394,406;0,417);(0,417;0,500)");
|
||||
|
||||
ep.clear ();
|
||||
out.clear ();
|
||||
out2.clear ();
|
||||
|
||||
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
|
||||
ep.insert (*i, 0);
|
||||
}
|
||||
ep.insert (db::Edge (-100, 500, 600, 500), 1);
|
||||
ep.insert (db::Edge (400, -100, 400, 600), 1);
|
||||
ep.insert (db::Edge (-100, -100, -100, 600), 1);
|
||||
ep.insert (db::Edge (600, -100, 600, 600), 1);
|
||||
ep.insert (db::Edge (-100, -100, 600, -100), 1);
|
||||
|
||||
ep.process (ec, op);
|
||||
|
||||
s = tl::join (out2.begin (), out2.end (), ";");
|
||||
EXPECT_EQ (s, "(-100,-100;-100,500);(-100,-100;400,-100);(400,-100;400,0);(400,-100;600,-100);"
|
||||
"(600,-100;600,500);(400,400;400,500);(-100,500;-100,600);(-100,500;0,500);"
|
||||
"(300,500;400,500);(400,500;400,600);(400,500;600,500);(600,500;600,600)");
|
||||
|
||||
s = tl::join (out.begin (), out.end (), ";");
|
||||
EXPECT_EQ (s, "(400,0;400,400);(0,500;300,500)");
|
||||
}
|
||||
|
||||
// TrapezoidGenerator
|
||||
|
||||
// Basic
|
||||
|
|
|
|||
|
|
@ -120,13 +120,16 @@ TEST(2)
|
|||
r2.insert (db::Box (db::Point (0, 10), db::Point (100, 210)));
|
||||
|
||||
EXPECT_EQ (db::compare ((r & r1), "(10,200;100,200);(100,0;10,0)"), true);
|
||||
EXPECT_EQ (db::compare (r.andnot(r1).first, "(10,200;100,200);(100,0;10,0)"), true);
|
||||
EXPECT_EQ (db::compare ((r & r2), "(0,10;0,200);(100,200;100,10)"), true);
|
||||
EXPECT_EQ (db::compare (r.andnot(r2).first, "(0,10;0,200);(100,200;100,10)"), true);
|
||||
db::Edges o1 = r;
|
||||
o1 &= r1;
|
||||
EXPECT_EQ (o1.is_merged (), true);
|
||||
EXPECT_EQ (db::compare (o1, "(10,200;100,200);(100,0;10,0)"), true);
|
||||
|
||||
EXPECT_EQ (db::compare ((r - r1), "(0,0;0,200);(100,200;100,0);(0,200;10,200);(10,0;0,0)"), true);
|
||||
EXPECT_EQ (db::compare (r.andnot(r1).second, "(0,0;0,200);(100,200;100,0);(0,200;10,200);(10,0;0,0)"), true);
|
||||
db::Edges o2 = r;
|
||||
o2 -= r1;
|
||||
EXPECT_EQ (o2.is_merged (), true);
|
||||
|
|
@ -392,31 +395,41 @@ TEST(8)
|
|||
e2.insert (db::Edge (db::Point (0, 100), db::Point (100, 100)));
|
||||
|
||||
EXPECT_EQ (e.selected_interacting (e2).to_string (), "(0,0;0,200)");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).first.to_string (), "(0,0;0,200)");
|
||||
EXPECT_EQ (e.selected_not_interacting (e2).to_string (), "(250,200;300,0)");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).second.to_string (), "(250,200;300,0)");
|
||||
|
||||
e2.clear ();
|
||||
e2.insert (db::Edge (db::Point (0, 100), db::Point (0, 100)));
|
||||
|
||||
EXPECT_EQ (e.selected_interacting (e2).to_string (), "(0,0;0,200)");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).first.to_string (), "(0,0;0,200)");
|
||||
EXPECT_EQ (e.selected_not_interacting (e2).to_string (), "(250,200;300,0)");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).second.to_string (), "(250,200;300,0)");
|
||||
|
||||
e2.clear ();
|
||||
e2.insert (db::Edge (db::Point (100, 0), db::Point (0, 0)));
|
||||
|
||||
EXPECT_EQ (e.selected_interacting (e2).to_string (), "(0,0;0,200)");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).first.to_string (), "(0,0;0,200)");
|
||||
EXPECT_EQ (e.selected_not_interacting (e2).to_string (), "(250,200;300,0)");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).second.to_string (), "(250,200;300,0)");
|
||||
|
||||
e2.clear ();
|
||||
e2.insert (db::Edge (db::Point (-100, -1), db::Point (100, -1)));
|
||||
|
||||
EXPECT_EQ (e.selected_interacting (e2).to_string (), "");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).first.to_string (), "");
|
||||
EXPECT_EQ (db::compare (e.selected_not_interacting (e2), "(0,0;0,200);(250,200;300,0)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_interacting_differential (e2).second, "(0,0;0,200);(250,200;300,0)"), true);
|
||||
|
||||
e2.clear ();
|
||||
e2.insert (db::Edge (db::Point (-100, 0), db::Point (100, 0)));
|
||||
|
||||
EXPECT_EQ (e.selected_interacting (e2).to_string (), "(0,0;0,200)");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).first.to_string (), "(0,0;0,200)");
|
||||
EXPECT_EQ (e.selected_not_interacting (e2).to_string (), "(250,200;300,0)");
|
||||
EXPECT_EQ (e.selected_interacting_differential (e2).second.to_string (), "(250,200;300,0)");
|
||||
|
||||
db::Edges ee = e;
|
||||
e.select_interacting (e2);
|
||||
|
|
@ -785,7 +798,9 @@ TEST(20)
|
|||
EXPECT_EQ (r2.merged ().to_string (100), "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(10,40;40,40);(40,40;40,10);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,70;140,40);(140,40;80,40)");
|
||||
EXPECT_EQ (rr1.to_string (100), "(0,0;0,30;30,30;30,0);(50,0;50,30;80,30;80,0);(50,40;50,70;80,70;80,40)");
|
||||
EXPECT_EQ (r2.selected_interacting (rr1).to_string (100), "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,40;80,40)");
|
||||
EXPECT_EQ (r2.selected_interacting_differential (rr1).first.to_string (100), "(60,10;60,20);(60,20;70,20);(70,20;70,10);(70,10;60,10);(10,10;10,40);(40,10;10,10);(80,40;80,70);(80,70;140,70);(140,40;80,40)");
|
||||
EXPECT_EQ (r2.selected_not_interacting (rr1).to_string (100), "(10,40;40,40);(40,40;40,10);(140,70;140,40)");
|
||||
EXPECT_EQ (r2.selected_interacting_differential (rr1).second.to_string (100), "(10,40;40,40);(40,40;40,10);(140,70;140,40)");
|
||||
|
||||
db::Edges r2dup = r2;
|
||||
r2.select_interacting (rr1);
|
||||
|
|
@ -809,7 +824,9 @@ TEST(21)
|
|||
db::Edges e, ee;
|
||||
e.insert (db::Edge (-100, 100, 200, 100));
|
||||
EXPECT_EQ ((e & r).to_string (), "(0,100;100,100)");
|
||||
EXPECT_EQ (e.andnot(r).first.to_string (), "(0,100;100,100)");
|
||||
EXPECT_EQ (e.inside_part (r).to_string (), "(0,100;100,100)");
|
||||
EXPECT_EQ (e.inside_outside_part (r).first.to_string (), "(0,100;100,100)");
|
||||
|
||||
ee = e;
|
||||
ee &= r;
|
||||
|
|
@ -820,7 +837,9 @@ TEST(21)
|
|||
EXPECT_EQ (ee.to_string (), "(0,100;100,100)");
|
||||
|
||||
EXPECT_EQ (db::compare ((e - r), "(-100,100;0,100);(100,100;200,100)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot(r).second, "(-100,100;0,100);(100,100;200,100)"), true);
|
||||
EXPECT_EQ (db::compare (e.outside_part (r), "(-100,100;0,100);(100,100;200,100)"), true);
|
||||
EXPECT_EQ (db::compare (e.inside_outside_part (r).second, "(-100,100;0,100);(100,100;200,100)"), true);
|
||||
|
||||
ee = e;
|
||||
ee -= r;
|
||||
|
|
@ -833,7 +852,9 @@ TEST(21)
|
|||
e.clear ();
|
||||
e.insert (db::Edge (-100, 0, 200, 0));
|
||||
EXPECT_EQ ((e & r).to_string (), "(0,0;100,0)");
|
||||
EXPECT_EQ (e.andnot(r).first.to_string (), "(0,0;100,0)");
|
||||
EXPECT_EQ (e.inside_part (r).to_string (), "");
|
||||
EXPECT_EQ (e.inside_outside_part (r).first.to_string (), "");
|
||||
|
||||
ee = e;
|
||||
ee &= r;
|
||||
|
|
@ -844,6 +865,7 @@ TEST(21)
|
|||
EXPECT_EQ (ee.to_string (), "");
|
||||
|
||||
EXPECT_EQ (db::compare ((e - r), "(-100,0;0,0);(100,0;200,0)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot(r).second, "(-100,0;0,0);(100,0;200,0)"), true);
|
||||
EXPECT_EQ (db::compare (e.outside_part (r), "(-100,0;0,0);(0,0;100,0);(100,0;200,0)"), true);
|
||||
|
||||
ee = e;
|
||||
|
|
@ -874,6 +896,7 @@ TEST(22)
|
|||
ee.insert (db::Edge (4000,-2000,-2000,-2000));
|
||||
|
||||
EXPECT_EQ (db::compare ((e & ee), "(400,0;-2000,0);(500,-174;400,0);(1000,0;900,-173);(4000,0;1000,0)"), true);
|
||||
EXPECT_EQ (db::compare (e.andnot(ee).first, "(400,0;-2000,0);(500,-174;400,0);(1000,0;900,-173);(4000,0;1000,0)"), true);
|
||||
EXPECT_EQ (db::compare (e.intersections (ee), "(400,0;-2000,0);(500,-174;400,0);(1000,0;900,-173);(4000,0;1000,0)"), true);
|
||||
|
||||
// Edge/edge intersections
|
||||
|
|
@ -883,6 +906,7 @@ TEST(22)
|
|||
ee.insert (db::Edge (-50, 50, 50, 50));
|
||||
ee.insert (db::Edge (-50, 100, 50, 100));
|
||||
EXPECT_EQ ((e & ee).to_string (), ""); // AND does not report intersection points
|
||||
EXPECT_EQ (e.andnot(ee).first.to_string (), ""); // AND does not report intersection points
|
||||
EXPECT_EQ (db::compare (e.intersections (ee), "(0,50;0,50);(0,100;0,100)"), true);
|
||||
|
||||
// Edge is intersected by pair with connection point on this line
|
||||
|
|
@ -894,6 +918,7 @@ TEST(22)
|
|||
ee.insert (db::Edge (-50, 100, 0, 100));
|
||||
ee.insert (db::Edge (0, 100, 50, 100));
|
||||
EXPECT_EQ ((e & ee).to_string (), ""); // AND does not report intersection points
|
||||
EXPECT_EQ (e.andnot(ee).first.to_string (), ""); // AND does not report intersection points
|
||||
EXPECT_EQ (db::compare (e.intersections (ee), "(0,50;0,50);(0,60;0,60);(0,100;0,100)"), true);
|
||||
|
||||
// Coincident edges are crossed by another one
|
||||
|
|
@ -904,6 +929,7 @@ TEST(22)
|
|||
ee.insert (db::Edge (-50, 100, 50, 100));
|
||||
ee.insert (db::Edge (-50, 200, 50, 200));
|
||||
EXPECT_EQ ((e & ee).to_string (), "(0,0;0,150)");
|
||||
EXPECT_EQ (e.andnot(ee).first.to_string (), "(0,0;0,150)");
|
||||
EXPECT_EQ (db::compare (e.intersections (ee), "(0,0;0,150);(0,200;0,200)"), true);
|
||||
}
|
||||
|
||||
|
|
@ -939,6 +965,162 @@ TEST(23)
|
|||
EXPECT_EQ (e2.pull_interacting (e).to_string (), "(0,0;0,200)");
|
||||
}
|
||||
|
||||
// Edges::selected_inside(region)
|
||||
TEST(24)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Region r;
|
||||
r.insert (db::Box (0, -1000, 2000, 0));
|
||||
r.insert (db::Box (1000, 1000, 2000, 1500));
|
||||
r.insert (db::Box (1000, 1500, 2000, 2000));
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_inside (db::Region ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (db::Region ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (db::Region ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (db::Region ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_inside (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside_differential (r).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside_differential (r).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside (r), "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (r), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (r).first, "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (r).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
}
|
||||
|
||||
// Edges::selected_inside(edges)
|
||||
TEST(25)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Edges ee;
|
||||
for (int i = 0; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, -1000, i, 0));
|
||||
}
|
||||
for (int i = 1000; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, 1000, i, 1500));
|
||||
ee.insert (db::Edge (i, 1500, i, 2000));
|
||||
}
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_inside (db::Edges ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (db::Edges ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (db::Edges ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (db::Edges ()).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_inside (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside_differential (ee).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_inside_differential (ee).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside (ee), "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_inside (ee), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (ee).first, "(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_inside_differential (ee).second, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1500,1000;1500,2100);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
}
|
||||
|
||||
// Edges::selected_outside(region)
|
||||
TEST(26)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Region r;
|
||||
r.insert (db::Box (0, -1000, 2000, 0));
|
||||
r.insert (db::Box (1000, 1000, 2000, 1500));
|
||||
r.insert (db::Box (1000, 1500, 2000, 2000));
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_outside (db::Region ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (db::Region ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (db::Region ()).first, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (db::Region ()).second, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_outside (r), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside_differential (r).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside_differential (r).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside (r), "(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (r), "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (r).first, "(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (r).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1700,1500;1600,2500);(1900,1000;1900,2000)"), true);
|
||||
}
|
||||
|
||||
// Edges::selected_outside(edges)
|
||||
TEST(27)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (100, 0, 100, 3000));
|
||||
e.insert (db::Edge (1100, -1000, 1100, 2000));
|
||||
e.insert (db::Edge (1200, -1000, 1200, 0));
|
||||
e.insert (db::Edge (1300, -800, 1300, -200));
|
||||
e.insert (db::Edge (1400, 1000, 1400, 1100));
|
||||
e.insert (db::Edge (1500, 1000, 1500, 2100));
|
||||
e.insert (db::Edge (1600, -800, 1600, -400));
|
||||
e.insert (db::Edge (1600, -400, 1600, -200));
|
||||
e.insert (db::Edge (1700, 1500, 1600, 2500));
|
||||
e.insert (db::Edge (1800, 2500, 1800, 3500));
|
||||
e.insert (db::Edge (1900, 1000, 1900, 2000));
|
||||
e.insert (db::Edge (-1500, 0, -1500, 1000));
|
||||
|
||||
db::Edges ee;
|
||||
for (int i = 0; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, -1000, i, 0));
|
||||
}
|
||||
for (int i = 1000; i <= 2000; i += 100) {
|
||||
ee.insert (db::Edge (i, 1000, i, 1500));
|
||||
ee.insert (db::Edge (i, 1500, i, 2000));
|
||||
}
|
||||
|
||||
EXPECT_EQ (db::compare (e.selected_outside (db::Edges ()), "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (db::Edges ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (db::Edges ()).first, "(0,0;0,1000);(100,0;100,3000);(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-400);(1600,-400;1600,-200);(1700,1500;1600,2500);(1800,2500;1800,3500);(1900,1000;1900,2000);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (db::Edges ()).second, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_not_outside (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside_differential (ee).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().selected_outside_differential (ee).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside (ee), "(0,0;0,1000);(100,0;100,3000);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_not_outside (ee), "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (ee).first, "(0,0;0,1000);(100,0;100,3000);(1700,1500;1600,2500);(1800,2500;1800,3500);(-1500,0;-1500,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.selected_outside_differential (ee).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
}
|
||||
|
||||
// GitHub issue #72 (Edges/Region NOT issue)
|
||||
TEST(100)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "tlUnitTest.h"
|
||||
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 10))), true);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (10, 0), db::Point (20, 00)), db::Edge (db::Point (0, 0), db::Point (10, 0))), true);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (11, 0), db::Point (20, 00)), db::Edge (db::Point (0, 0), db::Point (10, 0))), false);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 1), db::Point (10, 10))), true);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (1, 0), db::Point (1, 10))), true);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 1), db::Point (0, 10))), false);
|
||||
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 10), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (0, 11), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (10, 20), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_interacts (db::Edge (db::Point (10, 20), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 20))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (-10, -10), db::Point (10, 20))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (5, 5), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 20))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (20, 20))), true);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 2), db::Point (20, 22))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (0, 20))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (1, 1), db::Point (20, 20))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (30, 30), db::Point (20, 20))), false);
|
||||
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon ()), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (15, 15)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 10), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 11), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (0, 5), db::Point (10, 5)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_inside (db::Edge (db::Point (-5, 5), db::Point (15, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 20))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (10, 10), db::Point (20, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (-10, -10), db::Point (10, 20))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (5, 5), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (10, 20))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (20, 20))), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 2), db::Point (20, 22))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (0, 0), db::Point (0, 20))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (1, 1), db::Point (20, 20))), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Edge (db::Point (30, 30), db::Point (20, 20))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (1700, 1500), db::Point (1600, 2500)), db::Edge (db::Point (1700, 1000), db::Point (1700, 2000))), true);
|
||||
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon ()), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (15, 15)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (0, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 10), db::Point (10, 10)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 11), db::Point (10, 11)), db::Polygon (db::Box (0, 0, 10, 10))), true);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (0, 5), db::Point (10, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-5, 5), db::Point (15, 5)), db::Polygon (db::Box (0, 0, 10, 10))), false);
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +71,7 @@ SOURCES = \
|
|||
dbEdgePairRelationsTests.cc \
|
||||
dbEdgePairTests.cc \
|
||||
dbEdgeTests.cc \
|
||||
dbEdgesUtilsTests.cc \
|
||||
dbClipTests.cc \
|
||||
dbCellMappingTests.cc \
|
||||
dbCellHullGeneratorTests.cc \
|
||||
|
|
|
|||
|
|
@ -1873,7 +1873,9 @@ CODE
|
|||
# This method returns a two-element array containing one layer for the
|
||||
# AND result and one for the NOT result.
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
# This method is available for polygon and edge layers.
|
||||
# For polygon layers, the other input must be a polygon layer too.
|
||||
# For edge layers, the other input can be polygon or edge.
|
||||
#
|
||||
# It can be used to initialize two variables with the AND and NOT results:
|
||||
#
|
||||
|
|
@ -1889,8 +1891,12 @@ CODE
|
|||
@engine._context("andnot") do
|
||||
|
||||
check_is_layer(other)
|
||||
requires_region
|
||||
other.requires_region
|
||||
requires_edges_or_region
|
||||
if self.data.is_a?(RBA::Edges)
|
||||
other.requires_edges_or_region
|
||||
elsif self.data.is_a?(RBA::Region)
|
||||
other.requires_region
|
||||
end
|
||||
|
||||
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :andnot, other.data)
|
||||
|
||||
|
|
@ -2140,54 +2146,94 @@ CODE
|
|||
|
||||
# %DRC%
|
||||
# @name inside
|
||||
# @brief Selects shapes or regions of self which are inside the other region
|
||||
# @brief Selects edges or polygons of self which are inside edges or polygons from the other layer
|
||||
# @synopsis layer.inside(other)
|
||||
# This method selects all shapes or regions from self which are inside the other region.
|
||||
# completely (completely covered by polygons from the other region). If self is
|
||||
# in raw mode, this method will select individual shapes. Otherwise, this method
|
||||
# will select coherent regions and no part of these regions may be outside the
|
||||
# other region.
|
||||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_inside.
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
# If layer is a polygon layer, the other layer needs to be a polygon layer too.
|
||||
# In this case, this method selects all polygons which are completely inside
|
||||
# polygons from the other layer.
|
||||
#
|
||||
# The following image shows the effect of the "inside" method (input1: red, input2: blue):
|
||||
# If layer is an edge layer, the other layer can be polygon or edge layer. In the
|
||||
# first case, all edges completely inside the polygons from the other layer are
|
||||
# selected. If the other layer is an edge layer, all edges completely contained
|
||||
# in edges from the other layer are selected.
|
||||
#
|
||||
# Merged semantics applies - i.e. edges or polygons are joined before the
|
||||
# result is computed, unless the layers are in \raw mode.
|
||||
#
|
||||
# This method returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_inside. \not_inside is a function computing the inverse of \inside.
|
||||
# \split_inside is a function computing both results in a single call. \outside
|
||||
# is a similar function selecting edges or polygons outside other edges or polygons.
|
||||
#
|
||||
# The following image shows the effect of the "inside" method for polygons (input1: red, input2: blue):
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_inside.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# The following images show the effect of the "inside" method for edge layers and edge or polygon layers
|
||||
# the second input. Note that the edges are computed from the polygons in this example
|
||||
# (input1: red, input2: blue):
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_inside_ee.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_inside_ep.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
|
||||
# %DRC%
|
||||
# @name not_inside
|
||||
# @brief Selects shapes or regions of self which are not inside the other region
|
||||
# @brief Selects edges or polygons of self which are not inside edges or polygons from the other layer
|
||||
# @synopsis layer.not_inside(other)
|
||||
# This method selects all shapes or regions from self which are not inside the other region.
|
||||
# completely (completely covered by polygons from the other region). If self is
|
||||
# in raw mode, this method will select individual shapes. Otherwise, this method
|
||||
# will select coherent regions and no part of these regions may be outside the
|
||||
# other region.
|
||||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
#
|
||||
# This method computes the inverse of \inside - i.e. edges or polygons from the layer
|
||||
# not being inside polygons or edges from the other layer.
|
||||
#
|
||||
# This method returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_not_inside.
|
||||
# \split_inside is a function computing both results of \inside and \not_inside in a single call. \outside
|
||||
# is a similar function selecting edges or polygons outside other edges or polygons. Note
|
||||
# that "outside" is not the same than "not inside".
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
#
|
||||
# The following image shows the effect of the "not_inside" method (input1: red, input2: blue):
|
||||
# The following image shows the effect of the "not_inside" method for polygon layers (input1: red, input2: blue):
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_not_inside.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# The following images show the effect of the "not_inside" method for edge layers and edge or polygon layers
|
||||
# the second input. Note that the edges are computed from the polygons in this example
|
||||
# (input1: red, input2: blue):
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_not_inside_ee.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_not_inside_ep.png) @/td
|
||||
# @/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
|
||||
# This method returns the polygons or edges inside of polygons or edges 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:
|
||||
#
|
||||
|
|
@ -2197,82 +2243,110 @@ CODE
|
|||
|
||||
# %DRC%
|
||||
# @name select_inside
|
||||
# @brief Selects shapes or regions of self which are inside the other region
|
||||
# @brief Selects edges or polygons of self which are inside edges or polygons from the other layer
|
||||
# @synopsis layer.select_inside(other)
|
||||
# This method selects all shapes or regions from self which are inside the other region.
|
||||
# completely (completely covered by polygons from the other region). If self is
|
||||
# in raw mode, this method will select individual shapes. Otherwise, this method
|
||||
# will select coherent regions and no part of these regions may be outside the
|
||||
# other region.
|
||||
# It modifies self to contain the selected shapes. A version which does not modify self
|
||||
# is \inside.
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
# This method is the in-place version of \inside - i.e. it modifies the layer instead
|
||||
# of returning a new layer and leaving the original layer untouched.
|
||||
|
||||
# %DRC%
|
||||
# @name select_not_inside
|
||||
# @brief Selects shapes or regions of self which are not inside the other region
|
||||
# @brief Selects edges or polygons of self which are not inside edges or polygons from the other layer
|
||||
# @synopsis layer.select_not_inside(other)
|
||||
# This method selects all shapes or regions from self which are not inside the other region.
|
||||
# completely (completely covered by polygons from the other region). If self is
|
||||
# in raw mode, this method will select individual shapes. Otherwise, this method
|
||||
# will select coherent regions and no part of these regions may be outside the
|
||||
# other region.
|
||||
# It modifies self to contain the selected shapes. A version which does not modify self
|
||||
# is \not_inside.
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
# This method is the in-place version of \inside - i.e. it modifies the layer instead
|
||||
# of returning a new layer and leaving the original layer untouched.
|
||||
|
||||
# %DRC%
|
||||
# @name outside
|
||||
# @brief Selects shapes or regions of self which are outside the other region
|
||||
# @brief Selects edges or polygons of self which are outside edges or polygons from the other layer
|
||||
# @synopsis layer.outside(other)
|
||||
# This method selects all shapes or regions from self which are completely outside
|
||||
# the other region (no part of these shapes or regions may be covered by shapes from
|
||||
# the other region). If self is in raw mode, this method will select individual
|
||||
# shapes. Otherwise, this method will select coherent regions and no part of these
|
||||
# regions may overlap with shapes from the other region.
|
||||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_outside.
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
# If layer is a polygon layer, the other layer needs to be a polygon layer too.
|
||||
# In this case, this method selects all polygons which are entirely outside
|
||||
# polygons from the other layer.
|
||||
#
|
||||
# The following image shows the effect of the "outside" method (input1: red, input2: blue):
|
||||
# If layer is an edge layer, the other layer can be polygon or edge layer. In the
|
||||
# first case, all edges entirely outside the polygons from the other layer are
|
||||
# selected. If the other layer is an edge layer, all edges entirely outside
|
||||
# of edges from the other layer are selected.
|
||||
#
|
||||
# Merged semantics applies - i.e. edges or polygons are joined before the
|
||||
# result is computed, unless the layers are in \raw mode.
|
||||
#
|
||||
# This method returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_outside. \not_outside is a function computing the inverse of \outside.
|
||||
# \split_outside is a function computing both results in a single call. \outside
|
||||
# is a similar function selecting edges or polygons outside other edges or polygons.
|
||||
#
|
||||
# The following image shows the effect of the "outside" method for polygons (input1: red, input2: blue):
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_outside.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# The following images show the effect of the "outside" method for edge layers and edge or polygon layers
|
||||
# the second input. Note that the edges are computed from the polygons in this example
|
||||
# (input1: red, input2: blue):
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_outside_ee.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_outside_ep.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
|
||||
# %DRC%
|
||||
# @name not_outside
|
||||
# @brief Selects shapes or regions of self which are not outside the other region
|
||||
# @brief Selects edges or polygons of self which are not outside edges or polygons from the other layer
|
||||
# @synopsis layer.not_outside(other)
|
||||
# This method selects all shapes or regions from self which are not completely outside
|
||||
# the other region (part of these shapes or regions may be covered by shapes from
|
||||
# the other region). If self is in raw mode, this method will select individual
|
||||
# shapes. Otherwise, this method will select coherent regions and no part of these
|
||||
# regions may overlap with shapes from the other region.
|
||||
# It returns a new layer containing the selected shapes. A version which modifies self
|
||||
#
|
||||
# This method computes the inverse of \outside - i.e. edges or polygons from the layer
|
||||
# not being outside polygons or edges from the other layer.
|
||||
#
|
||||
# This method returns a new layer containing the selected shapes. A version which modifies self
|
||||
# is \select_not_outside.
|
||||
# \split_outside is a function computing both results of \outside and \not_outside in a single call. \outside
|
||||
# is a similar function selecting edges or polygons outside other edges or polygons. Note
|
||||
# that "outside" is not the same than "not outside".
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
#
|
||||
# The following image shows the effect of the "not_outside" method (input1: red, input2: blue):
|
||||
# The following image shows the effect of the "not_outside" method for polygon layers (input1: red, input2: blue):
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_not_outside.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# The following images show the effect of the "not_outside" method for edge layers and edge or polygon layers
|
||||
# the second input. Note that the edges are computed from the polygons in this example
|
||||
# (input1: red, input2: blue):
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_not_outside_ee.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_not_outside_ep.png) @/td
|
||||
# @/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
|
||||
# This method returns the polygons or edges outside of polygons or edges 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:
|
||||
#
|
||||
|
|
@ -2282,31 +2356,19 @@ CODE
|
|||
|
||||
# %DRC%
|
||||
# @name select_outside
|
||||
# @brief Selects shapes or regions of self which are outside the other region
|
||||
# @brief Selects edges or polygons of self which are outside edges or polygons from the other layer
|
||||
# @synopsis layer.select_outside(other)
|
||||
# This method selects all shapes or regions from self which are completely outside
|
||||
# the other region (no part of these shapes or regions may be covered by shapes from
|
||||
# the other region). If self is in raw mode, this method will select individual
|
||||
# shapes. Otherwise, this method will select coherent regions and no part of these
|
||||
# regions may overlap with shapes from the other region.
|
||||
# It modifies self to contain the selected shapes. A version which does not modify self
|
||||
# is \outside.
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
# This method is the in-place version of \outside - i.e. it modifies the layer instead
|
||||
# of returning a new layer and leaving the original layer untouched.
|
||||
|
||||
# %DRC%
|
||||
# @name select_not_outside
|
||||
# @brief Selects shapes or regions of self which are not outside the other region
|
||||
# @brief Selects edges or polygons of self which are not outside edges or polygons from the other layer
|
||||
# @synopsis layer.select_not_outside(other)
|
||||
# This method selects all shapes or regions from self which are not completely outside
|
||||
# the other region (part of these shapes or regions may be covered by shapes from
|
||||
# the other region). If self is in raw mode, this method will select individual
|
||||
# shapes. Otherwise, this method will select coherent regions and no part of these
|
||||
# regions may overlap with shapes from the other region.
|
||||
# It modifies self to contain the selected shapes. A version which does not modify self
|
||||
# is \not_outside.
|
||||
#
|
||||
# This method is available for polygon layers.
|
||||
# This method is the in-place version of \outside - i.e. it modifies the layer instead
|
||||
# of returning a new layer and leaving the original layer untouched.
|
||||
|
||||
# %DRC%
|
||||
# @name in
|
||||
|
|
@ -2439,7 +2501,7 @@ CODE
|
|||
# @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
|
||||
# This method returns the polygons or edges 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:
|
||||
#
|
||||
|
|
@ -2513,6 +2575,9 @@ CODE
|
|||
#
|
||||
# This method is available for edge layers. The argument must be a polygon layer.
|
||||
#
|
||||
# \outside_part is a method computing the opposite part. \inside_outside_part is a
|
||||
# method computing both inside and outside part in a single call.
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_inside_part.png) @/td
|
||||
|
|
@ -2529,12 +2594,26 @@ CODE
|
|||
#
|
||||
# This method is available for edge layers. The argument must be a polygon layer.
|
||||
#
|
||||
# \inside_part is a method computing the opposite part. \inside_outside_part is a
|
||||
# method computing both inside and outside part in a single call.
|
||||
#
|
||||
# @table
|
||||
# @tr
|
||||
# @td @img(/images/drc_outside_part.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
|
||||
# %DRC%
|
||||
# @name inside_outside_part
|
||||
# @brief Returns the parts of the edges inside and outside the given region
|
||||
# @synopsis (inside_part, outside_part) = layer.inside_outside_part(region)
|
||||
# The method is available for edge layers. The argument must be a polygon layer.
|
||||
#
|
||||
# This method returns two layers: the first with the edge parts inside the given region
|
||||
# and the second with the parts outside the given region. It is equivalent
|
||||
# to calling \inside_part and \outside_part, but more efficient if both parts
|
||||
# need to be computed.
|
||||
|
||||
# %DRC%
|
||||
# @name pull_interacting
|
||||
# @brief Selects shapes or edges of other which touch or overlap shapes from the this region
|
||||
|
|
@ -2608,7 +2687,28 @@ CODE
|
|||
CODE
|
||||
end
|
||||
|
||||
%w(| ^ inside not_inside outside not_outside in not_in).each do |f|
|
||||
%w(inside not_inside outside not_outside).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
requires_edges_or_region
|
||||
if self.data.is_a?(RBA::Edges)
|
||||
other.requires_edges_or_region
|
||||
else
|
||||
other.requires_region
|
||||
end
|
||||
|
||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data))
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
%w(| ^ in not_in).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
|
||||
|
|
@ -2723,8 +2823,31 @@ CODE
|
|||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
requires_region
|
||||
other.requires_edges_texts_or_region
|
||||
requires_edges_or_region
|
||||
if self.data.is_a?(RBA::Edges)
|
||||
other.requires_edges_or_region
|
||||
elsif self.data.is_a?(RBA::Region)
|
||||
other.requires_edges_texts_or_region
|
||||
end
|
||||
|
||||
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_outside_part).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other, *args)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
requires_edges
|
||||
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]) ]
|
||||
|
|
@ -2803,8 +2926,12 @@ CODE
|
|||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
requires_region
|
||||
requires_same_type(other)
|
||||
requires_edges_or_region
|
||||
if self.data.is_a?(RBA::Edges)
|
||||
other.requires_edges_or_region
|
||||
else
|
||||
other.requires_region
|
||||
end
|
||||
|
||||
if @engine.is_tiled?
|
||||
self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data)
|
||||
|
|
@ -2821,15 +2948,19 @@ CODE
|
|||
|
||||
%w(split_inside split_outside).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other)
|
||||
def #{f}(other, *args)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
check_is_layer(other)
|
||||
requires_region
|
||||
other.requires_region
|
||||
requires_edges_or_region
|
||||
if self.data.is_a?(RBA::Edges)
|
||||
other.requires_edges_or_region
|
||||
elsif self.data.is_a?(RBA::Region)
|
||||
other.requires_region
|
||||
end
|
||||
|
||||
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#include "dbLibrary.h"
|
||||
#include "dbLibraryManager.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "layLayoutView.h"
|
||||
#include "laySelector.h"
|
||||
#include "layFinder.h"
|
||||
#include "layLayerProperties.h"
|
||||
|
|
@ -100,7 +100,7 @@ edt::RoundCornerOptionsDialog *
|
|||
MainService::round_corners_dialog ()
|
||||
{
|
||||
if (! mp_round_corners_dialog) {
|
||||
mp_round_corners_dialog = new edt::RoundCornerOptionsDialog (view ()->widget ());
|
||||
mp_round_corners_dialog = new edt::RoundCornerOptionsDialog (lay::widget_from_view (view ()));
|
||||
}
|
||||
return mp_round_corners_dialog;
|
||||
}
|
||||
|
|
@ -109,7 +109,7 @@ edt::AlignOptionsDialog *
|
|||
MainService::align_options_dialog ()
|
||||
{
|
||||
if (! mp_align_options_dialog) {
|
||||
mp_align_options_dialog = new edt::AlignOptionsDialog (view ()->widget ());
|
||||
mp_align_options_dialog = new edt::AlignOptionsDialog (lay::widget_from_view (view ()));
|
||||
}
|
||||
return mp_align_options_dialog;
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ edt::DistributeOptionsDialog *
|
|||
MainService::distribute_options_dialog ()
|
||||
{
|
||||
if (! mp_distribute_options_dialog) {
|
||||
mp_distribute_options_dialog = new edt::DistributeOptionsDialog (view ()->widget ());
|
||||
mp_distribute_options_dialog = new edt::DistributeOptionsDialog (lay::widget_from_view (view ()));
|
||||
}
|
||||
return mp_distribute_options_dialog;
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ lay::FlattenInstOptionsDialog *
|
|||
MainService::flatten_inst_options_dialog ()
|
||||
{
|
||||
if (! mp_flatten_inst_options_dialog) {
|
||||
mp_flatten_inst_options_dialog = new lay::FlattenInstOptionsDialog (view ()->widget (), false /*don't allow pruning*/);
|
||||
mp_flatten_inst_options_dialog = new lay::FlattenInstOptionsDialog (lay::widget_from_view (view ()), false /*don't allow pruning*/);
|
||||
}
|
||||
return mp_flatten_inst_options_dialog;
|
||||
}
|
||||
|
|
@ -136,7 +136,7 @@ edt::MakeCellOptionsDialog *
|
|||
MainService::make_cell_options_dialog ()
|
||||
{
|
||||
if (! mp_make_cell_options_dialog) {
|
||||
mp_make_cell_options_dialog = new edt::MakeCellOptionsDialog (view ()->widget ());
|
||||
mp_make_cell_options_dialog = new edt::MakeCellOptionsDialog (lay::widget_from_view (view ()));
|
||||
}
|
||||
return mp_make_cell_options_dialog;
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ edt::MakeArrayOptionsDialog *
|
|||
MainService::make_array_options_dialog ()
|
||||
{
|
||||
if (! mp_make_array_options_dialog) {
|
||||
mp_make_array_options_dialog = new edt::MakeArrayOptionsDialog (view ()->widget ());
|
||||
mp_make_array_options_dialog = new edt::MakeArrayOptionsDialog (lay::widget_from_view (view ()));
|
||||
}
|
||||
return mp_make_array_options_dialog;
|
||||
}
|
||||
|
|
@ -1228,7 +1228,7 @@ MainService::cm_convert_to_pcell ()
|
|||
}
|
||||
|
||||
bool ok = false;
|
||||
QString item = QInputDialog::getItem (view ()->widget (),
|
||||
QString item = QInputDialog::getItem (lay::widget_from_view (view ()),
|
||||
tr ("Select Target PCell"),
|
||||
tr ("Select the PCell the shape should be converted into"),
|
||||
items, 0, false, &ok);
|
||||
|
|
@ -1333,7 +1333,7 @@ MainService::cm_convert_to_pcell ()
|
|||
if (any_non_converted) {
|
||||
tl::warn << tl::to_string (tr ("Some of the shapes could not be converted to the desired PCell"));
|
||||
#if defined(HAVE_QT)
|
||||
QMessageBox::warning (view ()->widget (), tr ("Warning"), tr ("Some of the shapes could not be converted to the desired PCell"));
|
||||
QMessageBox::warning (lay::widget_from_view (view ()), tr ("Warning"), tr ("Some of the shapes could not be converted to the desired PCell"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1565,7 +1565,7 @@ MainService::cm_size ()
|
|||
#if defined(HAVE_QT)
|
||||
// TODO: keep the value persistent so we can set it externally in the Qt-less case
|
||||
bool ok = false;
|
||||
QString s = QInputDialog::getText (view ()->widget (),
|
||||
QString s = QInputDialog::getText (lay::widget_from_view (view ()),
|
||||
tr ("Sizing"),
|
||||
tr ("Sizing (in micron, positive or negative). Two values (dx, dy) for anisotropic sizing."),
|
||||
QLineEdit::Normal, QString::fromUtf8 ("0.0"),
|
||||
|
|
@ -2159,7 +2159,8 @@ MainService::cm_tap ()
|
|||
#endif
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
if (! view ()->canvas ()->widget ()) {
|
||||
QWidget *view_widget = lay::widget_from_view (view ());
|
||||
if (! view_widget) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -2202,7 +2203,8 @@ MainService::cm_tap ()
|
|||
|
||||
#if defined(HAVE_QT)
|
||||
// TODO: what to do here in Qt-less case? Store results in configuration so they can be retrieved externally?
|
||||
std::unique_ptr<QMenu> menu (new QMenu (view ()->widget ()));
|
||||
|
||||
std::unique_ptr<QMenu> menu (new QMenu (view_widget));
|
||||
menu->show ();
|
||||
|
||||
int icon_size = menu->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ RecentConfigurationPage::render_to (QTreeWidgetItem *item, int column, const std
|
|||
|
||||
case RecentConfigurationPage::Layer:
|
||||
{
|
||||
int icon_size = view ()->widget ()->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
|
||||
int icon_size = item->treeWidget ()->style ()->pixelMetric (QStyle::PM_ButtonIconSize);
|
||||
lay::LayerPropertiesConstIterator l;
|
||||
try {
|
||||
l = lp_iter_from_string (view (), values [column]);
|
||||
|
|
@ -348,7 +348,7 @@ RecentConfigurationPage::update_list (const std::list<std::vector<std::string> >
|
|||
}
|
||||
|
||||
static bool
|
||||
set_or_request_current_layer (lay::LayoutViewBase *view, unsigned int cv_index, const db::LayerProperties &lp)
|
||||
set_or_request_current_layer (QWidget *parent, lay::LayoutViewBase *view, unsigned int cv_index, const db::LayerProperties &lp)
|
||||
{
|
||||
bool ok = view->set_current_layer (cv_index, lp);
|
||||
if (ok) {
|
||||
|
|
@ -364,7 +364,7 @@ set_or_request_current_layer (lay::LayoutViewBase *view, unsigned int cv_index,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (QMessageBox::question (view->widget (), tr ("Create Layer"), tr ("Layer %1 does not exist yet. Create it now?").arg (tl::to_qstring (lp.to_string ()))) == QMessageBox::Yes) {
|
||||
if (QMessageBox::question (parent, tr ("Create Layer"), tr ("Layer %1 does not exist yet. Create it now?").arg (tl::to_qstring (lp.to_string ()))) == QMessageBox::Yes) {
|
||||
|
||||
lay::LayerPropertiesNode lpn;
|
||||
lpn.set_source (lay::ParsedLayerSource (lp, cv_index));
|
||||
|
|
@ -400,7 +400,7 @@ RecentConfigurationPage::item_clicked (QTreeWidgetItem *item)
|
|||
ex.read (cv_index);
|
||||
}
|
||||
|
||||
set_or_request_current_layer (view (), cv_index, lp);
|
||||
set_or_request_current_layer (item->treeWidget (), view (), cv_index, lp);
|
||||
|
||||
} else {
|
||||
dispatcher ()->config_set (c->cfg_name, v);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
# include "edtDialogs.h"
|
||||
#endif
|
||||
#include "layFinder.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
#include "layLayoutView.h"
|
||||
#include "laySnap.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlTimer.h"
|
||||
|
|
@ -315,7 +315,7 @@ void
|
|||
Service::copy_selected ()
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
edt::CopyModeDialog mode_dialog (view ()->widget ());
|
||||
edt::CopyModeDialog mode_dialog (lay::widget_from_view (view ()));
|
||||
|
||||
bool need_to_ask_for_copy_mode = false;
|
||||
unsigned int inst_mode = 0;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ static int t_object () { return T_object; }
|
|||
static int t_vector () { return T_vector; }
|
||||
static int t_map () { return T_map; }
|
||||
|
||||
static int type (const ArgType *t)
|
||||
static int type (const ArgType *t)
|
||||
{
|
||||
return t->type ();
|
||||
}
|
||||
|
|
@ -105,9 +105,13 @@ Class<ArgType> decl_ArgType ("tl", "ArgType",
|
|||
"@brief Return the basic type (see t_.. constants)\n"
|
||||
) +
|
||||
gsi::method ("inner", &ArgType::inner,
|
||||
"@brief Returns the inner ArgType object (i.e. value of a vector)\n"
|
||||
"@brief Returns the inner ArgType object (i.e. value of a vector/map)\n"
|
||||
"Starting with version 0.22, this method replaces the is_vector method.\n"
|
||||
) +
|
||||
gsi::method ("inner_k", &ArgType::inner_k,
|
||||
"@brief Returns the inner ArgType object (i.e. key of a map)\n"
|
||||
"This method has been introduced in version 0.27."
|
||||
) +
|
||||
gsi::method ("pass_obj?", &ArgType::pass_obj,
|
||||
"@brief True, if the ownership over an object represented by this type is passed to the receiver\n"
|
||||
"In case of the return type, a value of true indicates, that the object is a freshly created one and "
|
||||
|
|
@ -283,6 +287,12 @@ Class<ClassBase> decl_Class ("tl", "Class",
|
|||
gsi::iterator ("each_method", &ClassBase::begin_methods, &ClassBase::end_methods,
|
||||
"@brief Iterate over all methods of this class\n"
|
||||
) +
|
||||
gsi::iterator ("each_child_class", &ClassBase::begin_child_classes, &ClassBase::end_child_classes,
|
||||
"@brief Iterate over all child classes defined within this class\n"
|
||||
) +
|
||||
gsi::method ("parent", &ClassBase::parent,
|
||||
"@brief The parent of the class\n"
|
||||
) +
|
||||
gsi::method ("name", &ClassBase::name,
|
||||
"@brief The name of the class\n"
|
||||
) +
|
||||
|
|
@ -309,5 +319,3 @@ Class<ClassBase> decl_Class ("tl", "Class",
|
|||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -51,27 +51,26 @@ Navigator::Navigator (QWidget *parent)
|
|||
img::Object *
|
||||
Navigator::setup (lay::Dispatcher *root, img::Object *img)
|
||||
{
|
||||
mp_view = new lay::LayoutView (0, false, root, this, "img_navigator_view", lay::LayoutView::LV_Naked + lay::LayoutView::LV_NoZoom + lay::LayoutView::LV_NoServices + lay::LayoutView::LV_NoGrid);
|
||||
tl_assert (mp_view->widget ());
|
||||
mp_view->widget ()->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
mp_view->widget ()->setMinimumWidth (100);
|
||||
mp_view->widget ()->setMinimumHeight (100);
|
||||
mp_view = new lay::LayoutViewWidget (0, false, root, this, lay::LayoutView::LV_Naked + lay::LayoutView::LV_NoZoom + lay::LayoutView::LV_NoServices + lay::LayoutView::LV_NoGrid);
|
||||
mp_view->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
mp_view->setMinimumWidth (100);
|
||||
mp_view->setMinimumHeight (100);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout (this);
|
||||
layout->addWidget (mp_view->widget ());
|
||||
layout->setStretchFactor (mp_view->widget (), 1);
|
||||
layout->addWidget (mp_view);
|
||||
layout->setStretchFactor (mp_view, 1);
|
||||
layout->setContentsMargins (0, 0, 0, 0);
|
||||
layout->setSpacing (0);
|
||||
setLayout (layout);
|
||||
|
||||
mp_zoom_service = new lay::ZoomService (mp_view);
|
||||
mp_zoom_service = new lay::ZoomService (view ());
|
||||
|
||||
img::Service *img_target = mp_view->get_plugin<img::Service> ();
|
||||
img::Service *img_target = view ()->get_plugin<img::Service> ();
|
||||
if (img_target) {
|
||||
img_target->clear_images ();
|
||||
img::Object *img_object = img_target->insert_image (*img);
|
||||
img_object->set_matrix (db::Matrix3d (1.0));
|
||||
mp_view->zoom_fit ();
|
||||
view ()->zoom_fit ();
|
||||
return img_object;
|
||||
} else {
|
||||
return 0;
|
||||
|
|
@ -91,10 +90,15 @@ Navigator::~Navigator ()
|
|||
}
|
||||
}
|
||||
|
||||
lay::LayoutView *Navigator::view ()
|
||||
{
|
||||
return mp_view->view ();
|
||||
}
|
||||
|
||||
void
|
||||
Navigator::activate_service (lay::ViewService *service)
|
||||
{
|
||||
mp_view->canvas ()->activate (service);
|
||||
view ()->canvas ()->activate (service);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
namespace lay
|
||||
{
|
||||
class Dispatcher;
|
||||
class LayoutViewWidget;
|
||||
class LayoutView;
|
||||
class ZoomService;
|
||||
class ViewService;
|
||||
|
|
@ -55,15 +56,12 @@ public:
|
|||
void background_color (QColor c);
|
||||
img::Object *setup (lay::Dispatcher *root, img::Object *img);
|
||||
|
||||
lay::LayoutView *view ()
|
||||
{
|
||||
return mp_view;
|
||||
}
|
||||
lay::LayoutView *view ();
|
||||
|
||||
void activate_service (lay::ViewService *service);
|
||||
|
||||
private:
|
||||
lay::LayoutView *mp_view;
|
||||
lay::LayoutViewWidget *mp_view;
|
||||
lay::ZoomService *mp_zoom_service;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,278 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ReaderErrorForm</class>
|
||||
<widget class="QDialog" name="ReaderErrorForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>496</width>
|
||||
<height>297</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Script Error</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="2" column="3">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>411</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>411</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="msg_label">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="3">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>71</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="3">
|
||||
<widget class="QLabel" name="icon_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" rowspan="3">
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>71</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="details_frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="details_text">
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Ubuntu'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Liberation Mono';"><br /></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="details_pb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Details >> </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>341</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="ok_button">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>ok_button</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>ReaderErrorForm</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>457</x>
|
||||
<y>330</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>271</x>
|
||||
<y>177</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
@ -103,7 +103,9 @@ polygons will be written to the output (labels: red, input2: blue):
|
|||
This method returns a two-element array containing one layer for the
|
||||
AND result and one for the NOT result.
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
This method is available for polygon and edge layers.
|
||||
For polygon layers, the other input must be a polygon layer too.
|
||||
For edge layers, the other input can be polygon or edge.
|
||||
</p><p>
|
||||
It can be used to initialize two variables with the AND and NOT results:
|
||||
</p><p>
|
||||
|
|
@ -1343,30 +1345,67 @@ pl = polygon_layer
|
|||
pl.insert(box(0.0, 0.0, 100.0, 200.0)
|
||||
</pre>
|
||||
</p>
|
||||
<a name="inside"/><h2>"inside" - Selects shapes or regions of self which are inside the other region</h2>
|
||||
<a name="inside"/><h2>"inside" - Selects edges or polygons of self which are inside edges or polygons from the other layer</h2>
|
||||
<keyword name="inside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.inside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which are inside the other region.
|
||||
completely (completely covered by polygons from the other region). If self is
|
||||
in raw mode, this method will select individual shapes. Otherwise, this method
|
||||
will select coherent regions and no part of these regions may be outside the
|
||||
other region.
|
||||
It returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_inside">select_inside</a>.
|
||||
If layer is a polygon layer, the other layer needs to be a polygon layer too.
|
||||
In this case, this method selects all polygons which are completely inside
|
||||
polygons from the other layer.
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
If layer is an edge layer, the other layer can be polygon or edge layer. In the
|
||||
first case, all edges completely inside the polygons from the other layer are
|
||||
selected. If the other layer is an edge layer, all edges completely contained
|
||||
in edges from the other layer are selected.
|
||||
</p><p>
|
||||
The following image shows the effect of the "inside" method (input1: red, input2: blue):
|
||||
Merged semantics applies - i.e. edges or polygons are joined before the
|
||||
result is computed, unless the layers are in <a href="#raw">raw</a> mode.
|
||||
</p><p>
|
||||
This method returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_inside">select_inside</a>. <a href="#not_inside">not_inside</a> is a function computing the inverse of <a href="#inside">inside</a>.
|
||||
<a href="#split_inside">split_inside</a> is a function computing both results in a single call. <a href="#outside">outside</a>
|
||||
is a similar function selecting edges or polygons outside other edges or polygons.
|
||||
</p><p>
|
||||
The following image shows the effect of the "inside" method for polygons (input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_inside.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
The following images show the effect of the "inside" method for edge layers and edge or polygon layers
|
||||
the second input. Note that the edges are computed from the polygons in this example
|
||||
(input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_inside_ee.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_inside_ep.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="inside_outside_part"/><h2>"inside_outside_part" - Returns the parts of the edges inside and outside the given region</h2>
|
||||
<keyword name="inside_outside_part"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>(inside_part, outside_part) = layer.inside_outside_part(region)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method is available for edge layers. The argument must be a polygon layer.
|
||||
</p><p>
|
||||
This method returns two layers: the first with the edge parts inside the given region
|
||||
and the second with the parts outside the given region. It is equivalent
|
||||
to calling <a href="#inside_part">inside_part</a> and <a href="#outside_part">outside_part</a>, but more efficient if both parts
|
||||
need to be computed.
|
||||
</p>
|
||||
<a name="inside_part"/><h2>"inside_part" - Returns the parts of the edges inside the given region</h2>
|
||||
<keyword name="inside_part"/>
|
||||
|
|
@ -1381,6 +1420,9 @@ of the polygons of the region.
|
|||
</p><p>
|
||||
This method is available for edge layers. The argument must be a polygon layer.
|
||||
</p><p>
|
||||
<a href="#outside_part">outside_part</a> is a method computing the opposite part. <a href="#inside_outside_part">inside_outside_part</a> is a
|
||||
method computing both inside and outside part in a single call.
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_inside_part.png"/></td>
|
||||
|
|
@ -1798,30 +1840,45 @@ The following image shows the effect of the "not_in" method (input1: red, input2
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="not_inside"/><h2>"not_inside" - Selects shapes or regions of self which are not inside the other region</h2>
|
||||
<a name="not_inside"/><h2>"not_inside" - Selects edges or polygons of self which are not inside edges or polygons from the other layer</h2>
|
||||
<keyword name="not_inside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.not_inside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which are not inside the other region.
|
||||
completely (completely covered by polygons from the other region). If self is
|
||||
in raw mode, this method will select individual shapes. Otherwise, this method
|
||||
will select coherent regions and no part of these regions may be outside the
|
||||
other region.
|
||||
It returns a new layer containing the selected shapes. A version which modifies self
|
||||
This method computes the inverse of <a href="#inside">inside</a> - i.e. edges or polygons from the layer
|
||||
not being inside polygons or edges from the other layer.
|
||||
</p><p>
|
||||
This method returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_not_inside">select_not_inside</a>.
|
||||
<a href="#split_inside">split_inside</a> is a function computing both results of <a href="#inside">inside</a> and <a href="#not_inside">not_inside</a> in a single call. <a href="#outside">outside</a>
|
||||
is a similar function selecting edges or polygons outside other edges or polygons. Note
|
||||
that "outside" is not the same than "not inside".
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
</p><p>
|
||||
The following image shows the effect of the "not_inside" method (input1: red, input2: blue):
|
||||
The following image shows the effect of the "not_inside" method for polygon layers (input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_not_inside.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
The following images show the effect of the "not_inside" method for edge layers and edge or polygon layers
|
||||
the second input. Note that the edges are computed from the polygons in this example
|
||||
(input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_not_inside_ee.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_not_inside_ep.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="not_interacting"/><h2>"not_interacting" - Selects shapes or regions of self which do not touch or overlap shapes from the other region</h2>
|
||||
<keyword name="not_interacting"/>
|
||||
|
|
@ -1867,30 +1924,45 @@ from the other layer. Two polygons overlapping or touching at two locations are
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="not_outside"/><h2>"not_outside" - Selects shapes or regions of self which are not outside the other region</h2>
|
||||
<a name="not_outside"/><h2>"not_outside" - Selects edges or polygons of self which are not outside edges or polygons from the other layer</h2>
|
||||
<keyword name="not_outside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.not_outside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which are not completely outside
|
||||
the other region (part of these shapes or regions may be covered by shapes from
|
||||
the other region). If self is in raw mode, this method will select individual
|
||||
shapes. Otherwise, this method will select coherent regions and no part of these
|
||||
regions may overlap with shapes from the other region.
|
||||
It returns a new layer containing the selected shapes. A version which modifies self
|
||||
This method computes the inverse of <a href="#outside">outside</a> - i.e. edges or polygons from the layer
|
||||
not being outside polygons or edges from the other layer.
|
||||
</p><p>
|
||||
This method returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_not_outside">select_not_outside</a>.
|
||||
<a href="#split_outside">split_outside</a> is a function computing both results of <a href="#outside">outside</a> and <a href="#not_outside">not_outside</a> in a single call. <a href="#outside">outside</a>
|
||||
is a similar function selecting edges or polygons outside other edges or polygons. Note
|
||||
that "outside" is not the same than "not outside".
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
</p><p>
|
||||
The following image shows the effect of the "not_outside" method (input1: red, input2: blue):
|
||||
The following image shows the effect of the "not_outside" method for polygon layers (input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_not_outside.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
The following images show the effect of the "not_outside" method for edge layers and edge or polygon layers
|
||||
the second input. Note that the edges are computed from the polygons in this example
|
||||
(input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_not_outside_ee.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_not_outside_ep.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="not_overlapping"/><h2>"not_overlapping" - Selects shapes or regions of self which do not overlap shapes from the other region</h2>
|
||||
<keyword name="not_overlapping"/>
|
||||
|
|
@ -2009,30 +2081,53 @@ a single <class_doc href="LayerInfo">LayerInfo</class_doc> object.
|
|||
See <a href="/about/drc_ref_global.xml#report">report</a> and <a href="/about/drc_ref_global.xml#target">target</a> on how to configure output to a target layout
|
||||
or report database.
|
||||
</p>
|
||||
<a name="outside"/><h2>"outside" - Selects shapes or regions of self which are outside the other region</h2>
|
||||
<a name="outside"/><h2>"outside" - Selects edges or polygons of self which are outside edges or polygons from the other layer</h2>
|
||||
<keyword name="outside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.outside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which are completely outside
|
||||
the other region (no part of these shapes or regions may be covered by shapes from
|
||||
the other region). If self is in raw mode, this method will select individual
|
||||
shapes. Otherwise, this method will select coherent regions and no part of these
|
||||
regions may overlap with shapes from the other region.
|
||||
It returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_outside">select_outside</a>.
|
||||
If layer is a polygon layer, the other layer needs to be a polygon layer too.
|
||||
In this case, this method selects all polygons which are entirely outside
|
||||
polygons from the other layer.
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
If layer is an edge layer, the other layer can be polygon or edge layer. In the
|
||||
first case, all edges entirely outside the polygons from the other layer are
|
||||
selected. If the other layer is an edge layer, all edges entirely outside
|
||||
of edges from the other layer are selected.
|
||||
</p><p>
|
||||
The following image shows the effect of the "outside" method (input1: red, input2: blue):
|
||||
Merged semantics applies - i.e. edges or polygons are joined before the
|
||||
result is computed, unless the layers are in <a href="#raw">raw</a> mode.
|
||||
</p><p>
|
||||
This method returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_outside">select_outside</a>. <a href="#not_outside">not_outside</a> is a function computing the inverse of <a href="#outside">outside</a>.
|
||||
<a href="#split_outside">split_outside</a> is a function computing both results in a single call. <a href="#outside">outside</a>
|
||||
is a similar function selecting edges or polygons outside other edges or polygons.
|
||||
</p><p>
|
||||
The following image shows the effect of the "outside" method for polygons (input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_outside.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
The following images show the effect of the "outside" method for edge layers and edge or polygon layers
|
||||
the second input. Note that the edges are computed from the polygons in this example
|
||||
(input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_outside_ee.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_outside_ep.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="outside_part"/><h2>"outside_part" - Returns the parts of the edges outside the given region</h2>
|
||||
<keyword name="outside_part"/>
|
||||
|
|
@ -2047,6 +2142,9 @@ of the polygons of the region.
|
|||
</p><p>
|
||||
This method is available for edge layers. The argument must be a polygon layer.
|
||||
</p><p>
|
||||
<a href="#inside_part">inside_part</a> is a method computing the opposite part. <a href="#inside_outside_part">inside_outside_part</a> is a
|
||||
method computing both inside and outside part in a single call.
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_outside_part.png"/></td>
|
||||
|
|
@ -2401,22 +2499,15 @@ is <a href="#covering">covering</a>.
|
|||
</p><p>
|
||||
This method is available for polygons only.
|
||||
</p>
|
||||
<a name="select_inside"/><h2>"select_inside" - Selects shapes or regions of self which are inside the other region</h2>
|
||||
<a name="select_inside"/><h2>"select_inside" - Selects edges or polygons of self which are inside edges or polygons from the other layer</h2>
|
||||
<keyword name="select_inside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select_inside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which are inside the other region.
|
||||
completely (completely covered by polygons from the other region). If self is
|
||||
in raw mode, this method will select individual shapes. Otherwise, this method
|
||||
will select coherent regions and no part of these regions may be outside the
|
||||
other region.
|
||||
It modifies self to contain the selected shapes. A version which does not modify self
|
||||
is <a href="#inside">inside</a>.
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
This method is the in-place version of <a href="#inside">inside</a> - i.e. it modifies the layer instead
|
||||
of returning a new layer and leaving the original layer untouched.
|
||||
</p>
|
||||
<a name="select_interacting"/><h2>"select_interacting" - Selects shapes or regions of self which touch or overlap shapes from the other region</h2>
|
||||
<keyword name="select_interacting"/>
|
||||
|
|
@ -2461,22 +2552,15 @@ is <a href="#not_covering">not_covering</a>.
|
|||
</p><p>
|
||||
This method is available for polygons only.
|
||||
</p>
|
||||
<a name="select_not_inside"/><h2>"select_not_inside" - Selects shapes or regions of self which are not inside the other region</h2>
|
||||
<a name="select_not_inside"/><h2>"select_not_inside" - Selects edges or polygons of self which are not inside edges or polygons from the other layer</h2>
|
||||
<keyword name="select_not_inside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select_not_inside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which are not inside the other region.
|
||||
completely (completely covered by polygons from the other region). If self is
|
||||
in raw mode, this method will select individual shapes. Otherwise, this method
|
||||
will select coherent regions and no part of these regions may be outside the
|
||||
other region.
|
||||
It modifies self to contain the selected shapes. A version which does not modify self
|
||||
is <a href="#not_inside">not_inside</a>.
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
This method is the in-place version of <a href="#inside">inside</a> - i.e. it modifies the layer instead
|
||||
of returning a new layer and leaving the original layer untouched.
|
||||
</p>
|
||||
<a name="select_not_interacting"/><h2>"select_not_interacting" - Selects shapes or regions of self which do not touch or overlap shapes from the other region</h2>
|
||||
<keyword name="select_not_interacting"/>
|
||||
|
|
@ -2503,22 +2587,15 @@ number of (different) shapes from the other layer. If a min and max count is giv
|
|||
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.
|
||||
</p>
|
||||
<a name="select_not_outside"/><h2>"select_not_outside" - Selects shapes or regions of self which are not outside the other region</h2>
|
||||
<a name="select_not_outside"/><h2>"select_not_outside" - Selects edges or polygons of self which are not outside edges or polygons from the other layer</h2>
|
||||
<keyword name="select_not_outside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select_not_outside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which are not completely outside
|
||||
the other region (part of these shapes or regions may be covered by shapes from
|
||||
the other region). If self is in raw mode, this method will select individual
|
||||
shapes. Otherwise, this method will select coherent regions and no part of these
|
||||
regions may overlap with shapes from the other region.
|
||||
It modifies self to contain the selected shapes. A version which does not modify self
|
||||
is <a href="#not_outside">not_outside</a>.
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
This method is the in-place version of <a href="#outside">outside</a> - i.e. it modifies the layer instead
|
||||
of returning a new layer and leaving the original layer untouched.
|
||||
</p>
|
||||
<a name="select_not_overlapping"/><h2>"select_not_overlapping" - Selects shapes or regions of self which do not overlap shapes from the other region</h2>
|
||||
<keyword name="select_not_overlapping"/>
|
||||
|
|
@ -2538,22 +2615,15 @@ is <a href="#not_overlapping">not_overlapping</a>.
|
|||
</p><p>
|
||||
This method is available for polygons only.
|
||||
</p>
|
||||
<a name="select_outside"/><h2>"select_outside" - Selects shapes or regions of self which are outside the other region</h2>
|
||||
<a name="select_outside"/><h2>"select_outside" - Selects edges or polygons of self which are outside edges or polygons from the other layer</h2>
|
||||
<keyword name="select_outside"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.select_outside(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which are completely outside
|
||||
the other region (no part of these shapes or regions may be covered by shapes from
|
||||
the other region). If self is in raw mode, this method will select individual
|
||||
shapes. Otherwise, this method will select coherent regions and no part of these
|
||||
regions may overlap with shapes from the other region.
|
||||
It modifies self to contain the selected shapes. A version which does not modify self
|
||||
is <a href="#outside">outside</a>.
|
||||
</p><p>
|
||||
This method is available for polygon layers.
|
||||
This method is the in-place version of <a href="#outside">outside</a> - i.e. it modifies the layer instead
|
||||
of returning a new layer and leaving the original layer untouched.
|
||||
</p>
|
||||
<a name="select_overlapping"/><h2>"select_overlapping" - Selects shapes or regions of self which overlap shapes from the other region</h2>
|
||||
<keyword name="select_overlapping"/>
|
||||
|
|
@ -2866,7 +2936,7 @@ The options of this method are the same than <a href="#covering">covering</a>.
|
|||
<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
|
||||
This method returns the polygons or edges inside of polygons or edges 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>
|
||||
|
|
@ -2881,7 +2951,7 @@ one layer and all others in a second layer. This method is equivalent to calling
|
|||
<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
|
||||
This method returns the polygons or edges 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>
|
||||
|
|
@ -2898,7 +2968,7 @@ The options of this method are the same than <a href="#interacting">interacting<
|
|||
<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
|
||||
This method returns the polygons or edges outside of polygons or edges 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>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ See <a href="/about/lvs_ref_netter.xml#align">Netter#align</a> for a description
|
|||
<p>
|
||||
See <a href="/about/lvs_ref_netter.xml#blank_circuit">Netter#blank_circuit</a> for a description of that function.
|
||||
</p>
|
||||
<a name="compare"/><h2>"compare" - Compares the extracted netlist vs. the schematic</h2>
|
||||
<a name="compare"/><h2>"compare" - Compares the extracted netlist vs. the schematic netlist</h2>
|
||||
<keyword name="compare"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -154,6 +154,15 @@ See <a href="/about/lvs_ref_netter.xml#min_caps">Netter#min_caps</a> for a descr
|
|||
<p>
|
||||
See <a href="/about/lvs_ref_netter.xml">Netter</a> for more details
|
||||
</p>
|
||||
<a name="no_lvs_hints"/><h2>"no_lvs_hints" - Disables LVS hints</h2>
|
||||
<keyword name="no_lvs_hints"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>no_lvs_hints</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="/about/lvs_ref_netter.xml#no_lvs_hints">Netter#no_lvs_hints</a> for a description of that feature.
|
||||
</p>
|
||||
<a name="report_lvs"/><h2>"report_lvs" - Specifies an LVS report for output</h2>
|
||||
<keyword name="report_lvs"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -302,6 +302,16 @@ with a resistance value above the given threshold (in Farad).
|
|||
After using this method, the netlist compare will ignore capacitance devices
|
||||
with a capacitance values below the given threshold (in Farad).
|
||||
</p>
|
||||
<a name="no_lvs_hints"/><h2>"no_lvs_hints" - Disables LVS hints</h2>
|
||||
<keyword name="no_lvs_hints"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>no_lvs_hints</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
LVS hints may be expensive to compute. Use this function to disable
|
||||
generation of LVS hints
|
||||
</p>
|
||||
<a name="same_circuits"/><h2>"same_circuits" - Establishes an equivalence between the circuits</h2>
|
||||
<keyword name="same_circuits"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<doc>
|
||||
|
||||
<title>Transformations in KLayout</title>
|
||||
<keyword name="transformation"/>
|
||||
|
||||
<p>
|
||||
KLayout supports a subset of affine transformations with the following contributions:
|
||||
|
|
@ -37,7 +38,9 @@
|
|||
given displacement vector.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="/about/transformation_overview.png"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The notation shown here is used in many places within KLayout. It is basically composed of the following parts
|
||||
|
|
@ -75,7 +78,9 @@
|
|||
multiples of 90 degree:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="/about/transformation_basic.png"/>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
KLayout is not restricted to these basic operations. Arbitrary angles are supported (i.e. "r45" or "m22.5"). Usually however,
|
||||
|
|
@ -83,5 +88,160 @@
|
|||
simple transformations involving only rotations by multiples of 90 degree and do not use scaling.
|
||||
</p>
|
||||
|
||||
<h2>Coding transformations</h2>
|
||||
<keyword name="transformation objects"/>
|
||||
|
||||
<p>
|
||||
Note that mirroring at an axis with a given angle "a" is equivalent to mirroring at the x axis followed by a rotation
|
||||
by twice the angle "a". For example:
|
||||
</p>
|
||||
|
||||
<pre>m45 == m0 followed by r90</pre>
|
||||
|
||||
<p>
|
||||
When coding transformations, two parameters are used to represent the rotation/mirror part:
|
||||
a rotation angle and a flag indicating mirroring at the x axis. The mirroring is applied before
|
||||
the rotation. In terms of these parameters, the basic transformations are:
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<tr><th>Rotation angle<br/>(degree)</th><th>Mirror flag <br/>= False</th><th>Mirror flag <br/>= True</th></tr>
|
||||
<tr><td>0</td><td>r0</td><td>m0</td></tr>
|
||||
<tr><td>90</td><td>r90</td><td>m45</td></tr>
|
||||
<tr><td>180</td><td>r180</td><td>m90</td></tr>
|
||||
<tr><td>270</td><td>r270</td><td>m135</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Transformation objects</h3>
|
||||
|
||||
<p>
|
||||
Transformation objects are convenient objects to operate with. They represent a
|
||||
transformation (technically a matrix) consisting of an angle/mirror and a displacement
|
||||
part. They support some basic operations:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Concatenation: <tt>T = T1 * T2</tt><br/><tt>T</tt> is transformation <tt>T2</tt> applied, then <tt>T1</tt> (note this order)</li>
|
||||
<li>Inversion: <tt>TI = T.inverted()</tt><br/><tt>TI</tt> is the inverse of <tt>T</tt>, i.e. <tt>TI * T = T * TI = 1</tt> where <tt>1</tt> is the neutral transformation which does not modify coordinates</li>
|
||||
<li>Application to geometrical objects: <tt>q = T * p</tt><br/>where <tt>p</tt> is a box, polygon, path, text, point, vector etc. and <tt>q</tt> is the transformed object</li>
|
||||
</ul>
|
||||
|
||||
<h3>Vectors and Points</h3>
|
||||
<keyword name="vector"/>
|
||||
<keyword name="point"/>
|
||||
|
||||
<p>
|
||||
In KLayout there are two two-dimensional coordinate objects: the vector and the point.
|
||||
Basically, the vector is the difference between two points:
|
||||
</p>
|
||||
|
||||
<pre>v = p2 - p1</pre>
|
||||
|
||||
<p>Here <tt>v</tt> is a vector object while <tt>p1</tt> and <tt>p2</tt> are points.</p>
|
||||
|
||||
<p>
|
||||
Regarding transformations, vectors and points behave differently. While for a point, the
|
||||
displacement is applied, it is not for vectors. So
|
||||
</p>
|
||||
|
||||
<pre>p' = T * p = M * p + d
|
||||
v' = T * v = M * v</pre>
|
||||
|
||||
<p>
|
||||
Here <tt>M</tt> is the 2x2 rotation/mirror matrix part of the transformation and <tt>d</tt> is the
|
||||
displacement vector
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The reason why the displacement is not applied to a vector is seen here:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
v' = T * v
|
||||
= T * (p2 - p1)
|
||||
= T * p2 - T * p1
|
||||
= (M * p2 + d) - (M * p1 + d)
|
||||
= M * p2 + d - M * p1 - d
|
||||
= M * p2 - M * p1
|
||||
= M * (p2 - p1)</pre>
|
||||
|
||||
<p>where the latter simply is:</p>
|
||||
|
||||
<pre>v' = M * v</pre>
|
||||
|
||||
<h3>Simple transformations</h3>
|
||||
<keyword name="simple transformation"/>
|
||||
<keyword name="Trans"/>
|
||||
<keyword name="DTrans"/>
|
||||
|
||||
<p>
|
||||
Simple transformations are represented by <class_doc href="DTrans"/> or <class_doc href="Trans"/> objects.
|
||||
The first operates with floating-point displacements in units of micrometers while the second one with integer displacements
|
||||
in database units. "DTrans" objects act on "D" type floating-point coordinate shapes (e.g. <class_doc href="DBox"/>) while "Trans" objects act
|
||||
on the integer coordinate shapes (e.g. <class_doc href="Box"/>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The basic construction parameters of "DTrans" and "Trans" are:
|
||||
</p>
|
||||
|
||||
<pre>Trans(angle, mirror, displacement)
|
||||
DTrans(angle, mirror, displacement)</pre>
|
||||
|
||||
<p>"displacement" is a <class_doc href="DVector"/> (for DTrans) or a <class_doc href="Vector"/> (for Trans).</p>
|
||||
|
||||
<p>"angle" is the rotation angle in units of 90 degree and "mirror" is the mirror flag:</p>
|
||||
|
||||
<table>
|
||||
<tr><th>angle</th><th>mirror <br/>= False</th><th>mirror <br/>= True</th></tr>
|
||||
<tr><td>0</td><td>r0</td><td>m0</td></tr>
|
||||
<tr><td>1</td><td>r90</td><td>m45</td></tr>
|
||||
<tr><td>2</td><td>r180</td><td>m90</td></tr>
|
||||
<tr><td>3</td><td>r270</td><td>m135</td></tr>
|
||||
</table>
|
||||
|
||||
<h3>Complex transformations</h3>
|
||||
<keyword name="complex transformation"/>
|
||||
<keyword name="CplxTrans"/>
|
||||
<keyword name="ICplxTrans"/>
|
||||
<keyword name="DCplxTrans"/>
|
||||
<keyword name="VCplxTrans"/>
|
||||
|
||||
<p>
|
||||
Complex transformations in addition to the simple transformations feature
|
||||
scaling (magnification) and arbitrary rotation angles. Other than simple transformations
|
||||
they do not necessarily preserve a grid and rounding is implied. Furthermore they imply a shift is physical scale
|
||||
which renders them difficult to use in physical frameworks (e.g. DRC). Hence their
|
||||
use is discouraged for certain applications.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The basic classes are <class_doc href="DCplxTrans"/> for the micrometer-unit (floating-point) version
|
||||
and <class_doc href="ICplxTrans"/> for the database-unit (integer) version. The
|
||||
construction parameters are:
|
||||
</p>
|
||||
|
||||
<pre>ICplxTrans(angle, mirror, magnification, displacement)
|
||||
DCplxTrans(angle, mirror, magnification, displacement)</pre>
|
||||
|
||||
<p>
|
||||
Here, "angle" is the rotation angle in degree (note the difference to "Trans" and "DTrans" where the
|
||||
rotation angle is in units for 90 degree. "magnification" is a factor (1.0 for "no change in scale").
|
||||
</p>
|
||||
|
||||
<p>
|
||||
There are two other variants useful for transforming coordinate systems: <class_doc href="CplxTrans"/> takes
|
||||
integer-unit objects and converts them to floating-point unit objects. It can be used to convert
|
||||
from database units to micrometer units when configured with a magnification equal to the database unit value:
|
||||
</p>
|
||||
|
||||
<pre>T = CplxTrans(magnification: dbu)
|
||||
q = T * p</pre>
|
||||
|
||||
<p>
|
||||
The other variant is <class_doc href="VCplxTrans"/> which converts floating-point unit objects
|
||||
to integer-unit ones. These objects are generated when inverting "CplxTrans" objects.
|
||||
</p>
|
||||
|
||||
</doc>
|
||||
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
|
@ -31,6 +31,7 @@ HEADERS = \
|
|||
layProgressWidget.h \
|
||||
layResourceHelpProvider.h \
|
||||
layRuntimeErrorForm.h \
|
||||
layReaderErrorForm.h \
|
||||
laySearchReplaceConfigPage.h \
|
||||
laySearchReplaceDialog.h \
|
||||
laySearchReplacePropertiesWidgets.h \
|
||||
|
|
@ -87,6 +88,7 @@ FORMS = \
|
|||
ReplacePropertiesShape.ui \
|
||||
ReplacePropertiesText.ui \
|
||||
RuntimeErrorForm.ui \
|
||||
ReaderErrorForm.ui \
|
||||
SearchPropertiesBox.ui \
|
||||
SearchPropertiesInstance.ui \
|
||||
SearchPropertiesPath.ui \
|
||||
|
|
@ -139,6 +141,7 @@ SOURCES = \
|
|||
layProgressWidget.cc \
|
||||
layResourceHelpProvider.cc \
|
||||
layRuntimeErrorForm.cc \
|
||||
layReaderErrorForm.cc \
|
||||
laySearchReplaceConfigPage.cc \
|
||||
laySearchReplaceDialog.cc \
|
||||
laySearchReplacePlugin.cc \
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "layVersion.h"
|
||||
#include "laySignalHandler.h"
|
||||
#include "layRuntimeErrorForm.h"
|
||||
#include "layReaderErrorForm.h"
|
||||
#include "layProgress.h"
|
||||
#include "layTextProgress.h"
|
||||
#include "layBackgroundAwareTreeStyle.h"
|
||||
|
|
@ -106,6 +107,7 @@ static void ui_exception_handler_tl (const tl::Exception &ex, QWidget *parent)
|
|||
const tl::ExitException *gsi_exit = dynamic_cast <const tl::ExitException *> (&ex);
|
||||
const tl::BreakException *gsi_break = dynamic_cast <const tl::BreakException *> (&ex);
|
||||
const tl::ScriptError *gsi_excpt = dynamic_cast <const tl::ScriptError *> (&ex);
|
||||
const db::ReaderUnknownFormatException *reader_excpt = dynamic_cast <const db::ReaderUnknownFormatException *> (&ex);
|
||||
|
||||
if (gsi_exit || gsi_break) {
|
||||
// exit and break exceptions are not shown - they are issued when a script is aborted or
|
||||
|
|
@ -131,11 +133,19 @@ static void ui_exception_handler_tl (const tl::Exception &ex, QWidget *parent)
|
|||
error_dialog.exec ();
|
||||
|
||||
} else {
|
||||
|
||||
tl::error << ex.msg ();
|
||||
if (! parent) {
|
||||
parent = QApplication::activeWindow () ? QApplication::activeWindow () : lay::MainWindow::instance ();
|
||||
}
|
||||
QMessageBox::critical (parent, QObject::tr ("Error"), tl::to_qstring (ex.msg ()));
|
||||
|
||||
if (reader_excpt) {
|
||||
lay::ReaderErrorForm error_dialog (parent, "reader_error_form", reader_excpt);
|
||||
error_dialog.exec ();
|
||||
} else {
|
||||
QMessageBox::critical (parent, QObject::tr ("Error"), tl::to_qstring (ex.msg ()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1280,7 +1290,7 @@ lay::LayoutView *
|
|||
ApplicationBase::create_view (db::Manager &manager)
|
||||
{
|
||||
// create a new view
|
||||
lay::LayoutView *view = new lay::LayoutView (&manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), 0 /*parent*/);
|
||||
lay::LayoutView *view = new lay::LayoutView (&manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher ());
|
||||
|
||||
// set initial attributes
|
||||
view->set_synchronous (m_sync_mode);
|
||||
|
|
@ -1573,6 +1583,10 @@ GuiApplication::shutdown ()
|
|||
}
|
||||
}
|
||||
|
||||
while (! (tl_widgets = topLevelWidgets ()).empty ()) {
|
||||
delete tl_widgets [0];
|
||||
}
|
||||
|
||||
if (mp_recorder) {
|
||||
delete mp_recorder;
|
||||
mp_recorder = 0;
|
||||
|
|
|
|||
|
|
@ -23,12 +23,13 @@
|
|||
#include "layControlWidgetStack.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QEvent>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
ControlWidgetStack::ControlWidgetStack(QWidget *parent, const char *name)
|
||||
: QFrame (parent), mp_current_widget (0)
|
||||
ControlWidgetStack::ControlWidgetStack(QWidget *parent, const char *name, bool size_follows_content)
|
||||
: QFrame (parent), mp_current_widget (0), m_size_follows_content (size_follows_content)
|
||||
{
|
||||
setObjectName (QString::fromUtf8 (name));
|
||||
|
||||
|
|
@ -66,10 +67,44 @@ void ControlWidgetStack::add_widget(QWidget *w)
|
|||
setMinimumWidth (mw);
|
||||
resize (minimumWidth (), height ());
|
||||
}
|
||||
|
||||
update_geometry ();
|
||||
}
|
||||
|
||||
void ControlWidgetStack::update_geometry ()
|
||||
{
|
||||
if (m_size_follows_content) {
|
||||
|
||||
int h = sizeHint ().height ();
|
||||
if (h > 0) {
|
||||
setMinimumHeight (h);
|
||||
setMaximumHeight (h);
|
||||
} else {
|
||||
setMinimumHeight (0);
|
||||
setMaximumHeight (QWIDGETSIZE_MAX);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool ControlWidgetStack::event(QEvent *e)
|
||||
{
|
||||
if (e->type () == QEvent::LayoutRequest) {
|
||||
update_geometry ();
|
||||
}
|
||||
return QWidget::event (e);
|
||||
}
|
||||
|
||||
QSize ControlWidgetStack::sizeHint() const
|
||||
{
|
||||
if (m_size_follows_content) {
|
||||
for (size_t i = 0; i < m_widgets.size (); ++i) {
|
||||
if (m_widgets [i] && m_widgets [i]->isVisible ()) {
|
||||
return m_widgets [i]->sizeHint ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int w = 0;
|
||||
for (size_t i = 0; i < m_widgets.size (); ++i) {
|
||||
w = std::max (m_widgets [i]->sizeHint ().width (), w);
|
||||
|
|
@ -88,6 +123,8 @@ void ControlWidgetStack::remove_widget(size_t index)
|
|||
if (m_widgets.size () == 0) {
|
||||
mp_bglabel->show ();
|
||||
}
|
||||
|
||||
update_geometry ();
|
||||
}
|
||||
|
||||
void ControlWidgetStack::raise_widget(size_t index)
|
||||
|
|
@ -111,6 +148,8 @@ void ControlWidgetStack::raise_widget(size_t index)
|
|||
} else {
|
||||
mp_bglabel->hide ();
|
||||
}
|
||||
|
||||
update_geometry ();
|
||||
}
|
||||
|
||||
QWidget *ControlWidgetStack::widget(size_t index)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class ControlWidgetStack
|
|||
: public QFrame
|
||||
{
|
||||
public:
|
||||
ControlWidgetStack (QWidget *parent = 0, const char *name = 0);
|
||||
ControlWidgetStack (QWidget *parent = 0, const char *name = 0, bool size_follows_content = false);
|
||||
|
||||
void focusInEvent (QFocusEvent *);
|
||||
|
||||
|
|
@ -66,10 +66,15 @@ protected:
|
|||
}
|
||||
|
||||
void resize_children ();
|
||||
void update_geometry ();
|
||||
|
||||
bool event (QEvent *e);
|
||||
|
||||
|
||||
std::vector <QWidget *> m_widgets;
|
||||
QWidget *mp_current_widget;
|
||||
QLabel *mp_bglabel;
|
||||
bool m_size_follows_content;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,14 @@
|
|||
<file alias="drc_not3.png">doc/images/drc_not3.png</file>
|
||||
<file alias="drc_inside_part.png">doc/images/drc_inside_part.png</file>
|
||||
<file alias="drc_outside_part.png">doc/images/drc_outside_part.png</file>
|
||||
<file alias="drc_inside_ep.png">doc/images/drc_inside_ep.png</file>
|
||||
<file alias="drc_inside_ee.png">doc/images/drc_inside_ee.png</file>
|
||||
<file alias="drc_not_inside_ep.png">doc/images/drc_not_inside_ep.png</file>
|
||||
<file alias="drc_not_inside_ee.png">doc/images/drc_not_inside_ee.png</file>
|
||||
<file alias="drc_outside_ep.png">doc/images/drc_outside_ep.png</file>
|
||||
<file alias="drc_outside_ee.png">doc/images/drc_outside_ee.png</file>
|
||||
<file alias="drc_not_outside_ep.png">doc/images/drc_not_outside_ep.png</file>
|
||||
<file alias="drc_not_outside_ee.png">doc/images/drc_not_outside_ee.png</file>
|
||||
<file alias="drc_covering.png">doc/images/drc_covering.png</file>
|
||||
<file alias="drc_not_covering.png">doc/images/drc_not_covering.png</file>
|
||||
<file alias="drc_interacting2.png">doc/images/drc_interacting2.png</file>
|
||||
|
|
|
|||
|
|
@ -63,14 +63,14 @@ public:
|
|||
menu_entries.push_back (lay::menu_item ("fill_tool::show", "fill_tool:edit_mode", "edit_menu.utils_menu.end", tl::to_string (QObject::tr ("Fill Tool"))));
|
||||
}
|
||||
|
||||
virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutViewBase *view) const
|
||||
{
|
||||
if (lay::has_gui ()) {
|
||||
return new FillDialog (root, view);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
virtual lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *, lay::LayoutViewBase *view) const
|
||||
{
|
||||
if (lay::has_gui ()) {
|
||||
return new FillDialog (lay::MainWindow::instance (), view);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new FillDialogPluginDeclaration (), 20000, "FillDialogPlugin");
|
||||
|
|
@ -78,9 +78,9 @@ static tl::RegisteredClass<lay::PluginDeclaration> config_decl (new FillDialogPl
|
|||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
FillDialog::FillDialog (lay::Dispatcher *main, LayoutViewBase *view)
|
||||
: QDialog (view->widget ()),
|
||||
lay::Plugin (main),
|
||||
FillDialog::FillDialog (QWidget *parent, LayoutViewBase *view)
|
||||
: QDialog (parent),
|
||||
lay::Plugin (view),
|
||||
Ui::FillDialog (),
|
||||
mp_view (view)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class LAY_PUBLIC FillDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FillDialog (lay::Dispatcher *root, lay::LayoutViewBase *view);
|
||||
FillDialog (QWidget *parent, lay::LayoutViewBase *view);
|
||||
~FillDialog ();
|
||||
|
||||
public slots:
|
||||
|
|
|
|||
|
|
@ -274,9 +274,9 @@ MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
|
|||
|
||||
mp_layer_toolbox_dock_widget = new QDockWidget (QObject::tr ("Layer Toolbox"), this);
|
||||
mp_layer_toolbox_dock_widget->setObjectName (QString::fromUtf8 ("lt_dock_widget"));
|
||||
mp_layer_toolbox = new LayerToolbox (mp_layer_toolbox_dock_widget, "layer_toolbox");
|
||||
mp_layer_toolbox_dock_widget->setWidget (mp_layer_toolbox);
|
||||
mp_layer_toolbox_dock_widget->setFocusProxy (mp_layer_toolbox);
|
||||
mp_layer_toolbox_stack = new ControlWidgetStack (mp_layer_toolbox_dock_widget, "layer_toolbox_stack", true);
|
||||
mp_layer_toolbox_dock_widget->setWidget (mp_layer_toolbox_stack);
|
||||
mp_layer_toolbox_dock_widget->setFocusProxy (mp_layer_toolbox_stack);
|
||||
connect (mp_layer_toolbox_dock_widget, SIGNAL (visibilityChanged (bool)), this, SLOT (dock_widget_visibility_changed (bool)));
|
||||
m_layer_toolbox_visible = true;
|
||||
|
||||
|
|
@ -594,18 +594,18 @@ BEGIN_PROTECTED
|
|||
|
||||
m_file_changed_timer.blockSignals (false);
|
||||
|
||||
std::map<QString, std::pair<lay::LayoutView *, int> > views_per_file;
|
||||
std::map<QString, std::pair<lay::LayoutViewWidget *, int> > views_per_file;
|
||||
|
||||
for (std::vector<lay::LayoutView *>::iterator v = mp_views.begin (); v != mp_views.end (); ++v) {
|
||||
for (int cv = 0; cv < int ((*v)->cellviews ()); ++cv) {
|
||||
views_per_file [tl::to_qstring ((*v)->cellview (cv)->filename ())] = std::make_pair (*v, cv);
|
||||
for (std::vector<lay::LayoutViewWidget *>::iterator v = mp_views.begin (); v != mp_views.end (); ++v) {
|
||||
for (int cv = 0; cv < int ((*v)->view ()->cellviews ()); ++cv) {
|
||||
views_per_file [tl::to_qstring ((*v)->view ()->cellview (cv)->filename ())] = std::make_pair (*v, cv);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::vector<QString>::const_iterator f = changed_files.begin (); f != changed_files.end (); ++f) {
|
||||
std::map<QString, std::pair<lay::LayoutView *, int> >::const_iterator v = views_per_file.find (*f);
|
||||
std::map<QString, std::pair<lay::LayoutViewWidget *, int> >::const_iterator v = views_per_file.find (*f);
|
||||
if (v != views_per_file.end ()) {
|
||||
v->second.first->reload_layout (v->second.second);
|
||||
v->second.first->view ()->reload_layout (v->second.second);
|
||||
reloaded_files.insert (*f);
|
||||
}
|
||||
}
|
||||
|
|
@ -667,7 +667,6 @@ void
|
|||
MainWindow::close_all ()
|
||||
{
|
||||
cancel ();
|
||||
mp_layer_toolbox->set_view (0);
|
||||
|
||||
// try a smooth shutdown of the current view
|
||||
lay::LayoutView::set_current (0);
|
||||
|
|
@ -675,7 +674,7 @@ MainWindow::close_all ()
|
|||
current_view_changed ();
|
||||
|
||||
for (unsigned int i = 0; i < mp_views.size (); ++i) {
|
||||
mp_views [i]->stop ();
|
||||
mp_views [i]->view ()->stop ();
|
||||
}
|
||||
|
||||
m_manager.clear ();
|
||||
|
|
@ -695,8 +694,9 @@ MainWindow::close_all ()
|
|||
|
||||
view_closed_event (int (mp_views.size () - 1));
|
||||
|
||||
lay::LayoutView *view = mp_views.back ();
|
||||
lay::LayoutViewWidget *view = mp_views.back ();
|
||||
mp_views.pop_back ();
|
||||
mp_layer_toolbox_stack->remove_widget (mp_views.size ());
|
||||
mp_lp_stack->remove_widget (mp_views.size ());
|
||||
mp_hp_stack->remove_widget (mp_views.size ());
|
||||
mp_libs_stack->remove_widget (mp_views.size ());
|
||||
|
|
@ -980,63 +980,6 @@ MainWindow::configure (const std::string &name, const std::string &value)
|
|||
|
||||
return true;
|
||||
|
||||
} else if (name == cfg_stipple_palette) {
|
||||
|
||||
lay::StipplePalette palette = lay::StipplePalette::default_palette ();
|
||||
|
||||
try {
|
||||
// empty string means: default palette
|
||||
if (! value.empty ()) {
|
||||
palette.from_string (value);
|
||||
}
|
||||
} catch (...) {
|
||||
// ignore errors: just reset the palette
|
||||
palette = lay::StipplePalette::default_palette ();
|
||||
}
|
||||
|
||||
mp_layer_toolbox->set_palette (palette);
|
||||
|
||||
// others need this property too ..
|
||||
return false;
|
||||
|
||||
} else if (name == cfg_line_style_palette) {
|
||||
|
||||
lay::LineStylePalette palette = lay::LineStylePalette::default_palette ();
|
||||
|
||||
try {
|
||||
// empty string means: default palette
|
||||
if (! value.empty ()) {
|
||||
palette.from_string (value);
|
||||
}
|
||||
} catch (...) {
|
||||
// ignore errors: just reset the palette
|
||||
palette = lay::LineStylePalette::default_palette ();
|
||||
}
|
||||
|
||||
mp_layer_toolbox->set_palette (palette);
|
||||
|
||||
// others need this property too ..
|
||||
return false;
|
||||
|
||||
} else if (name == cfg_color_palette) {
|
||||
|
||||
lay::ColorPalette palette = lay::ColorPalette::default_palette ();
|
||||
|
||||
try {
|
||||
// empty string means: default palette
|
||||
if (! value.empty ()) {
|
||||
palette.from_string (value);
|
||||
}
|
||||
} catch (...) {
|
||||
// ignore errors: just reset the palette
|
||||
palette = lay::ColorPalette::default_palette ();
|
||||
}
|
||||
|
||||
mp_layer_toolbox->set_palette (palette);
|
||||
|
||||
// others need this property too ..
|
||||
return false;
|
||||
|
||||
} else if (name == cfg_mru) {
|
||||
|
||||
tl::Extractor ex (value.c_str ());
|
||||
|
|
@ -1333,9 +1276,9 @@ MainWindow::libraries_changed ()
|
|||
{
|
||||
// if the libraries have changed, remove all selections and cancel any operations to avoid
|
||||
// that the view refers to an invalid instance or shape
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->clear_selection ();
|
||||
(*vp)->cancel ();
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->clear_selection ();
|
||||
(*vp)->view ()->cancel ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1650,7 +1593,7 @@ lay::LayoutView *
|
|||
MainWindow::view (int index)
|
||||
{
|
||||
if (index >= 0 && index < int (mp_views.size ())) {
|
||||
return mp_views [index];
|
||||
return mp_views [index]->view ();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1660,7 +1603,7 @@ const lay::LayoutView *
|
|||
MainWindow::view (int index) const
|
||||
{
|
||||
if (index >= 0 && index < int (mp_views.size ())) {
|
||||
return mp_views [index];
|
||||
return mp_views [index]->view ();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1670,7 +1613,7 @@ int
|
|||
MainWindow::index_of (const lay::LayoutView *view) const
|
||||
{
|
||||
for (int i = 0; i < int (mp_views.size ()); ++i) {
|
||||
if (mp_views [i] == view) {
|
||||
if (mp_views [i]->view () == view) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
@ -1696,8 +1639,8 @@ MainWindow::select_mode (int m)
|
|||
if (m_mode != m) {
|
||||
|
||||
m_mode = m;
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->mode (m);
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->mode (m);
|
||||
}
|
||||
|
||||
// Update the actions by checking the one that is selected programmatically. Use the toolbar menu for reference.
|
||||
|
|
@ -1707,9 +1650,8 @@ MainWindow::select_mode (int m)
|
|||
std::vector<std::string> items = menu ()->items ("@toolbar");
|
||||
for (std::vector<std::string>::const_iterator i = items.begin (); i != items.end (); ++i) {
|
||||
Action *a = menu ()->action (*i);
|
||||
if (a->is_checkable() && a->is_for_mode (m_mode)) {
|
||||
a->set_checked (true);
|
||||
break;
|
||||
if (a->is_checkable()) {
|
||||
a->set_checked (a->is_for_mode (m_mode));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1753,9 +1695,9 @@ void
|
|||
MainWindow::cm_undo ()
|
||||
{
|
||||
if (current_view () && m_manager.available_undo ().first) {
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->clear_selection ();
|
||||
(*vp)->cancel ();
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->clear_selection ();
|
||||
(*vp)->view ()->cancel ();
|
||||
}
|
||||
m_manager.undo ();
|
||||
}
|
||||
|
|
@ -1765,9 +1707,9 @@ void
|
|||
MainWindow::cm_redo ()
|
||||
{
|
||||
if (current_view () && m_manager.available_redo ().first) {
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->clear_selection ();
|
||||
(*vp)->cancel ();
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->clear_selection ();
|
||||
(*vp)->view ()->cancel ();
|
||||
}
|
||||
m_manager.redo ();
|
||||
}
|
||||
|
|
@ -1964,8 +1906,8 @@ MainWindow::cancel ()
|
|||
m_manager.commit ();
|
||||
}
|
||||
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->cancel ();
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->cancel ();
|
||||
}
|
||||
|
||||
select_mode (lay::LayoutView::default_mode ());
|
||||
|
|
@ -1975,8 +1917,8 @@ void
|
|||
MainWindow::load_layer_properties (const std::string &fn, bool all_views, bool add_default)
|
||||
{
|
||||
if (all_views) {
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->load_layer_props (fn, add_default);
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->load_layer_props (fn, add_default);
|
||||
}
|
||||
} else if (current_view ()) {
|
||||
current_view ()->load_layer_props (fn, add_default);
|
||||
|
|
@ -1987,8 +1929,8 @@ void
|
|||
MainWindow::load_layer_properties (const std::string &fn, int cv_index, bool all_views, bool add_default)
|
||||
{
|
||||
if (all_views) {
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->load_layer_props (fn, cv_index, add_default);
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->load_layer_props (fn, cv_index, add_default);
|
||||
}
|
||||
} else if (current_view ()) {
|
||||
current_view ()->load_layer_props (fn, cv_index, add_default);
|
||||
|
|
@ -2392,8 +2334,6 @@ MainWindow::select_view (int index)
|
|||
|
||||
view (index)->set_current ();
|
||||
|
||||
mp_layer_toolbox->set_view (current_view ());
|
||||
|
||||
if (current_view ()) {
|
||||
|
||||
if (box_set) {
|
||||
|
|
@ -2402,6 +2342,7 @@ MainWindow::select_view (int index)
|
|||
|
||||
mp_view_stack->raise_widget (index);
|
||||
mp_hp_stack->raise_widget (index);
|
||||
mp_layer_toolbox_stack->raise_widget (index);
|
||||
mp_lp_stack->raise_widget (index);
|
||||
mp_libs_stack->raise_widget (index);
|
||||
mp_eo_stack->raise_widget (index);
|
||||
|
|
@ -2571,15 +2512,17 @@ MainWindow::cm_clone ()
|
|||
void
|
||||
MainWindow::clone_current_view ()
|
||||
{
|
||||
lay::LayoutView *view = 0;
|
||||
lay::LayoutViewWidget *view_widget = 0;
|
||||
lay::LayoutView *curr = current_view ();
|
||||
if (! curr) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("No view open to clone")));
|
||||
}
|
||||
|
||||
// create a new view
|
||||
view = new lay::LayoutView (current_view (), &m_manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), mp_view_stack);
|
||||
add_view (view);
|
||||
view_widget = new lay::LayoutViewWidget (current_view (), &m_manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), mp_view_stack);
|
||||
add_view (view_widget);
|
||||
|
||||
lay::LayoutView *view = view_widget->view ();
|
||||
|
||||
// set initial attributes
|
||||
view->set_hier_levels (curr->get_hier_levels ());
|
||||
|
|
@ -2598,16 +2541,15 @@ MainWindow::clone_current_view ()
|
|||
|
||||
view->update_content ();
|
||||
|
||||
mp_views.back ()->set_current ();
|
||||
mp_views.back ()->view ()->set_current ();
|
||||
|
||||
mp_layer_toolbox->set_view (current_view ());
|
||||
|
||||
mp_view_stack->add_widget (view);
|
||||
mp_lp_stack->add_widget (view->layer_control_frame ());
|
||||
mp_hp_stack->add_widget (view->hierarchy_control_frame ());
|
||||
mp_libs_stack->add_widget (view->libraries_frame ());
|
||||
mp_eo_stack->add_widget (view->editor_options_frame ());
|
||||
mp_bm_stack->add_widget (view->bookmarks_frame ());
|
||||
mp_view_stack->add_widget (view_widget);
|
||||
mp_lp_stack->add_widget (view_widget->layer_control_frame ());
|
||||
mp_layer_toolbox_stack->add_widget (view_widget->layer_toolbox_frame ());
|
||||
mp_hp_stack->add_widget (view_widget->hierarchy_control_frame ());
|
||||
mp_libs_stack->add_widget (view_widget->libraries_frame ());
|
||||
mp_eo_stack->add_widget (view_widget->editor_options_frame ());
|
||||
mp_bm_stack->add_widget (view_widget->bookmarks_frame ());
|
||||
|
||||
bool f = m_disable_tab_selected;
|
||||
m_disable_tab_selected = true;
|
||||
|
|
@ -2752,9 +2694,9 @@ MainWindow::interactive_close_view (int index, bool all_cellviews)
|
|||
|
||||
int count = 0;
|
||||
|
||||
for (std::vector <lay::LayoutView *>::const_iterator v = mp_views.begin (); v != mp_views.end (); ++v) {
|
||||
for (unsigned int cvi = 0; cvi < (*v)->cellviews (); ++cvi) {
|
||||
if ((*v)->cellview (cvi)->name () == name) {
|
||||
for (std::vector <lay::LayoutViewWidget *>::const_iterator v = mp_views.begin (); v != mp_views.end (); ++v) {
|
||||
for (unsigned int cvi = 0; cvi < (*v)->view ()->cellviews (); ++cvi) {
|
||||
if ((*v)->view ()->cellview (cvi)->name () == name) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
|
@ -2855,6 +2797,7 @@ MainWindow::close_view (int index)
|
|||
mp_tab_bar->removeTab (index);
|
||||
mp_view_stack->remove_widget (index);
|
||||
mp_lp_stack->remove_widget (index);
|
||||
mp_layer_toolbox_stack->remove_widget (index);
|
||||
mp_hp_stack->remove_widget (index);
|
||||
mp_libs_stack->remove_widget (index);
|
||||
mp_eo_stack->remove_widget (index);
|
||||
|
|
@ -2863,7 +2806,7 @@ MainWindow::close_view (int index)
|
|||
view_closed_event (int (index));
|
||||
|
||||
// delete the view later as it may still be needed by event handlers or similar
|
||||
std::unique_ptr<lay::LayoutView> old_view (view (index));
|
||||
std::unique_ptr<lay::LayoutViewWidget> old_view (mp_views [index]);
|
||||
|
||||
mp_views.erase (mp_views.begin () + index, mp_views.begin () + index + 1);
|
||||
|
||||
|
|
@ -2879,7 +2822,6 @@ MainWindow::close_view (int index)
|
|||
|
||||
// last view closed
|
||||
|
||||
mp_layer_toolbox->set_view (0);
|
||||
current_view_changed ();
|
||||
|
||||
clear_current_pos ();
|
||||
|
|
@ -3364,33 +3306,33 @@ MainWindow::create_layout (const std::string &technology, int mode)
|
|||
}
|
||||
|
||||
void
|
||||
MainWindow::add_view (lay::LayoutView *view)
|
||||
MainWindow::add_view (lay::LayoutViewWidget *view)
|
||||
{
|
||||
tl_assert (view->widget ());
|
||||
|
||||
connect (view->widget (), SIGNAL (title_changed (lay::LayoutView *)), this, SLOT (view_title_changed (lay::LayoutView *)));
|
||||
connect (view->widget (), SIGNAL (dirty_changed (lay::LayoutView *)), this, SLOT (view_title_changed (lay::LayoutView *)));
|
||||
connect (view->widget (), SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ()));
|
||||
connect (view->widget (), SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ()));
|
||||
connect (view->widget (), SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int)));
|
||||
connect (view->widget (), SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool)));
|
||||
connect (view->widget (), SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ()));
|
||||
connect (view->widget (), SIGNAL (mode_change (int)), this, SLOT (select_mode (int)));
|
||||
connect (view, SIGNAL (title_changed (lay::LayoutView *)), this, SLOT (view_title_changed (lay::LayoutView *)));
|
||||
connect (view, SIGNAL (dirty_changed (lay::LayoutView *)), this, SLOT (view_title_changed (lay::LayoutView *)));
|
||||
connect (view, SIGNAL (edits_enabled_changed ()), this, SLOT (edits_enabled_changed ()));
|
||||
connect (view, SIGNAL (menu_needs_update ()), this, SLOT (menu_needs_update ()));
|
||||
connect (view, SIGNAL (show_message (const std::string &, int)), this, SLOT (message (const std::string &, int)));
|
||||
connect (view, SIGNAL (current_pos_changed (double, double, bool)), this, SLOT (current_pos (double, double, bool)));
|
||||
connect (view, SIGNAL (clear_current_pos ()), this, SLOT (clear_current_pos ()));
|
||||
connect (view, SIGNAL (mode_change (int)), this, SLOT (select_mode (int)));
|
||||
|
||||
mp_views.push_back (view);
|
||||
|
||||
// we must resize the widget here to set the geometry properly.
|
||||
// This is required to make zoom_fit work.
|
||||
view->widget ()->setGeometry (0, 0, mp_view_stack->width (), mp_view_stack->height ());
|
||||
view->widget ()->show ();
|
||||
view->setGeometry (0, 0, mp_view_stack->width (), mp_view_stack->height ());
|
||||
view->show ();
|
||||
}
|
||||
|
||||
int
|
||||
MainWindow::do_create_view ()
|
||||
{
|
||||
// create a new view
|
||||
lay::LayoutView *view = new lay::LayoutView (&m_manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), mp_view_stack);
|
||||
add_view (view);
|
||||
lay::LayoutViewWidget *view_widget = new lay::LayoutViewWidget (&m_manager, lay::ApplicationBase::instance ()->is_editable (), dispatcher (), mp_view_stack);
|
||||
add_view (view_widget);
|
||||
|
||||
lay::LayoutView *view = view_widget->view ();
|
||||
|
||||
// set initial attributes
|
||||
view->set_synchronous (synchronous ());
|
||||
|
|
@ -3416,12 +3358,11 @@ MainWindow::create_view ()
|
|||
int view_index = do_create_view ();
|
||||
|
||||
// add a new tab and make the new view the current one
|
||||
mp_views.back ()->set_current ();
|
||||
|
||||
mp_layer_toolbox->set_view (current_view ());
|
||||
mp_views.back ()->view ()->set_current ();
|
||||
|
||||
mp_view_stack->add_widget (mp_views.back ());
|
||||
mp_lp_stack->add_widget (mp_views.back ()->layer_control_frame ());
|
||||
mp_layer_toolbox_stack->add_widget (mp_views.back ()->layer_toolbox_frame ());
|
||||
mp_hp_stack->add_widget (mp_views.back ()->hierarchy_control_frame ());
|
||||
mp_libs_stack->add_widget (mp_views.back ()->libraries_frame ());
|
||||
mp_eo_stack->add_widget (mp_views.back ()->editor_options_frame ());
|
||||
|
|
@ -3480,12 +3421,11 @@ MainWindow::create_or_load_layout (const std::string *filename, const db::LoadLa
|
|||
// make the new view the current one
|
||||
if (mode == 1) {
|
||||
|
||||
mp_views.back ()->set_current ();
|
||||
|
||||
mp_layer_toolbox->set_view (current_view ());
|
||||
mp_views.back ()->view ()->set_current ();
|
||||
|
||||
mp_view_stack->add_widget (mp_views.back ());
|
||||
mp_lp_stack->add_widget (mp_views.back ()->layer_control_frame ());
|
||||
mp_layer_toolbox_stack->add_widget (mp_views.back ()->layer_toolbox_frame ());
|
||||
mp_hp_stack->add_widget (mp_views.back ()->hierarchy_control_frame ());
|
||||
mp_libs_stack->add_widget (mp_views.back ()->libraries_frame ());
|
||||
mp_eo_stack->add_widget (mp_views.back ()->editor_options_frame ());
|
||||
|
|
@ -3640,8 +3580,8 @@ void
|
|||
MainWindow::set_synchronous (bool sync_mode)
|
||||
{
|
||||
m_synchronous = sync_mode;
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->set_synchronous (sync_mode);
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->set_synchronous (sync_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4187,8 +4127,8 @@ MainWindow::plugin_registered (lay::PluginDeclaration *cls)
|
|||
cls->init_menu (dispatcher ());
|
||||
|
||||
// recreate all plugins
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->create_plugins ();
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->create_plugins ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4198,8 +4138,8 @@ MainWindow::plugin_removed (lay::PluginDeclaration *cls)
|
|||
cls->remove_menu_items (dispatcher ());
|
||||
|
||||
// recreate all plugins except the one that got removed
|
||||
for (std::vector <lay::LayoutView *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->create_plugins (cls);
|
||||
for (std::vector <lay::LayoutViewWidget *>::iterator vp = mp_views.begin (); vp != mp_views.end (); ++vp) {
|
||||
(*vp)->view ()->create_plugins (cls);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -687,10 +687,9 @@ private:
|
|||
QDockWidget *mp_navigator_dock_widget;
|
||||
lay::Navigator *mp_navigator;
|
||||
QDockWidget *mp_hp_dock_widget, *mp_lp_dock_widget, *mp_libs_dock_widget, *mp_eo_dock_widget, *mp_bm_dock_widget;
|
||||
ControlWidgetStack *mp_hp_stack, *mp_lp_stack, *mp_libs_stack, *mp_eo_stack, *mp_bm_stack;
|
||||
ControlWidgetStack *mp_hp_stack, *mp_lp_stack, *mp_layer_toolbox_stack, *mp_libs_stack, *mp_eo_stack, *mp_bm_stack;
|
||||
bool m_hp_visible, m_lp_visible, m_libs_visible, m_eo_visible, m_bm_visible, m_navigator_visible, m_layer_toolbox_visible, m_always_exit_without_saving;
|
||||
QDockWidget *mp_layer_toolbox_dock_widget;
|
||||
lay::LayerToolbox *mp_layer_toolbox;
|
||||
ViewWidgetStack *mp_view_stack;
|
||||
lay::FileDialog *mp_bookmarks_fdia;
|
||||
lay::FileDialog *mp_session_fdia;
|
||||
|
|
@ -703,7 +702,7 @@ private:
|
|||
lay::LogViewerDialog *mp_log_viewer_dialog;
|
||||
int m_mode;
|
||||
SettingsForm *mp_setup_form;
|
||||
std::vector <lay::LayoutView *> mp_views;
|
||||
std::vector <lay::LayoutViewWidget *> mp_views;
|
||||
int m_open_mode;
|
||||
int m_keep_backups;
|
||||
std::vector<std::pair<std::string, std::string> > m_mru;
|
||||
|
|
@ -808,7 +807,7 @@ private:
|
|||
void current_view_changed ();
|
||||
void update_window_title ();
|
||||
void update_tab_title (int i);
|
||||
void add_view (LayoutView *view);
|
||||
void add_view (LayoutViewWidget *view);
|
||||
|
||||
bool can_close ();
|
||||
lay::CellViewRef create_or_load_layout (const std::string *filename, const db::LoadLayoutOptions *options, const std::string &tech, const int mode);
|
||||
|
|
|
|||
|
|
@ -630,8 +630,8 @@ Navigator::view_closed (int index)
|
|||
void
|
||||
Navigator::resizeEvent (QResizeEvent *)
|
||||
{
|
||||
if (mp_view && mp_view->widget ()) {
|
||||
mp_view->widget ()->setGeometry (mp_placeholder_label->geometry ());
|
||||
if (mp_view) {
|
||||
mp_view->setGeometry (mp_placeholder_label->geometry ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -650,21 +650,20 @@ Navigator::attach_view (LayoutView *view)
|
|||
delete mp_service;
|
||||
mp_service = 0;
|
||||
|
||||
LayoutView *old_view = mp_view;
|
||||
LayoutViewWidget *old_view = mp_view;
|
||||
mp_view = 0;
|
||||
|
||||
if (mp_source_view) {
|
||||
|
||||
mp_view = new LayoutView (0, false, mp_source_view, this, "navigator", LayoutView::LV_Naked + LayoutView::LV_NoZoom + LayoutView::LV_NoServices + LayoutView::LV_NoGrid);
|
||||
tl_assert (mp_view->widget ());
|
||||
mp_view->widget ()->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
mp_view->widget ()->setMinimumWidth (100);
|
||||
mp_view->widget ()->setMinimumHeight (100);
|
||||
mp_view->widget ()->setGeometry (mp_placeholder_label->geometry ());
|
||||
mp_view->widget ()->show ();
|
||||
mp_view = new LayoutViewWidget (0, false, mp_source_view, this, LayoutView::LV_Naked + LayoutView::LV_NoZoom + LayoutView::LV_NoServices + LayoutView::LV_NoGrid);
|
||||
mp_view->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
mp_view->setMinimumWidth (100);
|
||||
mp_view->setMinimumHeight (100);
|
||||
mp_view->setGeometry (mp_placeholder_label->geometry ());
|
||||
mp_view->show ();
|
||||
|
||||
mp_service = new NavigatorService (mp_view);
|
||||
mp_view->canvas ()->activate (mp_service);
|
||||
mp_service = new NavigatorService (mp_view->view ());
|
||||
mp_view->view ()->canvas ()->activate (mp_service);
|
||||
|
||||
mp_source_view->cellviews_changed_event.add (this, &Navigator::content_changed);
|
||||
mp_source_view->cellview_changed_event.add (this, &Navigator::content_changed_with_int);
|
||||
|
|
@ -714,7 +713,7 @@ void
|
|||
Navigator::hier_levels_changed ()
|
||||
{
|
||||
if (m_show_all_hier_levels && mp_source_view && m_frozen_list.find (mp_source_view) == m_frozen_list.end ()) {
|
||||
mp_view->set_hier_levels (mp_source_view->get_hier_levels ());
|
||||
mp_view->view ()->set_hier_levels (mp_source_view->get_hier_levels ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -729,19 +728,19 @@ Navigator::update_layers ()
|
|||
void
|
||||
Navigator::update ()
|
||||
{
|
||||
if (! mp_view || ! mp_source_view) {
|
||||
if (! mp_view || ! mp_view->view () || ! mp_source_view) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_frozen_list.find (mp_source_view) == m_frozen_list.end ()) {
|
||||
mp_view->select_cellviews (mp_source_view->cellview_list ());
|
||||
mp_view->set_properties (mp_source_view->get_properties ());
|
||||
mp_view->view ()->select_cellviews (mp_source_view->cellview_list ());
|
||||
mp_view->view ()->set_properties (mp_source_view->get_properties ());
|
||||
} else {
|
||||
mp_view->select_cellviews (mp_source_view->cellview_list ());
|
||||
mp_view->set_properties (m_frozen_list [mp_source_view].layer_properties);
|
||||
mp_view->view ()->select_cellviews (mp_source_view->cellview_list ());
|
||||
mp_view->view ()->set_properties (m_frozen_list [mp_source_view].layer_properties);
|
||||
}
|
||||
|
||||
img::Service *img_target = mp_view->get_plugin<img::Service> ();
|
||||
img::Service *img_target = mp_view->view ()->get_plugin<img::Service> ();
|
||||
if (img_target) {
|
||||
|
||||
img_target->clear_images ();
|
||||
|
|
@ -759,16 +758,16 @@ Navigator::update ()
|
|||
|
||||
if (m_show_all_hier_levels && mp_source_view) {
|
||||
if (m_frozen_list.find (mp_source_view) == m_frozen_list.end ()) {
|
||||
mp_view->set_hier_levels (mp_source_view->get_hier_levels ());
|
||||
mp_view->view ()->set_hier_levels (mp_source_view->get_hier_levels ());
|
||||
} else {
|
||||
mp_view->set_hier_levels (m_frozen_list [mp_source_view].hierarchy_levels);
|
||||
mp_view->view ()->set_hier_levels (m_frozen_list [mp_source_view].hierarchy_levels);
|
||||
}
|
||||
} else {
|
||||
mp_view->set_hier_levels (std::make_pair (0, 0));
|
||||
mp_view->view ()->set_hier_levels (std::make_pair (0, 0));
|
||||
}
|
||||
|
||||
mp_view->zoom_fit ();
|
||||
mp_view->update_content ();
|
||||
mp_view->view ()->zoom_fit ();
|
||||
mp_view->view ()->update_content ();
|
||||
mp_service->update_marker ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ namespace lay
|
|||
|
||||
class MainWindow;
|
||||
class LayoutView;
|
||||
class LayoutViewWidget;
|
||||
class AbstractMenu;
|
||||
class DMarker;
|
||||
class NavigatorService;
|
||||
|
|
@ -98,7 +99,7 @@ private:
|
|||
bool m_update_layers_needed;
|
||||
bool m_update_needed;
|
||||
MainWindow *mp_main_window;
|
||||
LayoutView *mp_view;
|
||||
LayoutViewWidget *mp_view;
|
||||
QLabel *mp_placeholder_label;
|
||||
QFrame *mp_menu_bar;
|
||||
LayoutView *mp_source_view;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "layReaderErrorForm.h"
|
||||
#include "layQtTools.h"
|
||||
#include "dbReader.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
||||
static bool is_text (const std::string &s)
|
||||
{
|
||||
for (std::string::const_iterator i = s.begin (); i != s.end (); ++i) {
|
||||
unsigned char uc = (unsigned char) *i;
|
||||
if (uc < 32 && uc != '\t' && uc != '\r' && uc != '\n') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string format_hex_dump (const std::string &s)
|
||||
{
|
||||
const int bytes_per_line = 16;
|
||||
|
||||
std::string hex_dump;
|
||||
// Some rough estimate of the capacity
|
||||
hex_dump.reserve ((s.size () / bytes_per_line + 1) * (8 + bytes_per_line * 4) + 100);
|
||||
|
||||
const char *ce = s.c_str () + s.size ();
|
||||
for (const char *c = s.c_str (); c + bytes_per_line <= ce; c += bytes_per_line) {
|
||||
|
||||
hex_dump += tl::sprintf ("%04x ", c - s.c_str ());
|
||||
for (int i = 0; i < bytes_per_line; ++i) {
|
||||
hex_dump += tl::sprintf ("%02x ", (unsigned char) c [i]);
|
||||
}
|
||||
hex_dump += " ";
|
||||
for (int i = 0; i < bytes_per_line; ++i) {
|
||||
unsigned char uc = (unsigned char) c[i];
|
||||
hex_dump += (uc < 32 || uc >= 128) ? '.' : c[i];
|
||||
}
|
||||
|
||||
hex_dump += "\n";
|
||||
|
||||
}
|
||||
|
||||
return hex_dump;
|
||||
}
|
||||
|
||||
ReaderErrorForm::ReaderErrorForm (QWidget *parent, const char *name, const db::ReaderUnknownFormatException *error)
|
||||
: QDialog (parent), Ui::ReaderErrorForm ()
|
||||
{
|
||||
setObjectName (QString::fromUtf8 (name));
|
||||
|
||||
Ui::ReaderErrorForm::setupUi (this);
|
||||
|
||||
msg_label->setText (tl::to_qstring (error->basic_msg ()));
|
||||
|
||||
if (is_text (error->data ())) {
|
||||
details_text->setText (tl::to_qstring (error->msg () + "\n\n" + error->data () + (error->has_more () ? "..." : "")));
|
||||
} else {
|
||||
details_text->setText (tl::to_qstring (error->msg () + "\n\n" + format_hex_dump (error->data ()) + (error->has_more () ? "..." : "")));
|
||||
}
|
||||
|
||||
details_text->setFont (lay::monospace_font ());
|
||||
details_frame->hide ();
|
||||
|
||||
// "borrow" the error pixmap from the message box
|
||||
QMessageBox *mb = new QMessageBox (QMessageBox::Critical, QString (), QString ());
|
||||
QPixmap error_icon = mb->iconPixmap ();
|
||||
delete mb;
|
||||
icon_label->setPixmap (error_icon);
|
||||
|
||||
connect (details_pb, SIGNAL (clicked ()), this, SLOT (show_details ()));
|
||||
|
||||
resize (size ().width (), 50);
|
||||
}
|
||||
|
||||
void
|
||||
ReaderErrorForm::show_details ()
|
||||
{
|
||||
QString t (details_pb->text ());
|
||||
if (details_frame->isVisible ()) {
|
||||
details_frame->hide ();
|
||||
t.replace (QString::fromUtf8 ("<<"), QString::fromUtf8 (">>"));
|
||||
// It looks like the minimum size is set to a too large value internally.
|
||||
// Resetting it helps to keep a small-as-possible dialog size.
|
||||
setMinimumSize (QSize (0, 0));
|
||||
resize (size ().width (), 0);
|
||||
} else {
|
||||
details_frame->show ();
|
||||
t.replace (QString::fromUtf8 (">>"), QString::fromUtf8 ("<<"));
|
||||
resize (size ().width (), sizeHint ().height ());
|
||||
}
|
||||
details_pb->setText (t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2022 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_rbaReaderErrorForm
|
||||
#define HDR_rbaReaderErrorForm
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_ReaderErrorForm.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
class ReaderUnknownFormatException;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class ReaderErrorForm
|
||||
: public QDialog, private Ui::ReaderErrorForm
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ReaderErrorForm (QWidget *parent, const char *name, const db::ReaderUnknownFormatException *error);
|
||||
|
||||
public slots:
|
||||
void show_details ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -40,12 +40,12 @@ ViewWidgetStack::ViewWidgetStack (QWidget *parent, const char *name)
|
|||
mp_bglabel->show ();
|
||||
}
|
||||
|
||||
void ViewWidgetStack::add_widget (LayoutView *w)
|
||||
void ViewWidgetStack::add_widget (LayoutViewWidget *w)
|
||||
{
|
||||
tl_assert (w->widget ());
|
||||
tl_assert (w);
|
||||
|
||||
m_widgets.push_back (w);
|
||||
w->widget ()->setParent (this);
|
||||
w->setParent (this);
|
||||
resize_children ();
|
||||
raise_widget (m_widgets.size () - 1);
|
||||
|
||||
|
|
@ -66,20 +66,20 @@ void ViewWidgetStack::raise_widget (size_t index)
|
|||
{
|
||||
if (index < m_widgets.size ()) {
|
||||
mp_bglabel->hide ();
|
||||
m_widgets [index]->widget ()->show ();
|
||||
m_widgets [index]->show ();
|
||||
} else {
|
||||
mp_bglabel->show ();
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (std::vector <LayoutView *>::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child, ++i) {
|
||||
for (std::vector <LayoutViewWidget *>::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child, ++i) {
|
||||
if (i != index) {
|
||||
(*child)->widget ()->hide ();
|
||||
(*child)->hide ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LayoutView *ViewWidgetStack::widget (size_t index)
|
||||
LayoutViewWidget *ViewWidgetStack::widget (size_t index)
|
||||
{
|
||||
if (index < m_widgets.size ()) {
|
||||
return m_widgets [index];
|
||||
|
|
@ -96,8 +96,8 @@ QWidget *ViewWidgetStack::background_widget ()
|
|||
void ViewWidgetStack::resize_children ()
|
||||
{
|
||||
// set the geometry of all children
|
||||
for (std::vector <LayoutView *>::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child) {
|
||||
(*child)->widget ()->setGeometry (0, 0, width (), height ());
|
||||
for (std::vector <LayoutViewWidget *>::iterator child = m_widgets.begin (); child != m_widgets.end (); ++child) {
|
||||
(*child)->setGeometry (0, 0, width (), height ());
|
||||
}
|
||||
mp_bglabel->setGeometry (0, 0, width (), height ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class QLabel;
|
|||
namespace lay
|
||||
{
|
||||
|
||||
class LayoutView;
|
||||
class LayoutViewWidget;
|
||||
|
||||
class ViewWidgetStack
|
||||
: public QWidget
|
||||
|
|
@ -41,10 +41,10 @@ class ViewWidgetStack
|
|||
public:
|
||||
ViewWidgetStack (QWidget *parent = 0, const char *name = 0);
|
||||
|
||||
void add_widget (LayoutView *w);
|
||||
void add_widget (lay::LayoutViewWidget *w);
|
||||
void remove_widget (size_t index);
|
||||
void raise_widget (size_t index);
|
||||
LayoutView *widget (size_t index);
|
||||
LayoutViewWidget *widget (size_t index);
|
||||
QWidget *background_widget ();
|
||||
|
||||
protected:
|
||||
|
|
@ -55,7 +55,7 @@ protected:
|
|||
|
||||
void resize_children ();
|
||||
|
||||
std::vector <LayoutView *> m_widgets;
|
||||
std::vector <LayoutViewWidget *> m_widgets;
|
||||
QLabel *mp_bglabel;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -534,6 +534,12 @@ LAYBASIC_PUBLIC Class<lay::LayoutViewBase> decl_LayoutViewBase ("lay", "LayoutVi
|
|||
"\n"
|
||||
"This constant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::constant ("LV_NoPropertiesPopup", (unsigned int) lay::LayoutViewBase::LV_NoPropertiesPopup,
|
||||
"@brief This option disables the properties popup on double click\n"
|
||||
"Use this value with the constructor's 'options' argument.\n"
|
||||
"\n"
|
||||
"This constant has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::constant ("LV_NoServices", (unsigned int) lay::LayoutViewBase::LV_NoServices,
|
||||
"@brief This option disables all services except the ones for pure viewing\n"
|
||||
"Use this value with the constructor's 'options' argument.\n"
|
||||
|
|
|
|||
|
|
@ -36,7 +36,13 @@ public:
|
|||
if (triggered_cb.can_issue ()) {
|
||||
triggered_cb.issue<lay::Action> (&lay::Action::triggered);
|
||||
}
|
||||
on_triggered_event ();
|
||||
}
|
||||
|
||||
virtual void menu_opening ()
|
||||
{
|
||||
if (menu_opening_cb.can_issue ()) {
|
||||
menu_opening_cb.issue<lay::Action> (&lay::Action::menu_opening);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool wants_visible () const
|
||||
|
|
@ -58,9 +64,9 @@ public:
|
|||
}
|
||||
|
||||
gsi::Callback triggered_cb;
|
||||
gsi::Callback menu_opening_cb;
|
||||
gsi::Callback wants_visible_cb;
|
||||
gsi::Callback wants_enabled_cb;
|
||||
tl::Event on_triggered_event;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -192,10 +198,29 @@ Class<lay::AbstractMenu> decl_AbstractMenu ("lay", "AbstractMenu",
|
|||
"@param name The name of the submenu to insert \n"
|
||||
"@param title The title of the submenu to insert\n"
|
||||
) +
|
||||
method ("insert_menu", (void (lay::AbstractMenu::*) (const std::string &, const std::string &, lay::Action *)) &lay::AbstractMenu::insert_menu, gsi::arg ("path"), gsi::arg ("name"), gsi::arg ("action"),
|
||||
"@brief Inserts a new submenu before the item given by the path\n"
|
||||
"\n"
|
||||
"@param path The path to the item before which to insert the submenu\n"
|
||||
"@param name The name of the submenu to insert \n"
|
||||
"@param action The action object of the submenu to insert\n"
|
||||
"\n"
|
||||
"This method variant has been added in version 0.28."
|
||||
) +
|
||||
method ("clear_menu", &lay::AbstractMenu::clear_menu, gsi::arg ("path"),
|
||||
"@brief Deletes the children of the item given by the path\n"
|
||||
"\n"
|
||||
"@param path The path to the item whose children to delete\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.\n"
|
||||
) +
|
||||
method ("delete_item", &lay::AbstractMenu::delete_item, gsi::arg ("path"),
|
||||
"@brief Deletes the item given by the path\n"
|
||||
"\n"
|
||||
"@param path The path to the item to delete\n"
|
||||
"\n"
|
||||
"This method will also delete all children of the given item. "
|
||||
"To clear the children only, use \\clear_menu.\n"
|
||||
) +
|
||||
method ("group", &lay::AbstractMenu::group, gsi::arg ("group"),
|
||||
"@brief Gets the group members\n"
|
||||
|
|
@ -360,6 +385,15 @@ Class<lay::Action> decl_ActionBase ("lay", "ActionBase",
|
|||
"\n"
|
||||
"Passing an empty string will reset the icon.\n"
|
||||
) +
|
||||
#if defined(HAVE_QT) && defined(HAVE_QTBINDINGS)
|
||||
method ("icon=", &lay::Action::set_qicon, gsi::arg ("qicon"),
|
||||
"@brief Sets the icon to the given \\QIcon object\n"
|
||||
"\n"
|
||||
"@param qicon The QIcon object\n"
|
||||
"\n"
|
||||
"This variant has been added in version 0.28.\n"
|
||||
) +
|
||||
#endif
|
||||
method ("icon_text=", &lay::Action::set_icon_text, gsi::arg ("icon_text"),
|
||||
"@brief Sets the icon's text\n"
|
||||
"\n"
|
||||
|
|
@ -385,6 +419,18 @@ Class<lay::Action> decl_ActionBase ("lay", "ActionBase",
|
|||
) +
|
||||
method ("trigger", &lay::Action::trigger,
|
||||
"@brief Triggers the action programmatically"
|
||||
) +
|
||||
gsi::event ("on_triggered", &ActionStub::on_triggered_event,
|
||||
"@brief This event is called if the menu item is selected.\n"
|
||||
"\n"
|
||||
"This event has been introduced in version 0.21 and moved to the ActionBase class in 0.28.\n"
|
||||
) +
|
||||
gsi::event ("on_menu_opening", &ActionStub::on_menu_opening_event,
|
||||
"@brief This event is called if the menu item is a sub-menu and before the menu is opened.\n"
|
||||
"\n"
|
||||
"This event provides an opportunity to populate the menu before it is opened.\n"
|
||||
"\n"
|
||||
"This event has been introduced in version 0.28.\n"
|
||||
),
|
||||
"@hide\n"
|
||||
"@alias Action\n"
|
||||
|
|
@ -392,7 +438,18 @@ Class<lay::Action> decl_ActionBase ("lay", "ActionBase",
|
|||
|
||||
Class<ActionStub> decl_Action (decl_ActionBase, "lay", "Action",
|
||||
gsi::callback ("triggered", &ActionStub::triggered, &ActionStub::triggered_cb,
|
||||
"@brief This method is called if the menu item is selected"
|
||||
"@brief This method is called if the menu item is selected.\n"
|
||||
"\n"
|
||||
"Reimplement this method is a derived class to receive this event. "
|
||||
"You can also use the \\on_triggered event instead."
|
||||
) +
|
||||
gsi::callback ("menu_opening", &ActionStub::menu_opening, &ActionStub::menu_opening_cb,
|
||||
"@brief This method is called if the menu item is a sub-menu and before the menu is opened."
|
||||
"\n"
|
||||
"Reimplement this method is a derived class to receive this event. "
|
||||
"You can also use the \\on_menu_opening event instead.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.28."
|
||||
) +
|
||||
gsi::callback ("wants_visible", &ActionStub::wants_visible, &ActionStub::wants_visible_cb,
|
||||
"@brief Returns a value whether the action wants to become visible\n"
|
||||
|
|
@ -404,18 +461,13 @@ Class<ActionStub> decl_Action (decl_ActionBase, "lay", "Action",
|
|||
"This feature has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::callback ("wants_enabled", &ActionStub::wants_enabled, &ActionStub::wants_enabled_cb,
|
||||
"@brief Returns a value whether the action wants to become enabled\n"
|
||||
"@brief Returns a value whether the action wants to become enabled.\n"
|
||||
"This is a dynamic query for enabled state which the system uses to dynamically show or hide "
|
||||
"menu items. This information is evaluated in addition "
|
||||
"to \\is_enabled? and contributes to the effective enabled status from "
|
||||
"\\is_effective_enabled?.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.28.\n"
|
||||
) +
|
||||
gsi::event ("on_triggered", &ActionStub::on_triggered_event,
|
||||
"@brief This event is called if the menu item is selected\n"
|
||||
"\n"
|
||||
"This event has been introduced in version 0.21.\n"
|
||||
),
|
||||
"@brief The abstraction for an action (i.e. used inside menus)\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -541,8 +541,14 @@ Action::configure_from_title (const std::string &s)
|
|||
void
|
||||
Action::menu_about_to_show ()
|
||||
{
|
||||
// keeps a reference to self in case the action handler code removes actions
|
||||
tl::shared_ptr<Action> self_holder (this);
|
||||
|
||||
BEGIN_PROTECTED
|
||||
|
||||
on_menu_opening_event ();
|
||||
menu_opening ();
|
||||
|
||||
if (! mp_dispatcher || ! mp_dispatcher->menu ()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -565,7 +571,11 @@ Action::menu_about_to_show ()
|
|||
void
|
||||
Action::qaction_triggered ()
|
||||
{
|
||||
// keeps a reference to self in case the action handler code removes actions
|
||||
tl::shared_ptr<Action> self_holder (this);
|
||||
|
||||
BEGIN_PROTECTED
|
||||
on_triggered_event ();
|
||||
triggered ();
|
||||
END_PROTECTED
|
||||
}
|
||||
|
|
@ -574,11 +584,15 @@ Action::qaction_triggered ()
|
|||
void
|
||||
Action::trigger ()
|
||||
{
|
||||
// keeps a reference to self in case the action handler code removes actions
|
||||
tl::shared_ptr<Action> self_holder (this);
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
if (qaction ()) {
|
||||
qaction ()->trigger ();
|
||||
}
|
||||
#else
|
||||
on_triggered_event ();
|
||||
triggered ();
|
||||
#endif
|
||||
}
|
||||
|
|
@ -589,6 +603,12 @@ Action::triggered ()
|
|||
// .. no action yet, the reimplementation must provide some ..
|
||||
}
|
||||
|
||||
void
|
||||
Action::menu_opening ()
|
||||
{
|
||||
// .. no action yet, the reimplementation must provide some ..
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
QAction *
|
||||
Action::qaction () const
|
||||
|
|
@ -602,6 +622,61 @@ Action::menu () const
|
|||
return mp_menu;
|
||||
}
|
||||
|
||||
void
|
||||
Action::set_menu (QMenu *menu, bool owned)
|
||||
{
|
||||
if (mp_menu == menu || ! lay::has_gui () || ! mp_action) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mp_menu && ! menu) {
|
||||
|
||||
QAction *new_action = new ActionObject (0);
|
||||
configure_action (new_action);
|
||||
|
||||
if (m_owned) {
|
||||
delete mp_menu;
|
||||
}
|
||||
mp_menu = 0;
|
||||
|
||||
mp_action = new_action;
|
||||
m_owned = true;
|
||||
|
||||
} else if (mp_menu && menu) {
|
||||
|
||||
configure_action (menu->menuAction ());
|
||||
|
||||
if (m_owned) {
|
||||
delete mp_menu;
|
||||
}
|
||||
|
||||
mp_menu = menu;
|
||||
m_owned = owned;
|
||||
mp_action = menu->menuAction ();
|
||||
|
||||
} else if (! mp_menu && menu) {
|
||||
|
||||
configure_action (menu->menuAction ());
|
||||
|
||||
if (m_owned) {
|
||||
delete mp_action;
|
||||
}
|
||||
|
||||
mp_menu = menu;
|
||||
m_owned = owned;
|
||||
mp_action = menu->menuAction ();
|
||||
|
||||
}
|
||||
|
||||
if (mp_menu) {
|
||||
connect (mp_menu, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
connect (mp_menu, SIGNAL (aboutToShow ()), this, SLOT (menu_about_to_show ()));
|
||||
} else {
|
||||
connect (mp_action, SIGNAL (destroyed (QObject *)), this, SLOT (was_destroyed (QObject *)));
|
||||
}
|
||||
connect (mp_action, SIGNAL (triggered ()), this, SLOT (qaction_triggered ()));
|
||||
}
|
||||
|
||||
void
|
||||
Action::was_destroyed (QObject *obj)
|
||||
{
|
||||
|
|
@ -628,6 +703,31 @@ Action::sync_qaction ()
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Action::configure_action (QAction *target) const
|
||||
{
|
||||
target->setVisible (is_effective_visible ());
|
||||
target->setShortcut (get_key_sequence ());
|
||||
target->setEnabled (is_effective_enabled ());
|
||||
target->setToolTip (tl::to_qstring (get_tool_tip ()));
|
||||
target->setCheckable (is_checkable ());
|
||||
target->setChecked (is_checked ());
|
||||
target->setIconText (tl::to_qstring (get_icon_text ()));
|
||||
target->setSeparator (is_separator ());
|
||||
target->setText (tl::to_qstring (get_title ()));
|
||||
|
||||
if (qaction ()) {
|
||||
target->setIcon (qaction ()->icon ());
|
||||
target->setObjectName (qaction ()->objectName ());
|
||||
} else if (m_icon.empty ()) {
|
||||
target->setIcon (QIcon ());
|
||||
} else {
|
||||
target->setIcon (QIcon (tl::to_qstring (m_icon)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Action::set_visible (bool v)
|
||||
{
|
||||
|
|
@ -891,6 +991,17 @@ Action::set_icon (const std::string &filename)
|
|||
m_icon = filename;
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Action::set_qicon (const QIcon &icon)
|
||||
{
|
||||
if (qaction ()) {
|
||||
qaction ()->setIcon (icon);
|
||||
}
|
||||
m_icon.clear ();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string
|
||||
Action::get_tool_tip () const
|
||||
{
|
||||
|
|
@ -1072,13 +1183,10 @@ AbstractMenu::build_detached (const std::string &name, QFrame *mbar)
|
|||
menu_button->setText (tl::to_qstring (c->action ()->get_title ()));
|
||||
|
||||
if (c->menu () == 0) {
|
||||
QMenu *menu = new QMenu (mp_dispatcher->menu_parent_widget ());
|
||||
menu_button->setMenu (menu);
|
||||
c->set_action (new Action (menu), true);
|
||||
} else {
|
||||
menu_button->setMenu (c->menu ());
|
||||
c->set_menu (new QMenu (mp_dispatcher->menu_parent_widget ()), true);
|
||||
}
|
||||
|
||||
menu_button->setMenu (c->menu ());
|
||||
build (c->menu (), c->children);
|
||||
|
||||
} else {
|
||||
|
|
@ -1120,7 +1228,6 @@ static QAction *insert_action_after (QWidget *widget, QAction *after, QAction *a
|
|||
void
|
||||
AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
||||
{
|
||||
m_helper_menu_items.clear ();
|
||||
if (tbar) {
|
||||
tbar->clear ();
|
||||
}
|
||||
|
|
@ -1153,14 +1260,15 @@ AbstractMenu::build (QMenuBar *mbar, QToolBar *tbar)
|
|||
|
||||
if (c->menu () == 0) {
|
||||
QMenu *menu = new QMenu (tl::to_qstring (c->action ()->get_title ()), mp_dispatcher->menu_parent_widget ());
|
||||
// HINT: it is necessary to add the menu action to a widget below the main window.
|
||||
// Otherwise, the keyboard shortcuts do not work for menu items inside such a
|
||||
// popup menu. It seems not to have a negative effect to add the menu to the
|
||||
// main widget.
|
||||
if (mp_dispatcher->menu_parent_widget ()) {
|
||||
mp_dispatcher->menu_parent_widget ()->addAction (menu->menuAction ());
|
||||
}
|
||||
c->set_action (new Action (menu), true);
|
||||
c->action ()->set_menu (menu, true);
|
||||
}
|
||||
|
||||
// HINT: it is necessary to add the menu action to a widget below the main window.
|
||||
// Otherwise, the keyboard shortcuts do not work for menu items inside such a
|
||||
// popup menu. It seems not to have a negative effect to add the menu to the
|
||||
// main widget.
|
||||
if (mp_dispatcher->menu_parent_widget ()) {
|
||||
mp_dispatcher->menu_parent_widget ()->addAction (c->menu ()->menuAction ());
|
||||
}
|
||||
|
||||
// prepare a detached menu which can be used as context menus
|
||||
|
|
@ -1235,13 +1343,14 @@ AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
|
|||
if (c->has_submenu ()) {
|
||||
|
||||
if (! c->menu ()) {
|
||||
// HINT: the action acts as a container for the title. Unfortunately, we cannot create a
|
||||
// menu with a given action. The action is provided by addMenu instead.
|
||||
|
||||
QMenu *menu = new QMenu (mp_dispatcher->menu_parent_widget ());
|
||||
menu->setTitle (tl::to_qstring (c->action ()->get_title ()));
|
||||
c->set_action (new Action (menu), true);
|
||||
c->set_menu (menu, true);
|
||||
prev_action = insert_action_after (m, prev_action, menu->menuAction ());
|
||||
|
||||
} else {
|
||||
|
||||
// Move the action to the end if present in the menu already
|
||||
std::set<std::pair<size_t, QAction *> >::iterator a = present_actions.find (std::make_pair (id_from_action (c->menu ()->menuAction ()), c->menu ()->menuAction ()));
|
||||
if (a != present_actions.end ()) {
|
||||
|
|
@ -1254,6 +1363,7 @@ AbstractMenu::build (QMenu *m, std::list<AbstractMenuItem> &items)
|
|||
} else {
|
||||
prev_action = insert_action_after (m, prev_action, c->menu ()->menuAction ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
build (c->menu (), c->children);
|
||||
|
|
@ -1288,23 +1398,16 @@ AbstractMenu::build (QToolBar *t, std::list<AbstractMenuItem> &items)
|
|||
for (std::list<AbstractMenuItem>::iterator c = items.begin (); c != items.end (); ++c) {
|
||||
|
||||
if (! c->children.empty ()) {
|
||||
|
||||
// To support tool buttons with menu we have to attach a helper menu
|
||||
// item to the QAction object.
|
||||
// TODO: this hurts if we use this QAction otherwise. In this case, this
|
||||
// QAction would get a menu too. However, hopefully this usage is constrained
|
||||
// to special toolbar buttons only.
|
||||
// In order to be able to manage the QMenu ourselves, we must not give it a parent.
|
||||
QMenu *menu = new QMenu (0);
|
||||
m_helper_menu_items.push_back (menu); // will be owned by the stable vector
|
||||
c->action ()->qaction ()->setMenu (menu);
|
||||
t->addAction (c->action ()->qaction ());
|
||||
build (menu, c->children);
|
||||
|
||||
} else {
|
||||
t->addAction (c->action ()->qaction ());
|
||||
if (! c->menu ()) {
|
||||
c->set_menu (new QMenu (0), true);
|
||||
}
|
||||
build (c->menu (), c->children);
|
||||
}
|
||||
|
||||
t->addAction (c->action ()->qaction ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1437,6 +1540,12 @@ AbstractMenu::insert_separator (const std::string &p, const std::string &name)
|
|||
void
|
||||
AbstractMenu::insert_menu (const std::string &p, const std::string &name, Action *action)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
if (! action->menu () && mp_dispatcher && mp_dispatcher->menu_parent_widget ()) {
|
||||
action->set_menu (new QMenu (), true);
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef std::vector<std::pair<AbstractMenuItem *, std::list<AbstractMenuItem>::iterator > > path_type;
|
||||
tl::Extractor extr (p.c_str ());
|
||||
path_type path = find_item (extr);
|
||||
|
|
|
|||
|
|
@ -271,6 +271,16 @@ public:
|
|||
*/
|
||||
void set_icon (const std::string &filename);
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Sets the icon from a QIcon object
|
||||
*
|
||||
* After using this function, "get_icon" will return an empty string as there
|
||||
* is no path for the icon file.
|
||||
*/
|
||||
void set_qicon (const QIcon &icon);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Set the icon's text
|
||||
*
|
||||
|
|
@ -306,10 +316,15 @@ public:
|
|||
void trigger ();
|
||||
|
||||
/**
|
||||
* @brief Reimplement this method to implement a trigger handler
|
||||
* @brief Reimplement this method for a trigger handler
|
||||
*/
|
||||
virtual void triggered ();
|
||||
|
||||
/**
|
||||
* @brief Reimplement this method for a handler called before a sub-menu is opening
|
||||
*/
|
||||
virtual void menu_opening ();
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the action is associated with a specific mode ID
|
||||
*/
|
||||
|
|
@ -358,6 +373,11 @@ public:
|
|||
* @brief Gets the QMenu object if the action is a menu action
|
||||
*/
|
||||
QMenu *menu () const;
|
||||
|
||||
/**
|
||||
* @brief Sets the menu object
|
||||
*/
|
||||
void set_menu (QMenu *menu, bool owned);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -368,6 +388,16 @@ public:
|
|||
return mp_dispatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This event is called when the action is triggered
|
||||
*/
|
||||
tl::Event on_triggered_event;
|
||||
|
||||
/**
|
||||
* @brief This event gets called when the action is a sub-menu and the menu is opened
|
||||
*/
|
||||
tl::Event on_menu_opening_event;
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
protected slots:
|
||||
void was_destroyed (QObject *obj);
|
||||
|
|
@ -407,6 +437,7 @@ private:
|
|||
#if defined(HAVE_QT)
|
||||
QKeySequence get_key_sequence () const;
|
||||
QKeySequence get_key_sequence_for (const std::string &sc) const;
|
||||
void configure_action (QAction *target) const;
|
||||
#endif
|
||||
|
||||
void configure_from_title (const std::string &s);
|
||||
|
|
@ -564,6 +595,11 @@ struct LAYBASIC_PUBLIC AbstractMenuItem
|
|||
{
|
||||
return mp_action->menu ();
|
||||
}
|
||||
|
||||
void set_menu (QMenu *menu, bool owned)
|
||||
{
|
||||
return mp_action->set_menu (menu, owned);
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_has_submenu ();
|
||||
|
|
@ -888,7 +924,6 @@ private:
|
|||
Dispatcher *mp_dispatcher;
|
||||
AbstractMenuItem m_root;
|
||||
#if defined(HAVE_QT)
|
||||
tl::stable_vector<QMenu> m_helper_menu_items;
|
||||
std::map<std::string, QActionGroup *> m_action_groups;
|
||||
#endif
|
||||
std::map<std::string, std::vector<ConfigureAction *> > m_config_action_by_name;
|
||||
|
|
|
|||
|
|
@ -25,10 +25,6 @@
|
|||
#include "dbClipboard.h"
|
||||
#include "tlAssert.h"
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
# include "layPropertiesDialog.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
|
|
@ -76,21 +72,11 @@ Editable::~Editable ()
|
|||
Editables::Editables (db::Manager *manager)
|
||||
: db::Object (manager), m_move_selection (false), m_any_move_operation (false)
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
mp_properties_dialog = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
Editables::~Editables ()
|
||||
{
|
||||
cancel_edits ();
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
if (mp_properties_dialog) {
|
||||
delete mp_properties_dialog;
|
||||
mp_properties_dialog = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -674,36 +660,17 @@ Editables::edit_cancel ()
|
|||
void
|
||||
Editables::cancel_edits ()
|
||||
{
|
||||
#if defined(HAVE_QT)
|
||||
// close the property dialog
|
||||
if (mp_properties_dialog) {
|
||||
mp_properties_dialog->hide ();
|
||||
}
|
||||
#endif
|
||||
|
||||
// cancel any edit operations
|
||||
for (iterator e = begin (); e != end (); ++e) {
|
||||
e->edit_cancel ();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
Editables::show_properties (QWidget *parent)
|
||||
Editables::show_properties ()
|
||||
{
|
||||
if (! has_selection ()) {
|
||||
// try to use the transient selection for the real one
|
||||
transient_to_selection ();
|
||||
}
|
||||
|
||||
// re-create a new properties dialog
|
||||
if (mp_properties_dialog) {
|
||||
delete mp_properties_dialog;
|
||||
}
|
||||
mp_properties_dialog = new lay::PropertiesDialog (parent, manager (), this);
|
||||
mp_properties_dialog->show ();
|
||||
// The default implementation does nothing
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ namespace lay
|
|||
class Editables;
|
||||
#if defined(HAVE_QT)
|
||||
class PropertiesPage;
|
||||
class PropertiesDialog;
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
@ -590,12 +589,10 @@ public:
|
|||
return m_editables.end ();
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief The "show properties" operation
|
||||
*/
|
||||
void show_properties (QWidget *parent);
|
||||
#endif
|
||||
virtual void show_properties ();
|
||||
|
||||
/**
|
||||
* @brief An event triggered if the selection changed
|
||||
|
|
@ -651,9 +648,6 @@ private:
|
|||
|
||||
tl::shared_collection<lay::Editable> m_editables;
|
||||
std::set<lay::Editable *> m_enabled;
|
||||
#if defined(HAVE_QT)
|
||||
lay::PropertiesDialog *mp_properties_dialog;
|
||||
#endif
|
||||
bool m_move_selection;
|
||||
bool m_any_move_operation;
|
||||
db::DBox m_last_selected_point;
|
||||
|
|
|
|||
|
|
@ -291,27 +291,6 @@ LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view)
|
|||
m_do_end_of_drawing_dm (this, &LayoutCanvas::do_end_of_drawing),
|
||||
m_image_cache_size (1)
|
||||
{
|
||||
tl::Color bg (0xffffffff), fg (0xff000000), active (0xffc0c0c0);
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
if (widget ()) {
|
||||
|
||||
#if QT_VERSION > 0x050000
|
||||
m_dpr = widget ()->devicePixelRatio ();
|
||||
#endif
|
||||
|
||||
widget ()->setObjectName (QString::fromUtf8 ("canvas"));
|
||||
widget ()->setBackgroundRole (QPalette::NoRole);
|
||||
|
||||
bg = tl::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Window).rgb ());
|
||||
fg = tl::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Text).rgb ());
|
||||
active = tl::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Mid).rgb ());
|
||||
|
||||
widget ()->setAttribute (Qt::WA_NoSystemBackground);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// The gamma value used for subsampling: something between 1.8 and 2.2.
|
||||
m_gamma = 2.0;
|
||||
|
||||
|
|
@ -321,6 +300,7 @@ LayoutCanvas::LayoutCanvas (lay::LayoutViewBase *view)
|
|||
|
||||
mp_redraw_thread = new lay::RedrawThread (this, view);
|
||||
|
||||
tl::Color bg (0xffffffff), fg (0xff000000), active (0xffc0c0c0);
|
||||
set_colors (bg, fg, active);
|
||||
}
|
||||
|
||||
|
|
@ -349,6 +329,32 @@ LayoutCanvas::~LayoutCanvas ()
|
|||
clear_fg_bitmaps ();
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
void
|
||||
LayoutCanvas::init_ui (QWidget *parent)
|
||||
{
|
||||
lay::ViewObjectUI::init_ui (parent);
|
||||
|
||||
if (widget ()) {
|
||||
|
||||
#if QT_VERSION > 0x050000
|
||||
m_dpr = widget ()->devicePixelRatio ();
|
||||
#endif
|
||||
|
||||
widget ()->setObjectName (QString::fromUtf8 ("canvas"));
|
||||
widget ()->setBackgroundRole (QPalette::NoRole);
|
||||
|
||||
tl::Color bg = tl::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Window).rgb ());
|
||||
tl::Color fg = tl::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Text).rgb ());
|
||||
tl::Color active = tl::Color (widget ()->palette ().color (QPalette::Normal, QPalette::Mid).rgb ());
|
||||
set_colors (bg, fg, active);
|
||||
|
||||
widget ()->setAttribute (Qt::WA_NoSystemBackground);
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
LayoutCanvas::key_event (unsigned int key, unsigned int buttons)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -143,6 +143,15 @@ public:
|
|||
LayoutCanvas (lay::LayoutViewBase *view);
|
||||
~LayoutCanvas ();
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Initializes the widgets
|
||||
*
|
||||
* This method needs to be called after the constructor to establish the drawing widget.
|
||||
*/
|
||||
virtual void init_ui (QWidget *parent);
|
||||
#endif
|
||||
|
||||
void set_colors (tl::Color background, tl::Color foreground, tl::Color active);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -413,15 +413,7 @@ LayoutViewBase::finish ()
|
|||
{
|
||||
// if we're the root dispatcher initialize the menu and build the context menus. No other menus are built so far.
|
||||
if (dispatcher () == this) {
|
||||
#if defined(HAVE_QT)
|
||||
set_menu_parent_widget (widget ());
|
||||
init_menu ();
|
||||
if (widget ()) {
|
||||
menu ()->build (0, 0);
|
||||
}
|
||||
#else
|
||||
init_menu ();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -514,6 +506,16 @@ LayoutViewBase::~LayoutViewBase ()
|
|||
mp_canvas = 0;
|
||||
}
|
||||
|
||||
void LayoutViewBase::unregister_plugin (lay::Plugin *pi)
|
||||
{
|
||||
for (std::vector<lay::Plugin *>::iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
|
||||
if (pi == *p) {
|
||||
mp_plugins.erase (p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutViewBase::resize (unsigned int width, unsigned int height)
|
||||
{
|
||||
mp_canvas->resize (width, height);
|
||||
|
|
@ -3447,14 +3449,6 @@ LayoutViewBase::box () const
|
|||
return mp_canvas->viewport ().box ();
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
QWidget *
|
||||
LayoutViewBase::widget ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
LayoutView *
|
||||
LayoutViewBase::get_ui ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ public:
|
|||
LV_NoTracker = 512,
|
||||
LV_NoSelection = 1024,
|
||||
LV_NoPlugins = 2048,
|
||||
LV_NoPropertiesPopup = 4096,
|
||||
LV_NoServices = LV_NoMove + LV_NoTracker + LV_NoSelection + LV_NoPlugins
|
||||
};
|
||||
|
||||
|
|
@ -1662,10 +1663,6 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Gets the canvas object (where the layout is drawn and view objects are placed)
|
||||
*
|
||||
* This method intentionally delivers the ViewObjectWidget, not the
|
||||
* LayoutCanvas to emphasize that the LayoutCanvas object shall not
|
||||
* be modified.
|
||||
*/
|
||||
lay::LayoutCanvas *canvas ()
|
||||
{
|
||||
|
|
@ -1690,7 +1687,7 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the hierarchy panel
|
||||
* @brief Gets the editor options page
|
||||
*/
|
||||
virtual lay::EditorOptionsPages *editor_options_pages ()
|
||||
{
|
||||
|
|
@ -1863,9 +1860,6 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Get the Drawings interface
|
||||
*
|
||||
* Although the Drawings interface is implemented by LayoutCanvas,
|
||||
* it is a different interface from ViewObjectWidget.
|
||||
*/
|
||||
lay::Drawings *drawings ()
|
||||
{
|
||||
|
|
@ -2647,13 +2641,6 @@ public:
|
|||
|
||||
virtual void deactivate_all_browsers ();
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
/**
|
||||
* @brief Gets the QWidget interface
|
||||
*/
|
||||
virtual QWidget *widget ();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Gets the LayoutView interface
|
||||
*/
|
||||
|
|
@ -2670,6 +2657,19 @@ public:
|
|||
return const_cast<LayoutViewBase *> (this)->get_ui ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unregisters the given plugin
|
||||
*/
|
||||
void unregister_plugin (lay::Plugin *pi);
|
||||
|
||||
/**
|
||||
* @brief Gets the options the view was created with
|
||||
*/
|
||||
unsigned int options () const
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
|
||||
private:
|
||||
// event handlers used to connect to the layout object's events
|
||||
void signal_hier_changed ();
|
||||
|
|
@ -2837,11 +2837,6 @@ private:
|
|||
void merge_dither_pattern (lay::LayerPropertiesList &props);
|
||||
|
||||
protected:
|
||||
unsigned int options () const
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
|
||||
lay::Plugin *active_plugin () const
|
||||
{
|
||||
return mp_active_plugin;
|
||||
|
|
@ -2861,9 +2856,9 @@ protected:
|
|||
|
||||
void free_resources ();
|
||||
void shutdown ();
|
||||
void finish ();
|
||||
void init_menu ();
|
||||
|
||||
virtual void finish ();
|
||||
virtual tl::Color default_background_color ();
|
||||
virtual void do_set_background_color (tl::Color color, tl::Color contrast);
|
||||
virtual void do_paste ();
|
||||
|
|
|
|||
|
|
@ -324,7 +324,9 @@ Plugin::Plugin (Plugin *parent, bool standalone)
|
|||
|
||||
Plugin::~Plugin ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
if (mp_parent) {
|
||||
mp_parent->unregister_plugin (this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -695,6 +695,14 @@ public:
|
|||
*/
|
||||
Dispatcher *dispatcher ();
|
||||
|
||||
/**
|
||||
* @brief Notifies the plugin that a child plugin got deleted
|
||||
*/
|
||||
virtual void unregister_plugin (lay::Plugin * /*plugin*/)
|
||||
{
|
||||
// .. this implementation does nothing ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Menu command handler
|
||||
*
|
||||
|
|
@ -777,6 +785,14 @@ public:
|
|||
return mp_plugin_declaration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the plugin parent
|
||||
*/
|
||||
Plugin *plugin_parent ()
|
||||
{
|
||||
return mp_parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Associate a service with the plugin declaration for that service (setter)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#if defined(HAVE_QT)
|
||||
# include <QMessageBox>
|
||||
# include <QApplication>
|
||||
#endif
|
||||
|
||||
namespace lay
|
||||
|
|
@ -185,12 +184,10 @@ SelectionService::mouse_double_click_event (const db::DPoint & /*p*/, unsigned i
|
|||
reset_box ();
|
||||
}
|
||||
|
||||
#if defined(HAVE_QT)
|
||||
if (prio && (buttons & lay::LeftButton) != 0) {
|
||||
mp_view->show_properties (QApplication::activeWindow ());
|
||||
mp_view->show_properties ();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,8 +216,8 @@ ViewService::set_cursor (lay::Cursor::cursor_shape cursor)
|
|||
class ViewObjectQWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
ViewObjectQWidget (ViewObjectUI *view)
|
||||
: QWidget (), mp_view (view)
|
||||
ViewObjectQWidget (QWidget *parent, ViewObjectUI *view)
|
||||
: QWidget (parent), mp_view (view)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -529,7 +529,7 @@ ViewObjectUI::init_ui (QWidget *parent)
|
|||
tl_assert (parent != 0);
|
||||
tl_assert (mp_widget == 0);
|
||||
|
||||
mp_widget = new ViewObjectQWidget (this);
|
||||
mp_widget = new ViewObjectQWidget (parent, this);
|
||||
mp_widget->setMouseTracking (true);
|
||||
mp_widget->setAcceptDrops (true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -597,7 +597,7 @@ public:
|
|||
/**
|
||||
* @brief Initializes the UI components
|
||||
*/
|
||||
void init_ui (QWidget *parent);
|
||||
virtual void init_ui (QWidget *parent);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -9,12 +9,10 @@ DEFINES += MAKE_LAYBASIC_LIBRARY
|
|||
!equals(HAVE_QT, 0) {
|
||||
|
||||
FORMS = \
|
||||
PropertiesDialog.ui \
|
||||
|
||||
SOURCES = \
|
||||
gtf.cc \
|
||||
layPluginConfigPage.cc \
|
||||
layPropertiesDialog.cc \
|
||||
layProperties.cc \
|
||||
layDragDropData.cc \
|
||||
layCursor.cc \
|
||||
|
|
@ -22,7 +20,6 @@ DEFINES += MAKE_LAYBASIC_LIBRARY
|
|||
HEADERS = \
|
||||
gtf.h \
|
||||
layPluginConfigPage.h \
|
||||
layPropertiesDialog.h \
|
||||
layProperties.h \
|
||||
layDragDropData.h \
|
||||
layCursor.h \
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#if defined(HAVE_QT)
|
||||
|
||||
#include <QDialog>
|
||||
#include <QApplication>
|
||||
|
||||
#include "layBrowser.h"
|
||||
#include "layLayoutViewBase.h"
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ struct CurrentStyleOp
|
|||
int prev_index, new_index;
|
||||
};
|
||||
|
||||
EditLineStylesForm::EditLineStylesForm (lay::LayoutViewBase *view, const lay::LineStyles &styles)
|
||||
: QDialog (view->widget ()), db::Object (0),
|
||||
EditLineStylesForm::EditLineStylesForm (QWidget *parent, lay::LayoutViewBase *view, const lay::LineStyles &styles)
|
||||
: QDialog (parent), db::Object (0),
|
||||
m_selected (-1), m_styles (styles), m_manager (true), mp_view (view)
|
||||
{
|
||||
m_selection_changed_enabled = false;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class EditLineStylesForm
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditLineStylesForm (lay::LayoutViewBase *view, const lay::LineStyles &styles);
|
||||
EditLineStylesForm (QWidget *parent, lay::LayoutViewBase *view, const lay::LineStyles &styles);
|
||||
~EditLineStylesForm ();
|
||||
|
||||
// ...
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ struct CurrentPatternOp
|
|||
int prev_index, new_index;
|
||||
};
|
||||
|
||||
EditStipplesForm::EditStipplesForm (lay::LayoutViewBase *view, const lay::DitherPattern &pattern)
|
||||
: QDialog (view->widget ()), db::Object (0),
|
||||
EditStipplesForm::EditStipplesForm (QWidget *parent, lay::LayoutViewBase *view, const lay::DitherPattern &pattern)
|
||||
: QDialog (parent), db::Object (0),
|
||||
m_selected (-1), m_pattern (pattern), m_manager (true), mp_view (view)
|
||||
{
|
||||
m_selection_changed_enabled = false;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class EditStipplesForm
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditStipplesForm (lay::LayoutViewBase *view, const lay::DitherPattern &pattern);
|
||||
EditStipplesForm (QWidget *parent, lay::LayoutViewBase *view, const lay::DitherPattern &pattern);
|
||||
~EditStipplesForm ();
|
||||
|
||||
// ...
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ LCPDitherPalette::button_clicked (int index)
|
|||
|
||||
// edit pattern
|
||||
lay::DitherPattern pattern (mp_view->dither_pattern ());
|
||||
lay::EditStipplesForm stipples_form (mp_view, pattern);
|
||||
lay::EditStipplesForm stipples_form (this, mp_view, pattern);
|
||||
if (stipples_form.exec () && stipples_form.pattern () != pattern) {
|
||||
emit pattern_changed (stipples_form.pattern ());
|
||||
}
|
||||
|
|
@ -686,7 +686,7 @@ LCPStylePalette::button_clicked (int index)
|
|||
|
||||
// edit pattern
|
||||
lay::LineStyles styles (mp_view->line_styles ());
|
||||
lay::EditLineStylesForm line_styles_form (mp_view, styles);
|
||||
lay::EditLineStylesForm line_styles_form (this, mp_view, styles);
|
||||
if (line_styles_form.exec () && line_styles_form.styles () != styles) {
|
||||
emit line_styles_changed (line_styles_form.styles ());
|
||||
}
|
||||
|
|
@ -1047,6 +1047,8 @@ LayerToolbox::panel_button_clicked (int index)
|
|||
int h = sizeHint ().height ();
|
||||
setMinimumHeight (h);
|
||||
setMaximumHeight (h);
|
||||
|
||||
updateGeometry ();
|
||||
}
|
||||
|
||||
template <class Op>
|
||||
|
|
@ -1108,10 +1110,10 @@ LayerToolbox::fill_color_changed (QColor c)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change fill color")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change fill color")));
|
||||
|
||||
SetColor op (c, 3 /*fill,frame and vertex*/);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1121,10 +1123,10 @@ LayerToolbox::frame_color_changed (QColor c)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change frame color")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change frame color")));
|
||||
|
||||
SetColor op (c, 1 /*frame and vertex*/);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetBrightness
|
||||
|
|
@ -1171,10 +1173,10 @@ LayerToolbox::fill_color_brightness (int delta)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change fill color brightness")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change fill color brightness")));
|
||||
|
||||
SetBrightness op (delta, 3 /*fill,frame and vertex*/);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1184,10 +1186,10 @@ LayerToolbox::frame_color_brightness (int delta)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change frame color brightness")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change frame color brightness")));
|
||||
|
||||
SetBrightness op (delta, 1 /*frame and vertex*/);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetDither
|
||||
|
|
@ -1216,9 +1218,8 @@ LayerToolbox::line_styles_changed (const lay::LineStyles &styles)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Edit line styles")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Edit line styles")));
|
||||
mp_view->set_line_styles (styles);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1228,9 +1229,8 @@ LayerToolbox::dither_pattern_changed (const lay::DitherPattern &pattern)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Edit stipple pattern")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Edit stipple pattern")));
|
||||
mp_view->set_dither_pattern (pattern);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1240,10 +1240,10 @@ LayerToolbox::dither_changed (int di)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Set stipple pattern")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Set stipple pattern")));
|
||||
|
||||
SetDither op (di);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetVisible
|
||||
|
|
@ -1268,15 +1268,10 @@ LayerToolbox::visibility_changed (bool visible)
|
|||
return;
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Show layer")));
|
||||
} else {
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Hide layer")));
|
||||
}
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (visible ? QObject::tr ("Show layer") : QObject::tr ("Hide layer")));
|
||||
|
||||
SetVisible op (visible);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetTransparency
|
||||
|
|
@ -1301,10 +1296,10 @@ LayerToolbox::transparency_changed (bool transparent)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change transparency")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change transparency")));
|
||||
|
||||
SetTransparency op (transparent);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetAnimation
|
||||
|
|
@ -1329,10 +1324,10 @@ LayerToolbox::animation_changed (int mode)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change animation mode")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change animation mode")));
|
||||
|
||||
SetAnimation op (mode);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetWidth
|
||||
|
|
@ -1357,10 +1352,10 @@ LayerToolbox::width_changed (int width)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change line width")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change line width")));
|
||||
|
||||
SetWidth op (width);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetXFill
|
||||
|
|
@ -1385,10 +1380,10 @@ LayerToolbox::xfill_changed (bool xf)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change cross fill")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change cross fill")));
|
||||
|
||||
SetXFill op (xf);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetLineStyle
|
||||
|
|
@ -1413,10 +1408,10 @@ LayerToolbox::line_style_changed (int ls)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change line style")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change line style")));
|
||||
|
||||
SetLineStyle op (ls);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
struct SetMarked
|
||||
|
|
@ -1441,10 +1436,10 @@ LayerToolbox::marked_changed (bool marked)
|
|||
return;
|
||||
}
|
||||
|
||||
mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Change marked vertices")));
|
||||
db::Transaction tr (mp_view->manager (), tl::to_string (QObject::tr ("Change marked vertices")));
|
||||
|
||||
SetMarked op (marked);
|
||||
foreach_selected (op);
|
||||
mp_view->manager ()->commit ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -181,7 +181,8 @@ EmptyWithinViewCache::determine_empty_layers (const db::Layout *layout, unsigned
|
|||
|
||||
LayerTreeModel::LayerTreeModel (QWidget *parent, lay::LayoutViewBase *view)
|
||||
: QAbstractItemModel (parent),
|
||||
mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0), m_phase ((unsigned int) -1), m_test_shapes_in_view (false), m_hide_empty_layers (false)
|
||||
mp_parent (parent), mp_view (view), m_filter_mode (false), m_id_start (0), m_id_end (0),
|
||||
m_phase ((unsigned int) -1), m_test_shapes_in_view (false), m_hide_empty_layers (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -849,9 +850,9 @@ LayerTreeModel::data (const QModelIndex &index, int role) const
|
|||
|
||||
} else if (role == Qt::BackgroundRole) {
|
||||
|
||||
if (m_selected_ids.find (size_t (index.internalPointer ())) != m_selected_ids.end ()) {
|
||||
if (mp_parent && m_selected_ids.find (size_t (index.internalPointer ())) != m_selected_ids.end ()) {
|
||||
// for selected items pick a color between Highlight and Base
|
||||
QPalette pl (mp_view->widget ()->palette ());
|
||||
QPalette pl (mp_parent->palette ());
|
||||
QColor c1 = pl.color (QPalette::Highlight);
|
||||
QColor cb = pl.color (QPalette::Base);
|
||||
return QVariant (QColor ((c1.red () + cb.red ()) / 2, (c1.green () + cb.green ()) / 2, (c1.blue () + cb.blue ()) / 2));
|
||||
|
|
|
|||
|
|
@ -251,6 +251,7 @@ signals:
|
|||
void hidden_flags_need_update ();
|
||||
|
||||
private:
|
||||
QWidget *mp_parent;
|
||||
lay::LayoutViewBase *mp_view;
|
||||
bool m_filter_mode;
|
||||
size_t m_id_start, m_id_end;
|
||||
|
|
|
|||
|
|
@ -41,10 +41,20 @@
|
|||
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Gets a suitable parent widget for the modal dialogs used in this module
|
||||
*/
|
||||
static QWidget *parent_widget ()
|
||||
{
|
||||
return QApplication::activeWindow ();
|
||||
}
|
||||
|
||||
static void
|
||||
collect_cells_to_delete (const db::Layout &layout, const db::Cell &cell, std::set<db::cell_index_type> &called)
|
||||
{
|
||||
|
|
@ -113,7 +123,7 @@ LayoutViewFunctions::menu_activated (const std::string &symbol)
|
|||
|
||||
if (symbol == "cm_show_properties") {
|
||||
|
||||
view ()->show_properties (view ()->widget ());
|
||||
view ()->show_properties ();
|
||||
|
||||
} else if (symbol == "cm_delete") {
|
||||
|
||||
|
|
@ -306,10 +316,10 @@ LayoutViewFunctions::menu_activated (const std::string &symbol)
|
|||
cm_new_layer ();
|
||||
}
|
||||
} else if (symbol == "cm_layout_props") {
|
||||
lay::LayoutPropertiesForm lp_form (view ()->widget (), view (), "layout_props_form");
|
||||
lay::LayoutPropertiesForm lp_form (parent_widget (), view (), "layout_props_form");
|
||||
lp_form.exec ();
|
||||
} else if (symbol == "cm_layout_stats") {
|
||||
lay::LayoutStatisticsForm lp_form (view ()->widget (), view (), "layout_props_form");
|
||||
lay::LayoutStatisticsForm lp_form (parent_widget (), view (), "layout_props_form");
|
||||
lp_form.exec ();
|
||||
} else if (symbol == "cm_reload") {
|
||||
cm_reload ();
|
||||
|
|
@ -429,7 +439,7 @@ LayoutViewFunctions::cm_cell_user_properties ()
|
|||
db::Cell &cell = layout.cell (path.back ());
|
||||
db::properties_id_type prop_id = cell.prop_id ();
|
||||
|
||||
lay::UserPropertiesForm props_form (view ()->widget ());
|
||||
lay::UserPropertiesForm props_form (parent_widget ());
|
||||
if (props_form.show (view (), cv_index, prop_id)) {
|
||||
|
||||
view ()->transaction (tl::to_string (tr ("Edit cell's user properties")));
|
||||
|
|
@ -464,7 +474,7 @@ LayoutViewFunctions::cm_cell_replace ()
|
|||
}
|
||||
|
||||
|
||||
lay::ReplaceCellOptionsDialog mode_dialog (view ()->widget ());
|
||||
lay::ReplaceCellOptionsDialog mode_dialog (parent_widget ());
|
||||
|
||||
db::cell_index_type with_cell = paths.front ().back ();
|
||||
int mode = needs_to_ask ? m_del_cell_mode : 0;
|
||||
|
|
@ -652,7 +662,7 @@ LayoutViewFunctions::cm_cell_delete ()
|
|||
mode = 0;
|
||||
}
|
||||
|
||||
lay::DeleteCellModeDialog mode_dialog (view ()->widget ());
|
||||
lay::DeleteCellModeDialog mode_dialog (parent_widget ());
|
||||
if (! needs_to_ask || mode_dialog.exec_dialog (mode)) {
|
||||
|
||||
if (needs_to_ask) {
|
||||
|
|
@ -775,7 +785,7 @@ LayoutViewFunctions::cm_cell_flatten ()
|
|||
}
|
||||
}
|
||||
|
||||
FlattenInstOptionsDialog options_dialog (view ()->widget ());
|
||||
FlattenInstOptionsDialog options_dialog (parent_widget ());
|
||||
|
||||
int flatten_insts_levels = -1;
|
||||
bool prune = true;
|
||||
|
|
@ -857,7 +867,7 @@ LayoutViewFunctions::cm_cell_rename ()
|
|||
|
||||
if (cv_index >= 0 && path.size () > 0) {
|
||||
|
||||
lay::RenameCellDialog name_dialog (view ()->widget ());
|
||||
lay::RenameCellDialog name_dialog (parent_widget ());
|
||||
|
||||
db::Layout &layout = view ()->cellview (cv_index)->layout ();
|
||||
std::string name (layout.cell_name (path.back ()));
|
||||
|
|
@ -1207,7 +1217,7 @@ LayoutViewFunctions::cm_new_cell ()
|
|||
static double s_new_cell_window_size = 2.0;
|
||||
static std::string s_new_cell_cell_name;
|
||||
|
||||
NewCellPropertiesDialog cell_prop_dia (view ()->widget ());
|
||||
NewCellPropertiesDialog cell_prop_dia (parent_widget ());
|
||||
if (cell_prop_dia.exec_dialog (& cv->layout (), s_new_cell_cell_name, s_new_cell_window_size)) {
|
||||
|
||||
db::cell_index_type new_ci = view ()->new_cell (view ()->active_cellview_index (), s_new_cell_cell_name.c_str ());
|
||||
|
|
@ -1270,7 +1280,7 @@ LayoutViewFunctions::cm_reload ()
|
|||
bool can_reload = true;
|
||||
if (dirty_layouts != 0) {
|
||||
|
||||
QMessageBox mbox (view ()->widget ());
|
||||
QMessageBox mbox (parent_widget ());
|
||||
mbox.setText (tl::to_qstring (tl::to_string (tr ("The following layouts need saving:\n\n")) + dirty_files + "\n\nPress 'Reload Without Saving' to reload anyhow and discard changes."));
|
||||
mbox.setWindowTitle (tr ("Save Needed"));
|
||||
mbox.setIcon (QMessageBox::Warning);
|
||||
|
|
@ -1323,7 +1333,7 @@ LayoutViewFunctions::transform_layout (const db::DCplxTrans &tr_mic)
|
|||
}
|
||||
|
||||
if (has_proxy &&
|
||||
QMessageBox::question (view ()->widget (),
|
||||
QMessageBox::question (parent_widget (),
|
||||
tr ("Transforming PCells Or Library Cells"),
|
||||
tr ("The layout contains PCells or library cells or both.\n"
|
||||
"Any changes to such cells may be lost when their layout is refreshed later.\n"
|
||||
|
|
@ -1410,7 +1420,7 @@ LayoutViewFunctions::cm_lay_scale ()
|
|||
void
|
||||
LayoutViewFunctions::cm_lay_move ()
|
||||
{
|
||||
lay::MoveOptionsDialog options (view ()->widget ());
|
||||
lay::MoveOptionsDialog options (parent_widget ());
|
||||
if (options.exec_dialog (m_move_dist)) {
|
||||
transform_layout (db::DCplxTrans (m_move_dist));
|
||||
}
|
||||
|
|
@ -1530,7 +1540,7 @@ LayoutViewFunctions::cm_sel_move_to ()
|
|||
double y = sel_bbox.bottom () + (sel_bbox.height () * (1 + m_move_to_origin_mode_y) * 0.5);
|
||||
db::DPoint move_target (x, y);
|
||||
|
||||
lay::MoveToOptionsDialog options (view ()->widget ());
|
||||
lay::MoveToOptionsDialog options (parent_widget ());
|
||||
if (options.exec_dialog (m_move_to_origin_mode_x, m_move_to_origin_mode_y, move_target)) {
|
||||
|
||||
x = sel_bbox.left () + (sel_bbox.width () * (1 + m_move_to_origin_mode_x) * 0.5);
|
||||
|
|
@ -1544,7 +1554,7 @@ LayoutViewFunctions::cm_sel_move_to ()
|
|||
void
|
||||
LayoutViewFunctions::cm_sel_move ()
|
||||
{
|
||||
lay::MoveOptionsDialog options (view ()->widget ());
|
||||
lay::MoveOptionsDialog options (parent_widget ());
|
||||
if (options.exec_dialog (m_move_dist)) {
|
||||
do_transform (db::DCplxTrans (m_move_dist));
|
||||
}
|
||||
|
|
@ -1578,7 +1588,7 @@ LayoutViewFunctions::cm_copy_layer ()
|
|||
|
||||
}
|
||||
|
||||
lay::DuplicateLayerDialog dialog (view ()->widget ());
|
||||
lay::DuplicateLayerDialog dialog (parent_widget ());
|
||||
if (dialog.exec_dialog (view (), m_copy_cva, m_copy_layera, m_copy_cvr, m_copy_layerr, m_duplicate_hier_mode, m_clear_before)) {
|
||||
|
||||
bool supports_undo = true;
|
||||
|
|
@ -1738,7 +1748,7 @@ LayoutViewFunctions::cm_new_layer ()
|
|||
|
||||
const lay::CellView &cv = view ()->cellview (index);
|
||||
|
||||
lay::NewLayerPropertiesDialog prop_dia (view ()->widget ());
|
||||
lay::NewLayerPropertiesDialog prop_dia (parent_widget ());
|
||||
if (prop_dia.exec_dialog (cv, m_new_layer_props)) {
|
||||
|
||||
for (unsigned int l = 0; l < cv->layout ().layers (); ++l) {
|
||||
|
|
@ -1776,7 +1786,7 @@ LayoutViewFunctions::cm_align_cell_origin ()
|
|||
throw tl::Exception (tl::to_string (tr ("Cannot use this function on a PCell or library cell")));
|
||||
}
|
||||
|
||||
lay::AlignCellOptionsDialog dialog (view ()->widget ());
|
||||
lay::AlignCellOptionsDialog dialog (parent_widget ());
|
||||
if (dialog.exec_dialog (m_align_cell_options)) {
|
||||
|
||||
view ()->clear_selection ();
|
||||
|
|
@ -1877,7 +1887,7 @@ LayoutViewFunctions::cm_edit_layer ()
|
|||
db::LayerProperties layer_props = layout.get_properties ((unsigned int) sel->layer_index ());
|
||||
db::LayerProperties old_props = layer_props;
|
||||
|
||||
lay::NewLayerPropertiesDialog prop_dia (view ()->widget ());
|
||||
lay::NewLayerPropertiesDialog prop_dia (parent_widget ());
|
||||
if (prop_dia.exec_dialog (cv, layer_props)) {
|
||||
|
||||
for (unsigned int l = 0; l < layout.layers (); ++l) {
|
||||
|
|
@ -2020,7 +2030,7 @@ LayoutViewFunctions::cm_clear_layer ()
|
|||
throw tl::Exception (tl::to_string (tr ("No layer selected for clearing")));
|
||||
}
|
||||
|
||||
lay::ClearLayerModeDialog mode_dialog (view ()->widget ());
|
||||
lay::ClearLayerModeDialog mode_dialog (parent_widget ());
|
||||
if (mode_dialog.exec_dialog (m_layer_hier_mode)) {
|
||||
|
||||
view ()->cancel_edits ();
|
||||
|
|
|
|||