Merge pull request #1147 from KLayout/wip

Wip
This commit is contained in:
Matthias Köfferlein 2022-09-04 09:08:08 +02:00 committed by GitHub
commit 7a9e9989d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
144 changed files with 47108 additions and 1554 deletions

View File

@ -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

View File

@ -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))

View File

@ -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])

View File

@ -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

View File

@ -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 &region, 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 *

View File

@ -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 &region) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, 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 &region, EdgeInteractionMode mode, bool inverse) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, 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;
};
}

View File

@ -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;

View File

@ -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 &region) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, 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 &region, EdgeInteractionMode mode, bool inverse) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode) const;
DeepEdges *apply_filter (const EdgeFilterBase &filter) const;
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;

View File

@ -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;
};
}

View File

@ -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 ());

View File

@ -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;
};

View File

@ -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
*

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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 (); }

View File

@ -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; }

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}
}
// -----------------------------------------------------------------------------------------------

View File

@ -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

View File

@ -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

View File

@ -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
*

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
};
/**

View File

@ -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"

View File

@ -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"
);

View File

@ -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
);
}

View File

@ -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"),

View File

@ -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"
) +

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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);
}

View File

@ -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

View File

@ -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)
{

View File

@ -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);
}

View File

@ -71,6 +71,7 @@ SOURCES = \
dbEdgePairRelationsTests.cc \
dbEdgePairTests.cc \
dbEdgeTests.cc \
dbEdgesUtilsTests.cc \
dbClipTests.cc \
dbCellMappingTests.cc \
dbCellHullGeneratorTests.cc \

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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",
);
}

View File

@ -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

View File

@ -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;
};

View File

@ -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>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-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';&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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 &gt;&gt; </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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -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 \

View File

@ -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;

View File

@ -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)

View File

@ -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;
};
}

View File

@ -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>

View 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)
{

View File

@ -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:

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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 ();
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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

View File

@ -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 ());
}

View File

@ -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;
};

View File

@ -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"

View File

@ -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"

View File

@ -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);

View File

@ -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;

View File

@ -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
}

View File

@ -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;

View File

@ -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)
{

View File

@ -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);
/**

View File

@ -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 ()
{

View File

@ -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 ();

View File

@ -324,7 +324,9 @@ Plugin::Plugin (Plugin *parent, bool standalone)
Plugin::~Plugin ()
{
// .. nothing yet ..
if (mp_parent) {
mp_parent->unregister_plugin (this);
}
}
void

View File

@ -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)
*

View File

@ -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;
}

View File

@ -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);
}

View File

@ -597,7 +597,7 @@ public:
/**
* @brief Initializes the UI components
*/
void init_ui (QWidget *parent);
virtual void init_ui (QWidget *parent);
#endif
/**

View File

@ -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 \

View File

@ -23,6 +23,7 @@
#if defined(HAVE_QT)
#include <QDialog>
#include <QApplication>
#include "layBrowser.h"
#include "layLayoutViewBase.h"

View File

@ -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;

View File

@ -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 ();
// ...

View File

@ -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;

View File

@ -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 ();
// ...

View File

@ -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

View File

@ -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));

View File

@ -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;

View File

@ -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 ();

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