mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into 1598-support-for-soft-connections
This commit is contained in:
commit
6ac1c32a8d
|
|
@ -1,3 +1,6 @@
|
|||
0.29.0 (2024-04-01):
|
||||
* TODO
|
||||
|
||||
0.28.17 (2024-02-16):
|
||||
* Enhancement: %GITHUB%/issues/1626 Technology specific grids
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 = [
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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 -> (boolean) true, if the parameter is not shown in the dialog
|
||||
# :readonly -> (boolean) true, if the parameter cannot be edited
|
||||
# :unit -> the unit string
|
||||
# :min_value -> the minimum value (only effective for numerical types and if no choices are present)
|
||||
# :max_value -> the maximum value (only effective for numerical types and if no choices are present)
|
||||
# :default -> the default value
|
||||
# :choices -> ([ [ d, v ], ...) choice descriptions/value for choice type
|
||||
# this method defines accessor methods for the parameters
|
||||
|
|
@ -373,6 +381,8 @@ module RBA
|
|||
args[:hidden] && pdecl.hidden = args[:hidden]
|
||||
args[:readonly] && pdecl.readonly = args[:readonly]
|
||||
args[:unit] && pdecl.unit = args[:unit]
|
||||
args[:min_value] && pdecl.min_value = args[:min_value]
|
||||
args[:max_value] && 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)"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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 ®ion, 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 ());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ®ion) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode) const;
|
||||
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 ®ion, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode, size_t min_count, size_t max_count) const;
|
||||
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
|
||||
AsIfFlatEdges (const AsIfFlatEdges &other);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
|
|
|
|||
|
|
@ -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 ®ion) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Edges &edges, EdgeInteractionMode mode) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, EdgeInteractionMode mode, bool inverse) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, EdgeInteractionMode mode) const;
|
||||
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 ®ion, EdgeInteractionMode mode, bool inverse, size_t min_count, size_t max_count) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_interacting_pair_generic (const Region ®ion, 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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 (); }
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, 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 ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, 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 ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, 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 ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, 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 ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, 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 ®ion, bool overlapping)
|
||||
RecursiveShapeIterator::RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, 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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const box_type ®ion, 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 ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, unsigned int layer, const region_type ®ion, 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 ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const box_type ®ion, 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 ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::vector<unsigned int> &layers, const region_type ®ion, 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 ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const box_type ®ion, 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 ®ion, bool overlapping = false);
|
||||
RecursiveShapeIterator (const layout_type &layout, const cell_type &cell, const std::set<unsigned int> &layers, const region_type ®ion, 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)");
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ SOURCES = \
|
|||
dbDeepTextsTests.cc \
|
||||
dbNetShapeTests.cc \
|
||||
dbHierNetsProcessorTests.cc \
|
||||
dbRegionProcessorTests.cc \
|
||||
dbAsIfFlatRegionTests.cc
|
||||
|
||||
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC
|
||||
|
|
|
|||
|
|
@ -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 < 0)
|
||||
out = in.drc(primary.corners < 0) # equivalent
|
||||
out = in.drc(corners > 0)
|
||||
out = in.drc(primary.corners > 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) > 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"/>
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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%
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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> ¶meters);
|
||||
void check_range (const tl::Variant& value, const db::PCellParameterDeclaration &decl);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 "View" 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><html>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. "0.01!,0.02,0.05".
|
||||
<br/><b>Note</b>: the general default grids can be overridden by technology specific default grids.</html></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>
|
||||
|
|
|
|||
|
|
@ -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 "View" menu</string>
|
||||
<string>These grids are available for selection from the "View" 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. "0.01!,0.02,0.05".</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue