Merge branch 'master' into 1598-support-for-soft-connections

This commit is contained in:
Matthias Koefferlein 2024-03-29 09:00:17 +01:00
commit 6ac1c32a8d
169 changed files with 6696 additions and 1753 deletions

View File

@ -1,3 +1,6 @@
0.29.0 (2024-04-01):
* TODO
0.28.17 (2024-02-16):
* Enhancement: %GITHUB%/issues/1626 Technology specific grids

View File

@ -1,3 +1,10 @@
klayout (0.29.0-1) unstable; urgency=low
* New features and bugfixes
- See changelog
-- Matthias Köfferlein <matthias@koefferlein.de> Fri, 01 Apr 2024 12:00:00 +0100
klayout (0.28.17-1) unstable; urgency=low
* New features and bugfixes

View File

@ -32,6 +32,9 @@ jobs:
cp311-cp311-win_amd64.whl:
python.version: '3.11'
python.architecture: 'x64'
cp312-cp312-win_amd64.whl:
python.version: '3.12'
python.architecture: 'x64'
cp36-cp36m-win32.whl:
python.version: '3.6'
python.architecture: 'x86'
@ -50,6 +53,9 @@ jobs:
cp311-cp311-win32.whl:
python.version: '3.11'
python.architecture: 'x86'
cp312-cp312-win32.whl:
python.version: '3.12'
python.architecture: 'x86'
maxParallel: 6
steps:
@ -130,6 +136,11 @@ jobs:
vmImage: 'windows-2019' # other options: 'macOS-10.13', 'ubuntu-16.04'
steps:
- checkout: none #skip checking out the default repository resource
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.12.x64'
inputs:
artifactName: 'wheel-3.12.x64'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.11.x64'
inputs:
@ -160,6 +171,11 @@ jobs:
inputs:
artifactName: 'wheel-3.6.x64'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.12.x86'
inputs:
artifactName: 'wheel-3.12.x86'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.11.x86'
inputs:

View File

@ -606,6 +606,35 @@ run_demo gen, "input.edges.with_length(0, 3.5)\n .extended(:out => 1.0)", "drc
run_demo gen, "input.edges.with_length(0, 3.5)\n .extended(:out => 1.0, :joined => true)", "drc_extended3.png"
run_demo gen, "input.edges.with_length(2.0)\n .extended(0.0, -0.5, 1.0, -0.5)", "drc_extended4.png"
class Gen
def produce(s1, s2)
pts = [
RBA::Point::new(1000, 0),
RBA::Point::new(1000, 5000),
RBA::Point::new(2000, 5000),
RBA::Point::new(2000, 7000),
RBA::Point::new(4000, 7000),
RBA::Point::new(4000, 5000),
RBA::Point::new(5000, 5000),
RBA::Point::new(5000, 0),
RBA::Point::new(4000, 0),
RBA::Point::new(4000, 1000),
RBA::Point::new(2000, 1000),
RBA::Point::new(2000, 0)
];
s1.insert(RBA::Polygon::new(pts))
end
end
gen = Gen::new
run_demo gen, "input.edges", "drc_edge_modes1.png"
run_demo gen, "input.edges(convex)", "drc_edge_modes2.png"
run_demo gen, "input.edges(concave)", "drc_edge_modes3.png"
run_demo gen, "input.edges(step)", "drc_edge_modes4.png"
run_demo gen, "input.edges(step_in)", "drc_edge_modes5.png"
run_demo gen, "input.edges(step_out)", "drc_edge_modes6.png"
class Gen
def produce(s1, s2)
pts = [

View File

@ -680,13 +680,17 @@ bool run_tiled_xor (const XORData &xor_data)
if (ll->second.first < 0) {
proc.input (in_a, db::RecursiveShapeIterator ());
} else {
proc.input (in_a, db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first));
db::RecursiveShapeIterator si (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first);
si.set_for_merged_input (true);
proc.input (in_a, si);
}
if (ll->second.second < 0) {
proc.input (in_b, db::RecursiveShapeIterator ());
} else {
proc.input (in_b, db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second));
db::RecursiveShapeIterator si (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second);
si.set_for_merged_input (true);
proc.input (in_b, si);
}
std::string expr = "var x=" + in_a + "^" + in_b + "; ";
@ -805,10 +809,12 @@ bool run_deep_xor (const XORData &xor_data)
if (ll->second.first >= 0) {
ri_a = db::RecursiveShapeIterator (*xor_data.layout_a, xor_data.layout_a->cell (xor_data.cell_a), ll->second.first);
ri_a.set_for_merged_input (true);
}
if (ll->second.second >= 0) {
ri_b = db::RecursiveShapeIterator (*xor_data.layout_b, xor_data.layout_b->cell (xor_data.cell_b), ll->second.second);
ri_b.set_for_merged_input (true);
}
db::Region in_a (ri_a, dss, db::ICplxTrans (xor_data.layout_a->dbu () / dbu));

View File

@ -118,6 +118,12 @@ Optional, named parameters are
@li
@b:unit@/b: the unit string
@/li
@li
@b:min_value@/b: the minimum value (effective for numerical types and if no choices are present)
@/li
@li
@b:max_value@/b: the maximum value (effective for numerical types and if no choices are present)
@/li
@li
@b:default@/b: the default value
@/li
@ -335,6 +341,8 @@ module RBA
# :hidden -&gt; (boolean) true, if the parameter is not shown in the dialog
# :readonly -&gt; (boolean) true, if the parameter cannot be edited
# :unit -&gt; the unit string
# :min_value -&gt; the minimum value (only effective for numerical types and if no choices are present)
# :max_value -&gt; the maximum value (only effective for numerical types and if no choices are present)
# :default -&gt; the default value
# :choices -&gt; ([ [ d, v ], ...) choice descriptions/value for choice type
# this method defines accessor methods for the parameters
@ -373,6 +381,8 @@ module RBA
args[:hidden] &amp;&amp; pdecl.hidden = args[:hidden]
args[:readonly] &amp;&amp; pdecl.readonly = args[:readonly]
args[:unit] &amp;&amp; pdecl.unit = args[:unit]
args[:min_value] &amp;&amp; pdecl.min_value = args[:min_value]
args[:max_value] &amp;&amp; pdecl.max_value = args[:max_value]
if args[:choices]
if !args[:choices].is_a?(Array)
raise ":choices value must be an array of two-element arrays (description, value)"

View File

@ -127,6 +127,12 @@ Optional, named parameters are
@li
@bunit@/b: the unit string
@/li
@li
@bmin_value@/b: the minimum value (effective for numerical types and if no choices are present)
@/li
@li
@bmax_value@/b: the maximum value (effective for numerical types and if no choices are present)
@/li
@li
@bdefault@/b: the default value
@/li

View File

@ -28,6 +28,7 @@
#include "dbEmptyEdges.h"
#include "dbEdges.h"
#include "dbEdgesUtils.h"
#include "dbEdgesLocalOperations.h"
#include "dbEdgeBoolean.h"
#include "dbBoxConvert.h"
#include "dbRegion.h"
@ -39,6 +40,7 @@
#include "dbPolygonGenerators.h"
#include "dbPolygon.h"
#include "dbPath.h"
#include "dbHierProcessor.h"
#include <sstream>
@ -94,104 +96,105 @@ AsIfFlatEdges::to_string (size_t nmax) const
return os.str ();
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse) const
namespace {
class OutputPairHolder
{
// shortcuts
if (other.empty () || empty ()) {
return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone ();
}
public:
OutputPairHolder (int inverse, bool merged_semantics)
{
m_e1.reset (new FlatEdges (merged_semantics));
m_results.push_back (& m_e1->raw_edges ());
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
AddressableEdgeDelivery e (begin_merged ());
for ( ; ! e.at_end (); ++e) {
scanner.insert1 (e.operator-> (), 0);
}
AddressablePolygonDelivery p = (mode == EdgesInside ? other.addressable_merged_polygons () : other.addressable_polygons ());
for ( ; ! p.at_end (); ++p) {
scanner.insert2 (p.operator-> (), 1);
}
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
if (! inverse) {
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> 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 ()) {
output->insert (*o);
}
if (inverse == 0) {
m_e2.reset (new FlatEdges (merged_semantics));
m_results.push_back (& m_e2->raw_edges ());
}
}
return output.release ();
std::pair<EdgesDelegate *, EdgesDelegate *> region_pair ()
{
return std::make_pair (m_e1.release (), m_e2.release ());
}
const std::vector<db::Shapes *> &results () { return m_results; }
private:
std::unique_ptr<FlatEdges> m_e1, m_e2;
std::vector<db::Shapes *> m_results;
};
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const
AsIfFlatEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
// shortcuts
if (edges.empty () || empty ()) {
if (max_count < min_count || other.empty () || empty ()) {
return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone ();
}
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
OutputPairHolder oph (inverse ? 1 : -1, merged_semantics () || is_merged ());
AddressableEdgeDelivery e (begin_merged ());
db::EdgesIterator edges (begin_merged ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
db::edge_to_polygon_interacting_local_operation<db::Polygon> op (mode, inverse ? db::edge_to_polygon_interacting_local_operation<db::Polygon>::Inverse : db::edge_to_polygon_interacting_local_operation<db::Polygon>::Normal, min_count, max_count);
db::local_processor<db::Edge, db::Polygon, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
std::vector<generic_shape_iterator<db::Polygon> > others;
// NOTE: with counting the other region needs to be merged
others.push_back (counting || mode != EdgesInteract ? other.begin_merged () : other.begin ());
proc.run_flat (edges, others, std::vector<bool> (), &op, oph.results ());
return oph.region_pair ().first;
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
// shortcuts
if (max_count < min_count || other.empty () || empty ()) {
return ((mode == EdgesOutside) == inverse) ? new EmptyEdges () : clone ();
}
// 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 ());
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
OutputPairHolder oph (inverse ? 1 : -1, merged_semantics () || is_merged ());
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
db::EdgesIterator edges (begin_merged ());
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal, min_count, max_count);
if (! inverse) {
db::local_processor<db::Edge, db::Edge, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
edge_interaction_filter<FlatEdges> filter (*output, mode);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
std::vector<generic_shape_iterator<db::Edge> > others;
// NOTE: with counting the other edge collection needs to be merged
others.push_back (counting || mode != EdgesInteract ? other.begin_merged () : other.begin ());
} else {
proc.run_flat (edges, others, std::vector<bool> (), &op, oph.results ());
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 (result.find (*o) == result.end ()) {
output->insert (*o);
}
}
}
return output.release ();
return oph.region_pair ().first;
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode) const
AsIfFlatEdges::selected_interacting_pair_generic (const Region &other, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
// shortcuts
if (region.empty () || empty ()) {
if (max_count < min_count || other.empty () || empty ()) {
if (mode != EdgesOutside) {
return std::make_pair (new EmptyEdges (), clone ());
} else {
@ -199,43 +202,34 @@ AsIfFlatEdges::selected_interacting_pair_generic (const Region &region, EdgeInte
}
}
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
OutputPairHolder oph (0, merged_semantics () || is_merged ());
AddressableEdgeDelivery e (begin_merged ());
db::EdgesIterator edges (begin_merged ());
for ( ; ! e.at_end (); ++e) {
scanner.insert1 (e.operator-> (), 0);
}
db::edge_to_polygon_interacting_local_operation<db::Polygon> op (mode, db::edge_to_polygon_interacting_local_operation<db::Polygon>::Both, min_count, max_count);
AddressablePolygonDelivery p = region.addressable_merged_polygons ();
db::local_processor<db::Edge, db::Polygon, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
for ( ; ! p.at_end (); ++p) {
scanner.insert2 (p.operator-> (), 1);
}
std::vector<generic_shape_iterator<db::Polygon> > others;
// NOTE: with counting the other region needs to be merged
others.push_back (counting || mode != EdgesInteract ? other.begin_merged () : other.begin ());
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
std::unique_ptr<FlatEdges> output2 (new FlatEdges (true));
proc.run_flat (edges, others, std::vector<bool> (), &op, oph.results ());
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 ());
return oph.region_pair ();
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode) const
AsIfFlatEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
// shortcuts
if (other.empty () || empty ()) {
if (max_count < min_count || other.empty () || empty ()) {
if (mode != EdgesOutside) {
return std::make_pair (new EmptyEdges (), clone ());
} else {
@ -243,36 +237,25 @@ AsIfFlatEdges::selected_interacting_pair_generic (const Edges &other, EdgeIntera
}
}
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
OutputPairHolder oph (0, merged_semantics () || is_merged ());
AddressableEdgeDelivery e (begin_merged ());
db::EdgesIterator edges (begin_merged ());
for ( ; ! e.at_end (); ++e) {
scanner.insert (e.operator-> (), 0);
}
db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both, min_count, max_count);
AddressableEdgeDelivery ee = other.addressable_merged_edges ();
db::local_processor<db::Edge, db::Edge, db::Edge> proc;
proc.set_base_verbosity (base_verbosity ());
proc.set_description (progress_desc ());
proc.set_report_progress (report_progress ());
for ( ; ! ee.at_end (); ++ee) {
scanner.insert (ee.operator-> (), 1);
}
std::vector<generic_shape_iterator<db::Edge> > others;
// NOTE: with counting the other edge collection needs to be merged
others.push_back (counting || mode != EdgesInteract ? other.begin_merged () : other.begin ());
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
std::unique_ptr<FlatEdges> output2 (new FlatEdges (true));
proc.run_flat (edges, others, std::vector<bool> (), &op, oph.results ());
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 ());
return oph.region_pair ();
}
@ -294,7 +277,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const
}
std::unique_ptr<FlatEdges> output (new FlatEdges (true));
edge_interaction_filter<FlatEdges> filter (*output, EdgesInteract);
edge_interaction_filter<FlatEdges> filter (*output, EdgesInteract, size_t (1), std::numeric_limits<size_t>::max ());
scanner.process (filter, 1, db::box_convert<db::Edge> ());
return output.release ();
@ -324,7 +307,7 @@ AsIfFlatEdges::pull_generic (const Region &other) const
std::unique_ptr<FlatRegion> output (new FlatRegion (true));
edge_to_region_interaction_filter<FlatRegion> filter (output.get (), EdgesInteract);
edge_to_polygon_interaction_filter<FlatRegion> filter (output.get (), EdgesInteract, size_t (1), std::numeric_limits<size_t>::max ());
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
return output.release ();
@ -343,111 +326,111 @@ AsIfFlatEdges::pull_interacting (const Region &other) const
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Edges &other) const
AsIfFlatEdges::selected_interacting (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, EdgesInteract, false);
return selected_interacting_generic (other, EdgesInteract, false, min_count, max_count);
}
EdgesDelegate *
AsIfFlatEdges::selected_not_interacting (const Edges &other) const
AsIfFlatEdges::selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, EdgesInteract, true);
return selected_interacting_generic (other, EdgesInteract, true, min_count, max_count);
}
EdgesDelegate *
AsIfFlatEdges::selected_interacting (const Region &other) const
AsIfFlatEdges::selected_interacting (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, EdgesInteract, false);
return selected_interacting_generic (other, EdgesInteract, false, min_count, max_count);
}
EdgesDelegate *
AsIfFlatEdges::selected_not_interacting (const Region &other) const
AsIfFlatEdges::selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_generic (other, EdgesInteract, true);
return selected_interacting_generic (other, EdgesInteract, true, min_count, max_count);
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_interacting_pair (const Region &other) const
AsIfFlatEdges::selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const
{
return selected_interacting_pair_generic (other, EdgesInteract);
return selected_interacting_pair_generic (other, EdgesInteract, min_count, max_count);
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_interacting_pair (const Edges &other) const
AsIfFlatEdges::selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const
{
return selected_interacting_pair_generic (other, EdgesInteract);
return selected_interacting_pair_generic (other, EdgesInteract, min_count, max_count);
}
EdgesDelegate *
AsIfFlatEdges::selected_outside (const Region &other) const
{
return selected_interacting_generic (other, EdgesOutside, false);
return selected_interacting_generic (other, EdgesOutside, false, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_not_outside (const Region &other) const
{
return selected_interacting_generic (other, EdgesOutside, true);
return selected_interacting_generic (other, EdgesOutside, true, size_t (1), std::numeric_limits<size_t>::max ());
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_outside_pair (const Region &other) const
{
return selected_interacting_pair_generic (other, EdgesOutside);
return selected_interacting_pair_generic (other, EdgesOutside, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_inside (const Region &other) const
{
return selected_interacting_generic (other, EdgesInside, false);
return selected_interacting_generic (other, EdgesInside, false, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_not_inside (const Region &other) const
{
return selected_interacting_generic (other, EdgesInside, true);
return selected_interacting_generic (other, EdgesInside, true, size_t (1), std::numeric_limits<size_t>::max ());
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_inside_pair (const Region &other) const
{
return selected_interacting_pair_generic (other, EdgesInside);
return selected_interacting_pair_generic (other, EdgesInside, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_outside (const Edges &other) const
{
return selected_interacting_generic (other, EdgesOutside, false);
return selected_interacting_generic (other, EdgesOutside, false, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_not_outside (const Edges &other) const
{
return selected_interacting_generic (other, EdgesOutside, true);
return selected_interacting_generic (other, EdgesOutside, true, size_t (1), std::numeric_limits<size_t>::max ());
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_outside_pair (const Edges &other) const
{
return selected_interacting_pair_generic (other, EdgesOutside);
return selected_interacting_pair_generic (other, EdgesOutside, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_inside (const Edges &other) const
{
return selected_interacting_generic (other, EdgesInside, false);
return selected_interacting_generic (other, EdgesInside, false, size_t (1), std::numeric_limits<size_t>::max ());
}
EdgesDelegate *
AsIfFlatEdges::selected_not_inside (const Edges &other) const
{
return selected_interacting_generic (other, EdgesInside, true);
return selected_interacting_generic (other, EdgesInside, true, size_t (1), std::numeric_limits<size_t>::max ());
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::selected_inside_pair (const Edges &other) const
{
return selected_interacting_pair_generic (other, EdgesInside);
return selected_interacting_pair_generic (other, EdgesInside, size_t (1), std::numeric_limits<size_t>::max ());
}
@ -769,6 +752,118 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co
return result.release ();
}
EdgesDelegate *
AsIfFlatEdges::merged () const
{
if (empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (0, EdgeOr);
}
}
EdgesDelegate *
AsIfFlatEdges::and_with (const Edges &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (&other, EdgeAnd);
}
}
EdgesDelegate *
AsIfFlatEdges::not_with (const Edges &other) const
{
if (empty ()) {
return new db::EmptyEdges ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeNot);
}
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::andnot_with (const Edges &other) const
{
if (empty ()) {
return std::make_pair (new db::EmptyEdges (), new db::EmptyEdges ());
} else if (other.empty ()) {
return std::make_pair (new db::EmptyEdges (), clone ());
} else {
return boolean_andnot (&other);
}
}
EdgesDelegate *
AsIfFlatEdges::and_with (const Region &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return edge_region_op (other, db::EdgePolygonOp::Inside, true /*include borders*/).first;
}
}
EdgesDelegate *
AsIfFlatEdges::not_with (const Region &other) const
{
if (empty ()) {
return new db::EmptyEdges ();
} else if (other.empty ()) {
return clone ();
} else {
return edge_region_op (other, db::EdgePolygonOp::Outside, true /*include borders*/).first;
}
}
std::pair<EdgesDelegate *, EdgesDelegate *>
AsIfFlatEdges::andnot_with (const Region &other) const
{
if (empty ()) {
return std::make_pair (new db::EmptyEdges (), new db::EmptyEdges ());
} else if (other.empty ()) {
return std::make_pair (new db::EmptyEdges (), clone ());
} else {
return edge_region_op (other, db::EdgePolygonOp::Both, true /*include borders*/);
}
}
EdgesDelegate *
AsIfFlatEdges::xor_with (const Edges &other) const
{
if (empty ()) {
return other.delegate ()->clone ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeXor);
}
}
EdgesDelegate *
AsIfFlatEdges::or_with (const Edges &other) const
{
if (empty ()) {
return other.delegate ()->clone ();
} else if (other.empty ()) {
return clone ();
} else {
return boolean (&other, EdgeOr);
}
}
EdgesDelegate *
AsIfFlatEdges::intersections (const Edges &other) const
{
if (empty () || other.empty ()) {
return new db::EmptyEdges ();
} else {
return boolean (&other, EdgeIntersections);
}
}
EdgesDelegate *
AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
{
@ -781,9 +876,7 @@ AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
AddressableEdgeDelivery e (begin ());
for ( ; ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (e.operator-> (), 0);
}
scanner.insert (e.operator-> (), 0);
}
AddressableEdgeDelivery ee;
@ -791,9 +884,7 @@ AsIfFlatEdges::boolean (const Edges *other, EdgeBoolOp op) const
if (other) {
ee = other->addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
if (! ee->is_degenerate ()) {
scanner.insert (ee.operator-> (), 1);
}
scanner.insert (ee.operator-> (), 1);
}
}
@ -815,9 +906,7 @@ AsIfFlatEdges::boolean_andnot (const Edges *other) const
AddressableEdgeDelivery e (begin ());
for ( ; ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (e.operator-> (), 0);
}
scanner.insert (e.operator-> (), 0);
}
AddressableEdgeDelivery ee;
@ -825,9 +914,7 @@ AsIfFlatEdges::boolean_andnot (const Edges *other) const
if (other) {
ee = other->addressable_edges ();
for ( ; ! ee.at_end (); ++ee) {
if (! ee->is_degenerate ()) {
scanner.insert (ee.operator-> (), 1);
}
scanner.insert (ee.operator-> (), 1);
}
}
@ -852,6 +939,8 @@ AsIfFlatEdges::edge_region_op (const Region &other, db::EdgePolygonOp::mode_t mo
db::EdgeProcessor ep (report_progress (), progress_desc ());
bool has_dots = false;
for (db::Region::const_iterator p = other.begin (); ! p.at_end (); ++p) {
if (p->box ().touches (bbox ())) {
ep.insert (*p, 0);
@ -859,7 +948,11 @@ AsIfFlatEdges::edge_region_op (const Region &other, db::EdgePolygonOp::mode_t mo
}
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
ep.insert (*e, 1);
if (e->is_degenerate ()) {
has_dots = true;
} else {
ep.insert (*e, 1);
}
}
std::unique_ptr<FlatEdges> output_second;
@ -874,6 +967,36 @@ AsIfFlatEdges::edge_region_op (const Region &other, db::EdgePolygonOp::mode_t mo
db::EdgePolygonOp op (mode, include_borders);
ep.process (cc, op);
// process dots which are not captured by the booleans using the interaction function
if (has_dots) {
std::unique_ptr<FlatEdges> dots (new FlatEdges (false));
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (e->is_degenerate ()) {
dots->insert (*e);
}
}
std::pair<EdgesDelegate *, EdgesDelegate *> res (0, 0);
if (mode == EdgePolygonOp::Both) {
res = dots->selected_interacting_pair_generic (other, include_borders ? EdgesInteract : EdgesInside, size_t (1), std::numeric_limits<size_t>::max ());
} else if (mode == EdgePolygonOp::Inside) {
res.first = dots->selected_interacting_generic (other, include_borders ? EdgesInteract : EdgesInside, false, size_t (1), std::numeric_limits<size_t>::max ());
} else if (mode == EdgePolygonOp::Outside) {
res.first = dots->selected_interacting_generic (other, include_borders ? EdgesInteract : EdgesOutside, include_borders, size_t (1), std::numeric_limits<size_t>::max ());
}
if (res.first) {
output->add_in_place (db::Edges (res.first));
}
if (res.second) {
output_second->add_in_place (db::Edges (res.second));
}
}
return std::make_pair (output.release (), output_second.release ());
}

View File

@ -107,55 +107,25 @@ public:
return merged ();
}
virtual EdgesDelegate *merged () const
{
return boolean (0, EdgeOr);
}
virtual EdgesDelegate *merged () const;
virtual EdgesDelegate *and_with (const Edges &other) const
{
return boolean (&other, EdgeAnd);
}
virtual EdgesDelegate *and_with (const Edges &other) const;
virtual EdgesDelegate *not_with (const Edges &other) const
{
return boolean (&other, EdgeNot);
}
virtual EdgesDelegate *not_with (const Edges &other) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &other) const
{
return boolean_andnot (&other);
}
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Edges &other) const;
virtual EdgesDelegate *and_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Inside, true /*include borders*/).first;
}
virtual EdgesDelegate *and_with (const Region &other) const;
virtual EdgesDelegate *not_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Outside, true /*include borders*/).first;
}
virtual EdgesDelegate *not_with (const Region &other) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &other) const
{
return edge_region_op (other, db::EdgePolygonOp::Both, true /*include borders*/);
}
virtual std::pair<EdgesDelegate *, EdgesDelegate *> andnot_with (const Region &other) const;
virtual EdgesDelegate *xor_with (const Edges &other) const
{
return boolean (&other, EdgeXor);
}
virtual EdgesDelegate *xor_with (const Edges &other) const;
virtual EdgesDelegate *or_with (const Edges &other) const
{
return boolean (&other, EdgeOr);
}
virtual EdgesDelegate *or_with (const Edges &other) const;
virtual EdgesDelegate *intersections (const Edges &other) const
{
return boolean (&other, EdgeIntersections);
}
virtual EdgesDelegate *intersections (const Edges &other) const;
virtual EdgesDelegate *add_in_place (const Edges &other)
{
@ -183,12 +153,12 @@ public:
virtual EdgesDelegate *pull_interacting (const Edges &) const;
virtual RegionDelegate *pull_interacting (const Region &) const;
virtual EdgesDelegate *selected_interacting (const Edges &) const;
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_interacting (const Edges &, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_not_interacting (const Edges &, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_interacting (const Region &, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_not_interacting (const Region &, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_outside (const Edges &other) const;
virtual EdgesDelegate *selected_not_outside (const Edges &other) const;
@ -217,10 +187,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, 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;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
AsIfFlatEdges (const AsIfFlatEdges &other);

View File

@ -143,7 +143,7 @@ AsIfFlatRegion::to_string (size_t nmax) const
}
EdgesDelegate *
AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
AsIfFlatRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBase *proc) const
{
std::unique_ptr<FlatEdges> result (new FlatEdges ());
db::PropertyMapper pm (result->properties_repository (), properties_repository ());
@ -154,17 +154,41 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
}
result->reserve (n);
std::vector<db::Edge> heap;
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
db::properties_id_type prop_id = p.prop_id ();
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected (*e)) {
if (prop_id != 0) {
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
} else {
result->insert (*e);
if (proc) {
heap.clear ();
proc->process (*p, heap);
for (auto e = heap.begin (); e != heap.end (); ++e) {
if (! filter || filter->selected (*e)) {
if (prop_id != 0) {
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
} else {
result->insert (*e);
}
}
}
} else {
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected (*e)) {
if (prop_id != 0) {
result->insert (db::EdgeWithProperties (*e, pm (prop_id)));
} else {
result->insert (*e);
}
}
}
}
}
return result.release ();
@ -195,6 +219,8 @@ AsIfFlatRegion::area (const db::Box &box) const
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
if (box.empty () || p->box ().inside (box)) {
a += p->area ();
} else if (p->is_box ()) {
a += (p->box () & box).area ();
} else {
std::vector<db::Polygon> clipped;
clip_poly (*p, box, clipped);

View File

@ -84,7 +84,7 @@ public:
virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy);
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const;
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter)
{
@ -137,32 +137,32 @@ public:
virtual RegionDelegate *selected_outside (const Region &other) const
{
return selected_interacting_generic (other, 1, false, Positive, size_t (0), std::numeric_limits<size_t>::max ()).first;
return selected_interacting_generic (other, 1, false, Positive, size_t (1), std::numeric_limits<size_t>::max ()).first;
}
virtual RegionDelegate *selected_not_outside (const Region &other) const
{
return selected_interacting_generic (other, 1, false, Negative, size_t (0), std::numeric_limits<size_t>::max ()).first;
return selected_interacting_generic (other, 1, false, Negative, size_t (1), std::numeric_limits<size_t>::max ()).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_outside_pair (const Region &other) const
{
return selected_interacting_generic (other, 1, false, PositiveAndNegative, size_t (0), std::numeric_limits<size_t>::max ());
return selected_interacting_generic (other, 1, false, PositiveAndNegative, size_t (1), std::numeric_limits<size_t>::max ());
}
virtual RegionDelegate *selected_inside (const Region &other) const
{
return selected_interacting_generic (other, -1, true, Positive, size_t (0), std::numeric_limits<size_t>::max ()).first;
return selected_interacting_generic (other, -1, true, Positive, size_t (1), std::numeric_limits<size_t>::max ()).first;
}
virtual RegionDelegate *selected_not_inside (const Region &other) const
{
return selected_interacting_generic (other, -1, true, Negative, size_t (0), std::numeric_limits<size_t>::max ()).first;
return selected_interacting_generic (other, -1, true, Negative, size_t (1), std::numeric_limits<size_t>::max ()).first;
}
virtual std::pair<RegionDelegate *, RegionDelegate *> selected_inside_pair (const Region &other) const
{
return selected_interacting_generic (other, -1, true, PositiveAndNegative, size_t (0), std::numeric_limits<size_t>::max ());
return selected_interacting_generic (other, -1, true, PositiveAndNegative, size_t (1), std::numeric_limits<size_t>::max ());
}
virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const

View File

@ -254,6 +254,27 @@ struct DB_PUBLIC_TEMPLATE box
*/
box<C, R> &operator+= (const point<C> &p);
/**
* @brief Subtraction of boxes.
*
* The -= operator subtracts the argument box from *this.
* Subtraction leaves the bounding box of the region resulting
* from the geometrical NOT of *this and the argument box.
* Subtracting a box from itself gives an empty box.
* Subtracting a box that does not cover a full side of
* *this will not modify the box.
*
* @param b The box to subtract from *this.
*
* @return The result box.
*/
box<C, R> &operator-= (const box<C, R> &b);
/**
* @brief A method version for operator- (mainly for automation purposes)
*/
box<C, R> subtracted (const box<C, R> &b) const;
/**
* @brief Intersection of boxes.
*
@ -784,6 +805,50 @@ box<C, R>::operator+= (const point<C> &p)
return *this;
}
template <class C, class R>
inline box<C, R>
box<C, R>::subtracted (const box<C, R> &b) const
{
box<C, R> r (*this);
r -= b;
return r;
}
template <class C, class R>
inline box<C, R> &
box<C, R>::operator-= (const box<C, R> &bx)
{
if (bx.empty () || empty ()) {
return *this;
}
coord_type l = m_p1.x (), r = m_p2.x ();
coord_type b = m_p1.y (), t = m_p2.y ();
if (bx.bottom () <= bottom () && bx.top () >= top ()) {
if (bx.left () <= left ()) {
l = std::max (bx.right (), left ());
}
if (bx.right () >= right ()) {
r = std::min (bx.left (), right ());
}
}
if (bx.left () <= left () && bx.right () >= right ()) {
if (bx.bottom () <= bottom ()) {
b = std::max (bx.top (), bottom ());
}
if (bx.top () >= top ()) {
t = std::min (bx.bottom (), top ());
}
}
m_p1 = point_type (l, b);
m_p2 = point_type (r, t);
return *this;
}
template <class C, class R>
inline box<C, R> &
box<C, R>::operator&= (const box<C, R> &b)
@ -1363,6 +1428,23 @@ operator+ (const box<C> &b1, const box<C> &b2)
return bb;
}
/**
* @brief Box subtraction mapped on the - operator
*
* @param b1 The first box
* @param b2 The second box to subtract from the first
*
* @return The bounding box of the region formed but subtracting b2 from b1
*/
template <class C>
inline box<C>
operator- (const box<C> &b1, const box<C> &b2)
{
box<C> bb (b1);
bb -= b2;
return bb;
}
/**
* @brief "Folding" of two boxes
*

View File

@ -1079,7 +1079,7 @@ public:
m_cl.erase (cli);
}
} else if (m_report_single) {
} else if (m_report_single && m_ignore_single.find (obj) == m_ignore_single.end ()) {
// single-object entry: create a cluster and feed it a single-object signature
Cluster cl (m_cl_template);
@ -1089,6 +1089,13 @@ public:
}
}
void ignore_single (const Obj *o)
{
if (m_report_single) {
m_ignore_single.insert (o);
}
}
void add_asymm (const Obj *o1, const Prop &p1, const Obj *o2, const Prop &p2)
{
om_iterator_type om1 = m_om.find (om_key_type (o1, p1));
@ -1166,6 +1173,7 @@ private:
bool m_report_single;
cl_type m_cl;
om_type m_om;
std::set<const Obj *> m_ignore_single;
};
}

View File

@ -914,10 +914,19 @@ EdgesDelegate *DeepEdges::merged () const
return res.release ();
}
DeepLayer
std::pair<DeepLayer, DeepLayer>
DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
{
std::vector<unsigned int> output_layers;
DeepLayer dl_out (deep_layer ().derived ());
output_layers.push_back (dl_out.layer ());
DeepLayer dl_out2;
if (op == EdgeAndNot) {
dl_out2 = DeepLayer (deep_layer ().derived ());
output_layers.push_back (dl_out2.layer ());
}
db::EdgeBoolAndOrNotLocalOperation local_op (op);
@ -927,14 +936,34 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), output_layers);
return dl_out;
return std::make_pair (dl_out, dl_out2);
}
std::pair<DeepLayer, DeepLayer>
DeepEdges::edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t mode, bool include_borders) const
{
// first, extract dots
DeepLayer dots (deep_layer ().derived ());
bool has_dots = false;
db::Layout &layout = const_cast<db::Layout &> (dots.layout ());
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (deep_layer ().layer ());
db::Shapes &st = c->shapes (dots.layer ());
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
if (si->edge ().is_degenerate ()) {
st.insert (*si);
has_dots = true;
}
}
}
// normal processing (dots will vanish)
std::vector<unsigned int> output_layers;
DeepLayer dl_out (deep_layer ().derived ());
@ -956,6 +985,29 @@ DeepEdges::edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t mode,
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), output_layers);
if (has_dots) {
// process dots
std::pair<EdgesDelegate *, EdgesDelegate *> res (0, 0);
if (mode == EdgePolygonOp::Both) {
res = db::DeepEdges (dots).selected_interacting_pair_generic_impl (other, include_borders ? EdgesInteract : EdgesInside, size_t (1), std::numeric_limits<size_t>::max ());
} else if (mode == EdgePolygonOp::Inside) {
res.first = db::DeepEdges (dots).selected_interacting_generic_impl (other, include_borders ? EdgesInteract : EdgesInside, false, size_t (1), std::numeric_limits<size_t>::max ());
} else if (mode == EdgePolygonOp::Outside) {
res.first = db::DeepEdges (dots).selected_interacting_generic_impl (other, include_borders ? EdgesInteract : EdgesOutside, include_borders, size_t (1), std::numeric_limits<size_t>::max ());
}
if (res.first) {
db::DeepEdges (dl_out).add_in_place (db::Edges (res.first));
}
if (res.second) {
db::DeepEdges (dl_out2).add_in_place (db::Edges (res.second));
}
}
return std::make_pair (dl_out, dl_out2);
}
@ -963,17 +1015,22 @@ EdgesDelegate *DeepEdges::intersections (const Edges &other) const
{
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
if (empty () || other.empty ()) {
if (empty ()) {
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) {
return AsIfFlatEdges::intersections (other);
} else {
return new DeepEdges (and_or_not_with (other_deep, EdgeIntersections));
return new DeepEdges (and_or_not_with (other_deep, EdgeIntersections).first);
}
}
@ -995,9 +1052,13 @@ EdgesDelegate *DeepEdges::and_with (const Edges &other) const
return AsIfFlatEdges::and_with (other);
} else if (deep_layer () == other_deep->deep_layer ()) {
return clone ();
} else {
return new DeepEdges (and_or_not_with (other_deep, EdgeAnd));
return new DeepEdges (and_or_not_with (other_deep, EdgeAnd).first);
}
}
@ -1014,9 +1075,13 @@ EdgesDelegate *DeepEdges::not_with (const Edges &other) const
return AsIfFlatEdges::not_with (other);
} else if (deep_layer () == other_deep->deep_layer ()) {
return new DeepEdges (deep_layer ().derived ());
} else {
return new DeepEdges (and_or_not_with (other_deep, EdgeNot));
return new DeepEdges (and_or_not_with (other_deep, EdgeNot).first);
}
}
@ -1092,7 +1157,7 @@ EdgesDelegate *DeepEdges::not_with (const Region &other) const
std::pair<EdgesDelegate *, EdgesDelegate *>
DeepEdges::andnot_with (const Edges &other) const
{
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
if (empty ()) {
@ -1107,9 +1172,13 @@ DeepEdges::andnot_with (const Edges &other) const
return AsIfFlatEdges::andnot_with (other);
} else if (deep_layer () == other_deep->deep_layer ()) {
return std::make_pair (clone (), new DeepEdges (deep_layer ().derived ()));
} else {
auto res = edge_region_op (other_deep, EdgePolygonOp::Both, true /*include borders*/);
auto res = and_or_not_with (other_deep, EdgeAndNot);
return std::make_pair (new DeepEdges (res.first), new DeepEdges (res.second));
}
@ -1131,12 +1200,16 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const
return AsIfFlatEdges::xor_with (other);
} else if (deep_layer () == other_deep->deep_layer ()) {
return new DeepEdges (deep_layer ().derived ());
} else {
// Implement XOR as (A-B)+(B-A) - only this implementation
// is compatible with the local processor scheme
DeepLayer n1 (and_or_not_with (other_deep, EdgeNot));
DeepLayer n2 (other_deep->and_or_not_with (this, EdgeNot));
DeepLayer n1 (and_or_not_with (other_deep, EdgeNot).first);
DeepLayer n2 (other_deep->and_or_not_with (this, EdgeNot).first);
n1.add_from (n2);
return new DeepEdges (n1);
@ -1146,6 +1219,11 @@ EdgesDelegate *DeepEdges::xor_with (const Edges &other) const
EdgesDelegate *DeepEdges::or_with (const Edges &other) const
{
const DeepEdges *other_deep = dynamic_cast <const DeepEdges *> (other.delegate ());
if (other_deep && other_deep->deep_layer () == deep_layer ()) {
return clone ();
}
// NOTE: in the hierarchical case we don't do a merge on "or": just map to add
return add (other);
}
@ -1354,362 +1432,8 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t
return res.release ();
}
namespace
{
class Edge2EdgeInteractingLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
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 ..
}
virtual db::Coord dist () const
{
// touching is sufficient
return 1;
}
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
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;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert (&subject, 0);
}
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 1);
}
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, 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, m_mode);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
}
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
{
if (m_mode == EdgesOutside) {
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
} else {
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"));
}
private:
EdgeInteractionMode m_mode;
output_mode_t m_output_mode;
};
class Edge2EdgePullLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
Edge2EdgePullLocalOperation ()
{
// .. nothing yet ..
}
virtual db::Coord dist () const
{
// touching is sufficient
return 1;
}
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::Edge> &result = results.front ();
db::box_scanner<db::Edge, size_t> scanner;
std::set<db::Edge> others;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert (&subject, 1);
}
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 0);
}
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result, EdgesInteract);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
{
return Drop;
}
virtual std::string description () const
{
return tl::to_string (tr ("Select interacting edges from other"));
}
};
class Edge2PolygonInteractingLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::Edge>
{
public:
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 ..
}
virtual db::Coord dist () const
{
// touching is sufficient
return 1;
}
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
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;
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert1 (&subject, 0);
}
std::list<db::Polygon> heap;
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
heap.push_back (o->obj ().transformed (o->trans ()));
scanner.insert2 (& heap.back (), 1);
}
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, 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, m_mode);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
}
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
{
if (m_mode == EdgesOutside) {
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
} else {
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
}
}
virtual std::string description () const
{
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:
EdgeInteractionMode m_mode;
output_mode_t m_output_mode;
};
struct ResultInserter
{
typedef db::Polygon value_type;
ResultInserter (db::Layout *layout, std::unordered_set<db::PolygonRef> &result)
: mp_layout (layout), mp_result (&result)
{
// .. nothing yet ..
}
void insert (const db::Polygon &p)
{
(*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ()));
}
private:
db::Layout *mp_layout;
std::unordered_set<db::PolygonRef> *mp_result;
};
class Edge2PolygonPullLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::PolygonRef>
{
public:
Edge2PolygonPullLocalOperation ()
{
// .. nothing yet ..
}
virtual db::Coord dist () const
{
// touching is sufficient
return 1;
}
virtual void do_compute_local (db::Layout *layout, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner;
std::set<db::PolygonRef> others;
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert1 (&subject, 1);
}
std::list<db::Polygon> heap;
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
heap.push_back (o->obj ().transformed (o->trans ()));
scanner.insert2 (& heap.back (), 0);
}
ResultInserter inserter (layout, result);
edge_to_region_interaction_filter<ResultInserter> filter (&inserter, EdgesInteract);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
virtual OnEmptyIntruderHint on_empty_intruder_hint () const
{
return Drop;
}
virtual std::string description () const
{
return tl::to_string (tr ("Select interacting regions"));
}
};
}
EdgesDelegate *
DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse) const
DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
std::unique_ptr<db::DeepRegion> dr_holder;
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
@ -1719,23 +1443,33 @@ DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMod
other_deep = dr_holder.get ();
}
return selected_interacting_generic_impl (other_deep, mode, inverse, min_count, max_count);
}
EdgesDelegate *
DeepEdges::selected_interacting_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
const db::DeepLayer &edges = merged_deep_layer ();
DeepLayer dl_out (edges.derived ());
db::Edge2PolygonInteractingLocalOperation op (mode, inverse ? db::Edge2PolygonInteractingLocalOperation::Inverse : db::Edge2PolygonInteractingLocalOperation::Normal);
db::edge_to_polygon_interacting_local_operation<db::PolygonRef> op (mode, inverse ? db::edge_to_polygon_interacting_local_operation<db::PolygonRef>::Inverse : db::edge_to_polygon_interacting_local_operation<db::PolygonRef>::Normal, min_count, max_count);
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 (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
proc.run (&op, edges.layer (), (mode == EdgesInside ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
// NOTE: with counting the other region needs to be merged
proc.run (&op, edges.layer (), (counting || mode != EdgesInteract ? 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
DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
std::unique_ptr<db::DeepRegion> dr_holder;
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
@ -1745,6 +1479,15 @@ DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteracti
other_deep = dr_holder.get ();
}
return selected_interacting_pair_generic_impl (other_deep, mode, min_count, max_count);
}
std::pair<EdgesDelegate *, EdgesDelegate *>
DeepEdges::selected_interacting_pair_generic_impl (const db::DeepRegion *other_deep, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
const db::DeepLayer &edges = merged_deep_layer ();
DeepLayer dl_out (edges.derived ());
@ -1755,20 +1498,24 @@ DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteracti
output_layers.push_back (dl_out.layer ());
output_layers.push_back (dl_out2.layer ());
db::Edge2PolygonInteractingLocalOperation op (mode, db::Edge2PolygonInteractingLocalOperation::Both);
db::edge_to_polygon_interacting_local_operation<db::PolygonRef> op (mode, db::edge_to_polygon_interacting_local_operation<db::PolygonRef>::Both, min_count, max_count);
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 (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
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);
// NOTE: with counting the other region needs to be merged
proc.run (&op, edges.layer (), (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->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, EdgeInteractionMode mode, bool inverse) const
DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
std::unique_ptr<db::DeepEdges> dr_holder;
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
if (! other_deep) {
@ -1777,24 +1524,44 @@ DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode
other_deep = dr_holder.get ();
}
if (deep_layer () == other_deep->deep_layer () && !counting) {
if ((mode == EdgesOutside) == inverse) {
return clone ();
} else {
return new DeepEdges (deep_layer ().derived ());
}
}
const db::DeepLayer &edges = merged_deep_layer ();
// NOTE: with counting the other region needs to be merged
const db::DeepLayer &other_edges = (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ());
DeepLayer dl_out (edges.derived ());
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal);
db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal, min_count, max_count);
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 (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (edges.store ()->threads ());
proc.run (&op, edges.layer (), (mode == EdgesInside ? other_deep->merged_deep_layer () : other_deep->deep_layer ()).layer (), dl_out.layer ());
if (edges == other_edges) {
// with counting and two identical inputs, a copy needs to be made
db::DeepLayer copy (other_edges.copy ());
proc.run (&op, edges.layer (), copy.layer (), dl_out.layer ());
} else {
proc.run (&op, edges.layer (), other_edges.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
DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractionMode mode, size_t min_count, size_t max_count) const
{
min_count = std::max (size_t (1), min_count);
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
std::unique_ptr<db::DeepEdges> dr_holder;
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
if (! other_deep) {
@ -1803,8 +1570,19 @@ DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractio
other_deep = dr_holder.get ();
}
if (deep_layer () == other_deep->deep_layer () && !counting) {
if (mode != EdgesOutside) {
return std::make_pair (clone (), new DeepEdges (deep_layer ().derived ()));
} else {
return std::make_pair (new DeepEdges (deep_layer ().derived ()), clone ());
}
}
const db::DeepLayer &edges = merged_deep_layer ();
// NOTE: with counting the other region needs to be merged
const db::DeepLayer &other_edges = (counting || mode != EdgesInteract ? other_deep->merged_deep_layer () : other_deep->deep_layer ());
DeepLayer dl_out (edges.derived ());
DeepLayer dl_out2 (edges.derived ());
@ -1813,13 +1591,20 @@ DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractio
output_layers.push_back (dl_out.layer ());
output_layers.push_back (dl_out2.layer ());
db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both);
db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both, min_count, max_count);
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 (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
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);
// NOTE: with counting the other region needs to be merged
if (edges == other_edges) {
// with counting and two identical inputs, a copy needs to be made
db::DeepLayer copy (other_edges.copy ());
proc.run (&op, edges.layer (), copy.layer (), output_layers);
} else {
proc.run (&op, edges.layer (), other_edges.layer (), output_layers);
}
return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2));
}
@ -1860,6 +1645,10 @@ EdgesDelegate *DeepEdges::pull_generic (const Edges &other) const
other_deep = dr_holder.get ();
}
if (deep_layer () == other_deep->deep_layer ()) {
return clone ();
}
const db::DeepLayer &edges = deep_layer ();
const db::DeepLayer &other_edges = other_deep->merged_deep_layer ();
@ -1886,6 +1675,10 @@ EdgesDelegate *DeepEdges::in (const Edges &other, bool invert) const
other_deep = dr_holder.get ();
}
if (deep_layer () == other_deep->deep_layer ()) {
return invert ? new db::DeepEdges (deep_layer ().derived ()) : clone ();
}
const db::DeepLayer &edges = merged_deep_layer ();
DeepLayer dl_out (edges.derived ());
@ -1915,6 +1708,10 @@ std::pair<EdgesDelegate *, EdgesDelegate *> DeepEdges::in_and_out (const Edges &
other_deep = dr_holder.get ();
}
if (deep_layer () == other_deep->deep_layer ()) {
return std::make_pair (clone (), new db::DeepEdges (deep_layer ().derived ()));
}
const db::DeepLayer &edges = merged_deep_layer ();
DeepLayer dl_out (edges.derived ());

View File

@ -188,15 +188,17 @@ private:
void init ();
void ensure_merged_edges_valid () const;
DeepLayer and_or_not_with(const DeepEdges *other, EdgeBoolOp op) const;
std::pair<DeepLayer, DeepLayer> and_or_not_with (const DeepEdges *other, EdgeBoolOp op) 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, 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;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region &region, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
EdgesDelegate *selected_interacting_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic_impl (const DeepRegion *other_deep, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
DeepEdges *apply_filter (const EdgeFilterBase &filter) const;
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;

View File

@ -797,6 +797,10 @@ DeepRegion::and_with (const Region &other, PropertyConstraint property_constrain
return AsIfFlatRegion::and_with (other, property_constraint);
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
return clone ();
} else {
return new DeepRegion (and_or_not_with (other_deep, true, property_constraint));
@ -817,6 +821,10 @@ DeepRegion::not_with (const Region &other, PropertyConstraint property_constrain
return AsIfFlatRegion::not_with (other, property_constraint);
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
return new DeepRegion (deep_layer ().derived ());
} else {
return new DeepRegion (and_or_not_with (other_deep, false, property_constraint));
@ -825,8 +833,13 @@ DeepRegion::not_with (const Region &other, PropertyConstraint property_constrain
}
RegionDelegate *
DeepRegion::or_with (const Region &other, db::PropertyConstraint /*property_constraint*/) const
DeepRegion::or_with (const Region &other, db::PropertyConstraint property_constraint) const
{
const DeepRegion *other_deep = dynamic_cast <const DeepRegion *> (other.delegate ());
if (other_deep && other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
return clone ();
}
// TODO: implement property_constraint
RegionDelegate *res = add (other);
return res->merged_in_place ();
@ -849,6 +862,10 @@ DeepRegion::andnot_with (const Region &other, PropertyConstraint property_constr
return AsIfFlatRegion::andnot_with (other, property_constraint);
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
return std::make_pair (clone (), new DeepRegion (deep_layer ().derived ()));
} else {
std::pair<DeepLayer, DeepLayer> res = and_and_not_with (other_deep, property_constraint);
@ -962,6 +979,10 @@ DeepRegion::xor_with (const Region &other, db::PropertyConstraint property_const
return AsIfFlatRegion::xor_with (other, property_constraint);
} else if (other_deep->deep_layer () == deep_layer () && pc_skip (property_constraint)) {
return new DeepRegion (deep_layer ().derived ());
} else {
// Implement XOR as (A-B)+(B-A) - only this implementation
@ -1335,7 +1356,7 @@ DeepRegion::snapped (db::Coord gx, db::Coord gy)
}
EdgesDelegate *
DeepRegion::edges (const EdgeFilterBase *filter) const
DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBase *proc) const
{
std::unique_ptr<db::DeepEdges> res (new db::DeepEdges (deep_layer ().derived ()));
@ -1343,7 +1364,7 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
return res.release ();
}
if (! filter && merged_semantics () && ! merged_polygons_available ()) {
if (! proc && ! filter && merged_semantics () && ! merged_polygons_available ()) {
// Hierarchical edge detector - no pre-merge required
@ -1388,15 +1409,32 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
const db::Shapes &s = c->shapes (polygons.layer ());
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
std::vector<db::Edge> heap;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
db::Polygon poly;
si->polygon (poly);
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) {
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
if (proc) {
heap.clear ();
proc->process (poly, heap);
for (auto e = heap.begin (); e != heap.end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) {
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
}
}
} else {
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
if (! filter || filter->selected ((*e).transformed (tr))) {
st.insert (db::EdgeWithProperties (*e, pm (si->prop_id ())));
}
}
}
}
@ -2110,6 +2148,16 @@ DeepRegion::in_and_out_generic (const Region &other, InteractingOutputMode outpu
other_deep = dr_holder.get ();
}
if (deep_layer () == other_deep->deep_layer ()) {
if (output_mode == PositiveAndNegative) {
return std::make_pair (clone (), new DeepRegion (deep_layer ().derived ()));
} else if (output_mode == Negative) {
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
} else {
return std::make_pair (clone (), (RegionDelegate *) 0);
}
}
const db::DeepLayer &polygons = merged_deep_layer ();
const db::DeepLayer &other_polygons = other_deep->merged_deep_layer ();
@ -2171,6 +2219,26 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
other_deep = dr_holder.get ();
}
if (deep_layer () == other_deep->deep_layer () && !counting) {
if (mode <= 0 /*inside or interacting*/) {
if (output_mode == PositiveAndNegative) {
return std::make_pair (clone (), new DeepRegion (deep_layer ().derived ()));
} else if (output_mode == Negative) {
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
} else {
return std::make_pair (clone (), (RegionDelegate *) 0);
}
} else {
if (output_mode == PositiveAndNegative) {
return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
} else if (output_mode == Negative) {
return std::make_pair (clone (), (RegionDelegate *) 0);
} else {
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
}
}
}
const db::DeepLayer &polygons = merged_deep_layer ();
// NOTE: with counting, the other polygons must be merged
const db::DeepLayer &other_polygons = counting ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
@ -2188,7 +2256,13 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
bool result_is_merged = (! split_after && (merged_semantics () || is_merged ()));
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
if (polygons == other_polygons) {
// with counting and two identical inputs we need to create a layer copy
db::DeepLayer other_copy (other_polygons.copy ());
proc.run (&op, polygons.layer (), other_copy.layer (), orh.layers ());
} else {
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
}
return orh.result_pair ();
}
@ -2268,6 +2342,10 @@ DeepRegion::pull_generic (const Region &other, int mode, bool touching) const
other_deep = dr_holder.get ();
}
if (deep_layer () == other_deep->deep_layer ()) {
return clone ();
}
// in "inside" mode, the first argument needs to be merged too
const db::DeepLayer &polygons = mode < 0 ? merged_deep_layer () : deep_layer ();
const db::DeepLayer &other_polygons = other_deep->merged_deep_layer ();

View File

@ -119,7 +119,7 @@ public:
virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy);
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const;
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter);
virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const;

View File

@ -86,14 +86,14 @@ struct EdgeBooleanCluster
{
typedef db::Edge::coord_type coord_type;
EdgeBooleanCluster (OutputContainer *output, EdgeBoolOp op)
: mp_output (output), mp_output2 (0), m_op (op)
EdgeBooleanCluster (OutputContainer *output, std::set<db::Point> *dots, EdgeBoolOp op)
: mp_output (output), mp_output2 (0), mp_dots (dots), mp_dots2 (0), m_op (op)
{
// .. nothing yet ..
}
EdgeBooleanCluster (OutputContainer *output, OutputContainer *output2, EdgeBoolOp op)
: mp_output (output), mp_output2 (output2), m_op (op)
EdgeBooleanCluster (OutputContainer *output, OutputContainer *output2, std::set<db::Point> *dots, std::set<db::Point> *dots2, EdgeBoolOp op)
: mp_output (output), mp_output2 (output2), mp_dots (dots), mp_dots2 (dots2), m_op (op)
{
// .. nothing yet ..
}
@ -106,24 +106,55 @@ struct EdgeBooleanCluster
if (begin () + 1 == end ()) {
if (begin ()->second == 0) {
if (m_op == EdgeAndNot) {
mp_output2->insert (*(begin ()->first));
if (begin ()->first->is_degenerate ()) {
if (mp_dots) {
mp_dots2->insert (begin ()->first->p1 ());
}
} else if (mp_output2) {
mp_output2->insert (*(begin ()->first));
}
} else if (m_op != EdgeAnd) {
mp_output->insert (*(begin ()->first));
if (begin ()->first->is_degenerate ()) {
if (mp_dots) {
mp_dots->insert (begin ()->first->p1 ());
}
} else if (mp_output) {
mp_output->insert (*(begin ()->first));
}
}
} else {
if (m_op != EdgeAnd && m_op != EdgeNot && m_op != EdgeAndNot) {
mp_output->insert (*(begin ()->first));
if (begin ()->first->is_degenerate ()) {
if (mp_dots) {
mp_dots->insert (begin ()->first->p1 ());
}
} else if (mp_output) {
mp_output->insert (*(begin ()->first));
}
}
}
return;
}
db::Edge r = *begin ()->first;
// search first non-degenerate, longest
iterator main = end ();
for (iterator i = begin (); i != end (); ++i) {
if (! i->first->is_degenerate () && (main == end () || main->first->length () < i->first->length ())) {
main = i;
}
}
if (main == end ()) {
return;
}
db::Edge r = *main->first;
double l1 = 0.0, l2 = r.double_length ();
double n = 1.0 / l2;
db::Point p1 = r.p1 (), p2 = r.p2 ();
for (iterator o = begin () + 1; o != end (); ++o) {
for (iterator o = begin (); o != end (); ++o) {
double ll1 = db::sprod (db::Vector (o->first->p1 () - r.p1 ()), r.d ()) * n;
double ll2 = db::sprod (db::Vector (o->first->p2 () - r.p1 ()), r.d ()) * n;
if (ll1 < l1) {
@ -245,6 +276,7 @@ struct EdgeBooleanCluster
private:
OutputContainer *mp_output, *mp_output2;
std::set<db::Point> *mp_dots, *mp_dots2;
db::EdgeBoolOp m_op;
};
@ -253,15 +285,8 @@ struct EdgeBooleanClusterCollector
: public db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> >
{
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 ..
}
EdgeBooleanClusterCollector (OutputContainer *output, OutputContainer *intersections, EdgeBoolOp op)
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, op), op != EdgeAnd /*report single*/),
mp_output (output), mp_intersections (intersections)
: db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> > (EdgeBooleanCluster<OutputContainer> (output, output2, &m_dots, &m_dots2, op == EdgeIntersections ? EdgeAnd : op), op != EdgeAnd && op != EdgeIntersections /*report single*/),
mp_output (output), mp_output2 (output2), m_op (op)
{
// .. nothing yet ..
}
@ -281,11 +306,78 @@ struct EdgeBooleanClusterCollector
db::cluster_collector<db::Edge, size_t, EdgeBooleanCluster<OutputContainer> >::add (o1, p1, o2, p2);
} else if (mp_intersections && p1 != p2) {
} else {
// dots vs. edge or dot is handled here, no need to copy dots
if (o1->is_degenerate ()) {
this->ignore_single (o1);
}
if (o2->is_degenerate ()) {
this->ignore_single (o2);
}
if (m_op == EdgeIntersections) {
if (p1 != p2) {
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (ip.first) {
m_dots.insert (ip.second);
}
}
} else if (m_op == EdgeAndNot) {
// handle case of dot vs. edge or dot
if (p1 != p2 && (o1->is_degenerate () || o2->is_degenerate ())) {
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (ip.first) {
m_dots.insert (ip.second);
}
if (o1->is_degenerate () && ! ip.first) {
m_dots2.insert (o1->p1 ());
}
}
} else if (m_op == EdgeAnd) {
// handle case of dot vs. edge or dot
if (p1 != p2 && (o1->is_degenerate () || o2->is_degenerate ())) {
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (ip.first) {
m_dots.insert (ip.second);
}
}
} else if (m_op == EdgeNot) {
// handle case of dot vs. edge or dot
if (p1 != p2 && o1->is_degenerate ()) {
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (! ip.first) {
m_dots.insert (o1->p1 ());
}
}
} else if (m_op == EdgeOr) {
// forward dots
if (o1->is_degenerate ()) {
m_dots.insert (o1->p1 ());
}
if (o2->is_degenerate ()) {
m_dots.insert (o2->p1 ());
}
} else if (m_op == EdgeXor) {
// handle case of dot vs. edge or dot
if (p1 != p2 && o1->is_degenerate () && o2->is_degenerate ()) {
if (o1->p1 () != o2->p1 ()) {
m_dots.insert (o1->p1 ());
m_dots.insert (o2->p1 ());
}
}
std::pair<bool, db::Point> ip = o1->intersect_point (*o2);
if (ip.first) {
m_intersections.insert (ip.second);
}
}
@ -340,35 +432,44 @@ struct EdgeBooleanClusterCollector
};
/**
* @brief Finalizes the implementation for "EdgeIntersections"
* @brief Finalizes the implementation for "sections"
* This method pushes those points which don't interact with the edges to the output container
* as degenerate edges. It needs to be called after the pass has been made.
*/
void finalize (bool)
{
if (m_intersections.empty ()) {
add_orphan_dots (m_dots, mp_output);
if (mp_output2) {
add_orphan_dots (m_dots2, mp_output2);
}
}
private:
OutputContainer *mp_output, *mp_output2;
EdgeBoolOp m_op;
std::set<db::Point> m_dots, m_dots2;
static void add_orphan_dots (const std::set<db::Point> &dots, OutputContainer *output)
{
if (dots.empty ()) {
return;
}
db::box_scanner2<db::Edge, size_t, db::Point, size_t> intersections_to_edge_scanner;
for (typename OutputContainer::const_iterator e = mp_output->begin (); e != mp_output->end (); ++e) {
intersections_to_edge_scanner.insert1 (e.operator-> (), 0);
db::box_scanner2<db::Edge, size_t, db::Point, size_t> dots_to_edge_scanner;
for (typename OutputContainer::const_iterator e = output->begin (); e != output->end (); ++e) {
dots_to_edge_scanner.insert1 (e.operator-> (), 0);
}
for (std::set<db::Point>::const_iterator p = m_intersections.begin (); p != m_intersections.end (); ++p) {
intersections_to_edge_scanner.insert2 (p.operator-> (), 0);
for (std::set<db::Point>::const_iterator p = dots.begin (); p != dots.end (); ++p) {
dots_to_edge_scanner.insert2 (p.operator-> (), 0);
}
std::set<db::Point> points_to_remove;
RemovePointsOnEdges rpoe (points_to_remove);
intersections_to_edge_scanner.process (rpoe, 1, db::box_convert<db::Edge> (), db::box_convert<db::Point> ());
dots_to_edge_scanner.process (rpoe, 1, db::box_convert<db::Edge> (), db::box_convert<db::Point> ());
std::set_difference (dots.begin (), dots.end (), points_to_remove.begin (), points_to_remove.end (), PointInserter (output));
std::set_difference (m_intersections.begin (), m_intersections.end (), points_to_remove.begin (), points_to_remove.end (), PointInserter (mp_intersections));
}
private:
OutputContainer *mp_output;
OutputContainer *mp_intersections;
std::set<db::Point> m_intersections;
};
/**

View File

@ -30,6 +30,9 @@
#include "dbOriginalLayerEdgePairs.h"
#include "dbEdges.h"
#include "dbRegion.h"
#include "dbLayout.h"
#include "dbWriter.h"
#include "tlStream.h"
#include "tlVariant.h"
@ -93,6 +96,23 @@ EdgePairs::EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
mp_delegate = new DeepEdgePairs (si, dss, trans);
}
void
EdgePairs::write (const std::string &fn) const
{
// method provided for debugging purposes
db::Layout layout;
const db::Cell &top = layout.cell (layout.add_cell ("EDGE_PAIRS"));
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
insert_into (&layout, top.cell_index (), li);
tl::OutputStream os (fn);
db::SaveLayoutOptions opt;
opt.set_format_from_filename (fn);
db::Writer writer (opt);
writer.write (layout, os);
}
template <class Sh>
void EdgePairs::insert (const Sh &shape)
{

View File

@ -185,6 +185,14 @@ public:
*/
explicit EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
/**
* @brief Writes the edge pair collection to a file
*
* This method is provided for debugging purposes. A flat image of the
* region is written to a layout file with a single top cell on layer 0/0.
*/
void write (const std::string &fn) const;
/**
* @brief Implementation of the ShapeCollection interface
*/

View File

@ -251,6 +251,13 @@ struct CutPoints
}
// do not insert points twice
for (auto c = cut_points.begin (); c != cut_points.end (); ++c) {
if (*c == p) {
return;
}
}
cut_points.push_back (p);
}
@ -1057,6 +1064,12 @@ EdgeProcessor::reserve (size_t n)
mp_work_edges->reserve (n);
}
size_t
EdgeProcessor::count () const
{
return mp_work_edges->size ();
}
void
EdgeProcessor::insert (const db::Edge &e, EdgeProcessor::property_type p)
{

View File

@ -695,6 +695,11 @@ public:
*/
void reserve (size_t n);
/**
* @brief Reports the number of edges stored in the processor
*/
size_t count () const;
/**
* @brief Insert an edge
*/

View File

@ -28,6 +28,9 @@
#include "dbFlatEdges.h"
#include "dbEdgesUtils.h"
#include "dbRegion.h"
#include "dbLayout.h"
#include "dbWriter.h"
#include "tlStream.h"
namespace db
{
@ -141,6 +144,23 @@ Edges::set_delegate (EdgesDelegate *delegate, bool keep_attributes)
}
}
void
Edges::write (const std::string &fn) const
{
// method provided for debugging purposes
db::Layout layout;
const db::Cell &top = layout.cell (layout.add_cell ("EDGES"));
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
insert_into (&layout, top.cell_index (), li);
tl::OutputStream os (fn);
db::SaveLayoutOptions opt;
opt.set_format_from_filename (fn);
db::Writer writer (opt);
writer.write (layout, os);
}
void
Edges::clear ()
{

View File

@ -833,6 +833,14 @@ public:
return *this;
}
/**
* @brief Writes the edge collection to a file
*
* This method is provided for debugging purposes. A flat image of the
* region is written to a layout file with a single top cell on layer 0/0.
*/
void write (const std::string &fn) const;
/**
* @brief Intersections with other edges
* Intersections are similar to "AND", but will also report
@ -991,9 +999,9 @@ public:
* Merged semantics applies. If merged semantics is chosen, the connected edge parts will be
* selected as a whole.
*/
Edges &select_interacting (const Region &other)
Edges &select_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_interacting (other));
set_delegate (mp_delegate->selected_interacting (other, min_count, max_count));
return *this;
}
@ -1002,9 +1010,9 @@ public:
*
* This method is an out-of-place version of select_interacting.
*/
Edges selected_interacting (const Region &other) const
Edges selected_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Edges (mp_delegate->selected_interacting (other));
return Edges (mp_delegate->selected_interacting (other, min_count, max_count));
}
/**
@ -1013,9 +1021,9 @@ public:
* Merged semantics applies. If merged semantics is chosen, the connected edge parts will be
* selected as a whole.
*/
Edges &select_not_interacting (const Region &other)
Edges &select_not_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_not_interacting (other));
set_delegate (mp_delegate->selected_not_interacting (other, min_count, max_count));
return *this;
}
@ -1024,17 +1032,17 @@ public:
*
* This method is an out-of-place version of select_not_interacting.
*/
Edges selected_not_interacting (const Region &other) const
Edges selected_not_interacting (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Edges (mp_delegate->selected_not_interacting (other));
return Edges (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**
* @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<Edges, Edges> selected_interacting_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other);
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
}
@ -1280,9 +1288,9 @@ public:
* Merged semantics applies. If merged semantics is chosen, the connected edge parts will be
* selected as a whole.
*/
Edges &select_interacting (const Edges &other)
Edges &select_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_interacting (other));
set_delegate (mp_delegate->selected_interacting (other, min_count, max_count));
return *this;
}
@ -1291,17 +1299,17 @@ public:
*
* This method is an out-of-place version of select_interacting.
*/
Edges selected_interacting (const Edges &other) const
Edges selected_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Edges (mp_delegate->selected_interacting (other));
return Edges (mp_delegate->selected_interacting (other, min_count, max_count));
}
/**
* @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<Edges, Edges> selected_interacting_differential (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other);
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->selected_interacting_pair (other, min_count, max_count);
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
}
@ -1311,9 +1319,9 @@ public:
* Merged semantics applies. If merged semantics is chosen, the connected edge parts will be
* selected as a whole.
*/
Edges &select_not_interacting (const Edges &other)
Edges &select_not_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ())
{
set_delegate (mp_delegate->selected_not_interacting (other));
set_delegate (mp_delegate->selected_not_interacting (other, min_count, max_count));
return *this;
}
@ -1322,9 +1330,9 @@ public:
*
* This method is an out-of-place version of select_not_interacting.
*/
Edges selected_not_interacting (const Edges &other) const
Edges selected_not_interacting (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits<size_t>::max ()) const
{
return Edges (mp_delegate->selected_not_interacting (other));
return Edges (mp_delegate->selected_not_interacting (other, min_count, max_count));
}
/**

View File

@ -255,12 +255,12 @@ public:
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_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual EdgesDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual EdgesDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual EdgesDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const = 0;
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const = 0;
virtual EdgesDelegate *selected_outside (const Region &other) const = 0;
virtual EdgesDelegate *selected_not_outside (const Region &other) const = 0;

View File

@ -94,6 +94,9 @@ EdgeBoolAndOrNotLocalOperation::do_compute_local (db::Layout * /*layout*/, db::C
if (! is_and) {
result.insert (subject);
}
if (result2) {
result2->insert (subject);
}
} else {
scanner.insert (&subject, 0);
any_subject = true;
@ -199,5 +202,357 @@ EdgeToPolygonLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell
}
}
// ---------------------------------------------------------------------------------------------
// Edge2EdgeInteractingLocalOperation implementation
Edge2EdgeInteractingLocalOperation::Edge2EdgeInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count)
: m_mode (mode), m_output_mode (output_mode), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
}
db::Coord Edge2EdgeInteractingLocalOperation::dist () const
{
// touching is sufficient
return 1;
}
void Edge2EdgeInteractingLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
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;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert (&subject, 0);
}
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 1);
}
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, m_mode, m_min_count, m_max_count);
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, m_mode, m_min_count, m_max_count);
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
}
OnEmptyIntruderHint Edge2EdgeInteractingLocalOperation::on_empty_intruder_hint () const
{
if (m_mode == EdgesOutside) {
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
} else {
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
}
}
std::string Edge2EdgeInteractingLocalOperation::description () const
{
return tl::to_string (tr ("Select interacting edges"));
}
// ---------------------------------------------------------------------------------------------
// Edge2EdgePullLocalOperation implementation
Edge2EdgePullLocalOperation::Edge2EdgePullLocalOperation ()
{
// .. nothing yet ..
}
db::Coord Edge2EdgePullLocalOperation::dist () const
{
// touching is sufficient
return 1;
}
void Edge2EdgePullLocalOperation::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::Edge> &result = results.front ();
db::box_scanner<db::Edge, size_t> scanner;
std::set<db::Edge> others;
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert (&subject, 1);
}
for (std::set<db::Edge>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert (o.operator-> (), 0);
}
edge_interaction_filter<std::unordered_set<db::Edge> > filter (result, EdgesInteract, size_t (1), std::numeric_limits<size_t>::max ());
scanner.process (filter, 1, db::box_convert<db::Edge> ());
}
OnEmptyIntruderHint Edge2EdgePullLocalOperation::on_empty_intruder_hint () const
{
return Drop;
}
std::string Edge2EdgePullLocalOperation::description () const
{
return tl::to_string (tr ("Select interacting edges from other"));
}
// ---------------------------------------------------------------------------------------------
// Edge2EdgePullLocalOperation implementation
template <class TI>
edge_to_polygon_interacting_local_operation<TI>::edge_to_polygon_interacting_local_operation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count)
: m_mode (mode), m_output_mode (output_mode), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
}
template <class TI>
db::Coord edge_to_polygon_interacting_local_operation<TI>::dist () const
{
// touching is sufficient
return 1;
}
static const db::Polygon *deref (const db::Polygon &poly, std::list<db::Polygon> &)
{
return &poly;
}
static const db::Polygon *deref (const db::PolygonRef &pref, std::list<db::Polygon> &heap)
{
heap.push_back (pref.obj ().transformed (pref.trans ()));
return & heap.back ();
}
template <class TI>
void edge_to_polygon_interacting_local_operation<TI>::do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, TI> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const
{
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<TI> others;
for (typename shape_interactions<db::Edge, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (typename shape_interactions<db::Edge, TI>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (typename shape_interactions<db::Edge, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert1 (&subject, 0);
}
std::list<db::Polygon> heap;
for (typename std::set<TI>::const_iterator o = others.begin (); o != others.end (); ++o) {
scanner.insert2 (deref (*o, heap), 1);
}
if (m_output_mode == Inverse || m_output_mode == Both) {
std::unordered_set<db::Edge> interacting;
edge_to_polygon_interaction_filter<std::unordered_set<db::Edge> > filter (&interacting, m_mode, m_min_count, m_max_count);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
for (typename shape_interactions<db::Edge, TI>::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_polygon_interaction_filter<std::unordered_set<db::Edge> > filter (&result, m_mode, m_min_count, m_max_count);
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
}
template <class TI>
OnEmptyIntruderHint edge_to_polygon_interacting_local_operation<TI>::on_empty_intruder_hint () const
{
if (m_mode == EdgesOutside) {
return m_output_mode == Both ? Copy : (m_output_mode == Inverse ? Drop : Copy);
} else {
return m_output_mode == Both ? CopyToSecond : (m_output_mode == Inverse ? Copy : Drop);
}
}
template <class TI>
std::string edge_to_polygon_interacting_local_operation<TI>::description () const
{
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 ();
}
template class edge_to_polygon_interacting_local_operation<db::Polygon>;
template class edge_to_polygon_interacting_local_operation<db::PolygonRef>;
// ---------------------------------------------------------------------------------------------
// Edge2EdgePullLocalOperation implementation
namespace {
struct ResultInserter
{
typedef db::Polygon value_type;
ResultInserter (db::Layout *layout, std::unordered_set<db::PolygonRef> &result)
: mp_layout (layout), mp_result (&result)
{
// .. nothing yet ..
}
void insert (const db::Polygon &p)
{
(*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ()));
}
private:
db::Layout *mp_layout;
std::unordered_set<db::PolygonRef> *mp_result;
};
}
Edge2PolygonPullLocalOperation::Edge2PolygonPullLocalOperation ()
{
// .. nothing yet ..
}
db::Coord Edge2PolygonPullLocalOperation::dist () const
{
// touching is sufficient
return 1;
}
void Edge2PolygonPullLocalOperation::do_compute_local (db::Layout *layout, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (results.size () == 1);
std::unordered_set<db::PolygonRef> &result = results.front ();
db::box_scanner2<db::Edge, size_t, db::Polygon, size_t> scanner;
std::set<db::PolygonRef> others;
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::Edge, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j).second);
}
}
for (shape_interactions<db::Edge, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::Edge &subject = interactions.subject_shape (i->first);
scanner.insert1 (&subject, 1);
}
std::list<db::Polygon> heap;
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
heap.push_back (o->obj ().transformed (o->trans ()));
scanner.insert2 (& heap.back (), 0);
}
ResultInserter inserter (layout, result);
edge_to_polygon_interaction_filter<ResultInserter> filter (&inserter, EdgesInteract, size_t (1), std::numeric_limits<size_t>::max ());
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
}
OnEmptyIntruderHint Edge2PolygonPullLocalOperation::on_empty_intruder_hint () const
{
return Drop;
}
std::string Edge2PolygonPullLocalOperation::description () const
{
return tl::to_string (tr ("Select interacting regions"));
}
}

View File

@ -31,6 +31,7 @@
#include "dbEdgeBoolean.h"
#include "dbEdgeProcessor.h"
#include "dbLocalOperation.h"
#include "dbEdgesUtils.h"
namespace db
{
@ -79,6 +80,81 @@ private:
bool m_include_borders;
};
/**
* @brief Implements edge-to-edge interactions
*/
class DB_PUBLIC Edge2EdgeInteractingLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
enum output_mode_t { Normal, Inverse, Both };
Edge2EdgeInteractingLocalOperation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
EdgeInteractionMode m_mode;
output_mode_t m_output_mode;
size_t m_min_count, m_max_count;
};
/**
* @brief Implements edge-to-edge interactions (pull mode)
*/
class DB_PUBLIC Edge2EdgePullLocalOperation
: public local_operation<db::Edge, db::Edge, db::Edge>
{
public:
Edge2EdgePullLocalOperation ();
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::Edge> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
};
/**
* @brief Implements edge-to-polygon interactions
*/
template<class TI>
class DB_PUBLIC edge_to_polygon_interacting_local_operation
: public local_operation<db::Edge, TI, db::Edge>
{
public:
enum output_mode_t { Normal, Inverse, Both };
edge_to_polygon_interacting_local_operation (EdgeInteractionMode mode, output_mode_t output_mode, size_t min_count, size_t max_count);
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Edge, TI> &interactions, std::vector<std::unordered_set<db::Edge> > &results, const db::LocalProcessorBase * /*proc*/) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
private:
EdgeInteractionMode m_mode;
output_mode_t m_output_mode;
size_t m_min_count, m_max_count;
};
/**
* @brief Implements edge-to-polygon interactions (pull mode)
*/
class DB_PUBLIC Edge2PolygonPullLocalOperation
: public local_operation<db::Edge, db::PolygonRef, db::PolygonRef>
{
public:
Edge2PolygonPullLocalOperation ();
virtual db::Coord dist () const;
virtual void do_compute_local (db::Layout *layout, db::Cell * /*cell*/, const shape_interactions<db::Edge, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, const db::LocalProcessorBase * /*proc*/) const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
virtual std::string description () const;
};
}
#endif

View File

@ -189,17 +189,22 @@ EdgeSegmentSelector::process (const db::Edge &edge, std::vector<db::Edge> &res)
{
double l = std::max (edge.double_length () * m_fraction, double (m_length));
db::DVector ds;
if (! edge.is_degenerate ()) {
ds = db::DVector (edge.d ()) * (l / edge.double_length ());
}
if (m_mode < 0) {
res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + db::DVector (edge.d ()) * (l / edge.double_length ()))));
res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + ds)));
} else if (m_mode > 0) {
res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - db::DVector (edge.d ()) * (l / edge.double_length ())), edge.p2 ()));
res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - ds), edge.p2 ()));
} else {
db::DVector dl = db::DVector (edge.d ()) * (0.5 * l / edge.double_length ());
db::DVector dl = ds * 0.5;
db::DPoint center = db::DPoint (edge.p1 ()) + db::DVector (edge.p2 () - edge.p1 ()) * 0.5;
res.push_back (db::Edge (db::Point (center - dl), db::Point (center + dl)));
@ -403,16 +408,24 @@ struct DetectTagEdgeSink
static bool
edge_is_inside_or_outside (bool outside, const db::Edge &a, const db::Polygon &b)
{
db::EdgeProcessor ep;
ep.insert (b, 0);
if (a.is_degenerate ()) {
ep.insert (a, 1);
return ((db::inside_poly (b.begin_edge (), a.p1 ()) <= 0) == outside);
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);
} else {
return es.result;
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, !outside /*include borders in inside*/);
ep.process (es, op);
return es.result;
}
}
bool edge_is_inside (const db::Edge &a, const db::Polygon &b)

View File

@ -339,16 +339,39 @@ class edge_interaction_filter
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
edge_interaction_filter (OutputContainer &output, EdgeInteractionMode mode)
: mp_output (&output), m_mode (mode)
edge_interaction_filter (OutputContainer &output, EdgeInteractionMode mode, size_t min_count, size_t max_count)
: mp_output (&output), m_mode (mode), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
// NOTE: "counting" does not really make much sense in Outside mode ...
m_counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
tl_assert (!m_counting || mode != EdgesOutside);
}
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);
if (p != 0) {
return;
}
if (m_counting) {
size_t count = 0;
auto i = m_counts.find (o);
if (i != m_counts.end ()) {
count = i->second;
}
bool match = (count >= m_min_count && count <= m_max_count);
if (match == (m_mode != EdgesOutside)) {
mp_output->insert (*o);
}
} else {
if (m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
mp_output->insert (*o);
}
}
}
@ -363,14 +386,22 @@ public:
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);
if (m_counting) {
m_counts[o] += 1;
} else {
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);
if (m_counting) {
m_counts[o] += 1;
} else {
m_seen.insert (o);
}
}
@ -380,7 +411,10 @@ public:
private:
OutputContainer *mp_output;
std::set<const db::Edge *> m_seen;
std::map<const db::Edge *, size_t> m_counts;
EdgeInteractionMode m_mode;
size_t m_min_count, m_max_count;
bool m_counting;
};
/**
@ -408,20 +442,39 @@ DB_PUBLIC bool edge_is_outside (const db::Edge &a, const db::Polygon &b);
* There is a special box converter which is able to sort that out as well.
*/
template <class OutputContainer, class OutputType = typename OutputContainer::value_type>
class edge_to_region_interaction_filter
class edge_to_polygon_interaction_filter
: public db::box_scanner_receiver2<db::Edge, size_t, db::Polygon, size_t>
{
public:
edge_to_region_interaction_filter (OutputContainer *output, EdgeInteractionMode mode)
: mp_output (output), m_mode (mode)
edge_to_polygon_interaction_filter (OutputContainer *output, EdgeInteractionMode mode, size_t min_count, size_t max_count)
: mp_output (output), m_mode (mode), m_min_count (min_count), m_max_count (max_count)
{
// .. nothing yet ..
// NOTE: "counting" does not really make much sense in Outside mode ...
m_counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
tl_assert (!m_counting || mode != EdgesOutside);
}
void finish (const OutputType *o)
{
if (m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
mp_output->insert (*o);
if (m_counting) {
size_t count = 0;
auto i = m_counts.find (o);
if (i != m_counts.end ()) {
count = i->second;
}
bool match = (count >= m_min_count && count <= m_max_count);
if (match == (m_mode != EdgesOutside)) {
mp_output->insert (*o);
}
} else {
if (m_mode == EdgesOutside && m_seen.find (o) == m_seen.end ()) {
mp_output->insert (*o);
}
}
}
@ -448,7 +501,18 @@ public:
const OutputType *ep = 0;
tl::select (ep, e, p);
if (m_seen.find (ep) == m_seen.end ()) {
if (m_counting) {
if ((m_mode == EdgesInteract && db::edge_interacts (*e, *p)) ||
(m_mode == EdgesInside && db::edge_is_inside (*e, *p)) ||
(m_mode == EdgesOutside && ! db::edge_is_outside (*e, *p))) {
// we report the result on "finish" here.
m_counts[ep] += 1;
}
} else if (m_seen.find (ep) == m_seen.end ()) {
if ((m_mode == EdgesInteract && db::edge_interacts (*e, *p)) ||
(m_mode == EdgesInside && db::edge_is_inside (*e, *p))) {
@ -468,8 +532,11 @@ public:
private:
OutputContainer *mp_output;
std::map<const OutputType *, size_t> m_counts;
std::set<const OutputType *> m_seen;
EdgeInteractionMode m_mode;
size_t m_min_count, m_max_count;
bool m_counting;
};
/**

View File

@ -94,12 +94,12 @@ public:
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_interacting (const Edges &, size_t, size_t) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_interacting (const Edges &, size_t, size_t) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_interacting (const Region &, size_t, size_t) const { return new EmptyEdges (); }
virtual EdgesDelegate *selected_not_interacting (const Region &, size_t, size_t) const { return new EmptyEdges (); }
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair (const Edges &, size_t, size_t) 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 (); }

View File

@ -176,7 +176,7 @@ EmptyRegion::angle_check (double, double, bool) const
}
EdgesDelegate *
EmptyRegion::edges (const EdgeFilterBase *) const
EmptyRegion::edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const
{
return new EmptyEdges ();
}

View File

@ -82,7 +82,7 @@ public:
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return this; }
virtual RegionDelegate *scaled_and_snapped (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return new EmptyRegion (); }
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
virtual EdgesDelegate *edges (const EdgeFilterBase *, const PolygonToEdgeProcessorBase *) const;
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; }
virtual RegionDelegate *filtered (const PolygonFilterBase &) const { return new EmptyRegion (); }
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &) { return this; }

View File

@ -133,9 +133,7 @@ FlatEdges::ensure_merged_edges_valid () const
scanner.reserve (mp_edges->size ());
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
scanner.insert (&*e, 0);
}
scanner.insert (&*e, 0);
}
scanner.process (cluster_collector, 1, db::box_convert<db::Edge> ());
@ -145,9 +143,7 @@ FlatEdges::ensure_merged_edges_valid () const
std::map<db::properties_id_type, std::vector<const db::Edge *> > edges_by_props;
for (EdgesIterator e (begin ()); ! e.at_end (); ++e) {
if (! e->is_degenerate ()) {
edges_by_props [e.prop_id ()].push_back (e.operator-> ());
}
edges_by_props [e.prop_id ()].push_back (e.operator-> ());
}
for (auto s2p = edges_by_props.begin (); s2p != edges_by_props.end (); ++s2p) {

View File

@ -43,7 +43,6 @@ FlatRegion::FlatRegion (const FlatRegion &other)
: MutableRegion (other), mp_polygons (other.mp_polygons), mp_merged_polygons (other.mp_merged_polygons), mp_properties_repository (other.mp_properties_repository)
{
init ();
m_is_merged = other.m_is_merged;
m_merged_polygons_valid = other.m_merged_polygons_valid;
}
@ -52,15 +51,22 @@ FlatRegion::FlatRegion (const db::Shapes &polygons, bool is_merged)
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
{
init ();
m_is_merged = is_merged;
}
FlatRegion::FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
: MutableRegion (), mp_polygons (new db::Shapes (polygons)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
{
init ();
m_is_merged = is_merged;
transform_generic (trans);
set_merged_semantics (merged_semantics);
}
FlatRegion::FlatRegion (bool is_merged)
: MutableRegion (), mp_polygons (new db::Shapes (false)), mp_merged_polygons (new db::Shapes (false)), mp_properties_repository (new db::PropertiesRepository ())
{
init ();
m_is_merged = is_merged;
}

View File

@ -52,7 +52,8 @@ public:
typedef polygon_layer_wp_type::iterator polygon_iterator_wp_type;
FlatRegion ();
FlatRegion (const db::Shapes &polygons, bool is_merged);
FlatRegion (const db::Shapes &polygons, bool is_merged = false);
FlatRegion (const db::Shapes &polygons, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged = false);
FlatRegion (bool is_merged);
FlatRegion (const FlatRegion &other);

View File

@ -2575,6 +2575,7 @@ template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRef, db::Edge,
template class DB_PUBLIC local_processor_cell_contexts<db::PolygonRef, db::PolygonRef, db::EdgePair>;
template class DB_PUBLIC local_processor_cell_contexts<db::Polygon, db::Polygon, db::EdgePair>;
template class DB_PUBLIC local_processor_cell_contexts<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_processor_cell_contexts<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor_cell_contexts<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_cell_contexts<db::Edge, db::Edge, db::EdgePair>;
@ -2591,6 +2592,7 @@ template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Text>;
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Edge>;
template class DB_PUBLIC shape_interactions<db::Edge, db::Edge>;
template class DB_PUBLIC shape_interactions<db::Edge, db::PolygonRef>;
template class DB_PUBLIC shape_interactions<db::Edge, db::Polygon>;
template class DB_PUBLIC shape_interactions<db::TextRef, db::TextRef>;
template class DB_PUBLIC shape_interactions<db::TextRef, db::PolygonRef>;
@ -2621,6 +2623,7 @@ template class DB_PUBLIC local_processor_context_computation_task<db::Polygon, d
template class DB_PUBLIC local_processor_context_computation_task<db::Polygon, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::Edge, db::EdgePair>;
template class DB_PUBLIC local_processor_context_computation_task<db::Edge, db::PolygonRef, db::PolygonRef>;
@ -2644,6 +2647,7 @@ template class DB_PUBLIC local_processor_result_computation_task<db::PolygonRef,
template class DB_PUBLIC local_processor_result_computation_task<db::Polygon, db::Polygon, db::EdgePair>;
template class DB_PUBLIC local_processor_result_computation_task<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor_result_computation_task<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_processor_result_computation_task<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor_result_computation_task<db::Edge, db::Edge, db::EdgePair>;
// explicit instantiations
@ -2671,6 +2675,7 @@ template class DB_PUBLIC local_processor<db::Polygon, db::Polygon, db::EdgePair>
template class DB_PUBLIC local_processor<db::Polygon, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_processor<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_processor<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_processor<db::Edge, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_processor<db::Edge, db::Edge, db::EdgePair>;
template class DB_PUBLIC local_processor<db::TextRef, db::PolygonRef, db::TextRef>;

View File

@ -101,6 +101,7 @@ template class DB_PUBLIC local_operation<db::Polygon, db::Polygon, db::EdgePair>
template class DB_PUBLIC local_operation<db::Polygon, db::TextRef, db::TextRef>;
template class DB_PUBLIC local_operation<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_operation<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_operation<db::Edge, db::Polygon, db::Edge>;
template class DB_PUBLIC local_operation<db::Edge, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::Edge, db::Edge, db::EdgePair>;
template class DB_PUBLIC local_operation<db::TextRef, db::PolygonRef, db::PolygonRef>;

View File

@ -30,6 +30,7 @@
#include "dbLayout.h"
#include "tlVariant.h"
#include "tlObject.h"
#include "tlOptional.h"
namespace db
{
@ -267,6 +268,56 @@ public:
m_choice_descriptions = choice_descriptions;
}
/**
* @brief Sets the minimum value
*
* The minimum value is a visual feature and limits the allowed values for numerical
* entry boxes. This applies to parameters of type int or double. The minimum value
* is not effective if choices are present.
*
* The minimum value is not enforced - for example there is no restriction implemented
* when setting values programmatically.
*
* Setting this attribute to "nil" (the default) implies "no limit".
*/
void set_min_value (const tl::Variant &min)
{
m_min_value = min;
}
/**
* @brief Gets the minimum value (see \set_min_value)
*/
const tl::Variant &min_value () const
{
return m_min_value;
}
/**
* @brief Sets the maximum value
*
* The maximum value is a visual feature and limits the allowed values for numerical
* entry boxes. This applies to parameters of type int or double. The maximum value
* is not effective if choices are present.
*
* The maximum value is not enforced - for example there is no restriction implemented
* when setting values programmatically.
*
* Setting this attribute to "nil" (the default) implies "no limit".
*/
void set_max_value (const tl::Variant &max)
{
m_max_value = max;
}
/**
* @brief Gets the maximum value (see \set_max_value)
*/
const tl::Variant &max_value () const
{
return m_max_value;
}
/**
* @brief Equality
*/
@ -280,7 +331,9 @@ public:
m_type == d.m_type &&
m_name == d.m_name &&
m_description == d.m_description &&
m_unit == d.m_unit;
m_unit == d.m_unit &&
m_min_value == d.m_min_value &&
m_max_value == d.m_max_value;
}
private:
@ -291,6 +344,7 @@ private:
type m_type;
std::string m_name;
std::string m_description, m_unit;
tl::Variant m_min_value, m_max_value;
};
/**

View File

@ -48,6 +48,8 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
mp_shape_prop_sel = d.mp_shape_prop_sel;
m_shape_inv_prop_sel = d.m_shape_inv_prop_sel;
m_overlapping = d.m_overlapping;
m_for_merged_input = d.m_for_merged_input;
m_start = d.m_start;
m_stop = d.m_stop;
@ -80,6 +82,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
m_cells = d.m_cells;
m_local_complex_region_stack = d.m_local_complex_region_stack;
m_local_region_stack = d.m_local_region_stack;
m_skip_shapes_stack = d.m_skip_shapes_stack;
m_needs_reinit = d.m_needs_reinit;
m_inst_quad_id = d.m_inst_quad_id;
m_inst_quad_id_stack = d.m_inst_quad_id_stack;
@ -99,6 +102,7 @@ RecursiveShapeIterator::RecursiveShapeIterator ()
mp_cell = 0;
m_current_layer = 0;
m_overlapping = false;
m_for_merged_input = false;
m_max_depth = std::numeric_limits<int>::max (); // all
m_min_depth = 0;
m_shape_flags = shape_iterator::All;
@ -116,6 +120,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes)
mp_shapes = &shapes;
mp_top_cell = 0;
m_overlapping = false;
m_for_merged_input = false;
init ();
init_region (box_type::world ());
}
@ -127,6 +132,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
mp_shapes = &shapes;
mp_top_cell = 0;
m_overlapping = overlapping;
m_for_merged_input = false;
init ();
init_region (region);
}
@ -138,11 +144,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const shapes_type &shapes, const
mp_shapes = &shapes;
mp_top_cell = 0;
m_overlapping = overlapping;
m_for_merged_input = false;
init ();
init_region (region);
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout, layer)
{
m_layer = layer;
@ -151,11 +158,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init ();
init_region (region);
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout, layer)
{
m_layer = layer;
@ -164,11 +172,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init ();
init_region (region);
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, bool for_merged_input)
: m_box_convert (layout, layer)
{
m_layer = layer;
@ -177,11 +186,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = false;
m_for_merged_input = for_merged_input;
init ();
init_region (box_type::world ());
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout)
{
m_layer = 0;
@ -191,11 +201,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init ();
init_region (region);
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout)
{
m_layer = 0;
@ -205,11 +216,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init ();
init_region (region);
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, bool for_merged_input)
: m_box_convert (layout)
{
m_layer = 0;
@ -219,11 +231,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = false;
m_for_merged_input = for_merged_input;
init ();
init_region (box_type::world ());
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout)
{
m_layer = 0;
@ -233,11 +246,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init ();
init_region (region);
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, bool overlapping)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, bool overlapping, bool for_merged_input)
: m_box_convert (layout)
{
m_layer = 0;
@ -247,11 +261,12 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = overlapping;
m_for_merged_input = for_merged_input;
init ();
init_region (region);
}
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers)
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, bool for_merged_input)
: m_box_convert (layout)
{
m_layer = 0;
@ -261,6 +276,7 @@ RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const
mp_shapes = 0;
mp_top_cell = &cell;
m_overlapping = false;
m_for_merged_input = for_merged_input;
init ();
init_region (box_type::world ());
}
@ -447,6 +463,8 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
m_local_region_stack.clear ();
m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
m_skip_shapes_stack.clear ();
m_skip_shapes_stack.push_back (false);
m_local_complex_region_stack.clear ();
if (mp_complex_region.get ()) {
@ -723,11 +741,21 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
if (is_empty) {
// skip entire cell
++m_inst;
new_inst (receiver);
} else {
down (receiver);
} else if (!down (receiver)) {
// skip this instance array member
++m_inst_array;
new_inst_member (receiver);
if (m_inst_array.at_end ()) {
++m_inst;
new_inst (receiver);
}
}
} else {
@ -755,9 +783,42 @@ RecursiveShapeIterator::next_shape (RecursiveShapeReceiver *receiver) const
}
}
void
bool
RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
{
bool skip_shapes = false;
if (m_for_merged_input && ! m_skip_shapes_stack.back () && (! m_has_layers || m_layers.size () == 1)) {
// Try some optimization: if the instance we're looking at is entirely covered
// by a rectangle (other objects are too expensive to check), then we skip it
//
// We check 10 shapes max.
box_type inst_bx;
if (m_inst->size () == 1) {
inst_bx = m_inst->bbox (m_box_convert);
} else {
inst_bx = m_inst->complex_trans (*m_inst_array) * m_box_convert (m_inst->cell_inst ().object ());
}
unsigned int l = m_has_layers ? m_layers.front () : m_layer;
auto si = cell ()->shapes (l).begin_overlapping (inst_bx, m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
size_t nmax = 10;
while (! si.at_end () && nmax-- > 0) {
if (inst_bx.inside (si->rectangle ())) {
skip_shapes = true;
break;
}
++si;
}
}
if (skip_shapes && (! receiver || ! receiver->wants_all_cells ())) {
return false;
}
tl_assert (mp_layout);
m_trans_stack.push_back (m_trans);
@ -779,11 +840,13 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
box_type new_region = box_type::world ();
// compute the region inside the new cell
if (new_region != m_region) {
new_region = m_trans.inverted () * m_region;
if (new_region != m_local_region_stack.back ()) {
new_region = m_inst->complex_trans (*m_inst_array).inverted () * m_local_region_stack.back ();
new_region &= cell_bbox (cell_index ());
}
m_local_region_stack.push_back (new_region);
m_skip_shapes_stack.push_back (m_skip_shapes_stack.back () || skip_shapes);
if (! m_local_complex_region_stack.empty ()) {
@ -817,11 +880,25 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
}
if (receiver) {
receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
}
// do not descend if the box is empty
new_cell (receiver);
if (m_local_region_stack.back ().empty ()) {
pop ();
return false;
} else {
if (receiver) {
receiver->enter_cell (this, cell (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
}
new_cell (receiver);
return true;
}
}
void
@ -831,6 +908,12 @@ RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
receiver->leave_cell (this, cell ());
}
pop ();
}
void
RecursiveShapeIterator::pop () const
{
m_shape = shape_iterator ();
m_shape_quad_id = 0;
@ -846,6 +929,7 @@ RecursiveShapeIterator::up (RecursiveShapeReceiver *receiver) const
mp_cell = m_cells.back ();
m_cells.pop_back ();
m_local_region_stack.pop_back ();
m_skip_shapes_stack.pop_back ();
if (! m_local_complex_region_stack.empty ()) {
m_local_complex_region_stack.pop_back ();
}
@ -870,7 +954,7 @@ RecursiveShapeIterator::start_shapes () const
void
RecursiveShapeIterator::new_layer () const
{
if (int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
if (m_skip_shapes_stack.back () || int (m_trans_stack.size ()) < m_min_depth || int (m_trans_stack.size ()) > m_max_depth) {
m_shape = shape_iterator ();
} else if (! m_overlapping) {
m_shape = cell ()->shapes (m_layer).begin_touching (m_local_region_stack.back (), m_shape_flags, mp_shape_prop_sel, m_shape_inv_prop_sel);
@ -901,12 +985,16 @@ RecursiveShapeIterator::new_cell (RecursiveShapeReceiver *receiver) const
new_layer ();
m_inst = cell ()->begin_touching (m_local_region_stack.back ());
if (m_overlapping) {
m_inst = cell ()->begin_touching (m_local_region_stack.back ().enlarged (box_type::vector_type (-1, -1)));
} else {
m_inst = cell ()->begin_touching (m_local_region_stack.back ());
}
m_inst_quad_id = 0;
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
if (! m_local_complex_region_stack.empty () && (! receiver || ! receiver->wants_all_cells ())) {
skip_inst_iter_for_complex_region ();
}
@ -922,7 +1010,7 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
while (! m_inst.at_end ()) {
// skip instance quad if possible
if (! m_local_complex_region_stack.empty ()) {
if (! m_local_complex_region_stack.empty () && (! receiver || ! receiver->wants_all_cells ())) {
skip_inst_iter_for_complex_region ();
if (m_inst.at_end ()) {
break;
@ -950,7 +1038,11 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
// a singular iterator
m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false);
} else if (with_region) {
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
if (m_overlapping) {
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back ().enlarged (box_type::vector_type (-1, -1)), m_box_convert);
} else {
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
}
} else {
m_inst_array = m_inst->cell_inst ().begin ();
}

View File

@ -122,12 +122,13 @@ public:
* @param layer The layer from which to deliver the shapes
* @param region The region from which to select the shapes
* @param overlapping Specify overlapping mode
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
* overlap the given region by at least one database unit.
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type &region, bool overlapping = false, bool for_merged_input = false);
/**
* @brief Standard constructor
@ -137,13 +138,14 @@ public:
* @param layer The layer from which to deliver the shapes
* @param region The complex region from which to select the shapes
* @param overlapping Specify overlapping mode
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
* overlap the given region by at least one database unit. It allows specification of a complex
* search region.
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type &region, bool overlapping = false, bool for_merged_input = false);
/**
* @brief Standard constructor for "world" iteration
@ -153,8 +155,9 @@ public:
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
* @param layer The layer from which to deliver the shapes
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, bool for_merged_input = false);
/**
* @brief Standard constructor with a layer selection
@ -164,12 +167,13 @@ public:
* @param layers The layers from which to deliver the shapes
* @param region The region from which to select the shapes
* @param overlapping Specify overlapping mode
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
* overlap the given region by at least one database unit.
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type &region, bool overlapping = false, bool for_merged_input = false);
/**
* @brief Standard constructor with a layer selection
@ -179,13 +183,14 @@ public:
* @param layers The layers from which to deliver the shapes
* @param region The complex region from which to select the shapes
* @param overlapping Specify overlapping mode
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
* overlap the given region by at least one database unit. It allows specification of a complex
* search region.
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type &region, bool overlapping = false, bool for_merged_input = false);
/**
* @brief Standard constructor with a layer selection
@ -195,12 +200,13 @@ public:
* @param layers The layers from which to deliver the shapes
* @param region The region from which to select the shapes
* @param overlapping Specify overlapping mode
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
* overlap the given region by at least one database unit.
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type &region, bool overlapping = false, bool for_merged_input = false);
/**
* @brief Standard constructor with a layer selection
@ -210,13 +216,14 @@ public:
* @param layers The layers from which to deliver the shapes
* @param region The complex region from which to select the shapes
* @param overlapping Specify overlapping mode
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*
* By default the iterator operates in touching mode - i.e. shapes that touch the given region
* are returned. By specifying the "overlapping" flag with a true value, the iterator delivers shapes that
* overlap the given region by at least one database unit. It allows specification of a complex
* search region.
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, bool overlapping = false);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type &region, bool overlapping = false, bool for_merged_input = false);
/**
* @brief Standard constructor for "world" iteration with a layer set
@ -226,8 +233,9 @@ public:
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
* @param layers The layers from which to deliver the shapes
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, bool for_merged_input = false);
/**
* @brief Standard constructor for "world" iteration with a layer set
@ -237,8 +245,9 @@ public:
* @param layout The layout from which to get the cell hierarchy
* @param cell The starting cell
* @param layers The layers from which to deliver the shapes
* @param for_merged_input Optimize for merged input - drop shapes that are completely covered by others
*/
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers);
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, bool for_merged_input = false);
/**
* @brief Destructor
@ -427,6 +436,25 @@ public:
}
}
/**
* @brief Gets a flag indicating whether optimizing for merged input
*/
bool for_merged_input () const
{
return m_for_merged_input;
}
/**
* @brief Sets a flag indicating whether optimizing for merged input
*/
void set_for_merged_input (bool f)
{
if (m_for_merged_input != f) {
m_for_merged_input = f;
m_needs_reinit = true;
}
}
/**
* @brief Sets a global transformation
*
@ -812,7 +840,7 @@ private:
unsigned int m_shape_flags;
const shape_iterator::property_selector *mp_shape_prop_sel;
bool m_shape_inv_prop_sel;
bool m_overlapping;
bool m_overlapping, m_for_merged_input;
std::set<db::cell_index_type> m_start, m_stop;
cplx_trans_type m_global_trans;
db::PropertiesTranslator m_property_translator;
@ -839,6 +867,7 @@ private:
mutable std::vector<const cell_type *> m_cells;
mutable std::vector<box_tree_type> m_local_complex_region_stack;
mutable std::vector<box_type> m_local_region_stack;
mutable std::vector<bool> m_skip_shapes_stack;
mutable bool m_needs_reinit;
mutable size_t m_inst_quad_id;
mutable std::vector<size_t> m_inst_quad_id_stack;
@ -858,7 +887,8 @@ private:
void new_cell (RecursiveShapeReceiver *receiver) const;
void new_layer () const;
void up (RecursiveShapeReceiver *receiver) const;
void down (RecursiveShapeReceiver *receiver) const;
bool down (RecursiveShapeReceiver *receiver) const;
void pop () const;
bool is_outside_complex_region (const db::Box &box) const;

View File

@ -31,6 +31,9 @@
#include "dbFlatEdges.h"
#include "dbPolygonTools.h"
#include "dbCompoundOperation.h"
#include "dbLayout.h"
#include "dbWriter.h"
#include "tlStream.h"
#include "tlGlobPattern.h"
// NOTE: include this to provide the symbols for "make_variant"
@ -74,14 +77,42 @@ Region &Region::operator= (const Region &other)
return *this;
}
Region::Region (const RecursiveShapeIterator &si)
Region::Region (const RecursiveShapeIterator &si, bool merged_semantics, bool is_merged)
{
mp_delegate = new OriginalLayerRegion (si);
mp_delegate = new OriginalLayerRegion (si, db::ICplxTrans (), merged_semantics, is_merged);
}
Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics)
Region::Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
{
mp_delegate = new OriginalLayerRegion (si, trans, merged_semantics);
mp_delegate = new OriginalLayerRegion (si, trans, merged_semantics, is_merged);
}
Region::Region (const Shapes &shapes, bool merged_semantics, bool is_merged)
{
db::FlatRegion *flat_region = new FlatRegion (is_merged);
flat_region->reserve (shapes.size (db::ShapeIterator::Regions));
// NOTE: we need to normalize the shapes to polygons because this is what the flat region expects
for (auto s = shapes.begin (db::ShapeIterator::Regions); ! s.at_end (); ++s) {
flat_region->insert (*s);
}
mp_delegate = flat_region;
mp_delegate->set_merged_semantics (merged_semantics);
}
Region::Region (const Shapes &shapes, const db::ICplxTrans &trans, bool merged_semantics, bool is_merged)
{
db::FlatRegion *flat_region = new FlatRegion (is_merged);
flat_region->reserve (shapes.size (db::ShapeIterator::Regions));
// NOTE: we need to normalize the shapes to polygons because this is what the flat region expects
for (auto s = shapes.begin (db::ShapeIterator::Regions); ! s.at_end (); ++s) {
flat_region->insert (*s, trans);
}
mp_delegate = flat_region;
mp_delegate->set_merged_semantics (merged_semantics);
}
Region::Region (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
@ -101,6 +132,23 @@ Region::Region (DeepShapeStore &dss)
mp_delegate = new db::DeepRegion (db::DeepLayer (&dss, layout_index, dss.layout (layout_index).insert_layer ()));
}
void
Region::write (const std::string &fn) const
{
// method provided for debugging purposes
db::Layout layout;
const db::Cell &top = layout.cell (layout.add_cell ("REGION"));
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
insert_into (&layout, top.cell_index (), li);
tl::OutputStream os (fn);
db::SaveLayoutOptions opt;
opt.set_format_from_filename (fn);
db::Writer writer (opt);
writer.write (layout, os);
}
const db::RecursiveShapeIterator &
Region::iter () const
{
@ -556,16 +604,23 @@ Region::texts_as_dots (const std::string &pat, bool pattern, db::DeepShapeStore
fill_texts (si.first, pat, pattern, dot_delivery<db::FlatEdges> (), res.get (), si.second, dr);
return Edges (res.release ());
Edges edges (res.release ());
edges.set_merged_semantics (false);
return edges;
}
db::Edges edges;
text_shape_receiver<dot_delivery<db::Shapes> > pipe = text_shape_receiver<dot_delivery<db::Shapes> > (dot_delivery<db::Shapes> (), pat, pattern, dr);
if (dr && dr->deep_layer ().store () == &store) {
return Edges (new db::DeepEdges (store.create_copy (dr->deep_layer (), &pipe)));
edges = Edges (new db::DeepEdges (store.create_copy (dr->deep_layer (), &pipe)));
} else {
return Edges (new db::DeepEdges (store.create_custom_layer (si.first, &pipe, si.second)));
edges = Edges (new db::DeepEdges (store.create_custom_layer (si.first, &pipe, si.second)));
}
edges.set_merged_semantics (false);
return edges;
}
Region

View File

@ -199,7 +199,7 @@ public:
* Creates a region from a recursive shape iterator. This allows feeding a region
* from a hierarchy of cells.
*/
explicit Region (const RecursiveShapeIterator &si);
explicit Region (const RecursiveShapeIterator &si, bool merged_semantics = true, bool is_merged = false);
/**
* @brief Constructor from a RecursiveShapeIterator with a transformation
@ -208,7 +208,23 @@ public:
* from a hierarchy of cells. The transformation is useful to scale to a specific
* DBU for example.
*/
explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true);
explicit Region (const RecursiveShapeIterator &si, const db::ICplxTrans &trans, bool merged_semantics = true, bool is_merged = false);
/**
* @brief Constructor from a Shapes container
*
* Creates a region from a shapes container.
*/
explicit Region (const Shapes &si, bool merged_semantics = true, bool is_merged = false);
/**
* @brief Constructor from a Shapes container with a transformation
*
* Creates a region from a recursive shape iterator. This allows feeding a region
* from a hierarchy of cells. The transformation is useful to scale to a specific
* DBU for example.
*/
explicit Region (const Shapes &si, const db::ICplxTrans &trans, bool merged_semantics = true, bool is_merged = false);
/**
* @brief Constructor from a RecursiveShapeIterator providing a deep representation
@ -232,6 +248,14 @@ public:
*/
explicit Region (DeepShapeStore &dss);
/**
* @brief Writes the region to a file
*
* This method is provided for debugging purposes. A flat image of the
* region is written to a layout file with a single top cell on layer 0/0.
*/
void write (const std::string &fn) const;
/**
* @brief Implementation of the ShapeCollection interface
*/
@ -770,7 +794,7 @@ public:
*/
Edges edges () const
{
return Edges (mp_delegate->edges (0));
return Edges (mp_delegate->edges (0, 0));
}
/**
@ -783,7 +807,34 @@ public:
*/
Edges edges (const EdgeFilterBase &filter) const
{
return mp_delegate->edges (&filter);
return mp_delegate->edges (&filter, 0);
}
/**
* @brief Returns an edge set containing all edges of the polygons in this region
*
* Merged semantics applies. In merged semantics, only full, outer edges are delivered.
* This version allows specifying a polygon to edge processor with additional features
* like extraction of convex edges only.
*/
Edges edges (const db::PolygonToEdgeProcessorBase &proc) const
{
return Edges (mp_delegate->edges (0, &proc));
}
/**
* @brief Returns an edge set containing all edges of the polygons in this region
*
* This version allows one to specify a filter by which the edges are filtered before they are
* returned.
*
* Merged semantics applies. In merged semantics, only full, outer edges are delivered.
* This version allows specifying a polygon to edge processor with additional features
* like extraction of convex edges only.
*/
Edges edges (const EdgeFilterBase &filter, const db::PolygonToEdgeProcessorBase &proc) const
{
return mp_delegate->edges (&filter, &proc);
}
/**

View File

@ -133,7 +133,7 @@ Edge2EdgeCheckBase::finish (const Edge *o, size_t p)
std::set<db::Edge> partial_edges;
db::EdgeBooleanCluster<std::set<db::Edge> > ec (&partial_edges, db::EdgeNot);
db::EdgeBooleanCluster<std::set<db::Edge> > ec (&partial_edges, 0, db::EdgeNot);
ec.add (o, 0);
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = i0; i != m_e2ep.end () && i->first == k; ++i) {

View File

@ -211,7 +211,7 @@ public:
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0;
virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0;
virtual EdgesDelegate *edges (const EdgeFilterBase *filter) const = 0;
virtual EdgesDelegate *edges (const EdgeFilterBase *filter, const db::PolygonToEdgeProcessorBase *proc) const = 0;
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) = 0;
virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const = 0;
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter) = 0;

View File

@ -136,10 +136,104 @@ bool RelativeExtentsAsEdges::result_must_not_be_merged () const
// -----------------------------------------------------------------------------------
// PolygonToEdgeProcessor implementation
PolygonToEdgeProcessor::PolygonToEdgeProcessor (PolygonToEdgeProcessor::EdgeMode mode)
: m_mode (mode)
{
// .. nothing yet ..
}
inline void
next (db::Polygon::contour_type::simple_iterator &iter, const db::Polygon::contour_type &contour)
{
if (++iter == contour.end ()) {
iter = contour.begin ();
}
}
static void
contour_to_edges (const db::Polygon::contour_type &contour, PolygonToEdgeProcessor::EdgeMode mode, std::vector<db::Edge> &result)
{
if (contour.size () < 3) {
return;
}
db::Polygon::contour_type::simple_iterator pm1 = contour.begin ();
db::Polygon::contour_type::simple_iterator p0 = pm1;
next (p0, contour);
db::Polygon::contour_type::simple_iterator p1 = p0;
next (p1, contour);
db::Polygon::contour_type::simple_iterator p2 = p1;
next (p2, contour);
while (pm1 != contour.end ()) {
int s1 = db::vprod_sign (*p0 - *pm1, *p1 - *p0);
int s2 = db::vprod_sign (*p1 - *p0, *p2 - *p1);
bool take = true;
switch (mode) {
case PolygonToEdgeProcessor::All:
default:
break;
case PolygonToEdgeProcessor::Convex:
take = s1 < 0 && s2 < 0;
break;
case PolygonToEdgeProcessor::NotConvex:
take = ! (s1 < 0 && s2 < 0);
break;
case PolygonToEdgeProcessor::Concave:
take = s1 > 0 && s2 > 0;
break;
case PolygonToEdgeProcessor::NotConcave:
take = ! (s1 > 0 && s2 > 0);
break;
case PolygonToEdgeProcessor::StepOut:
take = s1 > 0 && s2 < 0;
break;
case PolygonToEdgeProcessor::NotStepOut:
take = ! (s1 > 0 && s2 < 0);
break;
case PolygonToEdgeProcessor::StepIn:
take = s1 < 0 && s2 > 0;
break;
case PolygonToEdgeProcessor::NotStepIn:
take = ! (s1 < 0 && s2 > 0);
break;
case PolygonToEdgeProcessor::Step:
take = s1 * s2 < 0;
break;
case PolygonToEdgeProcessor::NotStep:
take = ! (s1 * s2 < 0);
break;
}
if (take) {
result.push_back (db::Edge (*p0, *p1));
}
++pm1;
next (p0, contour);
next (p1, contour);
next (p2, contour);
}
}
void PolygonToEdgeProcessor::process (const db::Polygon &poly, std::vector<db::Edge> &result) const
{
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
result.push_back (*e);
if (m_mode == All) {
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) {
result.push_back (*e);
}
} else {
for (unsigned int i = 0; i < poly.holes () + 1; ++i) {
contour_to_edges (poly.contour (i), m_mode, result);
}
}
}

View File

@ -293,12 +293,15 @@ class DB_PUBLIC PolygonToEdgeProcessor
: public db::PolygonToEdgeProcessorBase
{
public:
PolygonToEdgeProcessor ()
{
// .. nothing yet ..
}
enum EdgeMode { All = 0, Convex, Concave, StepIn, StepOut, Step,
NotConvex, NotConcave, NotStepIn, NotStepOut, NotStep };
PolygonToEdgeProcessor (EdgeMode mode = All);
void process (const db::Polygon &poly, std::vector<db::Edge> &result) const;
private:
EdgeMode m_mode;
};
/**

View File

@ -807,6 +807,61 @@ Shape::box_type Shape::bbox () const
}
}
Shape::box_type Shape::rectangle () const
{
if (is_box ()) {
return box ();
}
switch (m_type) {
case db::Shape::Polygon:
return polygon ().is_box () ? polygon ().box () : box_type ();
case db::Shape::PolygonRef:
case db::Shape::PolygonPtrArrayMember:
return polygon_ref ().is_box () ? polygon_ref ().box () : box_type ();
case db::Shape::SimplePolygon:
return simple_polygon ().is_box () ? simple_polygon ().box () : box_type ();
case db::Shape::SimplePolygonRef:
case db::Shape::SimplePolygonPtrArrayMember:
return simple_polygon_ref ().is_box () ? simple_polygon_ref ().box () : box_type ();
case db::Shape::Path:
{
const path_type &p = path ();
if (! p.round () && p.points () <= 2 && p.points () > 0) {
point_type p1 = *p.begin ();
point_type p2 = p1;
if (p.points () == 2) {
p2 = *++p.begin ();
}
if (p1.x () == p2.x () || p1.y () == p2.y ()) {
return p.box ();
}
}
}
break;
case db::Shape::PathRef:
case db::Shape::PathPtrArrayMember:
{
const path_ref_type &p = path_ref ();
if (! p.ptr ()->round () && p.ptr ()->points () <= 2 && p.ptr ()->points () > 0) {
point_type p1 = *p.begin ();
point_type p2 = p1;
if (p.ptr ()->points () == 2) {
p2 = *++p.begin ();
}
if (p1.x () == p2.x () || p1.y () == p2.y ()) {
return p.box ();
}
}
}
break;
default:
break;
}
return box_type ();
}
std::string
Shape::to_string () const
{

View File

@ -2651,6 +2651,16 @@ public:
*/
box_type bbox () const;
/**
* @brief Returns the box if the object represents a rectangle or an empty box if not
*
* This method returns the rectangle (aka box) the shape represents a polygon
* that is a rectangle, a path with two points and no rounded ends or an actual box.
*
* If not, an empty box is returned.
*/
box_type rectangle () const;
/**
* @brief Compute the area of the shape
*/

View File

@ -53,6 +53,12 @@ ShapeProcessor::reserve (size_t n)
m_processor.reserve (n);
}
size_t
ShapeProcessor::count () const
{
return m_processor.count ();
}
void
ShapeProcessor::process (db::EdgeSink &es, EdgeEvaluatorBase &op)
{

View File

@ -196,6 +196,11 @@ public:
*/
void reserve (size_t n);
/**
* @brief Reports the number of edges stored in the processor
*/
size_t count () const;
/**
* @brief Sets the base verbosity of the processor (see EdgeProcessor::set_base_verbosity for details)
*/

View File

@ -30,6 +30,42 @@
namespace db
{
// ------------------------------------------------------------------
// Implementation of StreamFormatDeclaration
std::string StreamFormatDeclaration::all_formats_string ()
{
std::string fmts = tl::to_string (tr ("All layout files ("));
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end (); ++rdr) {
if (rdr != tl::Registrar<db::StreamFormatDeclaration>::begin ()) {
fmts += " ";
}
std::string f = rdr->file_format ();
if (!f.empty ()) {
const char *fp = f.c_str ();
while (*fp && *fp != '(') {
++fp;
}
if (*fp) {
++fp;
}
while (*fp && *fp != ')') {
fmts += *fp++;
}
}
}
fmts += ")";
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end (); ++rdr) {
if (!rdr->file_format ().empty ()) {
fmts += ";;";
fmts += rdr->file_format ();
}
}
return fmts;
}
// ------------------------------------------------------------------
// Implementation of load_options_xml_element_list

View File

@ -136,6 +136,11 @@ public:
{
return 0;
}
/**
* @brief Returns a string for the file dialogs that describes all formats
*/
static std::string all_formats_string ();
};
/**

View File

@ -347,12 +347,10 @@ Technology::get_display_string () const
return d;
}
std::vector<double>
Technology::default_grid_list () const
static void
parse_default_grids (const std::string &s, std::vector<double> &grids, double &default_grid)
{
tl::Extractor ex (m_default_grids.c_str ());
std::vector<double> grids;
tl::Extractor ex (s.c_str ());
// convert the list of grids to a list of doubles
while (! ex.at_end ()) {
@ -361,12 +359,32 @@ Technology::default_grid_list () const
break;
}
grids.push_back (g);
if (ex.test ("!")) {
default_grid = g;
}
ex.test (",");
}
}
std::vector<double>
Technology::default_grid_list () const
{
std::vector<double> grids;
double default_grid = 0.0;
parse_default_grids (m_default_grids, grids, default_grid);
return grids;
}
double
Technology::default_grid () const
{
std::vector<double> grids;
double default_grid = 0.0;
parse_default_grids (m_default_grids, grids, default_grid);
return default_grid;
}
tl::XMLElementList
Technology::xml_elements ()
{

View File

@ -480,6 +480,15 @@ public:
*/
std::vector<double> default_grid_list () const;
/**
* @brief Gets the default grid (strong grid), parsed from the list
*
* The default grid is the one marked with an exclamation mark in the
* grid list (e.g. "0.01!,0.02,0.05"). If there is not such default
* grid, this method returns zero.
*/
double default_grid () const;
/**
* @brief Sets the default default grids
*/

View File

@ -30,7 +30,9 @@
#include "dbOriginalLayerTexts.h"
#include "dbEdges.h"
#include "dbRegion.h"
#include "dbLayout.h"
#include "dbWriter.h"
#include "tlStream.h"
#include "tlVariant.h"
#include <sstream>
@ -90,6 +92,23 @@ Texts::Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::I
mp_delegate = new DeepTexts (si, dss, trans);
}
void
Texts::write (const std::string &fn) const
{
// method provided for debugging purposes
db::Layout layout;
const db::Cell &top = layout.cell (layout.add_cell ("TEXTS"));
unsigned int li = layout.insert_layer (db::LayerProperties (0, 0));
insert_into (&layout, top.cell_index (), li);
tl::OutputStream os (fn);
db::SaveLayoutOptions opt;
opt.set_format_from_filename (fn);
db::Writer writer (opt);
writer.write (layout, os);
}
template <class Sh>
void Texts::insert (const Sh &shape)
{

View File

@ -181,6 +181,14 @@ public:
*/
explicit Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
/**
* @brief Writes the text collection to a file
*
* This method is provided for debugging purposes. A flat image of the
* region is written to a layout file with a single top cell on layer 0/0.
*/
void write (const std::string &fn) const;
/**
* @brief Implementation of the ShapeCollection interface
*/

View File

@ -324,6 +324,21 @@ struct box_defs
"\n"
"@return The joined box\n"
) +
method ("-", &C::subtracted, gsi::arg ("box"),
"@brief Subtraction of boxes\n"
"\n"
"\n"
"The - operator subtracts the argument box from self.\n"
"This will return the bounding box of the are covered by self, but not by argument box. "
"Subtracting a box from itself will render an empty box. Subtracting another box from "
"self will modify the first box only if the argument box covers one side entirely.\n"
"\n"
"@param box The box to subtract from this box.\n"
"\n"
"@return The result box\n"
"\n"
"This feature has been introduced in version 0.29."
) +
method ("&", &C::intersection, gsi::arg ("box"),
"@brief Returns the intersection of this box with another box\n"
"\n"

View File

@ -316,13 +316,13 @@ static db::CompoundRegionOperationNode *new_minkowski_sum_node4 (db::CompoundReg
return new db::CompoundRegionProcessingOperationNode (new db::minkowski_sum_computation<std::vector<db::Point> > (p), input, true /*processor is owned*/);
}
static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNode *input)
static db::CompoundRegionOperationNode *new_edges (db::CompoundRegionOperationNode *input, db::PolygonToEdgeProcessor::EdgeMode edge_mode)
{
check_non_null (input, "input");
if (input->result_type () == db::CompoundRegionOperationNode::EdgePairs) {
return new db::CompoundRegionEdgePairToEdgeProcessingOperationNode (new db::EdgePairToEdgesProcessor (), input, true /*processor is owned*/);
} else if (input->result_type () == db::CompoundRegionOperationNode::Region) {
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (), input, true /*processor is owned*/);
return new db::CompoundRegionToEdgeProcessingOperationNode (new db::PolygonToEdgeProcessor (edge_mode), input, true /*processor is owned*/);
} else {
input->keep ();
return input;
@ -567,13 +567,13 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
gsi::constructor ("new_geometrical_boolean", &new_geometrical_boolean, gsi::arg ("op"), gsi::arg ("a"), gsi::arg ("b"),
"@brief Creates a node representing a geometrical boolean operation between the inputs.\n"
) +
gsi::constructor ("new_interacting", &new_interacting, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
gsi::constructor ("new_interacting", &new_interacting, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
"@brief Creates a node representing an interacting selection operation between the inputs.\n"
) +
gsi::constructor ("new_overlapping", &new_overlapping, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
gsi::constructor ("new_overlapping", &new_overlapping, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
"@brief Creates a node representing an overlapping selection operation between the inputs.\n"
) +
gsi::constructor ("new_enclosing", &new_enclosing, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (0)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
gsi::constructor ("new_enclosing", &new_enclosing, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", std::numeric_limits<size_t>::max (), "unlimited"),
"@brief Creates a node representing an inside selection operation between the inputs.\n"
) +
gsi::constructor ("new_inside", &new_inside, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("inverse", false),
@ -746,8 +746,12 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
"@brief Creates a node filtering the input for rectangular or square shapes.\n"
"If 'is_square' is true, only squares will be selected. If 'inverse' is true, the non-rectangle/non-square shapes are returned.\n"
) +
gsi::constructor ("new_edges", &new_edges, gsi::arg ("input"),
gsi::constructor ("new_edges", &new_edges, gsi::arg ("input"), gsi::arg ("mode", db::PolygonToEdgeProcessor::All, "All"),
"@brief Creates a node converting polygons into its edges.\n"
"The 'mode' argument allows selecting specific edges when generating edges from a polygon. "
"See \\EdgeMode for the various options. By default, all edges are generated from polygons.\n"
"\n"
"The 'mode' argument has been added in version 0.29."
) +
gsi::constructor ("new_edge_length_filter", &new_edge_length_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.\n"

View File

@ -602,6 +602,12 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"\n"
"This constructor has been introduced in version 0.26."
) +
method ("write", &db::EdgePairs::write, gsi::arg ("filename"),
"@brief Writes the region to a file\n"
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
"\n"
"This method has been introduced in version 0.29."
) +
method ("insert_into", &db::EdgePairs::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"),
"@brief Inserts this edge pairs into the given layout, below the given cell and into the given layer.\n"
"If the edge pair collection is a hierarchical one, a suitable hierarchy will be built below the top cell or "

View File

@ -656,14 +656,14 @@ static std::vector<db::Edges> split_outside_with_region (const db::Edges *r, con
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)
static std::vector<db::Edges> split_interacting_with_edges (const db::Edges *r, const db::Edges &other, size_t min_count, size_t max_count)
{
return as_2edges_vector (r->selected_interacting_differential (other));
return as_2edges_vector (r->selected_interacting_differential (other, min_count, max_count));
}
static std::vector<db::Edges> split_interacting_with_region (const db::Edges *r, const db::Region &other)
static std::vector<db::Edges> split_interacting_with_region (const db::Edges *r, const db::Region &other, size_t min_count, size_t max_count)
{
return as_2edges_vector (r->selected_interacting_differential (other));
return as_2edges_vector (r->selected_interacting_differential (other, min_count, max_count));
}
@ -1233,61 +1233,107 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"\n"
"The 'join_with' alias has been introduced in version 0.28.12."
) +
method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &, size_t, size_t) const) &db::Edges::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the 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"
"'min_count' and 'max_count' impose a constraint on the number of times an edge of this collection "
"has to interact with (different) edges of the other collection to make the edge selected. An edge is "
"selected by this method if the number of edges interacting with an edge of this collection is between min_count and max_count "
"(including max_count).\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"),
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Edges &, size_t, size_t) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the 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"
) +
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_interacting, gsi::arg ("other"),
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times an edge of this collection "
"has to interact with (different) edges of the other collection to make the edge selected. An edge is "
"not selected by this method if the number of edges interacting with an edge of this collection is between min_count and max_count "
"(including max_count).\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Edges &, size_t, size_t)) &db::Edges::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the 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"
) +
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Edges &)) &db::Edges::select_not_interacting, gsi::arg ("other"),
"\n"
"This is the in-place version of \\interacting - i.e. self is modified rather than a new collection is returned.\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Edges &, size_t, size_t)) &db::Edges::select_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the 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"
) +
method_ext ("split_interacting", &split_interacting_with_edges, gsi::arg ("other"),
"\n"
"This is the in-place version of \\not_interacting - i.e. self is modified rather than a new collection is returned.\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method_ext ("split_interacting", &split_interacting_with_edges, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief 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."
"It has been introduced in version 0.28.\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
method ("interacting", (db::Edges (db::Edges::*) (const db::Region &, size_t, size_t) const) &db::Edges::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the 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"
) +
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"),
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times an edge of this collection "
"has to interact with (different) polygons of the other region to make the edge selected. An edge is "
"selected by this method if the number of polygons interacting with an edge of this collection is between min_count and max_count "
"(including max_count).\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &, size_t, size_t) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Returns the 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"
) +
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"),
"\n"
"'min_count' and 'max_count' impose a constraint on the number of times an edge of this collection "
"has to interact with (different) polygons of the other region to make the edge selected. An edge is "
"not selected by this method if the number of polygons interacting with an edge of this collection is between min_count and max_count "
"(including max_count).\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &, size_t, size_t)) &db::Edges::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the 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"
) +
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"),
"\n"
"This is the in-place version of \\interacting - i.e. self is modified rather than a new collection is returned.\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &, size_t, size_t)) &db::Edges::select_not_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief Selects the 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"
) +
method_ext ("split_interacting", &split_interacting_with_region, gsi::arg ("other"),
"\n"
"This is the in-place version of \\not_interacting - i.e. self is modified rather than a new collection is returned.\n"
"\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
method_ext ("split_interacting", &split_interacting_with_region, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits<size_t>::max ()), "unlimited"),
"@brief 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."
"It has been introduced in version 0.28.\n"
"'min_count' and 'max_count' have been introduced in version 0.29."
) +
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"
@ -1521,6 +1567,12 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"\n"
"This method has been added in version 0.28.\n"
) +
method ("write", &db::Edges::write, gsi::arg ("filename"),
"@brief Writes the region to a file\n"
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
"\n"
"This method has been introduced in version 0.29."
) +
method ("clear", &db::Edges::clear,
"@brief Clears the edge collection\n"
) +

View File

@ -29,6 +29,7 @@
#include "dbPCellDeclaration.h"
#include "dbLibrary.h"
#include "dbLibraryManager.h"
#include "tlLog.h"
namespace gsi
{
@ -701,23 +702,23 @@ Class<PCellDeclarationImpl> decl_PCellDeclaration (decl_PCellDeclaration_Native,
// ---------------------------------------------------------------
// db::PCellParameterDeclaration binding
unsigned int get_type (const db::PCellParameterDeclaration *pd)
static unsigned int get_type (const db::PCellParameterDeclaration *pd)
{
return (unsigned int) pd->get_type ();
}
void set_type (db::PCellParameterDeclaration *pd, unsigned int t)
static void set_type (db::PCellParameterDeclaration *pd, unsigned int t)
{
pd->set_type (db::PCellParameterDeclaration::type (t));
}
void clear_choices (db::PCellParameterDeclaration *pd)
static void clear_choices (db::PCellParameterDeclaration *pd)
{
pd->set_choices (std::vector<tl::Variant> ());
pd->set_choice_descriptions (std::vector<std::string> ());
}
void add_choice (db::PCellParameterDeclaration *pd, const std::string &d, const tl::Variant &v)
static void add_choice (db::PCellParameterDeclaration *pd, const std::string &d, const tl::Variant &v)
{
std::vector<tl::Variant> vv = pd->get_choices ();
std::vector<std::string> dd = pd->get_choice_descriptions ();
@ -772,26 +773,7 @@ static unsigned int pd_type_none ()
return (unsigned int) db::PCellParameterDeclaration::t_none;
}
db::PCellParameterDeclaration *ctor_pcell_parameter (const std::string &name, unsigned int type, const std::string &description)
{
db::PCellParameterDeclaration *pd = new db::PCellParameterDeclaration ();
pd->set_name (name);
pd->set_type (db::PCellParameterDeclaration::type (type));
pd->set_description (description);
return pd;
}
db::PCellParameterDeclaration *ctor_pcell_parameter_2 (const std::string &name, unsigned int type, const std::string &description, const tl::Variant &def)
{
db::PCellParameterDeclaration *pd = new db::PCellParameterDeclaration ();
pd->set_name (name);
pd->set_type (db::PCellParameterDeclaration::type (type));
pd->set_description (description);
pd->set_default (def);
return pd;
}
db::PCellParameterDeclaration *ctor_pcell_parameter_3 (const std::string &name, unsigned int type, const std::string &description, const tl::Variant &def, const std::string &unit)
db::PCellParameterDeclaration *ctor_pcell_parameter (const std::string &name, unsigned int type, const std::string &description, const tl::Variant &def, const std::string &unit)
{
db::PCellParameterDeclaration *pd = new db::PCellParameterDeclaration ();
pd->set_name (name);
@ -803,20 +785,7 @@ db::PCellParameterDeclaration *ctor_pcell_parameter_3 (const std::string &name,
}
Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCellParameterDeclaration",
gsi::constructor ("new", &ctor_pcell_parameter, gsi::arg ("name"), gsi::arg ("type"), gsi::arg ("description"),
"@brief Create a new parameter declaration with the given name and type\n"
"@param name The parameter name\n"
"@param type One of the Type... constants describing the type of the parameter\n"
"@param description The description text\n"
) +
gsi::constructor ("new", &ctor_pcell_parameter_2, gsi::arg ("name"), gsi::arg ("type"), gsi::arg ("description"), gsi::arg ("default"),
"@brief Create a new parameter declaration with the given name, type and default value\n"
"@param name The parameter name\n"
"@param type One of the Type... constants describing the type of the parameter\n"
"@param description The description text\n"
"@param default The default (initial) value\n"
) +
gsi::constructor ("new", &ctor_pcell_parameter_3, gsi::arg ("name"), gsi::arg ("type"), gsi::arg ("description"), gsi::arg ("default"), gsi::arg ("unit"),
gsi::constructor ("new", &ctor_pcell_parameter, gsi::arg ("name"), gsi::arg ("type"), gsi::arg ("description"), gsi::arg ("default", tl::Variant (), "nil"), gsi::arg ("unit", std::string ()),
"@brief Create a new parameter declaration with the given name, type, default value and unit string\n"
"@param name The parameter name\n"
"@param type One of the Type... constants describing the type of the parameter\n"
@ -874,6 +843,7 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
"This method will add the given value with the given description to the list of\n"
"choices. If choices are defined, KLayout will show a drop-down box instead of an\n"
"entry field in the parameter user interface.\n"
"If a range is already set for this parameter the choice will not be added and a warning message is showed.\n"
) +
gsi::method ("choice_values", &db::PCellParameterDeclaration::get_choices,
"@brief Returns a list of choice values\n"
@ -881,6 +851,44 @@ Class<db::PCellParameterDeclaration> decl_PCellParameterDeclaration ("db", "PCel
gsi::method ("choice_descriptions", &db::PCellParameterDeclaration::get_choice_descriptions,
"@brief Returns a list of choice descriptions\n"
) +
gsi::method ("min_value", &db::PCellParameterDeclaration::min_value,
"@brief Gets the minimum value allowed\n"
"See \\min_value= for a description of this attribute.\n"
"\n"
"This attribute has been added in version 0.29."
) +
gsi::method ("min_value=", &db::PCellParameterDeclaration::set_min_value, gsi::arg ("value"),
"@brief Sets the minimum value allowed\n"
"The minimum value is a visual feature and limits the allowed values for numerical\n"
"entry boxes. This applies to parameters of type int or double. The minimum value\n"
"is not effective if choices are present.\n"
"\n"
"The minimum value is not enforced - for example there is no restriction implemented\n"
"when setting values programmatically.\n"
"\n"
"Setting this attribute to \"nil\" (the default) implies \"no limit\".\n"
"\n"
"This attribute has been added in version 0.29."
) +
gsi::method ("max_value", &db::PCellParameterDeclaration::max_value,
"@brief Gets the maximum value allowed\n"
"See \\max_value= for a description of this attribute.\n"
"\n"
"This attribute has been added in version 0.29."
) +
gsi::method ("max_value=", &db::PCellParameterDeclaration::set_max_value, gsi::arg ("value"),
"@brief Sets the maximum value allowed\n"
"The maximum value is a visual feature and limits the allowed values for numerical\n"
"entry boxes. This applies to parameters of type int or double. The maximum value\n"
"is not effective if choices are present.\n"
"\n"
"The maximum value is not enforced - for example there is no restriction implemented\n"
"when setting values programmatically.\n"
"\n"
"Setting this attribute to \"nil\" (the default) implies \"no limit\".\n"
"\n"
"This attribute has been added in version 0.29."
) +
gsi::method ("default", &db::PCellParameterDeclaration::get_default,
"@brief Gets the default value\n"
) +

View File

@ -31,6 +31,39 @@
namespace gsi
{
template <class C>
static std::vector<C> split_poly (const C *p)
{
std::vector<C> parts;
db::split_polygon (*p, parts);
return parts;
}
template <class C>
static void break_polygon (const C &poly, size_t max_vertex_count, double max_area_ratio, std::vector<C> &result)
{
if ((max_vertex_count > 0 && poly.vertices () > max_vertex_count) ||
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {
std::vector<C> split_polygons;
db::split_polygon (poly, split_polygons);
for (auto p = split_polygons.begin (); p != split_polygons.end (); ++p) {
break_polygon (*p, max_vertex_count, max_area_ratio, result);
}
} else {
result.push_back (poly);
}
}
template <class C>
static std::vector<C> break_poly (const C *p, size_t max_vertex_count, double max_area_ratio)
{
std::vector<C> parts;
break_polygon (*p, max_vertex_count, max_area_ratio, parts);
return parts;
}
// ---------------------------------------------------------------
// simple polygon binding
@ -245,13 +278,6 @@ struct simple_polygon_defs
return db::interact (*p, spoly);
}
static std::vector<C> split_poly (const C *p)
{
std::vector<C> parts;
db::split_polygon (*p, parts);
return parts;
}
static gsi::Methods methods ()
{
return
@ -508,7 +534,7 @@ struct simple_polygon_defs
"\n"
"This method was introduced in version 0.25.\n"
) +
method_ext ("split", &split_poly,
method_ext ("split", &split_poly<C>,
"@brief Splits the polygon into two or more parts\n"
"This method will break the polygon into parts. The exact breaking algorithm is unspecified, the "
"result are smaller polygons of roughly equal number of points and 'less concave' nature. "
@ -521,6 +547,20 @@ struct simple_polygon_defs
"\n"
"This method has been introduced in version 0.25.3."
) +
method_ext ("break", &break_poly<C>, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"),
"@brief Splits the polygon into parts with a maximum vertex count and area ratio\n"
"The area ratio is the ratio between the bounding box area and the polygon area. Higher values "
"mean more 'skinny' polygons.\n"
"\n"
"This method will split the input polygon into pieces having a maximum of 'max_vertex_count' vertices "
"and an area ratio less than 'max_area_ratio'. 'max_vertex_count' can be zero. In this case the "
"limit is ignored. Also 'max_area_ratio' can be zero, in which case it is ignored as well.\n"
"\n"
"The method of splitting is unspecified. The algorithm will apply 'split' recursively until the "
"parts satisfy the limits.\n"
"\n"
"This method has been introduced in version 0.29."
) +
method_ext ("area", &area,
"@brief Gets the area of the polygon\n"
"The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise."
@ -1098,13 +1138,6 @@ struct polygon_defs
return db::interact (*p, spoly);
}
static std::vector<C> split_spoly (const C *p)
{
std::vector<C> parts;
db::split_polygon (*p, parts);
return parts;
}
static gsi::Methods methods ()
{
return
@ -1520,7 +1553,7 @@ struct polygon_defs
"\n"
"This method was introduced in version 0.25.\n"
) +
method_ext ("split", &split_spoly,
method_ext ("split", &split_poly<C>,
"@brief Splits the polygon into two or more parts\n"
"This method will break the polygon into parts. The exact breaking algorithm is unspecified, the "
"result are smaller polygons of roughly equal number of points and 'less concave' nature. "
@ -1533,6 +1566,20 @@ struct polygon_defs
"\n"
"This method has been introduced in version 0.25.3."
) +
method_ext ("break", &break_poly<C>, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"),
"@brief Splits the polygon into parts with a maximum vertex count and area ratio\n"
"The area ratio is the ratio between the bounding box area and the polygon area. Higher values "
"mean more 'skinny' polygons.\n"
"\n"
"This method will split the input polygon into pieces having a maximum of 'max_vertex_count' vertices "
"and an area ratio less than 'max_area_ratio'. 'max_vertex_count' can be zero. In this case the "
"limit is ignored. Also 'max_area_ratio' can be zero, in which case it is ignored as well.\n"
"\n"
"The method of splitting is unspecified. The algorithm will apply 'split' recursively until the "
"parts satisfy the limits.\n"
"\n"
"This method has been introduced in version 0.29."
) +
method_ext ("area", &area,
"@brief Gets the area of the polygon\n"
"The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise."

View File

@ -476,13 +476,29 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n"
"This method has been introduced in version 0.23.\n"
) +
gsi::method ("overlapping=", &db::RecursiveShapeIterator::set_overlapping, gsi::arg ("region"),
gsi::method ("overlapping=", &db::RecursiveShapeIterator::set_overlapping, gsi::arg ("flag"),
"@brief Sets a flag indicating whether overlapping shapes are selected when a region is used\n"
"\n"
"If this flag is false, shapes touching the search region are returned.\n"
"\n"
"This method has been introduced in version 0.23.\n"
) +
gsi::method ("for_merged_input?", &db::RecursiveShapeIterator::for_merged_input,
"@brief Gets a flag indicating whether iterator optimizes for merged input\n"
"\n"
"see \\for_merged_input= for details of this attribute.\n"
"\n"
"This method has been introduced in version 0.29.\n"
) +
gsi::method ("for_merged_input=", &db::RecursiveShapeIterator::set_for_merged_input, gsi::arg ("flag"),
"@brief Sets a flag indicating whether iterator optimizes for merged input\n"
"\n"
"If this flag is set to true, the iterator is allowed to skip shapes it deems irrelevant "
"because they are covered entirely by other shapes. This allows shortcutting hierarchy traversal in "
"some cases.\n"
"\n"
"This method has been introduced in version 0.29.\n"
) +
gsi::method ("unselect_all_cells", &db::RecursiveShapeIterator::unselect_all_cells,
"@brief Unselects all cells.\n"
"\n"

View File

@ -270,15 +270,6 @@ static db::Region *new_path (const db::Path &o)
return new db::Region (o);
}
static db::Region *new_shapes (const db::Shapes &s)
{
db::Region *r = new db::Region ();
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::All); !i.at_end (); ++i) {
r->insert (*i);
}
return r;
}
static db::Region *new_texts_as_boxes1 (const db::RecursiveShapeIterator &si, const std::string &pat, bool pattern, db::Coord enl)
{
return new db::Region (db::Region (si).texts_as_boxes (pat, pattern, enl));
@ -329,16 +320,26 @@ static db::Region *new_si (const db::RecursiveShapeIterator &si)
return new db::Region (si);
}
static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
{
return new db::Region (si, dss, area_ratio, max_vertex_count);
}
static db::Region *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
{
return new db::Region (si, trans);
}
static db::Region *new_sis (const db::Shapes &si)
{
return new db::Region (si);
}
static db::Region *new_sis2 (const db::Shapes &si, const db::ICplxTrans &trans)
{
return new db::Region (si, trans);
}
static db::Region *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
{
return new db::Region (si, dss, area_ratio, max_vertex_count);
}
static db::Region *new_sid2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const db::ICplxTrans &trans, double area_ratio, size_t max_vertex_count)
{
return new db::Region (si, dss, trans, true, area_ratio, max_vertex_count);
@ -1002,6 +1003,18 @@ size_dvm (db::Region *region, const db::Vector &dv, unsigned int mode)
return *region;
}
static db::Edges
edges (const db::Region *region, db::PolygonToEdgeProcessor::EdgeMode mode)
{
if (mode != db::PolygonToEdgeProcessor::All) {
db::PolygonToEdgeProcessor proc (mode);
return region->edges (proc);
} else {
// this version is more efficient in the hierarchical case
return region->edges ();
}
}
static std::vector<std::vector<double> >
rasterize2 (const db::Region *region, const db::Point &origin, const db::Vector &pixel_distance, const db::Vector &pixel_size, unsigned int nx, unsigned int ny)
{
@ -1076,13 +1089,6 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This constructor creates a region from a path.\n"
) +
constructor ("new", &new_shapes, gsi::arg ("shapes"),
"@brief Shapes constructor\n"
"\n"
"This constructor creates a region from a \\Shapes collection.\n"
"\n"
"This constructor has been introduced in version 0.25."
) +
constructor ("new", &new_si, gsi::arg ("shape_iterator"),
"@brief Constructor from a hierarchical shape set\n"
"\n"
@ -1114,6 +1120,24 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"r = RBA::Region::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
"@/code\n"
) +
constructor ("new", &new_sis, gsi::arg ("shapes"),
"@brief Constructor from a shapes container\n"
"\n"
"This constructor creates a region from the shapes container.\n"
"Text objects and edges are not inserted, because they cannot be converted to polygons.\n"
"This method allows feeding the shapes from a hierarchy of cells into the region.\n"
"\n"
"This constructor has been introduced in version 0.25 and extended in version 0.29."
) +
constructor ("new", &new_sis2, gsi::arg ("shapes"), gsi::arg ("trans"),
"@brief Constructor from a shapes container with a transformation\n"
"\n"
"This constructor creates a region from the shapes container after applying the transformation.\n"
"Text objects and edges are not inserted, because they cannot be converted to polygons.\n"
"This method allows feeding the shapes from a hierarchy of cells into the region.\n"
"\n"
"This constructor variant has been introduced in version 0.29."
) +
constructor ("new", &new_sid, gsi::arg ("shape_iterator"), gsi::arg ("deep_shape_store"), gsi::arg ("area_ratio", 0.0), gsi::arg ("max_vertex_count", size_t (0)),
"@brief Constructor for a deep region from a hierarchical shape set\n"
"\n"
@ -1197,6 +1221,12 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"This method has been introduced in version 0.26."
) +
method ("write", &db::Region::write, gsi::arg ("filename"),
"@brief Writes the region to a file\n"
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
"\n"
"This method has been introduced in version 0.29."
) +
factory_ext ("texts", &texts_as_boxes1, gsi::arg ("expr", std::string ("*")), gsi::arg ("as_pattern", true), gsi::arg ("enl", 1),
"@hide\n"
"This method is provided for DRC implementation only."
@ -2493,15 +2523,20 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"If the region is not merged, this method may return false even\n"
"if the merged region would be a box.\n"
) +
method ("edges", (db::Edges (db::Region::*) () const) &db::Region::edges,
method_ext ("edges", &edges, gsi::arg ("mode", db::PolygonToEdgeProcessor::All, "All"),
"@brief Returns an edge collection representing all edges of the polygons in this region\n"
"This method will decompose the polygons into the individual edges. Edges making up the hulls "
"of the polygons are oriented clockwise while edges making up the holes are oriented counterclockwise.\n"
"\n"
"The 'mode' parameter allows selecting specific edges, such as convex or concave ones. By default, "
"all edges are selected.\n"
"\n"
"The edge collection returned can be manipulated in various ways. See \\Edges for a description of the "
"possibilities of the edge collection.\n"
"features of the edge collection.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n"
"\n"
"The mode argument has been added in version 0.29."
) +
factory_ext ("decompose_convex", &decompose_convex<db::Shapes>, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"),
"@brief Decomposes the region into convex pieces.\n"
@ -2924,7 +2959,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"The 'shielded' and 'negative' options have been introduced in version 0.27. "
"'property_constraint' has been added in version 0.28.4.\n"
"'zero_distance_mode' has been added in version 0.29."
"'zero_distance_mode' has been added in version 0.28.16."
) +
method_ext ("space_check", &space2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"), gsi::arg ("shielded", true), gsi::arg ("opposite_filter", db::NoOppositeFilter, "NoOppositeFilter"), gsi::arg ("rect_filter", db::NoRectFilter, "NoRectFilter"), gsi::arg ("negative", false), gsi::arg ("property_constraint", db::IgnoreProperties, "IgnoreProperties"), gsi::arg ("zero_distance_mode", db::IncludeZeroDistanceWhenTouching, "IncludeZeroDistanceWhenTouching"),
"@brief Performs a space check with options\n"
@ -3577,6 +3612,48 @@ gsi::Enum<db::metrics_type> decl_Metrics ("db", "Metrics",
gsi::ClassExt<db::Region> inject_Metrics_in_Region (decl_Metrics.defs ());
gsi::ClassExt<db::Edges> inject_Metrics_in_Edges (decl_Metrics.defs ());
gsi::Enum<db::PolygonToEdgeProcessor::EdgeMode> decl_EdgeMode ("db", "EdgeMode",
gsi::enum_const ("All", db::PolygonToEdgeProcessor::All,
"@brief Selects all edges\n"
) +
gsi::enum_const ("Concave", db::PolygonToEdgeProcessor::Concave,
"@brief Selects only concave edges\n"
) +
gsi::enum_const ("NotConcave", db::PolygonToEdgeProcessor::NotConcave,
"@brief Selects only edges which are not concave\n"
) +
gsi::enum_const ("Convex", db::PolygonToEdgeProcessor::Convex,
"@brief Selects only convex edges\n"
) +
gsi::enum_const ("NotConvex", db::PolygonToEdgeProcessor::NotConvex,
"@brief Selects only edges which are not convex\n"
) +
gsi::enum_const ("Step", db::PolygonToEdgeProcessor::Step,
"@brief Selects only step edges leading inside or outside\n"
) +
gsi::enum_const ("NotStep", db::PolygonToEdgeProcessor::NotStep,
"@brief Selects only edges which are not steps\n"
) +
gsi::enum_const ("StepIn", db::PolygonToEdgeProcessor::StepIn,
"@brief Selects only step edges leading inside\n"
) +
gsi::enum_const ("NotStepIn", db::PolygonToEdgeProcessor::NotStepIn,
"@brief Selects only edges which are not steps leading inside\n"
) +
gsi::enum_const ("StepOut", db::PolygonToEdgeProcessor::StepOut,
"@brief Selects only step edges leading outside\n"
) +
gsi::enum_const ("NotStepOut", db::PolygonToEdgeProcessor::NotStepOut,
"@brief Selects only edges which are not steps leading outside\n"
),
"@brief This class represents the edge mode type for \\Region#edges.\n"
"\n"
"This enum has been introduced in version 0.29."
);
// Inject the Region::EdgeMode declarations into Region:
gsi::ClassExt<db::Region> inject_EdgeMode_in_Region (decl_EdgeMode.defs ());
gsi::Enum<db::zero_distance_mode> decl_ZeroDistanceMode ("db", "ZeroDistanceMode",
gsi::enum_const ("NeverIncludeZeroDistance", db::NeverIncludeZeroDistance,
"@brief Specifies that check functions should never include edges with zero distance.\n"
@ -3590,7 +3667,7 @@ gsi::Enum<db::zero_distance_mode> decl_ZeroDistanceMode ("db", "ZeroDistanceMode
gsi::enum_const ("IncludeZeroDistanceWhenTouching", db::IncludeZeroDistanceWhenTouching,
"@brief Specifies that check functions should include edges when they touch\n"
"With this specification, the check functions will also check edges if they share at least one common point. "
"This is the mode that includes checking the 'kissing corner' cases. This mode is default for version 0.29 and later. "
"This is the mode that includes checking the 'kissing corner' cases. This mode is default for version 0.28.16 and later. "
) +
gsi::enum_const ("IncludeZeroDistanceWhenCollinearAndTouching", db::IncludeZeroDistanceWhenCollinearAndTouching,
"@brief Specifies that check functions should include edges when they are collinear and touch\n"
@ -3609,7 +3686,7 @@ gsi::Enum<db::zero_distance_mode> decl_ZeroDistanceMode ("db", "ZeroDistanceMode
"if they share at least one common point (\\IncludeZeroDistanceWhenTouching). The latter mode allows activating checks for "
"the 'kissing corner' case and is the default mode in most checks."
"\n"
"This enum has been introduced in version 0.29."
"This enum has been introduced in version 0.28.16."
);
// Inject the Region::ZeroDistanceMode declarations into Region and Edges:

View File

@ -669,6 +669,26 @@ static tl::Variant get_dbox (const db::Shape *s)
}
}
static tl::Variant get_rectangle (const db::Shape *s)
{
db::Shape::box_type b = s->rectangle ();
if (! b.empty ()) {
return tl::Variant (b);
} else {
return tl::Variant ();
}
}
static tl::Variant get_drectangle (const db::Shape *s)
{
db::Shape::box_type b = s->rectangle ();
if (! b.empty ()) {
return tl::Variant (db::CplxTrans (shape_dbu (s)) * b);
} else {
return tl::Variant ();
}
}
static tl::Variant get_edge (const db::Shape *s)
{
db::Shape::edge_type p;
@ -1982,6 +2002,22 @@ Class<db::Shape> decl_Shape ("db", "Shape",
"\n"
"This method has been added in version 0.25.\n"
) +
gsi::method_ext ("rectangle", &get_rectangle,
"@brief Gets the rectangle if the object represents one or nil if not\n"
"\n"
"If the shape represents a rectangle - i.e. a box or box polygon, a path with two points and no round ends - "
"this method returns the box. If not, nil is returned.\n"
"\n"
"This method has been introduced in version 0.29."
) +
gsi::method_ext ("drectangle", &get_drectangle,
"@brief Gets the rectangle in micron units if the object represents one or nil if not\n"
"\n"
"If the shape represents a rectangle - i.e. a box or box polygon, a path with two points and no round ends - "
"this method returns the box. If not, nil is returned.\n"
"\n"
"This method has been introduced in version 0.29."
) +
gsi::method ("is_user_object?", &db::Shape::is_user_object,
"@brief Returns true if the shape is a user defined object\n"
) +

View File

@ -136,7 +136,7 @@ gsi::Class<db::TechnologyComponent> technology_component_decl ("db", "Technology
DB_PUBLIC gsi::Class<db::TechnologyComponent> &decl_dbTechnologyComponent () { return technology_component_decl; }
static void
set_default_grid_list (db::Technology *tech, const std::vector<double> &grids)
set_default_grid_list2 (db::Technology *tech, const std::vector<double> &grids, double default_grid)
{
std::string r;
for (auto g = grids.begin (); g != grids.end (); ++g) {
@ -144,10 +144,19 @@ set_default_grid_list (db::Technology *tech, const std::vector<double> &grids)
r += ",";
}
r += tl::micron_to_string (*g);
if (db::coord_traits<db::DCoord>::equals (*g, default_grid)) {
r += "!";
}
}
tech->set_default_grids (r);
}
static void
set_default_grid_list (db::Technology *tech, const std::vector<double> &grids)
{
set_default_grid_list2 (tech, grids, 0.0);
}
gsi::Class<db::Technology> technology_decl ("db", "Technology",
gsi::method ("name", &db::Technology::name,
"@brief Gets the name of the technology"
@ -238,12 +247,32 @@ gsi::Class<db::Technology> technology_decl ("db", "Technology",
"\n"
"This property has been introduced in version 0.28.17."
) +
gsi::method ("default_grid", &db::Technology::default_grid,
"@brief Gets the default grid\n"
"\n"
"The default grid is a specific one from the default grid list.\n"
"It indicates the one that is taken if the current grid is not matching one of "
"the default grids.\n"
"\n"
"To set the default grid, use \\set_default_grids.\n"
"\n"
"This property has been introduced in version 0.29."
) +
gsi::method_ext ("default_grids=", &set_default_grid_list, gsi::arg ("grids"),
"@brief Sets the default grids\n"
"If not empty, this list replaces the global grid list for this technology.\n"
"Note that this method will reset the default grid (see \\default_grid). Use "
"\\set_default_grids to set the default grids and the strong default one.\n"
"\n"
"This property has been introduced in version 0.28.17."
) +
gsi::method_ext ("set_default_grids", &set_default_grid_list2, gsi::arg ("grids"), gsi::arg ("default_grid", 0.0),
"@brief Sets the default grids and the strong default one\n"
"See \\default_grids and \\default_grid for a description of this property.\n"
"Note that the default grid has to be a member of the 'grids' array to become active.\n"
"\n"
"This method has been introduced in version 0.29."
) +
gsi::method ("layer_properties_file", &db::Technology::layer_properties_file,
"@brief Gets the path of the layer properties file\n"
"\n"

View File

@ -436,6 +436,12 @@ Class<db::Texts> decl_Texts (decl_dbShapeCollection, "db", "Texts",
"r = RBA::Texts::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
"@/code\n"
) +
method ("write", &db::Texts::write, gsi::arg ("filename"),
"@brief Writes the region to a file\n"
"This method is provided for debugging purposes. It writes the object to a flat layer 0/0 in a single top cell.\n"
"\n"
"This method has been introduced in version 0.29."
) +
method ("insert_into", &db::Texts::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"),
"@brief Inserts this texts into the given layout, below the given cell and into the given layer.\n"
"If the text collection is a hierarchical one, a suitable hierarchy will be built below the top cell or "

View File

@ -49,6 +49,17 @@ TEST(2)
EXPECT_EQ (b & db::Box (110, 220, 120, 250), empty);
EXPECT_EQ (b & db::Box (50, 100, 120, 250), db::Box (50, 100, 100, 200));
EXPECT_EQ (b & db::Box (50, 100, 60, 120), db::Box (50, 100, 60, 120));
EXPECT_EQ (b - b, db::Box ());
EXPECT_EQ (b - db::Box (), b);
EXPECT_EQ (db::Box () - b, db::Box ());
EXPECT_EQ (db::Box () - db::Box (), db::Box ());
EXPECT_EQ (b - db::Box (0, 0, 50, 50), b);
EXPECT_EQ (b - db::Box (0, 0, 50, 200), db::Box (50, 0, 100, 200));
EXPECT_EQ (b - db::Box (50, 0, 100, 200), db::Box (0, 0, 50, 200));
EXPECT_EQ (b - db::Box (0, 0, 100, 100), db::Box (0, 100, 100, 200));
EXPECT_EQ (b - db::Box (0, 100, 100, 200), db::Box (0, 0, 100, 100));
EXPECT_EQ (db::Box::world () - b, db::Box::world ());
EXPECT_EQ (b - db::Box::world (), db::Box ());
empty.move (db::Vector (10, 20));
EXPECT_EQ (empty == db::Box (), true);

View File

@ -133,7 +133,7 @@ TEST(3_Edge2EdgeBooleans)
db::Layout ly;
{
std::string fn (tl::testdata ());
fn += "/algo/deep_region_l1.gds";
fn += "/algo/deep_edges_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
@ -145,15 +145,23 @@ TEST(3_Edge2EdgeBooleans)
db::DeepShapeStore dss;
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l21 = ly.get_layer (db::LayerProperties (2, 1));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
unsigned int lempty = ly.insert_layer ();
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
db::Region r21 (db::RecursiveShapeIterator (ly, top_cell, l21), dss);
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
db::Region r2and3 = r2 & r3;
db::Edges e2 = r2.edges ();
db::Edges e21 = r21.edges ();
db::Edges e3 = r3.edges ();
db::Edges e3copy = r3.edges ();
db::Edges e2and3 = r2and3.edges ();
db::Edges eempty (db::RecursiveShapeIterator (ly, top_cell, lempty), dss);
db::Edges edots = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
db::Edges edotscopy = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
@ -162,11 +170,70 @@ TEST(3_Edge2EdgeBooleans)
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (3, 0)), r3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), edots.merged ());
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e3 & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), e3.intersections(e2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 & eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3 & e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), eempty & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), edots & edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), edots & e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), e21 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (28, 0)), edots & e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e3 - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e3 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), e3 - eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), e3 - e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (34, 0)), eempty - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (35, 0)), edots - edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (36, 0)), edots - e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (37, 0)), e21 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (38, 0)), edots - e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e3 ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e3 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (42, 0)), e3 ^ eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (43, 0)), e3 ^ e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (44, 0)), eempty ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (45, 0)), edots ^ edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (46, 0)), edots ^ e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (47, 0)), e21 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (48, 0)), edots ^ e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (50, 0)), e3.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (51, 0)), e3.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (52, 0)), e3.andnot(eempty).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (53, 0)), e3.andnot(e3copy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (54, 0)), eempty.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (55, 0)), edots.andnot(edotscopy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (56, 0)), edots.andnot(e2).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (57, 0)), e21.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (58, 0)), edots.andnot(e21).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (60, 0)), e3.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (61, 0)), e3.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (62, 0)), e3.andnot(eempty).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (63, 0)), e3.andnot(e3copy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (64, 0)), eempty.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (65, 0)), edots.andnot(edotscopy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (66, 0)), edots.andnot(e2).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (67, 0)), e21.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (68, 0)), edots.andnot(e21).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (70, 0)), e3.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (71, 0)), e3.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (72, 0)), e3.intersections(eempty));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (73, 0)), e3.intersections(e3copy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (74, 0)), eempty.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (75, 0)), edots.intersections(edotscopy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (76, 0)), edots.intersections(e2));
// test, whether dots are not merged
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (77, 0)), edots.intersections(e2).select_interacting(e2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (78, 0)), e21.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (79, 0)), edots.intersections(e21));
CHECKPOINT();
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au3.gds");
@ -1293,6 +1360,201 @@ TEST(20_in_and_out)
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au20.gds");
}
TEST(21_EdgeMergeWithDots)
{
db::Edges e;
e.insert (db::Edge (db::Point(0, 0), db::Point (100, 0)));
e.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
db::Edges ee = e;
ee.insert (db::Edge (db::Point(100, 0), db::Point (110, 0)));
db::Edges eee;
eee.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
eee.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
// make deep
db::DeepShapeStore dss;
db::Layout ly;
ly.add_cell ("TOP");
unsigned int l1 = ly.insert_layer ();
unsigned int l2 = ly.insert_layer ();
unsigned int l3 = 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);
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
ee.insert_into (&ly, top_cell.cell_index (), l2);
ee = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
eee.insert_into (&ly, top_cell.cell_index (), l3);
eee = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
EXPECT_EQ (e.merged ().to_string (), "(0,0;100,0);(110,0;110,0)");
// dots do not participate in merge
EXPECT_EQ (ee.merged ().to_string (), "(0,0;110,0)");
// dots do not participate in merge
EXPECT_EQ (eee.merged ().to_string (), "(110,0;110,0)");
}
TEST(22_InteractingWithCount)
{
db::Edges e;
e.insert (db::Edge (db::Point (0, 0), db::Point (100, 0)));
e.insert (db::Edge (db::Point (100, 0), db::Point (200, 0)));
e.insert (db::Edge (db::Point (0, 10), db::Point (200, 10)));
e.insert (db::Edge (db::Point (0, 20), db::Point (200, 20)));
e.insert (db::Edge (db::Point (0, 30), db::Point (200, 30)));
db::Edges e2;
e2.insert (db::Edge (db::Point (100, 0), db::Point (100, 10)));
e2.insert (db::Edge (db::Point (100, 0), db::Point (100, 30)));
e2.insert (db::Edge (db::Point (110, 10), db::Point (110, 30)));
e2.merge ();
e2.insert (db::Edge (db::Point (120, 20), db::Point (120, 20)));
e2.insert (db::Edge (db::Point (130, 30), db::Point (130, 30)));
e2.set_merged_semantics (false);
db::Region r2;
r2.insert (db::Box (db::Point (99, 0), db::Point (101, 10)));
r2.insert (db::Box (db::Point (99, 0), db::Point (101, 30)));
r2.insert (db::Box (db::Point (109, 10), db::Point (111, 30)));
r2.insert (db::Box (db::Point (119, 19), db::Point (121, 21)));
r2.insert (db::Box (db::Point (129, 29), db::Point (131, 31)));
// make deep
db::DeepShapeStore dss;
db::Layout ly;
ly.add_cell ("TOP");
unsigned int l1 = ly.insert_layer ();
unsigned int l2 = ly.insert_layer ();
unsigned int l3 = 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);
e = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
e2.insert_into (&ly, top_cell.cell_index (), l2);
e2 = db::Edges (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
// because it has dots
e2.set_merged_semantics (false);
r2.insert_into (&ly, top_cell.cell_index (), l3);
r2 = db::Region (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
db::Edges edup;
EXPECT_EQ (db::compare (e.selected_interacting (e2), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2), size_t(2)), "(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2), size_t(3)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (3)), "(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (4)), ""), true);
edup = e;
edup.select_interacting (e2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2), ""), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2), size_t(2)), "(0,0;200,0);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2), size_t(3)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (3)), "(0,0;200,0);(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (4)), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
edup = e;
edup.select_not_interacting (e2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (e2, size_t (2), size_t(3)).first, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (e2, size_t (2), size_t(3)).second, "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2), size_t(2)), "(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2), size_t(3)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (3)), "(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (4)), ""), true);
edup = e;
edup.select_interacting (r2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2), ""), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2), size_t(2)), "(0,0;200,0);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2), size_t(3)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (3)), "(0,0;200,0);(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (4)), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
edup = e;
edup.select_not_interacting (r2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (r2, size_t (2), size_t(3)).first, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (r2, size_t (2), size_t(3)).second, "(0,0;200,0)"), true);
}
TEST(23_SameInputs)
{
db::Layout ly;
{
std::string fn (tl::testdata ());
fn += "/algo/deep_region_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
db::DeepShapeStore dss;
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
db::Edges e2 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss)).edges ());
EXPECT_EQ ((e2 & e2).to_string (), e2.to_string ());
EXPECT_EQ ((e2 - e2).to_string (), "");
EXPECT_EQ (e2.andnot (e2).first.to_string (), e2.to_string ());
EXPECT_EQ (e2.andnot (e2).second.to_string (), "");
EXPECT_EQ ((e2 | e2).to_string (), e2.to_string ());
EXPECT_EQ ((e2 ^ e2).to_string (), "");
EXPECT_EQ (e2.in (e2).to_string (), e2.to_string ());
EXPECT_EQ (e2.in (e2, true).to_string (), "");
EXPECT_EQ (e2.in_and_out (e2).first.to_string (), e2.to_string ());
EXPECT_EQ (e2.in_and_out (e2).second.to_string (), "");
EXPECT_EQ (e2.selected_interacting (e2).to_string (), e2.to_string ());
EXPECT_EQ (e2.selected_not_interacting (e2).to_string (), "");
EXPECT_EQ (e2.selected_interacting_differential (e2).first.to_string (), e2.to_string ());
EXPECT_EQ (e2.selected_interacting_differential (e2).second.to_string (), "");
EXPECT_EQ ((e2.selected_interacting (e2, (size_t) 1, (size_t) 3) ^ e2).to_string (), "");
EXPECT_EQ ((e2.selected_interacting_differential (e2, (size_t) 1, (size_t) 3).first ^ e2).to_string (), "");
EXPECT_EQ (e2.selected_interacting_differential (e2, (size_t) 1, (size_t) 3).second.to_string (), "");
EXPECT_EQ (e2.selected_interacting (e2, (size_t) 4).to_string (), "");
EXPECT_EQ (e2.selected_interacting_differential (e2, (size_t) 4).first.to_string (), "");
EXPECT_EQ ((e2.selected_interacting_differential (e2, (size_t) 4).second ^ e2).to_string (), "");
EXPECT_EQ (e2.selected_inside (e2).to_string (), e2.to_string ());
EXPECT_EQ (e2.selected_not_inside (e2).to_string (), "");
EXPECT_EQ (e2.selected_inside_differential (e2).first.to_string (), e2.to_string ());
EXPECT_EQ (e2.selected_inside_differential (e2).second.to_string (), "");
EXPECT_EQ (e2.selected_outside (e2).to_string (), "");
EXPECT_EQ (e2.selected_not_outside (e2).to_string (), e2.to_string ());
EXPECT_EQ (e2.selected_outside_differential (e2).first.to_string (), "");
EXPECT_EQ (e2.selected_outside_differential (e2).second.to_string (), e2.to_string ());
EXPECT_EQ (e2.pull_interacting (e2).to_string (), e2.to_string ());
}
TEST(deep_edges_and_cheats)
{
db::Layout ly;

View File

@ -2649,6 +2649,66 @@ TEST(101_DeepFlatCollaboration)
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au101.gds");
}
TEST(102_SameInputs)
{
db::Layout ly;
{
std::string fn (tl::testdata ());
fn += "/algo/deep_region_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
db::DeepShapeStore dss;
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
EXPECT_EQ ((r2 & r2).to_string (), r2.to_string ());
EXPECT_EQ ((r2 - r2).to_string (), "");
EXPECT_EQ (r2.andnot (r2).first.to_string (), r2.to_string ());
EXPECT_EQ (r2.andnot (r2).second.to_string (), "");
EXPECT_EQ ((r2 | r2).to_string (), r2.to_string ());
EXPECT_EQ ((r2 ^ r2).to_string (), "");
EXPECT_EQ (r2.in (r2).to_string (), r2.to_string ());
EXPECT_EQ (r2.in (r2, true).to_string (), "");
EXPECT_EQ (r2.in_and_out (r2).first.to_string (), r2.to_string ());
EXPECT_EQ (r2.in_and_out (r2).second.to_string (), "");
EXPECT_EQ (r2.selected_enclosing (r2).to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_not_enclosing (r2).to_string (), "");
EXPECT_EQ (r2.selected_enclosing_differential (r2).first.to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_enclosing_differential (r2).second.to_string (), "");
EXPECT_EQ (r2.selected_interacting (r2).to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_not_interacting (r2).to_string (), "");
EXPECT_EQ (r2.selected_interacting_differential (r2).first.to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_interacting_differential (r2).second.to_string (), "");
EXPECT_EQ (r2.selected_interacting (r2, (size_t) 1, (size_t) 2).to_string (), r2.merged ().to_string ());
EXPECT_EQ (r2.selected_interacting_differential (r2, (size_t) 1, (size_t) 2).first.to_string (), r2.merged ().to_string ());
EXPECT_EQ (r2.selected_interacting_differential (r2, (size_t) 1, (size_t) 2).second.to_string (), "");
EXPECT_EQ (r2.selected_interacting (r2, (size_t) 2).to_string (), "");
EXPECT_EQ (r2.selected_interacting_differential (r2, (size_t) 2).first.to_string (), "");
EXPECT_EQ (r2.selected_interacting_differential (r2, (size_t) 2).second.to_string (), r2.merged ().to_string ());
EXPECT_EQ (r2.selected_inside (r2).to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_not_inside (r2).to_string (), "");
EXPECT_EQ (r2.selected_inside_differential (r2).first.to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_inside_differential (r2).second.to_string (), "");
EXPECT_EQ (r2.selected_outside (r2).to_string (), "");
EXPECT_EQ (r2.selected_not_outside (r2).to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_outside_differential (r2).first.to_string (), "");
EXPECT_EQ (r2.selected_outside_differential (r2).second.to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_overlapping (r2).to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_not_overlapping (r2).to_string (), "");
EXPECT_EQ (r2.selected_overlapping_differential (r2).first.to_string (), r2.to_string ());
EXPECT_EQ (r2.selected_overlapping_differential (r2).second.to_string (), "");
EXPECT_EQ (r2.pull_inside (r2).to_string (), r2.to_string ());
EXPECT_EQ (r2.pull_overlapping (r2).to_string (), r2.to_string ());
EXPECT_EQ (r2.pull_interacting (r2).to_string (), r2.to_string ());
}
TEST(issue_277)
{
db::Layout ly;

View File

@ -22,12 +22,14 @@
#include "tlUnitTest.h"
#include "tlStream.h"
#include "dbEdges.h"
#include "dbEdgesUtils.h"
#include "dbPolygonTools.h"
#include "dbRegion.h"
#include "dbTestSupport.h"
#include "dbReader.h"
#include <cstdlib>
@ -787,27 +789,27 @@ TEST(20)
EXPECT_EQ (r2.has_valid_edges (), false);
db::Region rr1 (db::RecursiveShapeIterator (ly, ly.cell (top), lp1), db::ICplxTrans (), false);
EXPECT_EQ (rr1.has_valid_polygons (), false);
EXPECT_EQ ((r1 & r2).to_string (100), "(80,70;80,40)");
EXPECT_EQ ((r1 + r2).to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(50,70;80,70);(80,70;80,40);(80,40;50,40);(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;110,70);(110,70;110,40);(110,40;80,40);(110,40;110,70);(110,70;140,70);(140,70;140,40);(140,40;110,40)");
EXPECT_EQ ((r1 + r2).merged ().to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(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);(50,70;140,70);(140,70;140,40);(140,40;50,40)");
EXPECT_EQ ((r1 | r2).to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(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);(50,70;140,70);(140,70;140,40);(140,40;50,40)");
EXPECT_EQ ((r1 ^ r2).to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(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);(50,70;140,70);(140,70;140,40);(140,40;50,40)");
EXPECT_EQ ((r1 ^ r1).to_string (100), "");
EXPECT_EQ ((r1 - r2).to_string (100), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(50,70;80,70);(80,40;50,40)");
EXPECT_EQ ((r1 - r1).to_string (100), "");
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)");
EXPECT_EQ (db::compare (r1 & r2, "(80,70;80,40)"), true);
EXPECT_EQ (db::compare (r1 + r2, "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(50,70;80,70);(80,70;80,40);(80,40;50,40);(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;110,70);(110,70;110,40);(110,40;80,40);(110,40;110,70);(110,70;140,70);(140,70;140,40);(140,40;110,40)"), true);
EXPECT_EQ (db::compare ((r1 + r2).merged (), "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(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);(50,70;140,70);(140,70;140,40);(140,40;50,40)"), true);
EXPECT_EQ (db::compare (r1 | r2, "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(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);(50,70;140,70);(140,70;140,40);(140,40;50,40)"), true);
EXPECT_EQ (db::compare (r1 ^ r2, "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(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);(50,70;140,70);(140,70;140,40);(140,40;50,40)"), true);
EXPECT_EQ (db::compare (r1 ^ r1, ""), true);
EXPECT_EQ (db::compare (r1 - r2, "(0,0;0,30);(0,30;30,30);(30,30;30,0);(30,0;0,0);(50,0;50,30);(50,30;80,30);(80,30;80,0);(80,0;50,0);(50,40;50,70);(50,70;80,70);(80,40;50,40)"), true);
EXPECT_EQ (db::compare (r1 - r1, ""), true);
EXPECT_EQ (db::compare (r2.merged (), "(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)"), true);
EXPECT_EQ (db::compare (rr1, "(0,0;0,30;30,30;30,0);(50,0;50,30;80,30;80,0);(50,40;50,70;80,70;80,40)"), true);
EXPECT_EQ (db::compare (r2.selected_interacting (rr1), "(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)"), true);
EXPECT_EQ (db::compare (r2.selected_interacting_differential (rr1).first, "(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)"), true);
EXPECT_EQ (db::compare (r2.selected_not_interacting (rr1), "(10,40;40,40);(40,40;40,10);(140,70;140,40)"), true);
EXPECT_EQ (db::compare (r2.selected_interacting_differential (rr1).second, "(10,40;40,40);(40,40;40,10);(140,70;140,40)"), true);
db::Edges r2dup = r2;
r2.select_interacting (rr1);
EXPECT_EQ (db::compare (r2, "(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)"), true);
r2 = r2dup;
r2.select_not_interacting (rr1);
EXPECT_EQ (r2.to_string (100), "(10,40;40,40);(40,40;40,10);(140,70;140,40)");
EXPECT_EQ (db::compare (r2, "(10,40;40,40);(40,40;40,10);(140,70;140,40)"), true);
r2 = db::Edges (db::RecursiveShapeIterator (ly, ly.cell (top), l2), false);
EXPECT_EQ (r2.has_valid_edges (), false);
@ -895,9 +897,9 @@ TEST(22)
ee.insert (db::Edge (4000,0,4000,-2000));
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);
EXPECT_EQ (db::compare ((e & ee), "(400,0;-2000,0);(500,-173;400,0);(1000,0;900,-174);(4000,0;1000,0)"), true);
EXPECT_EQ (db::compare (e.andnot(ee).first, "(400,0;-2000,0);(500,-173;400,0);(1000,0;900,-174);(4000,0;1000,0)"), true);
EXPECT_EQ (db::compare (e.intersections (ee), "(400,0;-2000,0);(500,-173;400,0);(1000,0;900,-174);(4000,0;1000,0)"), true);
// Edge/edge intersections
ee.clear ();
@ -1157,6 +1159,214 @@ TEST(28)
EXPECT_EQ (db::compare (ee.in (e, true), "(0,0;0,2000);(100,1000;0,2000)"), true);
}
// edge merge with dots -> dots are merged, but are retained
TEST(29)
{
db::Edges e;
e.insert (db::Edge (db::Point(0, 0), db::Point (100, 0)));
e.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
EXPECT_EQ (e.merged ().to_string (), "(0,0;100,0);(110,0;110,0)");
e.insert (db::Edge (db::Point(100, 0), db::Point (110, 0)));
// dots do not participate in merge
EXPECT_EQ (e.merged ().to_string (), "(0,0;110,0)");
e.clear ();
e.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
e.insert (db::Edge (db::Point(110, 0), db::Point (110, 0)));
// dots do not participate in merge
EXPECT_EQ (e.merged ().to_string (), "(110,0;110,0)");
}
// interacting with count
TEST(30)
{
db::Edges e;
e.insert (db::Edge (db::Point (0, 0), db::Point (100, 0)));
e.insert (db::Edge (db::Point (100, 0), db::Point (200, 0)));
e.insert (db::Edge (db::Point (0, 10), db::Point (200, 10)));
e.insert (db::Edge (db::Point (0, 20), db::Point (200, 20)));
e.insert (db::Edge (db::Point (0, 30), db::Point (200, 30)));
db::Edges e2;
e2.insert (db::Edge (db::Point (100, 0), db::Point (100, 10)));
e2.insert (db::Edge (db::Point (100, 0), db::Point (100, 30)));
e2.insert (db::Edge (db::Point (110, 10), db::Point (110, 30)));
e2.merge ();
e2.insert (db::Edge (db::Point (120, 20), db::Point (120, 20)));
e2.insert (db::Edge (db::Point (130, 30), db::Point (130, 30)));
e2.set_merged_semantics (false);
db::Edges edup;
EXPECT_EQ (db::compare (e.selected_interacting (e2), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2), size_t(2)), "(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (2), size_t(3)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (3)), "(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (e2, size_t (4)), ""), true);
edup = e;
edup.select_interacting (e2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2), ""), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2), size_t(2)), "(0,0;200,0);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (2), size_t(3)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (3)), "(0,0;200,0);(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (e2, size_t (4)), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
edup = e;
edup.select_not_interacting (e2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (e2, size_t (2), size_t(3)).first, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (e2, size_t (2), size_t(3)).second, "(0,0;200,0)"), true);
db::Region r2;
r2.insert (db::Box (db::Point (99, 0), db::Point (101, 10)));
r2.insert (db::Box (db::Point (99, 0), db::Point (101, 30)));
r2.insert (db::Box (db::Point (109, 10), db::Point (111, 30)));
r2.insert (db::Box (db::Point (119, 19), db::Point (121, 21)));
r2.insert (db::Box (db::Point (129, 29), db::Point (131, 31)));
EXPECT_EQ (db::compare (e.selected_interacting (r2), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2), size_t(2)), "(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (2), size_t(3)), "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (3)), "(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting (r2, size_t (4)), ""), true);
edup = e;
edup.select_interacting (r2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2), ""), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2), size_t(2)), "(0,0;200,0);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (2), size_t(3)), "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (3)), "(0,0;200,0);(0,10;200,10)"), true);
EXPECT_EQ (db::compare (e.selected_not_interacting (r2, size_t (4)), "(0,0;200,0);(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
edup = e;
edup.select_not_interacting (r2, size_t (2), size_t(3));
EXPECT_EQ (db::compare (edup, "(0,0;200,0)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (r2, size_t (2), size_t(3)).first, "(0,10;200,10);(0,20;200,20);(0,30;200,30)"), true);
EXPECT_EQ (db::compare (e.selected_interacting_differential (r2, size_t (2), size_t(3)).second, "(0,0;200,0)"), true);
}
// borrowed from deep edges tests
TEST(31)
{
db::Layout ly;
{
std::string fn (tl::testdata ());
fn += "/algo/deep_edges_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Cell &top_cell = ly.cell (top_cell_index);
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
unsigned int l21 = ly.get_layer (db::LayerProperties (2, 1));
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
unsigned int lempty = ly.insert_layer ();
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2));
db::Region r21 (db::RecursiveShapeIterator (ly, top_cell, l21));
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3));
db::Region r2and3 = r2 & r3;
db::Edges e2 = r2.edges ();
db::Edges e21 = r21.edges ();
db::Edges e3 = r3.edges ();
db::Edges e3copy = r3.edges ();
db::Edges e2and3 = r2and3.edges ();
db::Edges eempty (db::RecursiveShapeIterator (ly, top_cell, lempty));
db::Edges edots = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
db::Edges edotscopy = e2and3.processed (db::EdgeSegmentSelector (-1, 0, 0));
db::Layout target;
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (3, 0)), r3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), edots.merged ());
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e3 & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e3 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), e3 & eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), e3 & e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), eempty & e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), edots & edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), edots & e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), e21 & edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (28, 0)), edots & e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e3 - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e3 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), e3 - eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), e3 - e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (34, 0)), eempty - e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (35, 0)), edots - edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (36, 0)), edots - e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (37, 0)), e21 - edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (38, 0)), edots - e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e3 ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e3 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (42, 0)), e3 ^ eempty);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (43, 0)), e3 ^ e3copy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (44, 0)), eempty ^ e2and3);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (45, 0)), edots ^ edotscopy);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (46, 0)), edots ^ e2);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (47, 0)), e21 ^ edots);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (48, 0)), edots ^ e21);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (50, 0)), e3.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (51, 0)), e3.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (52, 0)), e3.andnot(eempty).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (53, 0)), e3.andnot(e3copy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (54, 0)), eempty.andnot(e2and3).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (55, 0)), edots.andnot(edotscopy).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (56, 0)), edots.andnot(e2).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (57, 0)), e21.andnot(edots).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (58, 0)), edots.andnot(e21).first);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (60, 0)), e3.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (61, 0)), e3.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (62, 0)), e3.andnot(eempty).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (63, 0)), e3.andnot(e3copy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (64, 0)), eempty.andnot(e2and3).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (65, 0)), edots.andnot(edotscopy).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (66, 0)), edots.andnot(e2).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (67, 0)), e21.andnot(edots).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (68, 0)), edots.andnot(e21).second);
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (70, 0)), e3.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (71, 0)), e3.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (72, 0)), e3.intersections(eempty));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (73, 0)), e3.intersections(e3copy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (74, 0)), eempty.intersections(e2and3));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (75, 0)), edots.intersections(edotscopy));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (76, 0)), edots.intersections(e2));
// test, whether dots are not merged
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (77, 0)), edots.intersections(e2).select_interacting(e2));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (78, 0)), e21.intersections(edots));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (79, 0)), edots.intersections(e21));
CHECKPOINT();
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au3_flat.gds");
}
// GitHub issue #72 (Edges/Region NOT issue)
TEST(100)
{

View File

@ -83,5 +83,25 @@ TEST(1)
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);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 5), db::Point (0, 5)), 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);
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 10),
db::Point (20, 10),
db::Point (20, -10),
db::Point (10, -10),
db::Point (10, 0)
};
db::Polygon poly;
poly.assign_hull (pts + 0, pts + sizeof(pts) / sizeof(pts[0]));
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 10), db::Point (20, 10)), poly), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, -10), db::Point (20, -10)), poly), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (11, 0)), poly), false);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (10, 0)), poly), true);
EXPECT_EQ (db::edge_is_outside (db::Edge (db::Point (-10, 0), db::Point (9, 0)), poly), true);
}

View File

@ -23,6 +23,7 @@
#include "tlUnitTest.h"
#include "tlStream.h"
#include "tlFileUtils.h"
#include "dbHierProcessor.h"
#include "dbTestSupport.h"
#include "dbReader.h"
@ -32,6 +33,9 @@
#include "dbLocalOperationUtils.h"
#include "dbRegionLocalOperations.h"
#include "dbPolygon.h"
#include "dbRecursiveInstanceIterator.h"
#include "dbDeepShapeStore.h"
#include "dbRegion.h"
static std::string testdata (const std::string &fn)
{
@ -1284,3 +1288,87 @@ TEST(Arrays)
run_test_bool2 (_this, "hlp18.oas", TMNot, 100);
}
TEST(XORTool)
{
test_is_long_runner ();
std::string fna (tl::combine_path (tl::testdata_private (), "xor/a.gds.gz"));
std::string fnb (tl::combine_path (tl::testdata_private (), "xor/b.gds.gz"));
std::string fn_au (tl::combine_path (tl::testdata_private (), "xor/xor_au.oas.gz"));
db::Layout lya, lyb;
unsigned int l1, l2;
db::LayerMap lmap;
lmap.map (db::LDPair (1, 0), l1 = lya.insert_layer ());
lyb.insert_layer ();
lmap.map (db::LDPair (2, 0), l2 = lya.insert_layer ());
lyb.insert_layer ();
{
tl::InputStream stream (fna);
db::Reader reader (stream);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
reader.read (lya, options);
}
{
tl::InputStream stream (fnb);
db::Reader reader (stream);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
reader.read (lyb, options);
}
db::Layout ly_out;
db::cell_index_type top_out = ly_out.add_cell ("TOP");
unsigned int l1_out = ly_out.insert_layer (db::LayerProperties (1, 0));
unsigned int l2_out = ly_out.insert_layer (db::LayerProperties (2, 0));
db::DeepShapeStore dss;
dss.set_wants_all_cells (true); // saves time for less cell mapping operations
{
db::RecursiveShapeIterator ri_a, ri_b;
ri_a = db::RecursiveShapeIterator (lya, lya.cell (*lya.begin_top_down ()), l1);
ri_a.set_for_merged_input (true);
ri_b = db::RecursiveShapeIterator (lyb, lyb.cell (*lyb.begin_top_down ()), l1);
ri_b.set_for_merged_input (true);
db::Region in_a (ri_a, dss, db::ICplxTrans (1.0));
db::Region in_b (ri_b, dss, db::ICplxTrans (1.0));
db::Region xor_res = in_a ^ in_b;
EXPECT_EQ (xor_res.count (), size_t (12));
xor_res.insert_into (&ly_out, top_out, l1_out);
}
{
db::RecursiveShapeIterator ri_a, ri_b;
ri_a = db::RecursiveShapeIterator (lya, lya.cell (*lya.begin_top_down ()), l2);
ri_a.set_for_merged_input (true);
ri_b = db::RecursiveShapeIterator (lyb, lyb.cell (*lyb.begin_top_down ()), l2);
ri_b.set_for_merged_input (true);
db::Region in_a (ri_a, dss, db::ICplxTrans (1.0));
db::Region in_b (ri_b, dss, db::ICplxTrans (1.0));
db::Region xor_res = in_a ^ in_b;
EXPECT_EQ (xor_res.count (), size_t (15984));
xor_res.insert_into (&ly_out, top_out, l2_out);
}
db::compare_layouts (_this, ly_out, fn_au, db::WriteOAS);
}

View File

@ -26,6 +26,10 @@
#include "dbLayoutDiff.h"
#include "tlString.h"
#include "tlUnitTest.h"
#include "tlFileUtils.h"
#include "tlStream.h"
#include "dbReader.h"
#include "dbWriter.h"
#include <vector>
@ -1554,3 +1558,225 @@ TEST(11_LayoutIsWeakPointer)
x = collect(i1, *g);
EXPECT_EQ (x, "");
}
TEST(12_ForMerged)
{
std::unique_ptr<db::Layout> g (new db::Layout ());
g->insert_layer (0);
g->insert_layer (1);
db::Cell &c0 (g->cell (g->add_cell ()));
db::Cell &c1 (g->cell (g->add_cell ()));
db::Cell &c2 (g->cell (g->add_cell ()));
db::Cell &c3 (g->cell (g->add_cell ()));
db::Box b (0, 100, 1000, 1200);
c0.shapes (0).insert (db::Box (0, 0, 3000, 2000));
c1.shapes (0).insert (b);
c2.shapes (0).insert (b);
c3.shapes (0).insert (b);
db::Trans tt;
c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), tt));
c0.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (100, -100))));
c0.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (1)));
c2.insert (db::CellInstArray (db::CellInst (c3.cell_index ()), db::Trans (db::Vector (1100, 0))));
std::string x;
db::RecursiveShapeIterator i1 (*g, c0, 0);
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
i1.set_for_merged_input (true);
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
std::vector<unsigned int> lv;
lv.push_back (0);
i1 = db::RecursiveShapeIterator (*g, c0, lv);
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
i1.set_for_merged_input (true);
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
lv.push_back (1); // empty, but kills "for merged" optimization
i1 = db::RecursiveShapeIterator (*g, c0, lv);
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
i1.set_for_merged_input (true);
x = collect(i1, *g);
// no longer optimized
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-100, 0, 100, 50));
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$3](100,0;1100,1100)/[$4](-1200,0;-100,1000)");
i1.set_for_merged_input (true);
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
i1 = db::RecursiveShapeIterator (*g, c0, 0, db::Box (-101, 0, 100, 50));
i1.set_overlapping (true);
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
i1.set_for_merged_input (true);
x = collect(i1, *g);
EXPECT_EQ (x, "[$1](0,0;3000,2000)/[$4](-1200,0;-100,1000)");
}
TEST(13_ForMergedPerformance)
{
test_is_long_runner ();
std::string fn (tl::combine_path (tl::testdata_private (), "oasis/caravel.oas.gz"));
db::Layout ly;
{
tl::InputStream is (fn);
db::Reader reader (is);
reader.read (ly);
}
unsigned l1 = ly.get_layer (db::LayerProperties (66, 20));
unsigned l2 = ly.get_layer (db::LayerProperties (235, 4));
db::RecursiveShapeIterator si1 (ly, ly.cell (*ly.begin_top_down ()), l1);
db::RecursiveShapeIterator si2 (ly, ly.cell (*ly.begin_top_down ()), l2);
size_t n1_expected_full = db::default_editable_mode () ? 1203072 : 1203078;
size_t n2_expected_full = 10;
{
tl::SelfTimer timer ("Standard loop on 66/20");
size_t n = 0;
while (! si1.at_end ()) {
++si1;
++n;
}
tl::info << "Counted " << n << " shapes on 66/20";
EXPECT_EQ (n, size_t (1218378));
}
{
tl::SelfTimer timer ("Standard loop on 235/4");
size_t n = 0;
while (! si2.at_end ()) {
++si2;
++n;
}
tl::info << "Counted " << n << " shapes on 235/4";
EXPECT_EQ (n, size_t (57462));
}
si1.set_for_merged_input (true);
si2.set_for_merged_input (true);
{
tl::SelfTimer timer ("'for_merged' loop on 66/20");
size_t n = 0;
while (! si1.at_end ()) {
++si1;
++n;
}
tl::info << "Counted " << n << " shapes on 66/20";
EXPECT_EQ (n, size_t (n1_expected_full));
}
{
tl::SelfTimer timer ("'for_merged' loop on 235/4");
size_t n = 0;
while (! si2.at_end ()) {
++si2;
++n;
}
tl::info << "Counted " << n << " shapes on 235/4";
EXPECT_EQ (n, size_t (n2_expected_full));
}
si1.set_for_merged_input (false);
si1.set_region (db::Box (0, 0, 1000000, 1000000));
si2.set_for_merged_input (false);
si2.set_region (db::Box (0, 0, 1000000, 1000000));
{
tl::SelfTimer timer ("Standard loop on 66/20");
size_t n = 0;
while (! si1.at_end ()) {
++si1;
++n;
}
tl::info << "Counted " << n << " shapes on 66/20";
EXPECT_EQ (n, size_t (218823));
}
{
tl::SelfTimer timer ("Standard loop on 235/4");
size_t n = 0;
while (! si2.at_end ()) {
++si2;
++n;
}
tl::info << "Counted " << n << " shapes on 235/4";
EXPECT_EQ (n, size_t (2578));
}
si1.set_for_merged_input (true);
si2.set_for_merged_input (true);
size_t n1_expected = db::default_editable_mode () ? 218068 : 218069;
size_t n2_expected = 2;
{
tl::SelfTimer timer ("'for_merged' loop on 66/20");
size_t n = 0;
while (! si1.at_end ()) {
++si1;
++n;
}
tl::info << "Counted " << n << " shapes on 66/20";
EXPECT_EQ (n, size_t (n1_expected));
}
{
tl::SelfTimer timer ("'for_merged' loop on 235/4");
size_t n = 0;
while (! si2.at_end ()) {
++si2;
++n;
}
tl::info << "Counted " << n << " shapes on 235/4";
EXPECT_EQ (n, size_t (n2_expected));
}
{
tl::SelfTimer timer ("XOR on tile of 66/20");
si1.set_for_merged_input (false);
db::Region r1 (si1);
si1.set_for_merged_input (true);
db::Region r2 (si1);
EXPECT_EQ (r1.count (), size_t (218823));
EXPECT_EQ (r2.count (), size_t (n1_expected));
EXPECT_EQ ((r1 ^ r2).count (), size_t (0));
}
{
tl::SelfTimer timer ("XOR on tile of 235/4");
si2.set_for_merged_input (false);
db::Region r1 (si2);
si2.set_for_merged_input (true);
db::Region r2 (si2);
EXPECT_EQ (r1.count (), size_t (2578));
EXPECT_EQ (r2.count (), size_t (n2_expected));
EXPECT_EQ ((r1 ^ r2).count (), size_t (0));
}
}

View File

@ -0,0 +1,80 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2024 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 "tlString.h"
#include "dbRegionProcessors.h"
TEST(1_RegionToEdgesProcessor)
{
db::Point hull[] = {
db::Point (0, 0),
db::Point (0, 1000),
db::Point (1000, 1000),
db::Point (1000, 2000),
db::Point (2000, 2000),
db::Point (2000, 1000),
db::Point (3000, 1000),
db::Point (3000, 0)
};
db::Point hole[] = {
db::Point (100, 100),
db::Point (2900, 100),
db::Point (2900, 900),
db::Point (100, 900)
};
db::Polygon poly;
poly.assign_hull (hull + 0, hull + sizeof (hull) / sizeof (hull[0]));
poly.insert_hole (hole + 0, hole + sizeof (hole) / sizeof (hole[0]));
std::vector<db::Edge> result;
result.clear ();
db::PolygonToEdgeProcessor ().process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,0;0,1000);(0,1000;1000,1000);(1000,1000;1000,2000);(1000,2000;2000,2000);(2000,2000;2000,1000);(2000,1000;3000,1000);(3000,1000;3000,0);(3000,0;0,0);(100,100;2900,100);(2900,100;2900,900);(2900,900;100,900);(100,900;100,100)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Concave).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(2900,100;2900,900);(2900,900;100,900);(100,900;100,100);(100,100;2900,100)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Convex).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(1000,2000;2000,2000);(3000,1000;3000,0);(3000,0;0,0);(0,0;0,1000)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::Step).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,1000;1000,1000);(1000,1000;1000,2000);(2000,2000;2000,1000);(2000,1000;3000,1000)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::StepOut).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(1000,1000;1000,2000);(2000,1000;3000,1000)");
result.clear ();
db::PolygonToEdgeProcessor (db::PolygonToEdgeProcessor::StepIn).process (poly, result);
EXPECT_EQ (tl::join (result.begin (), result.end (), ";"), "(0,1000;1000,1000);(2000,2000;2000,1000)");
}

View File

@ -2537,6 +2537,35 @@ TEST(55_PropertiesFilterFlat)
EXPECT_EQ (s->to_string (), "(1,2;1,202;101,202;101,2)");
}
TEST(56_RegionsFromShapes)
{
db::Shapes shapes;
shapes.insert (db::Box (0, 0, 100, 200));
shapes.insert (db::Box (50, 50, 150, 250));
EXPECT_EQ (db::Region (shapes).area (), 32500);
EXPECT_EQ (db::Region (shapes, false).area (), 40000);
EXPECT_EQ (db::Region (shapes, db::ICplxTrans (0.5)).area (), 8125);
EXPECT_EQ (db::Region (shapes, db::ICplxTrans (0.5), false).area (), 10000);
// for cross-checking: same for RecursiveShapeIterator
db::Layout layout;
unsigned int l1 = layout.insert_layer ();
db::Cell &top = layout.cell (layout.add_cell ("TOP"));
top.shapes (l1).insert (db::Box (0, 0, 100, 200));
top.shapes (l1).insert (db::Box (50, 50, 150, 250));
db::RecursiveShapeIterator si (layout, top, l1);
EXPECT_EQ (db::Region (si).area (), 32500);
EXPECT_EQ (db::Region (si, false).area (), 40000);
EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5)).area (), 8125);
EXPECT_EQ (db::Region (si, db::ICplxTrans (0.5), false).area (), 10000);
}
TEST(100_Processors)
{
db::Region r;

View File

@ -948,3 +948,89 @@ TEST(9)
EXPECT_EQ (si.at_end (), true);
}
// Rectangle
TEST(10)
{
db::Manager m (true);
db::Shapes s (&m, 0, db::default_editable_mode ());
db::ShapeIterator si;
s.insert (db::Point (100, 200));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
s.clear ();
s.insert (db::Edge (db::Point (100, 200), db::Point (200, 400)));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
s.clear ();
s.insert (db::EdgePair (db::Edge (db::Point (100, 200), db::Point (200, 400)), db::Edge (db::Point (0, 300), db::Point (100, 500))));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
s.clear ();
s.insert (db::Box (0, 0, 1000, 2000));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
s.clear ();
s.insert (db::ShortBox (0, 0, 1000, 2000));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
s.clear ();
s.insert (db::Polygon (db::Box (0, 0, 1000, 2000)));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
s.clear ();
s.insert (db::Polygon ());
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
s.clear ();
s.insert (db::SimplePolygon (db::Box (0, 0, 1000, 2000)));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle (), db::Box (0, 0, 1000, 2000));
s.clear ();
s.insert (db::SimplePolygon ());
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
s.clear ();
s.insert (db::Path ());
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
db::Point pts1 [1] = { db::Point (0, 0) };
db::Point pts2 [2] = { db::Point (0, 0), db::Point (1000, 0) };
db::Point pts2b [2] = { db::Point (0, 0), db::Point (1000, 1000) };
db::Point pts3 [3] = { db::Point (0, 0), db::Point (1000, 0), db::Point (1000, 1000) };
s.clear ();
s.insert (db::Path (pts1 + 0, pts1 + 1, 1000, 500, 500));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle (), db::Box (-500, -500, 500, 500));
s.clear ();
s.insert (db::Path (pts2 + 0, pts2 + 2, 1000, 500, 500));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle (), db::Box (-500, -500, 1500, 500));
s.clear ();
s.insert (db::Path (pts2 + 0, pts2 + 2, 1000, 500, 500, true));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
s.clear ();
s.insert (db::Path (pts2b + 0, pts2b + 2, 1000, 500, 500));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
s.clear ();
s.insert (db::Path (pts3 + 0, pts3 + 3, 1000, 500, 500));
si = s.begin (db::ShapeIterator::All);
EXPECT_EQ (si->rectangle ().empty (), true);
}

View File

@ -353,9 +353,9 @@ TEST(11)
EXPECT_EQ (x.try_read (tt2), true);
EXPECT_EQ (x.test ("a"), true);
EXPECT_EQ (tt2.to_string (), t2.to_string ());
x = tl::Extractor ("m22.5 *0.55 12.4,-17 ++");
x = tl::Extractor ("m22.5 *0.55 12.4,-17 ##");
EXPECT_EQ (x.try_read (tt2), true);
EXPECT_EQ (x.test ("++"), true);
EXPECT_EQ (x.test ("##"), true);
EXPECT_EQ (tt2.to_string (), "m22.5 *0.55 12.4,-17");
EXPECT_EQ (tt2.to_string (), t3.to_string ());
}

View File

@ -87,6 +87,7 @@ SOURCES = \
dbDeepTextsTests.cc \
dbNetShapeTests.cc \
dbHierNetsProcessorTests.cc \
dbRegionProcessorTests.cc \
dbAsIfFlatRegionTests.cc
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC

View File

@ -358,7 +358,7 @@ The plain function is equivalent to "primary.bbox_width".
This method acts on edge expressions and delivers a specific part of each edge.
See <a href="/about/drc_ref_layer.xml#centers">layer#centers</a> for details about this functionality.
</p>
<a name="corners"/><h2>"corners" - Applies smoothing</h2>
<a name="corners"/><h2>"corners" - Selects corners of polygons</h2>
<keyword name="corners"/>
<p>Usage:</p>
<ul>
@ -369,8 +369,10 @@ See <a href="/about/drc_ref_layer.xml#centers">layer#centers</a> for details abo
<p>
This operation acts on polygons and selects the corners of the polygons.
It can be put into a condition to select corners by their angles. The angle of
a corner is positive for a turn to the left if walking a polygon counterclockwise
and negative for the turn to the right. Angles take values between -180 and 180 degree.
a corner is positive for a turn to the left if walking a polygon clockwise
and negative for the turn to the right. Hence positive angles indicate concave
(inner) corners, negative ones indicate convex (outer) corners.
Angles take values between -180 and 180 degree.
</p><p>
When using "as_dots" for the argument, the operation will return single-point edges at
the selected corners. With "as_boxes" (the default), small (2x2 DBU) rectangles will be
@ -386,8 +388,8 @@ out = in.drc(primary.corners) # equivalent
The following example selects all inner corners:
</p><p>
<pre>
out = in.drc(corners &lt; 0)
out = in.drc(primary.corners &lt; 0) # equivalent
out = in.drc(corners &gt; 0)
out = in.drc(primary.corners &gt; 0) # equivalent
</pre>
</p><p>
The "corners" method is available as a plain function or as a method on <a href="/about/drc_ref_drc.xml">DRC</a> expressions.
@ -453,6 +455,7 @@ out = in.drc(covering(other) &gt; 2)
<p>Usage:</p>
<ul>
<li><tt>expression.edges</tt></li>
<li><tt>expression.edges(mode)</tt></li>
</ul>
<p>
Polygons will be separated into edges forming their contours. Edge pairs will be
@ -466,6 +469,20 @@ for the edges:
<pre>
out = in.drc(primary.edges)
</pre>
</p><p>
The "mode" argument allows selecting specific edges from polygons.
Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
"step" generates edges only if they provide a step between two other
edges. "step_in" creates edges that make a step towards the inside of
the polygon and "step_out" creates edges that make a step towards the
outside:
</p><p>
<pre>
out = in.drc(primary.edges(convex))
</pre>
</p><p>
The mode argument is ignored when translating other objects than
polygons.
</p>
<a name="end_segments"/><h2>"end_segments" - Returns the part at the end of each edge of the input</h2>
<keyword name="end_segments"/>

View File

@ -265,7 +265,7 @@ deliver objects that can be converted into polygons. Such objects are of class <
This method produces markers on the corners of the polygons. An angle criterion can be given which
selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
while negative angles indicate a right turn. Since polygons are oriented clockwise, positive angles
indicate concave corners while negative ones indicate convex corners.
indicate concave (inner) corners while negative ones indicate convex (outer) corners
</p><p>
The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
</p><p>
@ -783,6 +783,11 @@ apply to this method.
</ul>
<a name="edges"/><h2>"edges" - Decomposes the layer into single edges</h2>
<keyword name="edges"/>
<p>Usage:</p>
<ul>
<li><tt>layer.edges</tt></li>
<li><tt>layer.edges(mode)</tt></li>
</ul>
<p>
Edge pair collections are decomposed into the individual edges that make up
the edge pairs. Polygon layers are decomposed into the edges making up the
@ -791,6 +796,36 @@ is called on.
</p><p>
Merged semantics applies, i.e. the result reflects merged polygons rather than
individual ones unless raw mode is chosen.
</p><p>
The "mode" argument allows selecting specific edges from polygons.
Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
"step" generates edges only if they provide a step between two other
edges. "step_in" creates edges that make a step towards the inside of
the polygon and "step_out" creates edges that make a step towards the
outside:
</p><p>
<pre>
out = in.edges(convex)
</pre>
</p><p>
This feature is only available for polygon layers.
</p><p>
The following images show the effect of the mode argument:
</p><p>
<table>
<tr>
<td><img src="/images/drc_edge_modes1.png"/></td>
<td><img src="/images/drc_edge_modes2.png"/></td>
</tr>
<tr>
<td><img src="/images/drc_edge_modes3.png"/></td>
<td><img src="/images/drc_edge_modes4.png"/></td>
</tr>
<tr>
<td><img src="/images/drc_edge_modes5.png"/></td>
<td><img src="/images/drc_edge_modes6.png"/></td>
</tr>
</table>
</p>
<a name="edges?"/><h2>"edges?" - Returns true, if the layer is an edge layer</h2>
<keyword name="edges?"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -59,6 +59,12 @@
<file alias="drc_extended2.png">doc/images/drc_extended2.png</file>
<file alias="drc_extended3.png">doc/images/drc_extended3.png</file>
<file alias="drc_extended4.png">doc/images/drc_extended4.png</file>
<file alias="drc_edge_modes1.png">doc/images/drc_edge_modes1.png</file>
<file alias="drc_edge_modes2.png">doc/images/drc_edge_modes2.png</file>
<file alias="drc_edge_modes3.png">doc/images/drc_edge_modes3.png</file>
<file alias="drc_edge_modes4.png">doc/images/drc_edge_modes4.png</file>
<file alias="drc_edge_modes5.png">doc/images/drc_edge_modes5.png</file>
<file alias="drc_edge_modes6.png">doc/images/drc_edge_modes6.png</file>
<file alias="drc_extents1.png">doc/images/drc_extents1.png</file>
<file alias="drc_extents2.png">doc/images/drc_extents2.png</file>
<file alias="drc_inside.png">doc/images/drc_inside.png</file>

View File

@ -756,15 +756,17 @@ CODE
# %DRC%
# @name corners
# @brief Applies smoothing
# @brief Selects corners of polygons
# @synopsis expression.corners
# @synopsis expression.corners(as_dots)
# @synopsis expression.corners(as_boxes)
#
# This operation acts on polygons and selects the corners of the polygons.
# It can be put into a condition to select corners by their angles. The angle of
# a corner is positive for a turn to the left if walking a polygon counterclockwise
# and negative for the turn to the right. Angles take values between -180 and 180 degree.
# a corner is positive for a turn to the left if walking a polygon clockwise
# and negative for the turn to the right. Hence positive angles indicate concave
# (inner) corners, negative ones indicate convex (outer) corners.
# Angles take values between -180 and 180 degree.
#
# When using "as_dots" for the argument, the operation will return single-point edges at
# the selected corners. With "as_boxes" (the default), small (2x2 DBU) rectangles will be
@ -780,8 +782,8 @@ CODE
# The following example selects all inner corners:
#
# @code
# out = in.drc(corners < 0)
# out = in.drc(primary.corners < 0) # equivalent
# out = in.drc(corners > 0)
# out = in.drc(primary.corners > 0) # equivalent
# @/code
#
# The "corners" method is available as a plain function or as a method on \DRC# expressions.
@ -989,6 +991,7 @@ CODE
# @name edges
# @brief Converts the input shapes into edges
# @synopsis expression.edges
# @synopsis expression.edges(mode)
#
# Polygons will be separated into edges forming their contours. Edge pairs will be
# decomposed into individual edges.
@ -1001,9 +1004,38 @@ CODE
# @code
# out = in.drc(primary.edges)
# @/code
#
# The "mode" argument allows selecting specific edges from polygons.
# Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
# "step" generates edges only if they provide a step between two other
# edges. "step_in" creates edges that make a step towards the inside of
# the polygon and "step_out" creates edges that make a step towards the
# outside:
#
# @code
# out = in.drc(primary.edges(convex))
# @/code
#
# In addition, "not_.." variants are available which selects edges
# not qualifying for the specific mode:
#
# @code
# out = in.drc(primary.edges(not_convex))
# @/code
#
# The mode argument is ignored when translating other objects than
# polygons.
def edges
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges")
def edges(mode = nil)
if mode
if ! mode.is_a?(DRC::DRCEdgeMode)
raise "The mode argument needs to be a mode type (convex, concave, step, step_in or step_out)"
end
mode = mode.value
else
mode = RBA::EdgeMode::All
end
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges", mode)
end
# %DRC%

View File

@ -255,6 +255,46 @@ module DRC
DRCJoinFlag::new(true)
end
def convex
DRCEdgeMode::new(RBA::EdgeMode::Convex)
end
def not_convex
DRCEdgeMode::new(RBA::EdgeMode::NotConvex)
end
def concave
DRCEdgeMode::new(RBA::EdgeMode::Concave)
end
def not_concave
DRCEdgeMode::new(RBA::EdgeMode::NotConcave)
end
def step_in
DRCEdgeMode::new(RBA::EdgeMode::StepIn)
end
def not_step_in
DRCEdgeMode::new(RBA::EdgeMode::NotStepIn)
end
def step_out
DRCEdgeMode::new(RBA::EdgeMode::StepOut)
end
def not_step_out
DRCEdgeMode::new(RBA::EdgeMode::NotStepOut)
end
def step
DRCEdgeMode::new(RBA::EdgeMode::Step)
end
def not_step
DRCEdgeMode::new(RBA::EdgeMode::NotStep)
end
def padding_zero
DRCDensityPadding::new(:zero)
end

View File

@ -1232,7 +1232,7 @@ CODE
# This method produces markers on the corners of the polygons. An angle criterion can be given which
# selects corners based on the angle of the connecting edges. Positive angles indicate a left turn
# while negative angles indicate a right turn. Since polygons are oriented clockwise, positive angles
# indicate concave corners while negative ones indicate convex corners.
# indicate concave (inner) corners while negative ones indicate convex (outer) corners
#
# The markers generated can be point-like edges or small 2x2 DBU boxes. The latter is the default.
#
@ -3387,6 +3387,8 @@ CODE
# %DRC%
# @name edges
# @brief Decomposes the layer into single edges
# @synopsis layer.edges
# @synopsis layer.edges(mode)
#
# Edge pair collections are decomposed into the individual edges that make up
# the edge pairs. Polygon layers are decomposed into the edges making up the
@ -3395,13 +3397,61 @@ CODE
#
# Merged semantics applies, i.e. the result reflects merged polygons rather than
# individual ones unless raw mode is chosen.
#
# The "mode" argument allows selecting specific edges from polygons.
# Allowed values are: "convex", "concave", "step", "step_in" and "step_out".
# "step" generates edges only if they provide a step between two other
# edges. "step_in" creates edges that make a step towards the inside of
# the polygon and "step_out" creates edges that make a step towards the
# outside:
#
# @code
# out = in.edges(convex)
# @/code
#
# In addition, "not_.." variants are available which selects edges
# not qualifying for the specific mode:
#
# @code
# out = in.edges(not_convex)
# @/code
#
# The mode argument is only available for polygon layers.
#
# The following images show the effect of the mode argument:
#
# @table
# @tr
# @td @img(/images/drc_edge_modes1.png) @/td
# @td @img(/images/drc_edge_modes2.png) @/td
# @/tr
# @tr
# @td @img(/images/drc_edge_modes3.png) @/td
# @td @img(/images/drc_edge_modes4.png) @/td
# @/tr
# @tr
# @td @img(/images/drc_edge_modes5.png) @/td
# @td @img(/images/drc_edge_modes6.png) @/td
# @/tr
# @/table
%w(edges).each do |f|
eval <<"CODE"
def #{f}
def #{f}(mode = nil)
if mode
if ! mode.is_a?(DRC::DRCEdgeMode)
raise "The mode argument needs to be a mode type (convex, concave, step, step_in or step_out)"
end
if ! self.data.is_a?(RBA::Region)
raise "The mode argument is only available for polygon layers"
end
mode = mode.value
else
mode = RBA::EdgeMode::All
end
@engine._context("#{f}") do
if self.data.is_a?(RBA::Region)
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Edges, :#{f}))
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, RBA::Edges, :#{f}, mode))
elsif self.data.is_a?(RBA::EdgePairs)
DRCLayer::new(@engine, @engine._cmd(self.data, :#{f}))
else

View File

@ -57,6 +57,14 @@ module DRC
end
end
# A wrapper for the edge mode value for Region#edges
class DRCEdgeMode
attr_accessor :value
def initialize(v)
self.value = v
end
end
# A wrapper for the join flag for extended
class DRCJoinFlag
attr_accessor :value

View File

@ -1672,3 +1672,33 @@ TEST(92_issue1594_dual_top)
CHECKPOINT ();
compare_netlists (_this, output, au);
}
TEST(100_edge_interaction_with_count)
{
run_test (_this, "100", false);
}
TEST(100d_edge_interaction_with_count)
{
run_test (_this, "100", true);
}
TEST(101_edge_booleans_with_dots)
{
run_test (_this, "101", false);
}
TEST(101d_edge_booleans_with_dots)
{
run_test (_this, "101", true);
}
TEST(102_edge_modes)
{
run_test (_this, "102", false);
}
TEST(102d_edge_modes)
{
run_test (_this, "102", true);
}

View File

@ -399,6 +399,16 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
m_icon_widgets.push_back (icon_label);
m_all_widgets.back ().push_back (icon_label);
std::string range;
if (! p->min_value ().is_nil () || ! p->max_value ().is_nil ()) {
range = tl::sprintf (
" [%s, %s]" ,
p->min_value ().is_nil () ? "-\u221e" /*infinity*/ : p->min_value ().to_string (),
p->max_value ().is_nil () ? "\u221e" /*infinity*/ : p->max_value ().to_string ()
);
}
if (p->get_type () != db::PCellParameterDeclaration::t_callback) {
std::string leader;
@ -406,7 +416,8 @@ PCellParametersPage::setup (lay::LayoutViewBase *view, int cv_index, const db::P
leader = tl::sprintf ("[%s] ", p->get_name ());
}
QLabel *l = new QLabel (tl::to_qstring (leader + description), inner_frame);
QLabel *l = new QLabel (tl::to_qstring (leader + description + range), inner_frame);
inner_grid->addWidget (l, row, 1);
m_all_widgets.back ().push_back (l);
@ -702,9 +713,11 @@ PCellParametersPage::do_parameter_changed ()
bool ok = true;
db::ParameterStates states = m_states;
get_parameters (states, &ok); // includes coerce
update_widgets_from_states (states);
if (ok && ! lazy_evaluation ()) {
emit edited ();
if (ok) {
update_widgets_from_states (states);
if (! lazy_evaluation ()) {
emit edited ();
}
}
}
@ -762,6 +775,8 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool
ps.set_value (tl::Variant (v));
lay::indicate_error (le, (tl::Exception *) 0);
check_range(tl::Variant (v), *p);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
@ -786,6 +801,8 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool
ps.set_value (tl::Variant (v));
lay::indicate_error (le, (tl::Exception *) 0);
check_range(tl::Variant (v), *p);
} catch (tl::Exception &ex) {
lay::indicate_error (le, &ex);
@ -1085,6 +1102,18 @@ PCellParametersPage::states_from_parameters (db::ParameterStates &states, const
}
}
void
PCellParametersPage::check_range (const tl::Variant &value, const db::PCellParameterDeclaration &decl)
{
if (! decl.min_value ().is_nil () && value < decl.min_value ()) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("The value is lower than the minimum allowed value: given value is %s, minimum value is %s")), value.to_string (), decl.min_value ().to_string ()));
}
if (! decl.max_value ().is_nil () && ! (value < decl.max_value () || value == decl.max_value ())) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("The value is higher than the maximum allowed value: given value is %s, maximum value is %s")), value.to_string (), decl.max_value ().to_string ()));
}
}
}
#endif

View File

@ -181,6 +181,7 @@ private:
void get_parameters_internal (db::ParameterStates &states, bool &edit_error);
std::vector<tl::Variant> parameter_from_states (const db::ParameterStates &states) const;
void states_from_parameters (db::ParameterStates &states, const std::vector<tl::Variant> &parameters);
void check_range (const tl::Variant& value, const db::PCellParameterDeclaration &decl);
};
}

View File

@ -1,67 +1,75 @@
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainConfigPage3</class>
<widget class="QFrame" name="MainConfigPage3" >
<property name="geometry" >
<widget class="QFrame" name="MainConfigPage3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>475</width>
<height>81</height>
<width>504</width>
<height>180</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin" stdset="0">
<number>9</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Default Grids</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<layout class="QGridLayout">
<property name="margin" stdset="0">
<number>9</number>
</property>
<property name="spacing" >
<property name="spacing">
<number>6</number>
</property>
<item row="0" column="2" >
<widget class="QLabel" name="textLabel1_4" >
<property name="text" >
<item row="0" column="0">
<widget class="QLabel" name="textLabel1">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Grids for &quot;View&quot; menu</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="textLabel1_4">
<property name="text">
<string>µm (g1,g2,...)</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="grids_edit" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<item row="0" column="1">
<widget class="QLineEdit" name="grids_edit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="textLabel1" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="1" column="0" colspan="3">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;You can declare one grid a strong default to enforce an editing grid from this list. To do so, add an exclamation mark - e.g. &quot;0.01!,0.02,0.05&quot;.
&lt;br/&gt;&lt;b&gt;Note&lt;/b&gt;: the general default grids can be overridden by technology specific default grids.&lt;/html&gt;</string>
</property>
<property name="text" >
<string>Grids for "View" menu</string>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
@ -70,7 +78,7 @@
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11" />
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>625</width>
<height>587</height>
<height>616</height>
</rect>
</property>
<property name="windowTitle">
@ -331,6 +331,9 @@ properties</string>
<property name="text">
<string>The default database unit is used as database unit for freshly created layouts</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="12" column="0" colspan="4">
@ -352,7 +355,10 @@ properties</string>
<item row="11" column="1" colspan="3">
<widget class="QLabel" name="label_15">
<property name="text">
<string>These grids are available for selection from the &quot;View&quot; menu</string>
<string>These grids are available for selection from the &quot;View&quot; menu and will override the general ones. You can declare one grid as a strong default to enforce an editing grid from this list. To do so, add an exclamation mark to the grid - e.g. &quot;0.01!,0.02,0.05&quot;.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>

View File

@ -525,7 +525,7 @@ CustomizeMenuConfigPage::commit (lay::Dispatcher *dispatcher)
std::map<std::string, std::string>::iterator cb = m_current_bindings.find (kb->first);
if (cb != m_current_bindings.end ()) {
lay::Action *a = dispatcher->menu ()->action (kb->first);
if (cb->second != a->get_default_shortcut ()) {
if (a && cb->second != a->get_default_shortcut ()) {
if (cb->second.empty ()) {
kb->second = lay::Action::no_shortcut ();
} else {

View File

@ -175,9 +175,11 @@ MainWindow::MainWindow (QApplication *app, const char *name, bool undo_enabled)
m_disable_tab_selected (false),
m_exited (false),
dm_do_update_menu (this, &MainWindow::do_update_menu),
dm_do_update_grids (this, &MainWindow::do_update_grids),
dm_do_update_mru_menus (this, &MainWindow::do_update_mru_menus),
dm_exit (this, &MainWindow::exit),
m_grid_micron (0.001),
m_default_grid (0.0),
m_default_grids_updated (true),
m_new_layout_current_panel (false),
m_synchronized_views (false),
@ -498,34 +500,9 @@ MainWindow::~MainWindow ()
std::string
MainWindow::all_layout_file_formats () const
{
std::string fmts = tl::to_string (QObject::tr ("All layout files ("));
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end (); ++rdr) {
if (rdr != tl::Registrar<db::StreamFormatDeclaration>::begin ()) {
fmts += " ";
}
std::string f = rdr->file_format ();
if (!f.empty ()) {
const char *fp = f.c_str ();
while (*fp && *fp != '(') {
++fp;
}
if (*fp) {
++fp;
}
while (*fp && *fp != ')') {
fmts += *fp++;
}
}
}
fmts += ");;";
for (tl::Registrar<db::StreamFormatDeclaration>::iterator rdr = tl::Registrar<db::StreamFormatDeclaration>::begin (); rdr != tl::Registrar<db::StreamFormatDeclaration>::end (); ++rdr) {
if (!rdr->file_format ().empty ()) {
fmts += rdr->file_format ();
fmts += ";;";
}
}
fmts += tl::to_string (QObject::tr ("All files (*)"));
std::string fmts = db::StreamFormatDeclaration::all_formats_string ();
fmts += ";;";
fmts += tl::to_string (tr ("All files (*)"));
return fmts;
}
@ -583,7 +560,7 @@ MainWindow::technology_changed ()
}
m_default_grids_updated = true; // potentially ...
dm_do_update_menu ();
dm_do_update_grids ();
}
void
@ -939,7 +916,7 @@ MainWindow::config_finalize ()
// Update the default grids menu if necessary
if (m_default_grids_updated) {
dm_do_update_menu ();
dm_do_update_grids ();
}
// make the changes visible in the setup form if the form is visible
@ -972,6 +949,7 @@ MainWindow::configure (const std::string &name, const std::string &value)
tl::Extractor ex (value.c_str ());
m_default_grids.clear ();
m_default_grid = 0.0;
m_default_grids_updated = true;
// convert the list of grids to a list of doubles
@ -980,6 +958,9 @@ MainWindow::configure (const std::string &name, const std::string &value)
if (! ex.try_read (g)) {
break;
}
if (ex.test ("!")) {
m_default_grid = g;
}
m_default_grids.push_back (g);
ex.test (",");
}
@ -4041,6 +4022,38 @@ MainWindow::menu_changed ()
dm_do_update_menu ();
}
void
MainWindow::do_update_grids ()
{
const std::vector<double> *grids = &m_default_grids;
double default_grid = m_default_grid;
std::vector<double> tech_grids;
lay::TechnologyController *tc = lay::TechnologyController::instance ();
if (tc && tc->active_technology ()) {
tech_grids = tc->active_technology ()->default_grid_list ();
if (! tech_grids.empty ()) {
grids = &tech_grids;
default_grid = tc->active_technology ()->default_grid ();
}
}
if (default_grid > db::epsilon) {
for (auto g = grids->begin (); g != grids->end (); ++g) {
if (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron)) {
default_grid = 0.0;
break;
}
}
}
if (default_grid > db::epsilon) {
dispatcher ()->config_set (cfg_grid, default_grid);
}
do_update_menu ();
}
void
MainWindow::do_update_menu ()
{
@ -4082,7 +4095,7 @@ MainWindow::do_update_menu ()
lay::Action *ga = new lay::ConfigureAction (gs, cfg_grid, tl::to_string (*g));
ga->set_checkable (true);
ga->set_checked (fabs (*g - m_grid_micron) < 1e-10);
ga->set_checked (db::coord_traits<db::DCoord>::equals (*g, m_grid_micron));
for (std::vector<std::string>::const_iterator t = group.begin (); t != group.end (); ++t) {
menu ()->insert_item (*t + ".end", name, ga);

View File

@ -706,6 +706,7 @@ protected slots:
protected:
void update_content ();
void do_update_menu ();
void do_update_grids ();
void do_update_mru_menus ();
bool eventFilter (QObject *watched, QEvent *event);
@ -753,6 +754,7 @@ private:
bool m_disable_tab_selected;
bool m_exited;
tl::DeferredMethod<MainWindow> dm_do_update_menu;
tl::DeferredMethod<MainWindow> dm_do_update_grids;
tl::DeferredMethod<MainWindow> dm_do_update_mru_menus;
tl::DeferredMethod<MainWindow> dm_exit;
QTimer m_message_timer;
@ -765,6 +767,7 @@ private:
std::string m_initial_technology;
double m_grid_micron;
std::vector<double> m_default_grids;
double m_default_grid;
bool m_default_grids_updated;
std::vector<std::pair<std::string, std::string> > m_key_bindings;
bool m_new_layout_current_panel;

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