mirror of https://github.com/KLayout/klayout.git
Merge pull request #563 from KLayout/issue-487
Fix #487 (True text object support for DRC/LVS)
This commit is contained in:
commit
ba46ffb276
|
|
@ -2,9 +2,45 @@
|
|||
# Run with:
|
||||
# ./klayout -z -r ./create_drc_samples.rb -t -c klayoutrc_drc_samples
|
||||
|
||||
class QRCGenerator
|
||||
|
||||
def res_path
|
||||
"src/lay/lay"
|
||||
end
|
||||
|
||||
def img_path
|
||||
"doc/images"
|
||||
end
|
||||
|
||||
def initialize
|
||||
@path = res_path + "/" + "layDRCLVSHelpResources.qrc"
|
||||
@file = File.open(@path, "w")
|
||||
@file.puts("<RCC>")
|
||||
@file.puts(" <qresource prefix=\"/help/images\">")
|
||||
end
|
||||
|
||||
def <<(str)
|
||||
@file.puts(str)
|
||||
end
|
||||
|
||||
def finish
|
||||
@file.puts(" </qresource>")
|
||||
@file.puts("</RCC>")
|
||||
@file.close
|
||||
puts "---> resource file written to #{@path}"
|
||||
end
|
||||
|
||||
def self.instance
|
||||
@@inst ||= QRCGenerator::new
|
||||
@@inst
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def run_demo(gen, cmd, out)
|
||||
|
||||
img_path = "src/lay/lay/doc/images"
|
||||
res_path = QRCGenerator::instance.res_path
|
||||
img_path = QRCGenerator::instance.img_path
|
||||
|
||||
mw = RBA::Application::instance::main_window
|
||||
|
||||
|
|
@ -81,7 +117,9 @@ def run_demo(gen, cmd, out)
|
|||
input1 = input(1, 0)
|
||||
input = input1
|
||||
input2 = input(2, 0)
|
||||
#{cmd}.data
|
||||
labels1 = labels(1, 0)
|
||||
labels = labels1
|
||||
(#{cmd}).data
|
||||
SCRIPT
|
||||
|
||||
if data.is_a?(RBA::Region)
|
||||
|
|
@ -101,15 +139,19 @@ SCRIPT
|
|||
elsif data.is_a?(RBA::EdgePairs)
|
||||
cell.shapes(lout_poly).insert_as_polygons(data, 1)
|
||||
cell.shapes(lout).insert(data.edges)
|
||||
elsif data.is_a?(RBA::Texts)
|
||||
cell.shapes(lout).insert(data)
|
||||
end
|
||||
|
||||
view.update_content
|
||||
view.save_image(img_path + "/" + out, 400, 400)
|
||||
view.save_image(res_path + "/" + img_path + "/" + out, 400, 400)
|
||||
|
||||
puts "---> written #{img_path}/#{out}"
|
||||
puts "---> written #{res_path}/#{img_path}/#{out}"
|
||||
|
||||
mw.close_all
|
||||
|
||||
QRCGenerator::instance << " <file alias=\"#{out}\">#{img_path}/#{out}</file>"
|
||||
|
||||
end
|
||||
|
||||
class Gen
|
||||
|
|
@ -631,3 +673,41 @@ run_demo gen, "input.corners.sized(0.1)", "drc_corners1.png"
|
|||
run_demo gen, "input.corners(90.0).sized(0.1)", "drc_corners2.png"
|
||||
run_demo gen, "input.corners(-90.0 .. -45.0).sized(0.1)", "drc_corners3.png"
|
||||
|
||||
|
||||
class Gen
|
||||
def produce(s1, s2)
|
||||
s1.insert(RBA::Text::new("ABC", RBA::Trans::new(RBA::Vector::new(0, 2000))))
|
||||
s1.insert(RBA::Text::new("A", RBA::Trans::new(RBA::Vector::new(0, 6000))))
|
||||
s1.insert(RBA::Text::new("XYZ", RBA::Trans::new(RBA::Vector::new(4000, 2000))))
|
||||
s1.insert(RBA::Text::new("A*", RBA::Trans::new(RBA::Vector::new(4000, 6000))))
|
||||
end
|
||||
end
|
||||
|
||||
gen = Gen::new
|
||||
|
||||
run_demo gen, "labels.texts(\"A*\")", "drc_texts1.png"
|
||||
run_demo gen, "labels.texts(text(\"A*\"))", "drc_texts2.png"
|
||||
|
||||
class Gen
|
||||
def produce(s1, s2)
|
||||
s1.insert(RBA::Text::new("T1", RBA::Trans::new(RBA::Vector::new(0, 2000))))
|
||||
s1.insert(RBA::Text::new("T2", RBA::Trans::new(RBA::Vector::new(2000, 2000))))
|
||||
s1.insert(RBA::Text::new("T3", RBA::Trans::new(RBA::Vector::new(4000, 2000))))
|
||||
pts = [
|
||||
RBA::Point::new(2000, 0),
|
||||
RBA::Point::new(2000, 4000),
|
||||
RBA::Point::new(6000, 4000),
|
||||
RBA::Point::new(6000, 0)
|
||||
];
|
||||
s2.insert(RBA::Polygon::new(pts))
|
||||
end
|
||||
end
|
||||
|
||||
gen = Gen::new
|
||||
|
||||
run_demo gen, "labels & input2", "drc_textpoly1.png"
|
||||
run_demo gen, "labels - input2", "drc_textpoly2.png"
|
||||
|
||||
|
||||
QRCGenerator::instance.finish
|
||||
|
||||
|
|
|
|||
|
|
@ -184,7 +184,19 @@ SOURCES = \
|
|||
dbLayoutVsSchematic.cc \
|
||||
gsiDeclDbNetlistCrossReference.cc \
|
||||
gsiDeclDbLayoutVsSchematic.cc \
|
||||
dbNetlistObject.cc
|
||||
dbNetlistObject.cc \
|
||||
gsiDeclDbTexts.cc \
|
||||
dbTexts.cc \
|
||||
dbDeepTexts.cc \
|
||||
dbAsIfFlatTexts.cc \
|
||||
dbTextsDelegate.cc \
|
||||
dbEmptyTexts.cc \
|
||||
dbFlatTexts.cc \
|
||||
dbTextsUtils.cc \
|
||||
dbOriginalLayerTexts.cc \
|
||||
dbNetShape.cc \
|
||||
dbShapeCollection.cc \
|
||||
gsiDeclDbShapeCollection.cc
|
||||
|
||||
HEADERS = \
|
||||
dbArray.h \
|
||||
|
|
@ -331,7 +343,17 @@ HEADERS = \
|
|||
dbLayoutVsSchematicReader.h \
|
||||
dbLayoutVsSchematicFormatDefs.h \
|
||||
dbLayoutVsSchematic.h \
|
||||
dbNetlistObject.h
|
||||
dbNetlistObject.h \
|
||||
dbTexts.h \
|
||||
dbDeepTexts.h \
|
||||
dbAsIfFlatTexts.h \
|
||||
dbTextsDelegate.h \
|
||||
dbEmptyTexts.h \
|
||||
dbFlatTexts.h \
|
||||
dbTextsUtils.h \
|
||||
dbOriginalLayerTexts.h \
|
||||
dbNetShape.h \
|
||||
dbShapeCollection.h
|
||||
|
||||
!equals(HAVE_QT, "0") {
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ AsIfFlatEdgePairs::in (const EdgePairs &other, bool invert) const
|
|||
op.insert (*o);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs (false));
|
||||
std::auto_ptr<FlatEdgePairs> new_edge_pairs (new FlatEdgePairs ());
|
||||
|
||||
for (EdgePairsIterator o (begin ()); ! o.at_end (); ++o) {
|
||||
if ((op.find (*o) == op.end ()) == invert) {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,16 @@ AsIfFlatEdges::~AsIfFlatEdges ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatEdges &
|
||||
AsIfFlatEdges::operator= (const AsIfFlatEdges &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_bbox_valid = other.m_bbox_valid;
|
||||
m_bbox = other.m_bbox;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string
|
||||
AsIfFlatEdges::to_string (size_t nmax) const
|
||||
{
|
||||
|
|
@ -170,7 +180,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const
|
|||
{
|
||||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableEdgeDelivery e (begin (), true);
|
||||
AddressableEdgeDelivery e (begin (), has_valid_edges ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert (e.operator-> (), 1);
|
||||
|
|
@ -497,7 +507,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co
|
|||
db::box_scanner<db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve (size () + (other ? other->size () : 0));
|
||||
|
||||
AddressableEdgeDelivery e (begin_merged (), has_valid_edges ());
|
||||
AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ());
|
||||
|
||||
size_t n = 0;
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
|
|
|
|||
|
|
@ -185,10 +185,9 @@ protected:
|
|||
virtual RegionDelegate *pull_generic (const Region ®ion) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool inverse) const;
|
||||
|
||||
private:
|
||||
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
|
||||
|
||||
private:
|
||||
mutable bool m_bbox_valid;
|
||||
mutable db::Box m_bbox;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbFlatRegion.h"
|
||||
#include "dbFlatEdgePairs.h"
|
||||
#include "dbFlatEdges.h"
|
||||
#include "dbFlatTexts.h"
|
||||
#include "dbEmptyRegion.h"
|
||||
#include "dbEmptyEdgePairs.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
|
|
@ -55,6 +56,17 @@ AsIfFlatRegion::~AsIfFlatRegion ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatRegion &
|
||||
AsIfFlatRegion::operator= (const AsIfFlatRegion &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_bbox_valid = other.m_bbox_valid;
|
||||
m_bbox = other.m_bbox;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string
|
||||
AsIfFlatRegion::to_string (size_t nmax) const
|
||||
{
|
||||
|
|
@ -364,6 +376,50 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse)
|
|||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse) const
|
||||
{
|
||||
if (other.empty ()) {
|
||||
if (! inverse) {
|
||||
return new EmptyRegion ();
|
||||
} else {
|
||||
return clone ();
|
||||
}
|
||||
} else if (empty ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve1 (size ());
|
||||
scanner.reserve2 (other.size ());
|
||||
|
||||
std::auto_ptr<FlatRegion> output (new FlatRegion (true));
|
||||
region_to_text_interaction_filter<FlatRegion, db::Text> filter (*output, inverse);
|
||||
|
||||
AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
if (inverse) {
|
||||
filter.preset (p.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
AddressableTextDelivery e (other.addressable_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert2 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
|
||||
|
||||
if (inverse) {
|
||||
filter.fill_output ();
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const
|
||||
{
|
||||
|
|
@ -440,7 +496,7 @@ AsIfFlatRegion::pull_generic (const Edges &other) const
|
|||
std::auto_ptr<FlatEdges> output (new FlatEdges (false));
|
||||
region_to_edge_interaction_filter<Shapes, db::Edge> filter (output->raw_edges (), false);
|
||||
|
||||
AddressablePolygonDelivery p (begin (), has_valid_merged_polygons ());
|
||||
AddressablePolygonDelivery p (begin (), has_valid_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
|
|
@ -457,6 +513,39 @@ AsIfFlatRegion::pull_generic (const Edges &other) const
|
|||
return output.release ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatRegion::pull_generic (const Texts &other) const
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return other.delegate ()->clone ();
|
||||
} else if (empty ()) {
|
||||
return new EmptyTexts ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve1 (size ());
|
||||
scanner.reserve2 (other.size ());
|
||||
|
||||
std::auto_ptr<FlatTexts> output (new FlatTexts (false));
|
||||
region_to_text_interaction_filter<Shapes, db::Text, db::Text> filter (output->raw_texts (), false);
|
||||
|
||||
AddressablePolygonDelivery p (begin (), has_valid_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressableTextDelivery e (other.addressable_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert2 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -202,6 +202,16 @@ public:
|
|||
return selected_interacting_generic (other, true);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_interacting (const Texts &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, false);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, true);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_overlapping (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, false, false);
|
||||
|
|
@ -227,6 +237,11 @@ public:
|
|||
return pull_generic (other);
|
||||
}
|
||||
|
||||
virtual TextsDelegate *pull_interacting (const Texts &other) const
|
||||
{
|
||||
return pull_generic (other);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *pull_overlapping (const Region &other) const
|
||||
{
|
||||
return pull_generic (other, 0, false);
|
||||
|
|
@ -247,17 +262,20 @@ protected:
|
|||
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
|
||||
virtual EdgesDelegate *pull_generic (const Edges &other) const;
|
||||
virtual TextsDelegate *pull_generic (const Texts &other) const;
|
||||
|
||||
template <class Trans>
|
||||
static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes);
|
||||
template <class Trans>
|
||||
static void produce_markers_for_angle_check (const db::Polygon &poly, const Trans &tr, double min, double max, bool inverse, db::Shapes &shapes);
|
||||
|
||||
private:
|
||||
AsIfFlatRegion &operator= (const AsIfFlatRegion &other);
|
||||
|
||||
private:
|
||||
|
||||
mutable bool m_bbox_valid;
|
||||
mutable db::Box m_bbox;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,384 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbAsIfFlatTexts.h"
|
||||
#include "dbFlatTexts.h"
|
||||
#include "dbFlatRegion.h"
|
||||
#include "dbFlatEdges.h"
|
||||
#include "dbEmptyTexts.h"
|
||||
#include "dbEmptyRegion.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbBoxConvert.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbTextsUtils.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// AsIfFlagTexts implementation
|
||||
|
||||
AsIfFlatTexts::AsIfFlatTexts ()
|
||||
: TextsDelegate (), m_bbox_valid (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatTexts::~AsIfFlatTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AsIfFlatTexts &
|
||||
AsIfFlatTexts::operator= (const AsIfFlatTexts &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_bbox_valid = other.m_bbox_valid;
|
||||
m_bbox = other.m_bbox;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string
|
||||
AsIfFlatTexts::to_string (size_t nmax) const
|
||||
{
|
||||
std::ostringstream os;
|
||||
TextsIterator p (begin ());
|
||||
bool first = true;
|
||||
for ( ; ! p.at_end () && nmax != 0; ++p, --nmax) {
|
||||
if (! first) {
|
||||
os << ";";
|
||||
}
|
||||
first = false;
|
||||
os << p->to_string ();
|
||||
}
|
||||
if (! p.at_end ()) {
|
||||
os << "...";
|
||||
}
|
||||
return os.str ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::in (const Texts &other, bool invert) const
|
||||
{
|
||||
std::set <db::Text> op;
|
||||
for (TextsIterator o (other.begin ()); ! o.at_end (); ++o) {
|
||||
op.insert (*o);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts ());
|
||||
|
||||
for (TextsIterator o (begin ()); ! o.at_end (); ++o) {
|
||||
if ((op.find (*o) == op.end ()) == invert) {
|
||||
new_texts->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
}
|
||||
|
||||
size_t
|
||||
AsIfFlatTexts::size () const
|
||||
{
|
||||
size_t n = 0;
|
||||
for (TextsIterator t (begin ()); ! t.at_end (); ++t) {
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
Box AsIfFlatTexts::bbox () const
|
||||
{
|
||||
if (! m_bbox_valid) {
|
||||
m_bbox = compute_bbox ();
|
||||
m_bbox_valid = true;
|
||||
}
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
Box AsIfFlatTexts::compute_bbox () const
|
||||
{
|
||||
db::Box b;
|
||||
for (TextsIterator t (begin ()); ! t.at_end (); ++t) {
|
||||
b += t->box ();
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
void AsIfFlatTexts::update_bbox (const db::Box &b)
|
||||
{
|
||||
m_bbox = b;
|
||||
m_bbox_valid = true;
|
||||
}
|
||||
|
||||
void AsIfFlatTexts::invalidate_bbox ()
|
||||
{
|
||||
m_bbox_valid = false;
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::filtered (const TextFilterBase &filter) const
|
||||
{
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts ());
|
||||
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
if (filter.selected (*p)) {
|
||||
new_texts->insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatTexts::polygons (db::Coord e) const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> output (new FlatRegion ());
|
||||
|
||||
for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) {
|
||||
db::Box box = tp->box ();
|
||||
box.enlarge (db::Vector (e, e));
|
||||
output->insert (db::Polygon (box));
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatTexts::edges () const
|
||||
{
|
||||
std::auto_ptr<FlatEdges> output (new FlatEdges ());
|
||||
|
||||
for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) {
|
||||
db::Box box = tp->box ();
|
||||
output->insert (db::Edge (box.p1 (), box.p2 ()));
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::add (const Texts &other) const
|
||||
{
|
||||
FlatTexts *other_flat = dynamic_cast<FlatTexts *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts (*other_flat));
|
||||
new_texts->invalidate_cache ();
|
||||
|
||||
size_t n = new_texts->raw_texts ().size () + size ();
|
||||
|
||||
new_texts->reserve (n);
|
||||
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
new_texts->raw_texts ().insert (*p);
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
|
||||
} else {
|
||||
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts ());
|
||||
|
||||
size_t n = size () + other.size ();
|
||||
|
||||
new_texts->reserve (n);
|
||||
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
new_texts->raw_texts ().insert (*p);
|
||||
}
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
new_texts->raw_texts ().insert (*p);
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
AsIfFlatTexts::equals (const Texts &other) const
|
||||
{
|
||||
if (empty () != other.empty ()) {
|
||||
return false;
|
||||
}
|
||||
if (size () != other.size ()) {
|
||||
return false;
|
||||
}
|
||||
TextsIterator o1 (begin ());
|
||||
TextsIterator o2 (other.begin ());
|
||||
while (! o1.at_end () && ! o2.at_end ()) {
|
||||
if (*o1 != *o2) {
|
||||
return false;
|
||||
}
|
||||
++o1;
|
||||
++o2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
AsIfFlatTexts::less (const Texts &other) const
|
||||
{
|
||||
if (empty () != other.empty ()) {
|
||||
return empty () < other.empty ();
|
||||
}
|
||||
if (size () != other.size ()) {
|
||||
return (size () < other.size ());
|
||||
}
|
||||
TextsIterator o1 (begin ());
|
||||
TextsIterator o2 (other.begin ());
|
||||
while (! o1.at_end () && ! o2.at_end ()) {
|
||||
if (*o1 != *o2) {
|
||||
return *o1 < *o2;
|
||||
}
|
||||
++o1;
|
||||
++o2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
AsIfFlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
// improves performance when inserting an original layout into the same layout
|
||||
db::LayoutLocker locker (layout);
|
||||
|
||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||
for (TextsIterator t (begin ()); ! t.at_end (); ++t) {
|
||||
shapes.insert (*t);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsIfFlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
// improves performance when inserting an original layout into the same layout
|
||||
db::LayoutLocker locker (layout);
|
||||
|
||||
db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer);
|
||||
for (TextsIterator t (begin ()); ! t.at_end (); ++t) {
|
||||
db::Box box = t->box ();
|
||||
box.enlarge (db::Vector (enl, enl));
|
||||
shapes.insert (db::SimplePolygon (box));
|
||||
}
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::selected_interacting_generic (const Region &other, bool inverse) const
|
||||
{
|
||||
// shortcuts
|
||||
if (other.empty () || empty ()) {
|
||||
return new EmptyTexts ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Text, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableTextDelivery e (begin (), has_valid_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert1 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressablePolygonDelivery p = other.addressable_polygons ();
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert2 (p.operator-> (), 1);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatTexts> output (new FlatTexts ());
|
||||
|
||||
if (! inverse) {
|
||||
|
||||
text_to_region_interaction_filter<FlatTexts, db::Text> filter (*output);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
} else {
|
||||
|
||||
std::set<db::Text> interacting;
|
||||
text_to_region_interaction_filter<std::set<db::Text>, db::Text> filter (interacting);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (TextsIterator o (begin ()); ! o.at_end (); ++o) {
|
||||
if (interacting.find (*o) == interacting.end ()) {
|
||||
output->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatTexts::pull_generic (const Region &other) const
|
||||
{
|
||||
// shortcuts
|
||||
if (other.empty () || empty ()) {
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Text, size_t, db::Polygon, size_t> scanner (report_progress (), progress_desc ());
|
||||
|
||||
AddressableTextDelivery e (begin (), has_valid_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert1 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressablePolygonDelivery p = other.addressable_merged_polygons ();
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert2 (p.operator-> (), 1);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatRegion> output (new FlatRegion (true));
|
||||
|
||||
text_to_region_interaction_filter<FlatRegion, db::Text> filter (*output);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatTexts::pull_interacting (const Region &other) const
|
||||
{
|
||||
return pull_generic (other);
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::selected_interacting (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, false);
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
AsIfFlatTexts::selected_not_interacting (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbAsIfFlatTexts
|
||||
#define HDR_dbAsIfFlatTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbTextsDelegate.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
class Region;
|
||||
|
||||
/**
|
||||
* @brief Provides default flat implementations
|
||||
*/
|
||||
class DB_PUBLIC AsIfFlatTexts
|
||||
: public TextsDelegate
|
||||
{
|
||||
public:
|
||||
AsIfFlatTexts ();
|
||||
virtual ~AsIfFlatTexts ();
|
||||
|
||||
virtual size_t size () const;
|
||||
virtual std::string to_string (size_t) const;
|
||||
virtual Box bbox () const;
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter)
|
||||
{
|
||||
return filtered (filter);
|
||||
}
|
||||
|
||||
virtual TextsDelegate *filtered (const TextFilterBase &) const;
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other)
|
||||
{
|
||||
return add (other);
|
||||
}
|
||||
|
||||
virtual TextsDelegate *add (const Texts &other) const;
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const;
|
||||
virtual EdgesDelegate *edges () const;
|
||||
|
||||
virtual TextsDelegate *in (const Texts &, bool) const;
|
||||
|
||||
virtual bool equals (const Texts &other) const;
|
||||
virtual bool less (const Texts &other) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const;
|
||||
virtual TextsDelegate *selected_interacting (const Region &other) const;
|
||||
virtual TextsDelegate *selected_not_interacting (const Region &other) const;
|
||||
|
||||
protected:
|
||||
void update_bbox (const db::Box &box);
|
||||
void invalidate_bbox ();
|
||||
AsIfFlatTexts &operator= (const AsIfFlatTexts &other);
|
||||
|
||||
private:
|
||||
|
||||
mutable bool m_bbox_valid;
|
||||
mutable db::Box m_bbox;
|
||||
|
||||
virtual db::Box compute_bbox () const;
|
||||
virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -86,34 +86,33 @@ private:
|
|||
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs ()
|
||||
: AsIfFlatEdgePairs (), m_deep_layer ()
|
||||
: AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||
: AsIfFlatEdgePairs (), m_deep_layer (dss.create_edge_pair_layer (si))
|
||||
: AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
set_deep_layer (dss.create_edge_pair_layer (si));
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||
: AsIfFlatEdgePairs (), m_deep_layer (dss.create_edge_pair_layer (si, trans))
|
||||
: AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
set_deep_layer (dss.create_edge_pair_layer (si, trans));
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const DeepEdgePairs &other)
|
||||
: AsIfFlatEdgePairs (other),
|
||||
m_deep_layer (other.m_deep_layer.copy ())
|
||||
: AsIfFlatEdgePairs (other), db::DeepShapeCollectionDelegateBase (other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepEdgePairs::DeepEdgePairs (const DeepLayer &dl)
|
||||
: AsIfFlatEdgePairs (), m_deep_layer (dl)
|
||||
: AsIfFlatEdgePairs ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
set_deep_layer (dl);
|
||||
}
|
||||
|
||||
DeepEdgePairs::~DeepEdgePairs ()
|
||||
|
|
@ -133,7 +132,7 @@ EdgePairsIteratorDelegate *DeepEdgePairs::begin () const
|
|||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> DeepEdgePairs::begin_iter () const
|
||||
{
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
if (layout.cells () == 0) {
|
||||
|
||||
return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ());
|
||||
|
|
@ -141,7 +140,7 @@ std::pair<db::RecursiveShapeIterator, db::ICplxTrans> DeepEdgePairs::begin_iter
|
|||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
|
|
@ -151,10 +150,10 @@ size_t DeepEdgePairs::size () const
|
|||
{
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
db::CellCounter cc (&layout);
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) {
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size ();
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size ();
|
||||
}
|
||||
|
||||
return n;
|
||||
|
|
@ -167,7 +166,7 @@ std::string DeepEdgePairs::to_string (size_t nmax) const
|
|||
|
||||
Box DeepEdgePairs::bbox () const
|
||||
{
|
||||
return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ());
|
||||
return deep_layer ().initial_cell ().bbox (deep_layer ().layer ());
|
||||
}
|
||||
|
||||
bool DeepEdgePairs::empty () const
|
||||
|
|
@ -243,12 +242,12 @@ EdgePairsDelegate *DeepEdgePairs::filtered (const EdgePairFilterBase &filter) co
|
|||
|
||||
RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const
|
||||
{
|
||||
db::DeepLayer new_layer = m_deep_layer.derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::DeepLayer new_layer = deep_layer ().derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
db::Shapes &output = c->shapes (new_layer.layer ());
|
||||
for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
db::Polygon poly = s->edge_pair ().normalized ().to_polygon (e);
|
||||
if (poly.vertices () >= 3) {
|
||||
output.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
|
|
@ -261,12 +260,12 @@ RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const
|
|||
|
||||
EdgesDelegate *DeepEdgePairs::generic_edges (bool first, bool second) const
|
||||
{
|
||||
db::DeepLayer new_layer = m_deep_layer.derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::DeepLayer new_layer = deep_layer ().derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
db::Shapes &output = c->shapes (new_layer.layer ());
|
||||
for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) {
|
||||
db::EdgePair ep = s->edge_pair ();
|
||||
if (first) {
|
||||
output.insert (ep.first ());
|
||||
|
|
@ -304,8 +303,8 @@ EdgePairsDelegate *DeepEdgePairs::in (const EdgePairs &other, bool invert) const
|
|||
bool DeepEdgePairs::equals (const EdgePairs &other) const
|
||||
{
|
||||
const DeepEdgePairs *other_delegate = dynamic_cast<const DeepEdgePairs *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()
|
||||
&& other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) {
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()
|
||||
&& other_delegate->deep_layer ().layer () == deep_layer ().layer ()) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatEdgePairs::equals (other);
|
||||
|
|
@ -315,8 +314,8 @@ bool DeepEdgePairs::equals (const EdgePairs &other) const
|
|||
bool DeepEdgePairs::less (const EdgePairs &other) const
|
||||
{
|
||||
const DeepEdgePairs *other_delegate = dynamic_cast<const DeepEdgePairs *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) {
|
||||
return other_delegate->m_deep_layer.layer () < m_deep_layer.layer ();
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
return other_delegate->deep_layer ().layer () < deep_layer ().layer ();
|
||||
} else {
|
||||
return AsIfFlatEdgePairs::less (other);
|
||||
}
|
||||
|
|
@ -324,13 +323,12 @@ bool DeepEdgePairs::less (const EdgePairs &other) const
|
|||
|
||||
void DeepEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
m_deep_layer.insert_into (layout, into_cell, into_layer);
|
||||
deep_layer ().insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
void DeepEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
m_deep_layer.insert_into_as_polygons (layout, into_cell, into_layer, enl);
|
||||
deep_layer ().insert_into_as_polygons (layout, into_cell, into_layer, enl);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace db {
|
|||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepEdgePairs
|
||||
: public db::AsIfFlatEdgePairs
|
||||
: public db::AsIfFlatEdgePairs, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepEdgePairs ();
|
||||
|
|
@ -80,21 +80,14 @@ public:
|
|||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
const DeepLayer &deep_layer () const
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
}
|
||||
|
||||
DeepLayer &deep_layer ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
DeepEdgePairs &operator= (const DeepEdgePairs &other);
|
||||
|
||||
DeepLayer m_deep_layer;
|
||||
|
||||
void init ();
|
||||
EdgesDelegate *generic_edges (bool first, bool second) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -96,14 +96,16 @@ private:
|
|||
// DeepEdges implementation
|
||||
|
||||
DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, bool as_edges)
|
||||
: AsIfFlatEdges (), m_deep_layer (dss.create_edge_layer (si, as_edges)), m_merged_edges ()
|
||||
: AsIfFlatEdges (), m_merged_edges ()
|
||||
{
|
||||
set_deep_layer (dss.create_edge_layer (si, as_edges));
|
||||
init ();
|
||||
}
|
||||
|
||||
DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges, bool merged_semantics)
|
||||
: AsIfFlatEdges (), m_deep_layer (dss.create_edge_layer (si, as_edges, trans)), m_merged_edges ()
|
||||
: AsIfFlatEdges (), m_merged_edges ()
|
||||
{
|
||||
set_deep_layer (dss.create_edge_layer (si, as_edges, trans));
|
||||
init ();
|
||||
set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
|
@ -111,7 +113,7 @@ DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, con
|
|||
DeepEdges::DeepEdges (const db::Edges &other, DeepShapeStore &dss)
|
||||
: AsIfFlatEdges (), m_merged_edges ()
|
||||
{
|
||||
m_deep_layer = dss.create_from_flat (other);
|
||||
set_deep_layer (dss.create_from_flat (other));
|
||||
|
||||
init ();
|
||||
set_merged_semantics (other.merged_semantics ());
|
||||
|
|
@ -124,8 +126,9 @@ DeepEdges::DeepEdges ()
|
|||
}
|
||||
|
||||
DeepEdges::DeepEdges (const DeepLayer &dl)
|
||||
: AsIfFlatEdges (), m_deep_layer (dl)
|
||||
: AsIfFlatEdges ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
init ();
|
||||
}
|
||||
|
||||
|
|
@ -135,8 +138,7 @@ DeepEdges::~DeepEdges ()
|
|||
}
|
||||
|
||||
DeepEdges::DeepEdges (const DeepEdges &other)
|
||||
: AsIfFlatEdges (other),
|
||||
m_deep_layer (other.m_deep_layer.copy ()),
|
||||
: AsIfFlatEdges (other), DeepShapeCollectionDelegateBase (other),
|
||||
m_merged_edges_valid (other.m_merged_edges_valid),
|
||||
m_is_merged (other.m_is_merged)
|
||||
{
|
||||
|
|
@ -145,6 +147,25 @@ DeepEdges::DeepEdges (const DeepEdges &other)
|
|||
}
|
||||
}
|
||||
|
||||
DeepEdges &
|
||||
DeepEdges::operator= (const DeepEdges &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
|
||||
AsIfFlatEdges::operator= (other);
|
||||
DeepShapeCollectionDelegateBase::operator= (other);
|
||||
|
||||
m_merged_edges_valid = other.m_merged_edges_valid;
|
||||
m_is_merged = other.m_is_merged;
|
||||
if (m_merged_edges_valid) {
|
||||
m_merged_edges = other.m_merged_edges;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DeepEdges::init ()
|
||||
{
|
||||
m_merged_edges_valid = false;
|
||||
|
|
@ -182,7 +203,7 @@ DeepEdges::begin_merged () const
|
|||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
|
||||
DeepEdges::begin_iter () const
|
||||
{
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
if (layout.cells () == 0) {
|
||||
|
||||
return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ());
|
||||
|
|
@ -190,7 +211,7 @@ DeepEdges::begin_iter () const
|
|||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
|
|
@ -262,8 +283,8 @@ DeepEdges::iter () const
|
|||
bool DeepEdges::equals (const Edges &other) const
|
||||
{
|
||||
const DeepEdges *other_delegate = dynamic_cast<const DeepEdges *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()
|
||||
&& other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) {
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()
|
||||
&& other_delegate->deep_layer ().layer () == deep_layer ().layer ()) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatEdges::equals (other);
|
||||
|
|
@ -273,8 +294,8 @@ bool DeepEdges::equals (const Edges &other) const
|
|||
bool DeepEdges::less (const Edges &other) const
|
||||
{
|
||||
const DeepEdges *other_delegate = dynamic_cast<const DeepEdges *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) {
|
||||
return other_delegate->m_deep_layer.layer () < m_deep_layer.layer ();
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
return other_delegate->deep_layer ().layer () < deep_layer ().layer ();
|
||||
} else {
|
||||
return AsIfFlatEdges::less (other);
|
||||
}
|
||||
|
|
@ -384,27 +405,27 @@ DeepEdges::ensure_merged_edges_valid () const
|
|||
if (m_is_merged) {
|
||||
|
||||
// NOTE: this will reuse the deep layer reference
|
||||
m_merged_edges = m_deep_layer;
|
||||
m_merged_edges = deep_layer ();
|
||||
|
||||
} else {
|
||||
|
||||
m_merged_edges = m_deep_layer.derived ();
|
||||
m_merged_edges = deep_layer ().derived ();
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons");
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
db::hier_clusters<db::Edge> hc;
|
||||
db::Connectivity conn;
|
||||
conn.connect (m_deep_layer);
|
||||
conn.connect (deep_layer ());
|
||||
hc.set_base_verbosity (base_verbosity() + 10);
|
||||
hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Edges, conn);
|
||||
hc.build (layout, deep_layer ().initial_cell (), conn);
|
||||
|
||||
// collect the clusters and merge them into big polygons
|
||||
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
|
||||
// hopefully more efficient that collecting everything and will lead to reuse of parts.
|
||||
|
||||
ClusterMerger cm (m_deep_layer.layer (), hc, report_progress (), progress_desc ());
|
||||
ClusterMerger cm (deep_layer ().layer (), hc, report_progress (), progress_desc ());
|
||||
cm.set_base_verbosity (base_verbosity () + 10);
|
||||
|
||||
// TODO: iterate only over the called cells?
|
||||
|
|
@ -436,17 +457,17 @@ DeepEdges::set_is_merged (bool f)
|
|||
void
|
||||
DeepEdges::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
m_deep_layer.insert_into (layout, into_cell, into_layer);
|
||||
deep_layer ().insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
size_t DeepEdges::size () const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
db::CellCounter cc (&layout);
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) {
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size ();
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size ();
|
||||
}
|
||||
|
||||
return n;
|
||||
|
|
@ -454,7 +475,7 @@ size_t DeepEdges::size () const
|
|||
|
||||
Box DeepEdges::bbox () const
|
||||
{
|
||||
return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ());
|
||||
return deep_layer ().initial_cell ().bbox (deep_layer ().layer ());
|
||||
}
|
||||
|
||||
DeepEdges::length_type DeepEdges::length (const db::Box &box) const
|
||||
|
|
@ -650,11 +671,18 @@ EdgesDelegate *
|
|||
DeepEdges::filter_in_place (const EdgeFilterBase &filter)
|
||||
{
|
||||
// TODO: implement to be really in-place
|
||||
return filtered (filter);
|
||||
*this = *apply_filter (filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
DeepEdges::filtered (const EdgeFilterBase &filter) const
|
||||
{
|
||||
return apply_filter (filter);
|
||||
}
|
||||
|
||||
DeepEdges *
|
||||
DeepEdges::apply_filter (const EdgeFilterBase &filter) const
|
||||
{
|
||||
const db::DeepLayer &edges = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
|
||||
|
||||
|
|
@ -730,7 +758,7 @@ EdgesDelegate *DeepEdges::merged_in_place ()
|
|||
ensure_merged_edges_valid ();
|
||||
|
||||
// NOTE: this makes both layers share the same resource
|
||||
m_deep_layer = m_merged_edges;
|
||||
set_deep_layer (m_merged_edges);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
|
@ -753,17 +781,17 @@ EdgesDelegate *DeepEdges::merged () const
|
|||
DeepLayer
|
||||
DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
|
||||
{
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
db::EdgeBoolAndOrNotLocalOperation local_op (op);
|
||||
|
||||
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
proc.set_threads (deep_layer ().store ()->threads ());
|
||||
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, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return dl_out;
|
||||
}
|
||||
|
|
@ -771,17 +799,17 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const
|
|||
DeepLayer
|
||||
DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const
|
||||
{
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
db::EdgeToPolygonLocalOperation op (outside, include_borders);
|
||||
|
||||
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
db::local_processor<db::Edge, db::PolygonRef, db::Edge> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
proc.set_threads (deep_layer ().store ()->threads ());
|
||||
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
|
||||
|
||||
proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return dl_out;
|
||||
}
|
||||
|
|
@ -1051,7 +1079,7 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t
|
|||
db::Connectivity conn (db::Connectivity::EdgesConnectByPoints);
|
||||
conn.connect (edges);
|
||||
hc.set_base_verbosity (base_verbosity () + 10);
|
||||
hc.build (layout, edges.initial_cell (), db::ShapeIterator::Edges, conn);
|
||||
hc.build (layout, edges.initial_cell (), conn);
|
||||
|
||||
// TODO: iterate only over the called cells?
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
|
@ -1278,7 +1306,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
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);
|
||||
}
|
||||
|
|
@ -1295,7 +1323,7 @@ public:
|
|||
edge_to_region_interaction_filter<std::unordered_set<db::Edge> > filter (interacting);
|
||||
scanner.process (filter, 1, db::box_convert<db::Edge> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
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 ()) {
|
||||
result.insert (subject);
|
||||
|
|
@ -1374,7 +1402,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::Edge, db::Edge>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class DeepRegion;
|
|||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepEdges
|
||||
: public db::AsIfFlatEdges
|
||||
: public db::AsIfFlatEdges, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepEdges ();
|
||||
|
|
@ -144,14 +144,9 @@ public:
|
|||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
const DeepLayer &deep_layer () const
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
}
|
||||
|
||||
DeepLayer &deep_layer ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
@ -163,7 +158,6 @@ private:
|
|||
|
||||
DeepEdges &operator= (const DeepEdges &other);
|
||||
|
||||
DeepLayer m_deep_layer;
|
||||
mutable DeepLayer m_merged_edges;
|
||||
mutable bool m_merged_edges_valid;
|
||||
bool m_is_merged;
|
||||
|
|
@ -178,6 +172,8 @@ private:
|
|||
virtual RegionDelegate *pull_generic (const Region ®ion) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool invert) const;
|
||||
DeepEdges *apply_filter (const EdgeFilterBase &filter) const;
|
||||
|
||||
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "dbRegionUtils.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepEdgePairs.h"
|
||||
#include "dbDeepTexts.h"
|
||||
#include "dbShapeProcessor.h"
|
||||
#include "dbFlatRegion.h"
|
||||
#include "dbHierProcessor.h"
|
||||
|
|
@ -101,14 +102,16 @@ private:
|
|||
// DeepRegion implementation
|
||||
|
||||
DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count)
|
||||
: AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)), m_merged_polygons ()
|
||||
: AsIfFlatRegion (), m_merged_polygons ()
|
||||
{
|
||||
set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count));
|
||||
init ();
|
||||
}
|
||||
|
||||
DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics, double area_ratio, size_t max_vertex_count)
|
||||
: AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count, trans)), m_merged_polygons ()
|
||||
: AsIfFlatRegion (), m_merged_polygons ()
|
||||
{
|
||||
set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count, trans));
|
||||
init ();
|
||||
set_merged_semantics (merged_semantics);
|
||||
}
|
||||
|
|
@ -116,7 +119,7 @@ DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, c
|
|||
DeepRegion::DeepRegion (const db::Region &other, DeepShapeStore &dss)
|
||||
: AsIfFlatRegion (), m_merged_polygons ()
|
||||
{
|
||||
m_deep_layer = dss.create_from_flat (other, false);
|
||||
set_deep_layer (dss.create_from_flat (other, false));
|
||||
|
||||
init ();
|
||||
set_merged_semantics (other.merged_semantics ());
|
||||
|
|
@ -129,8 +132,9 @@ DeepRegion::DeepRegion ()
|
|||
}
|
||||
|
||||
DeepRegion::DeepRegion (const DeepLayer &dl)
|
||||
: AsIfFlatRegion (), m_deep_layer (dl)
|
||||
: AsIfFlatRegion ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
init ();
|
||||
}
|
||||
|
||||
|
|
@ -140,8 +144,7 @@ DeepRegion::~DeepRegion ()
|
|||
}
|
||||
|
||||
DeepRegion::DeepRegion (const DeepRegion &other)
|
||||
: AsIfFlatRegion (other),
|
||||
m_deep_layer (other.m_deep_layer.copy ()),
|
||||
: AsIfFlatRegion (other), DeepShapeCollectionDelegateBase (other),
|
||||
m_merged_polygons_valid (other.m_merged_polygons_valid),
|
||||
m_is_merged (other.m_is_merged)
|
||||
{
|
||||
|
|
@ -150,6 +153,25 @@ DeepRegion::DeepRegion (const DeepRegion &other)
|
|||
}
|
||||
}
|
||||
|
||||
DeepRegion &
|
||||
DeepRegion::operator= (const DeepRegion &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
|
||||
AsIfFlatRegion::operator= (other);
|
||||
DeepShapeCollectionDelegateBase::operator= (other);
|
||||
|
||||
m_merged_polygons_valid = other.m_merged_polygons_valid;
|
||||
m_is_merged = other.m_is_merged;
|
||||
if (m_merged_polygons_valid) {
|
||||
m_merged_polygons = other.m_merged_polygons;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DeepRegion::init ()
|
||||
{
|
||||
m_merged_polygons_valid = false;
|
||||
|
|
@ -192,7 +214,7 @@ DeepRegion::begin_merged () const
|
|||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
|
||||
DeepRegion::begin_iter () const
|
||||
{
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
if (layout.cells () == 0) {
|
||||
|
||||
return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ());
|
||||
|
|
@ -200,7 +222,7 @@ DeepRegion::begin_iter () const
|
|||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
|
|
@ -273,8 +295,8 @@ bool
|
|||
DeepRegion::equals (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_delegate = dynamic_cast<const DeepRegion *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()
|
||||
&& other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) {
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()
|
||||
&& other_delegate->deep_layer ().layer () == deep_layer ().layer ()) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatRegion::equals (other);
|
||||
|
|
@ -285,8 +307,8 @@ bool
|
|||
DeepRegion::less (const Region &other) const
|
||||
{
|
||||
const DeepRegion *other_delegate = dynamic_cast<const DeepRegion *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) {
|
||||
return other_delegate->m_deep_layer.layer () < m_deep_layer.layer ();
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
return other_delegate->deep_layer ().layer () < deep_layer ().layer ();
|
||||
} else {
|
||||
return AsIfFlatRegion::less (other);
|
||||
}
|
||||
|
|
@ -421,27 +443,27 @@ DeepRegion::ensure_merged_polygons_valid () const
|
|||
if (m_is_merged) {
|
||||
|
||||
// NOTE: this will reuse the deep layer reference
|
||||
m_merged_polygons = m_deep_layer;
|
||||
m_merged_polygons = deep_layer ();
|
||||
|
||||
} else {
|
||||
|
||||
m_merged_polygons = m_deep_layer.derived ();
|
||||
m_merged_polygons = deep_layer ().derived ();
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons");
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
db::hier_clusters<db::PolygonRef> hc;
|
||||
db::Connectivity conn;
|
||||
conn.connect (m_deep_layer);
|
||||
conn.connect (deep_layer ());
|
||||
hc.set_base_verbosity (base_verbosity () + 10);
|
||||
hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Polygons, conn);
|
||||
hc.build (layout, deep_layer ().initial_cell (), conn);
|
||||
|
||||
// collect the clusters and merge them into big polygons
|
||||
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
|
||||
// hopefully more efficient that collecting everything and will lead to reuse of parts.
|
||||
|
||||
ClusterMerger cm (m_deep_layer.layer (), layout, hc, min_coherence (), report_progress (), progress_desc ());
|
||||
ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence (), report_progress (), progress_desc ());
|
||||
cm.set_base_verbosity (base_verbosity () + 10);
|
||||
|
||||
// TODO: iterate only over the called cells?
|
||||
|
|
@ -473,7 +495,7 @@ DeepRegion::set_is_merged (bool f)
|
|||
void
|
||||
DeepRegion::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
m_deep_layer.insert_into (layout, into_cell, into_layer);
|
||||
deep_layer ().insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
|
|
@ -523,17 +545,17 @@ DeepRegion::not_with (const Region &other) const
|
|||
DeepLayer
|
||||
DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
|
||||
{
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
db::BoolAndOrNotLocalOperation op (and_op);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), m_deep_layer.breakout_cells (), other->deep_layer ().breakout_cells ());
|
||||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&deep_layer ().layout ()), const_cast<db::Cell *> (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
proc.set_threads (deep_layer ().store ()->threads ());
|
||||
proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ());
|
||||
|
||||
proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return dl_out;
|
||||
}
|
||||
|
|
@ -648,10 +670,10 @@ DeepRegion::size () const
|
|||
{
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = m_deep_layer.layout ();
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
db::CellCounter cc (&layout);
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) {
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size ();
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size ();
|
||||
}
|
||||
|
||||
return n;
|
||||
|
|
@ -726,7 +748,7 @@ DeepRegion::perimeter (const db::Box &box) const
|
|||
Box
|
||||
DeepRegion::bbox () const
|
||||
{
|
||||
return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ());
|
||||
return deep_layer ().initial_cell ().bbox (deep_layer ().layer ());
|
||||
}
|
||||
|
||||
std::string
|
||||
|
|
@ -1085,11 +1107,18 @@ RegionDelegate *
|
|||
DeepRegion::filter_in_place (const PolygonFilterBase &filter)
|
||||
{
|
||||
// TODO: implement to be really in-place
|
||||
return filtered (filter);
|
||||
*this = *apply_filter (filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::filtered (const PolygonFilterBase &filter) const
|
||||
{
|
||||
return apply_filter (filter);
|
||||
}
|
||||
|
||||
DeepRegion *
|
||||
DeepRegion::apply_filter (const PolygonFilterBase &filter) const
|
||||
{
|
||||
const db::DeepLayer &polygons = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
|
||||
|
||||
|
|
@ -1170,7 +1199,7 @@ DeepRegion::merged_in_place ()
|
|||
ensure_merged_polygons_valid ();
|
||||
|
||||
// NOTE: this makes both layers share the same resource
|
||||
m_deep_layer = m_merged_polygons;
|
||||
set_deep_layer (m_merged_polygons);
|
||||
|
||||
set_is_merged (true);
|
||||
return this;
|
||||
|
|
@ -1205,21 +1234,21 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const
|
|||
{
|
||||
tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons");
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_deep_layer.layout ());
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
db::hier_clusters<db::PolygonRef> hc;
|
||||
db::Connectivity conn;
|
||||
conn.connect (m_deep_layer);
|
||||
conn.connect (deep_layer ());
|
||||
hc.set_base_verbosity (base_verbosity () + 10);
|
||||
hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Polygons, conn);
|
||||
hc.build (layout, deep_layer ().initial_cell (), conn);
|
||||
|
||||
// collect the clusters and merge them into big polygons
|
||||
// NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is
|
||||
// hopefully more efficient that collecting everything and will lead to reuse of parts.
|
||||
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
DeepLayer dl_out (deep_layer ().derived ());
|
||||
|
||||
ClusterMerger cm (m_deep_layer.layer (), layout, hc, min_coherence, report_progress (), progress_desc ());
|
||||
ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence, report_progress (), progress_desc ());
|
||||
cm.set_base_verbosity (base_verbosity () + 10);
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
|
@ -1502,7 +1531,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
const_cast<db::Cell *> (&polygons.initial_cell ()),
|
||||
other_deep ? &other_deep->deep_layer ().layout () : const_cast<db::Layout *> (&polygons.layout ()),
|
||||
other_deep ? &other_deep->deep_layer ().initial_cell () : const_cast<db::Cell *> (&polygons.initial_cell ()),
|
||||
m_deep_layer.breakout_cells (),
|
||||
deep_layer ().breakout_cells (),
|
||||
other_deep ? other_deep->deep_layer ().breakout_cells () : 0);
|
||||
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
|
|
@ -1870,6 +1899,143 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct TextResultInserter
|
||||
{
|
||||
typedef db::TextRef value_type;
|
||||
|
||||
TextResultInserter (std::unordered_set<db::TextRef> &result)
|
||||
: mp_result (&result)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::TextRef &e)
|
||||
{
|
||||
(*mp_result).insert (e);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_set<db::TextRef> *mp_result;
|
||||
};
|
||||
|
||||
class PullWithTextLocalOperation
|
||||
: public local_operation<db::PolygonRef, db::TextRef, db::TextRef>
|
||||
{
|
||||
public:
|
||||
PullWithTextLocalOperation ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::Coord dist () const
|
||||
{
|
||||
// touching is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout *, const shape_interactions<db::PolygonRef, db::TextRef> &interactions, std::unordered_set<db::TextRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::Polygon, size_t, db::TextRef, size_t> scanner;
|
||||
|
||||
TextResultInserter inserter (result);
|
||||
region_to_text_interaction_filter<TextResultInserter, db::TextRef> filter (inserter, false);
|
||||
|
||||
for (shape_interactions<db::PolygonRef, db::TextRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::PolygonRef, db::TextRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
scanner.insert2 (& interactions.intruder_shape (*j), 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<db::Polygon> heap;
|
||||
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const db::PolygonRef &subject = interactions.subject_shape (i->first);
|
||||
heap.push_back (subject.obj ().transformed (subject.trans ()));
|
||||
|
||||
scanner.insert1 (&heap.back (), 0);
|
||||
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::TextRef> ());
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
return Drop;
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Pull texts from second by their geometric relation to first"));
|
||||
}
|
||||
};
|
||||
|
||||
class InteractingWithTextLocalOperation
|
||||
: public local_operation<db::PolygonRef, db::TextRef, db::PolygonRef>
|
||||
{
|
||||
public:
|
||||
InteractingWithTextLocalOperation (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::Coord dist () const
|
||||
{
|
||||
// touching is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::TextRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::Polygon, size_t, db::TextRef, size_t> scanner;
|
||||
|
||||
ResultInserter inserter (layout, result);
|
||||
region_to_text_interaction_filter<ResultInserter, db::TextRef> filter (inserter, m_inverse);
|
||||
|
||||
for (shape_interactions<db::PolygonRef, db::Text>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::PolygonRef, db::Text>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
scanner.insert2 (& interactions.intruder_shape (*j), 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<db::Polygon> heap;
|
||||
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const db::PolygonRef &subject = interactions.subject_shape (i->first);
|
||||
heap.push_back (subject.obj ().transformed (subject.trans ()));
|
||||
|
||||
scanner.insert1 (&heap.back (), 0);
|
||||
if (m_inverse) {
|
||||
filter.preset (&heap.back ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::TextRef> ());
|
||||
if (m_inverse) {
|
||||
filter.fill_output ();
|
||||
}
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
if (!m_inverse) {
|
||||
return Drop;
|
||||
} else {
|
||||
return Copy;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select regions by their geometric relation to texts"));
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
|
|
@ -2016,4 +2182,70 @@ DeepRegion::pull_generic (const Edges &other) const
|
|||
return res;
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
DeepRegion::pull_generic (const Texts &other) const
|
||||
{
|
||||
std::auto_ptr<db::DeepTexts> dr_holder;
|
||||
const db::DeepTexts *other_deep = dynamic_cast<const db::DeepTexts *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation
|
||||
dr_holder.reset (new db::DeepTexts (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
// in "inside" mode, the first argument needs to be merged too
|
||||
const db::DeepLayer &polygons = deep_layer ();
|
||||
const db::DeepLayer &other_texts = other_deep->deep_layer ();
|
||||
|
||||
DeepLayer dl_out (polygons.derived ());
|
||||
|
||||
db::PullWithTextLocalOperation op;
|
||||
|
||||
db::local_processor<db::PolygonRef, db::TextRef, db::TextRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_texts.layout (), &other_texts.initial_cell (), polygons.breakout_cells (), other_texts.breakout_cells ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (polygons.store ()->threads ());
|
||||
proc.run (&op, polygons.layer (), other_texts.layer (), dl_out.layer ());
|
||||
|
||||
db::DeepTexts *res = new db::DeepTexts (dl_out);
|
||||
res->set_is_merged (is_merged ());
|
||||
return res;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::selected_interacting_generic (const Texts &other, bool inverse) const
|
||||
{
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
bool split_after = false;
|
||||
|
||||
std::auto_ptr<db::DeepTexts> dr_holder;
|
||||
const db::DeepTexts *other_deep = dynamic_cast<const db::DeepTexts *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation
|
||||
dr_holder.reset (new db::DeepTexts (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (polygons.derived ());
|
||||
|
||||
db::InteractingWithTextLocalOperation op (inverse);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::TextRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (polygons.store ()->threads ());
|
||||
if (split_after) {
|
||||
proc.set_area_ratio (polygons.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
db::DeepRegion *res = new db::DeepRegion (dl_out);
|
||||
if (! split_after) {
|
||||
res->set_is_merged (merged_semantics () || is_merged ());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ namespace db {
|
|||
* @brief A deep, polygon-set delegate
|
||||
*/
|
||||
class DB_PUBLIC DeepRegion
|
||||
: public AsIfFlatRegion
|
||||
: public AsIfFlatRegion, public DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::layer<db::Polygon, db::unstable_layer_tag> polygon_layer_type;
|
||||
|
|
@ -159,14 +159,9 @@ public:
|
|||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
const DeepLayer &deep_layer () const
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
}
|
||||
|
||||
DeepLayer &deep_layer ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
@ -176,10 +171,10 @@ protected:
|
|||
|
||||
private:
|
||||
friend class DeepEdges;
|
||||
friend class DeepTexts;
|
||||
|
||||
DeepRegion &operator= (const DeepRegion &other);
|
||||
|
||||
DeepLayer m_deep_layer;
|
||||
mutable DeepLayer m_merged_polygons;
|
||||
mutable bool m_merged_polygons_valid;
|
||||
bool m_is_merged;
|
||||
|
|
@ -192,8 +187,11 @@ private:
|
|||
EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
|
||||
virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const;
|
||||
virtual EdgesDelegate *pull_generic (const Edges &other) const;
|
||||
virtual TextsDelegate *pull_generic (const Texts &other) const;
|
||||
DeepRegion *apply_filter (const PolygonFilterBase &filter) const;
|
||||
|
||||
template <class Result, class OutputContainer> OutputContainer *processed_impl (const polygon_processor<Result> &filter) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,7 +25,14 @@
|
|||
#include "dbCellMapping.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepEdgePairs.h"
|
||||
#include "dbDeepTexts.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include "tlTimer.h"
|
||||
|
||||
|
|
@ -48,6 +55,30 @@ DeepLayer::DeepLayer (const Region ®ion)
|
|||
*this = dr->deep_layer ();
|
||||
}
|
||||
|
||||
DeepLayer::DeepLayer (const Texts &texts)
|
||||
: mp_store (), m_layout (0), m_layer (0)
|
||||
{
|
||||
const db::DeepTexts *dr = dynamic_cast<db::DeepTexts *> (texts.delegate ());
|
||||
tl_assert (dr != 0);
|
||||
*this = dr->deep_layer ();
|
||||
}
|
||||
|
||||
DeepLayer::DeepLayer (const Edges &edges)
|
||||
: mp_store (), m_layout (0), m_layer (0)
|
||||
{
|
||||
const db::DeepEdges *dr = dynamic_cast<db::DeepEdges *> (edges.delegate ());
|
||||
tl_assert (dr != 0);
|
||||
*this = dr->deep_layer ();
|
||||
}
|
||||
|
||||
DeepLayer::DeepLayer (const EdgePairs &edge_pairs)
|
||||
: mp_store (), m_layout (0), m_layer (0)
|
||||
{
|
||||
const db::DeepEdgePairs *dr = dynamic_cast<db::DeepEdgePairs *> (edge_pairs.delegate ());
|
||||
tl_assert (dr != 0);
|
||||
*this = dr->deep_layer ();
|
||||
}
|
||||
|
||||
DeepLayer::DeepLayer (const DeepLayer &x)
|
||||
: mp_store (x.mp_store), m_layout (x.m_layout), m_layer (x.m_layer)
|
||||
{
|
||||
|
|
@ -459,9 +490,39 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Edges &edges, const db::IC
|
|||
return dl;
|
||||
}
|
||||
|
||||
std::pair<bool, DeepLayer> DeepShapeStore::layer_for_flat (const db::Region ®ion) const
|
||||
DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans)
|
||||
{
|
||||
return layer_for_flat (tl::id_of (region.delegate ()));
|
||||
// reuse existing layer
|
||||
std::pair<bool, DeepLayer> lff = layer_for_flat (tl::id_of (texts.delegate ()));
|
||||
if (lff.first) {
|
||||
return lff.second;
|
||||
}
|
||||
|
||||
require_singular ();
|
||||
|
||||
unsigned int layer = layout ().insert_layer ();
|
||||
|
||||
db::Shapes *shapes = &initial_cell ().shapes (layer);
|
||||
db::Box world = db::Box::world ();
|
||||
|
||||
db::TextBuildingHierarchyBuilderShapeReceiver tb (&layout ());
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> ii = texts.begin_iter ();
|
||||
db::ICplxTrans ttop = trans * ii.second;
|
||||
while (! ii.first.at_end ()) {
|
||||
tb.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes);
|
||||
++ii.first;
|
||||
}
|
||||
|
||||
DeepLayer dl (this, 0 /*singular layout index*/, layer);
|
||||
m_layers_for_flat [tl::id_of (texts.delegate ())] = std::make_pair (dl.layout_index (), dl.layer ());
|
||||
m_flat_region_id [std::make_pair (dl.layout_index (), dl.layer ())] = tl::id_of (texts.delegate ());
|
||||
return dl;
|
||||
}
|
||||
|
||||
std::pair<bool, DeepLayer> DeepShapeStore::layer_for_flat (const ShapeCollection &coll) const
|
||||
{
|
||||
return layer_for_flat (tl::id_of (coll.get_delegate ()));
|
||||
}
|
||||
|
||||
std::pair<bool, DeepLayer> DeepShapeStore::layer_for_flat (size_t region_id) const
|
||||
|
|
@ -807,64 +868,23 @@ DeepLayer DeepShapeStore::create_copy (const DeepLayer &source, HierarchyBuilder
|
|||
|
||||
DeepLayer DeepShapeStore::create_edge_layer (const db::RecursiveShapeIterator &si, bool as_edges, const db::ICplxTrans &trans)
|
||||
{
|
||||
unsigned int layout_index = layout_for_iter (si, trans);
|
||||
|
||||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
db::HierarchyBuilder &builder = m_layouts[layout_index]->builder;
|
||||
|
||||
unsigned int layer_index = init_layer (layout, si);
|
||||
builder.set_target_layer (layer_index);
|
||||
|
||||
// The chain of operators for producing edges
|
||||
db::EdgeBuildingHierarchyBuilderShapeReceiver refs (as_edges);
|
||||
|
||||
// Build the working hierarchy from the recursive shape iterator
|
||||
try {
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy")));
|
||||
db::LayoutLocker ll (&layout, true /*no update*/);
|
||||
|
||||
builder.set_shape_receiver (&refs);
|
||||
db::RecursiveShapeIterator (si).push (& builder);
|
||||
builder.set_shape_receiver (0);
|
||||
|
||||
} catch (...) {
|
||||
builder.set_shape_receiver (0);
|
||||
throw;
|
||||
}
|
||||
|
||||
return DeepLayer (this, layout_index, layer_index);
|
||||
return create_custom_layer (si, &refs, trans);
|
||||
}
|
||||
|
||||
DeepLayer DeepShapeStore::create_edge_pair_layer (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
unsigned int layout_index = layout_for_iter (si, trans);
|
||||
|
||||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
db::HierarchyBuilder &builder = m_layouts[layout_index]->builder;
|
||||
|
||||
unsigned int layer_index = init_layer (layout, si);
|
||||
builder.set_target_layer (layer_index);
|
||||
|
||||
// The chain of operators for producing the edge pairs
|
||||
db::EdgePairBuildingHierarchyBuilderShapeReceiver refs;
|
||||
return create_custom_layer (si, &refs, trans);
|
||||
}
|
||||
|
||||
// Build the working hierarchy from the recursive shape iterator
|
||||
try {
|
||||
DeepLayer DeepShapeStore::create_text_layer (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
unsigned int layout_index = layout_for_iter (si, trans);
|
||||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy")));
|
||||
db::LayoutLocker ll (&layout, true /*no update*/);
|
||||
|
||||
builder.set_shape_receiver (&refs);
|
||||
db::RecursiveShapeIterator (si).push (& builder);
|
||||
builder.set_shape_receiver (0);
|
||||
|
||||
} catch (...) {
|
||||
builder.set_shape_receiver (0);
|
||||
throw;
|
||||
}
|
||||
|
||||
return DeepLayer (this, layout_index, layer_index);
|
||||
db::TextBuildingHierarchyBuilderShapeReceiver refs (&layout);
|
||||
return create_custom_layer (si, &refs, trans);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1123,6 +1143,12 @@ DeepShapeStore::insert_as_polygons (const DeepLayer &deep_layer, db::Layout *int
|
|||
s->polygon (poly);
|
||||
out.insert (poly);
|
||||
|
||||
} else if (s->is_text ()) {
|
||||
|
||||
db::Text t;
|
||||
s->text (t);
|
||||
out.insert (db::SimplePolygon (t.box ().enlarged (db::Vector (enl, enl))));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ class DeepShapeStore;
|
|||
class DeepShapeStoreState;
|
||||
class Region;
|
||||
class Edges;
|
||||
class EdgePairs;
|
||||
class Texts;
|
||||
class ShapeCollection;
|
||||
|
||||
/**
|
||||
* @brief Represents a shape collection from the deep shape store
|
||||
|
|
@ -75,6 +78,24 @@ public:
|
|||
*/
|
||||
DeepLayer (const Region ®ion);
|
||||
|
||||
/**
|
||||
* @brief Conversion operator from texts collection to DeepLayer
|
||||
* This requires the texts to be a DeepTexts. Otherwise, this constructor will assert
|
||||
*/
|
||||
DeepLayer (const Texts ®ion);
|
||||
|
||||
/**
|
||||
* @brief Conversion operator from edges collection to DeepLayer
|
||||
* This requires the edges to be a DeepEdges. Otherwise, this constructor will assert
|
||||
*/
|
||||
DeepLayer (const Edges ®ion);
|
||||
|
||||
/**
|
||||
* @brief Conversion operator from edge pairs collection to DeepLayer
|
||||
* This requires the edge pairs to be a DeepEdgePairs. Otherwise, this constructor will assert
|
||||
*/
|
||||
DeepLayer (const EdgePairs ®ion);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
|
|
@ -338,15 +359,26 @@ public:
|
|||
* After a flat layer has been created for a region, it can be retrieved
|
||||
* from the region later with layer_for_flat (region).
|
||||
*/
|
||||
DeepLayer create_from_flat (const db::Edges ®ion, const db::ICplxTrans &trans = db::ICplxTrans ());
|
||||
DeepLayer create_from_flat (const db::Edges &edges, const db::ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Gets the layer for a given flat region.
|
||||
* @brief Creates a new layer from a flat text collection (or the text collection is made flat)
|
||||
*
|
||||
* This method is intended for use with singular-created DSS objects (see
|
||||
* singular constructor).
|
||||
*
|
||||
* After a flat layer has been created for a region, it can be retrieved
|
||||
* from the region later with layer_for_flat (region).
|
||||
*/
|
||||
DeepLayer create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Gets the layer for a given flat collection (Region, Edges, Texts, EdgePairs)
|
||||
*
|
||||
* If a layer has been created for a flat region with create_from_flat, it can be retrieved with this method.
|
||||
* The first return value is true in this case.
|
||||
*/
|
||||
std::pair<bool, DeepLayer> layer_for_flat (const db::Region ®ion) const;
|
||||
std::pair<bool, DeepLayer> layer_for_flat (const ShapeCollection &coll) const;
|
||||
|
||||
/**
|
||||
* @brief Same as layer_for_flat, but takes a region Id
|
||||
|
|
@ -395,6 +427,15 @@ public:
|
|||
*/
|
||||
DeepLayer create_edge_pair_layer (const db::RecursiveShapeIterator &si, const ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Inserts an text layer into the deep shape store
|
||||
*
|
||||
* This method will create a new layer inside the deep shape store as a
|
||||
* working copy of the original layer. This method creates a layer
|
||||
* for texts.
|
||||
*/
|
||||
DeepLayer create_text_layer (const db::RecursiveShapeIterator &si, const ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Inserts a polygon layer into the deep shape store using a custom preparation pipeline
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,613 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbDeepTexts.h"
|
||||
#include "dbCellGraphUtils.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbLocalOperation.h"
|
||||
#include "dbTextsUtils.h"
|
||||
#include "dbHierProcessor.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An iterator delegate for the deep text collection
|
||||
* TODO: this is kind of redundant with OriginalLayerIterator ..
|
||||
*/
|
||||
class DB_PUBLIC DeepTextsIterator
|
||||
: public TextsIteratorDelegate
|
||||
{
|
||||
public:
|
||||
DeepTextsIterator (const db::RecursiveShapeIterator &iter)
|
||||
: m_iter (iter)
|
||||
{
|
||||
set ();
|
||||
}
|
||||
|
||||
virtual ~DeepTextsIterator () { }
|
||||
|
||||
virtual bool at_end () const
|
||||
{
|
||||
return m_iter.at_end ();
|
||||
}
|
||||
|
||||
virtual void increment ()
|
||||
{
|
||||
++m_iter;
|
||||
set ();
|
||||
}
|
||||
|
||||
virtual const value_type *get () const
|
||||
{
|
||||
return &m_text;
|
||||
}
|
||||
|
||||
virtual TextsIteratorDelegate *clone () const
|
||||
{
|
||||
return new DeepTextsIterator (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Texts;
|
||||
|
||||
db::RecursiveShapeIterator m_iter;
|
||||
mutable value_type m_text;
|
||||
|
||||
void set () const {
|
||||
if (! m_iter.at_end ()) {
|
||||
m_iter.shape ().text (m_text);
|
||||
m_text.transform (m_iter.trans ());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
DeepTexts::DeepTexts ()
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_from_flat (other));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_text_layer (si));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
set_deep_layer (dss.create_text_layer (si, trans));
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const DeepTexts &other)
|
||||
: AsIfFlatTexts (other), DeepShapeCollectionDelegateBase (other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepTexts &
|
||||
DeepTexts::operator= (const DeepTexts &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
AsIfFlatTexts::operator= (other);
|
||||
DeepShapeCollectionDelegateBase::operator= (other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const DeepLayer &dl)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
set_deep_layer (dl);
|
||||
}
|
||||
|
||||
DeepTexts::~DeepTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::clone () const
|
||||
{
|
||||
return new DeepTexts (*this);
|
||||
}
|
||||
|
||||
TextsIteratorDelegate *DeepTexts::begin () const
|
||||
{
|
||||
return new DeepTextsIterator (begin_iter ().first);
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> DeepTexts::begin_iter () const
|
||||
{
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
if (layout.cells () == 0) {
|
||||
|
||||
return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ());
|
||||
|
||||
} else {
|
||||
|
||||
const db::Cell &top_cell = layout.cell (*layout.begin_top_down ());
|
||||
db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ());
|
||||
return std::make_pair (iter, db::ICplxTrans ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
size_t DeepTexts::size () const
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
db::CellCounter cc (&layout);
|
||||
for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) {
|
||||
n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size ();
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
std::string DeepTexts::to_string (size_t nmax) const
|
||||
{
|
||||
return db::AsIfFlatTexts::to_string (nmax);
|
||||
}
|
||||
|
||||
Box DeepTexts::bbox () const
|
||||
{
|
||||
return deep_layer ().initial_cell ().bbox (deep_layer ().layer ());
|
||||
}
|
||||
|
||||
bool DeepTexts::empty () const
|
||||
{
|
||||
return begin_iter ().first.at_end ();
|
||||
}
|
||||
|
||||
const db::Text *DeepTexts::nth (size_t) const
|
||||
{
|
||||
throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat text collections")));
|
||||
}
|
||||
|
||||
bool DeepTexts::has_valid_texts () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator *DeepTexts::iter () const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
DeepTexts::add_in_place (const Texts &other)
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const DeepTexts *other_deep = dynamic_cast <const DeepTexts *> (other.delegate ());
|
||||
if (other_deep) {
|
||||
|
||||
deep_layer ().add_from (other_deep->deep_layer ());
|
||||
|
||||
} else {
|
||||
|
||||
// non-deep to deep merge (flat)
|
||||
|
||||
db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ());
|
||||
for (db::Texts::const_iterator p = other.begin (); ! p.at_end (); ++p) {
|
||||
shapes.insert (*p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::add (const Texts &other) const
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return clone ();
|
||||
} else if (empty ()) {
|
||||
return other.delegate ()->clone ();
|
||||
} else {
|
||||
DeepTexts *new_texts = dynamic_cast<DeepTexts *> (clone ());
|
||||
new_texts->add_in_place (other);
|
||||
return new_texts;
|
||||
}
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::filter_in_place (const TextFilterBase &filter)
|
||||
{
|
||||
// TODO: implement as really in place
|
||||
*this = *apply_filter (filter);
|
||||
return this;
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::filtered (const TextFilterBase &filter) const
|
||||
{
|
||||
return apply_filter (filter);
|
||||
}
|
||||
|
||||
DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const
|
||||
{
|
||||
const db::DeepLayer &texts = deep_layer ();
|
||||
|
||||
std::auto_ptr<VariantsCollectorBase> vars;
|
||||
if (filter.vars ()) {
|
||||
|
||||
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
|
||||
|
||||
vars->collect (texts.layout (), texts.initial_cell ());
|
||||
|
||||
if (filter.wants_variants ()) {
|
||||
const_cast<db::DeepLayer &> (texts).separate_variants (*vars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (texts.layout ());
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
|
||||
|
||||
std::auto_ptr<db::DeepTexts> res (new db::DeepTexts (texts.derived ()));
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const db::Shapes &s = c->shapes (texts.layer ());
|
||||
|
||||
if (vars.get ()) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &vv = vars->variants (c->cell_index ());
|
||||
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
||||
|
||||
db::Shapes *st;
|
||||
if (vv.size () == 1) {
|
||||
st = & c->shapes (res->deep_layer ().layer ());
|
||||
} else {
|
||||
st = & to_commit [c->cell_index ()] [v->first];
|
||||
}
|
||||
|
||||
const db::ICplxTrans &tr = v->first;
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) {
|
||||
db::Text text;
|
||||
si->text (text);
|
||||
if (filter.selected (text.transformed (tr))) {
|
||||
st->insert (*si);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) {
|
||||
db::Text text;
|
||||
si->text (text);
|
||||
if (filter.selected (text)) {
|
||||
st.insert (*si);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! to_commit.empty () && vars.get ()) {
|
||||
res->deep_layer ().commit_shapes (*vars, to_commit);
|
||||
}
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *DeepTexts::polygons (db::Coord e) const
|
||||
{
|
||||
db::DeepLayer new_layer = deep_layer ().derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
db::Shapes &output = c->shapes (new_layer.layer ());
|
||||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) {
|
||||
db::Box box = s->bbox ();
|
||||
box.enlarge (db::Vector (e, e));
|
||||
db::Polygon poly (box);
|
||||
output.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
}
|
||||
}
|
||||
|
||||
return new db::DeepRegion (new_layer);
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepTexts::edges () const
|
||||
{
|
||||
db::DeepLayer new_layer = deep_layer ().derived ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
db::Shapes &output = c->shapes (new_layer.layer ());
|
||||
for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) {
|
||||
db::Box box = s->bbox ();
|
||||
output.insert (db::Edge (box.p1 (), box.p2 ()));
|
||||
}
|
||||
}
|
||||
|
||||
return new db::DeepEdges (new_layer);
|
||||
}
|
||||
|
||||
TextsDelegate *DeepTexts::in (const Texts &other, bool invert) const
|
||||
{
|
||||
// TODO: implement
|
||||
return AsIfFlatTexts::in (other, invert);
|
||||
}
|
||||
|
||||
bool DeepTexts::equals (const Texts &other) const
|
||||
{
|
||||
const DeepTexts *other_delegate = dynamic_cast<const DeepTexts *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()
|
||||
&& other_delegate->deep_layer ().layer () == deep_layer ().layer ()) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatTexts::equals (other);
|
||||
}
|
||||
}
|
||||
|
||||
bool DeepTexts::less (const Texts &other) const
|
||||
{
|
||||
const DeepTexts *other_delegate = dynamic_cast<const DeepTexts *> (other.delegate ());
|
||||
if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) {
|
||||
return other_delegate->deep_layer ().layer () < deep_layer ().layer ();
|
||||
} else {
|
||||
return AsIfFlatTexts::less (other);
|
||||
}
|
||||
}
|
||||
|
||||
void DeepTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
deep_layer ().insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
void DeepTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
deep_layer ().insert_into_as_polygons (layout, into_cell, into_layer, enl);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class Text2PolygonInteractingLocalOperation
|
||||
: public local_operation<db::TextRef, db::PolygonRef, db::TextRef>
|
||||
{
|
||||
public:
|
||||
Text2PolygonInteractingLocalOperation (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::Coord dist () const
|
||||
{
|
||||
// touching is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout * /*layout*/, const shape_interactions<db::TextRef, db::PolygonRef> &interactions, std::unordered_set<db::TextRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::TextRef, size_t, db::Polygon, size_t> scanner;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
others.insert (interactions.intruder_shape (*j));
|
||||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::TextRef &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_inverse) {
|
||||
|
||||
std::unordered_set<db::TextRef> interacting;
|
||||
text_to_region_interaction_filter<std::unordered_set<db::TextRef>, db::TextRef> filter (interacting);
|
||||
scanner.process (filter, 1, db::box_convert<db::TextRef> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::TextRef &subject = interactions.subject_shape (i->first);
|
||||
if (interacting.find (subject) == interacting.end ()) {
|
||||
result.insert (subject);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
text_to_region_interaction_filter<std::unordered_set<db::TextRef>, db::TextRef> filter (result);
|
||||
scanner.process (filter, 1, db::box_convert<db::TextRef> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
if (m_inverse) {
|
||||
return Copy;
|
||||
} else {
|
||||
return Drop;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select interacting texts"));
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
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 Text2PolygonPullLocalOperation
|
||||
: public local_operation<db::TextRef, db::PolygonRef, db::PolygonRef>
|
||||
{
|
||||
public:
|
||||
Text2PolygonPullLocalOperation ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual db::Coord dist () const
|
||||
{
|
||||
// touching is sufficient
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout *layout, const shape_interactions<db::TextRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::TextRef, size_t, db::Polygon, size_t> scanner;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
others.insert (interactions.intruder_shape (*j));
|
||||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::TextRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::TextRef &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);
|
||||
text_to_region_interaction_filter<ResultInserter, db::TextRef> filter (inserter);
|
||||
scanner.process (filter, 1, db::box_convert<db::TextRef> (), db::box_convert<db::Polygon> ());
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
return Drop;
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select interacting regions"));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
DeepTexts::selected_interacting_generic (const Region &other, bool inverse) const
|
||||
{
|
||||
std::auto_ptr<db::DeepRegion> dr_holder;
|
||||
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation
|
||||
dr_holder.reset (new db::DeepRegion (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &texts = deep_layer ();
|
||||
|
||||
DeepLayer dl_out (texts.derived ());
|
||||
|
||||
db::Text2PolygonInteractingLocalOperation op (inverse);
|
||||
|
||||
db::local_processor<db::TextRef, db::PolygonRef, db::TextRef> proc (const_cast<db::Layout *> (&texts.layout ()), const_cast<db::Cell *> (&texts.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (other.base_verbosity ());
|
||||
proc.set_threads (texts.store ()->threads ());
|
||||
|
||||
proc.run (&op, texts.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
return new db::DeepTexts (dl_out);
|
||||
}
|
||||
|
||||
RegionDelegate *DeepTexts::pull_generic (const Region &other) const
|
||||
{
|
||||
std::auto_ptr<db::DeepRegion> dr_holder;
|
||||
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation
|
||||
dr_holder.reset (new db::DeepRegion (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &texts = deep_layer ();
|
||||
const db::DeepLayer &other_polygons = other_deep->merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (other_polygons.derived ());
|
||||
|
||||
db::Text2PolygonPullLocalOperation op;
|
||||
|
||||
db::local_processor<db::TextRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&texts.layout ()), const_cast<db::Cell *> (&texts.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell ());
|
||||
proc.set_base_verbosity (other.base_verbosity ());
|
||||
proc.set_threads (texts.store ()->threads ());
|
||||
|
||||
proc.run (&op, texts.layer (), other_polygons.layer (), dl_out.layer ());
|
||||
|
||||
return new db::DeepRegion (dl_out);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbDeepTexts
|
||||
#define HDR_dbDeepTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatTexts.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbTexts.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief Provides hierarchical edges implementation
|
||||
*/
|
||||
class DB_PUBLIC DeepTexts
|
||||
: public db::AsIfFlatTexts, public db::DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepTexts ();
|
||||
DeepTexts (const db::Texts &other, DeepShapeStore &dss);
|
||||
DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss);
|
||||
DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
DeepTexts (const DeepTexts &other);
|
||||
DeepTexts (const DeepLayer &dl);
|
||||
|
||||
virtual ~DeepTexts ();
|
||||
|
||||
TextsDelegate *clone () const;
|
||||
|
||||
virtual TextsIteratorDelegate *begin () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
|
||||
virtual size_t size () const;
|
||||
virtual std::string to_string (size_t) const;
|
||||
virtual Box bbox () const;
|
||||
virtual bool empty () const;
|
||||
virtual const db::Text *nth (size_t n) const;
|
||||
virtual bool has_valid_texts () const;
|
||||
virtual const db::RecursiveShapeIterator *iter () const;
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter);
|
||||
virtual TextsDelegate *filtered (const TextFilterBase &) const;
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other);
|
||||
virtual TextsDelegate *add (const Texts &other) const;
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const;
|
||||
virtual EdgesDelegate *edges () const;
|
||||
|
||||
virtual TextsDelegate *in (const Texts &, bool) const;
|
||||
|
||||
virtual bool equals (const Texts &other) const;
|
||||
virtual bool less (const Texts &other) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
DeepTexts &operator= (const DeepTexts &other);
|
||||
|
||||
void init ();
|
||||
DeepTexts *apply_filter (const TextFilterBase &filter) const;
|
||||
|
||||
virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const;
|
||||
virtual RegionDelegate *pull_generic (const Region &other) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ EdgePairs::EdgePairs (EdgePairsDelegate *delegate)
|
|||
}
|
||||
|
||||
EdgePairs::EdgePairs (const EdgePairs &other)
|
||||
: gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ())
|
||||
: db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@
|
|||
#include "dbEdgePairsDelegate.h"
|
||||
#include "dbShape.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
|
||||
#include "gsiObject.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -230,7 +229,7 @@ public:
|
|||
* can be converted to polygons or to individual edges.
|
||||
*/
|
||||
class DB_PUBLIC EdgePairs
|
||||
: public gsi::ObjectBase
|
||||
: public db::ShapeCollection
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
@ -339,6 +338,14 @@ public:
|
|||
*/
|
||||
explicit EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
ShapeCollectionDelegateBase *get_delegate () const
|
||||
{
|
||||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying delegate object
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ EdgePairsDelegate::EdgePairsDelegate ()
|
|||
}
|
||||
|
||||
EdgePairsDelegate::EdgePairsDelegate (const EdgePairsDelegate &other)
|
||||
: tl::UniqueId ()
|
||||
: ShapeCollectionDelegateBase ()
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,9 +25,8 @@
|
|||
#define HDR_dbEdgePairsDelegate
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbEdgePair.h"
|
||||
#include "tlUniqueId.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
|
|
@ -59,7 +58,7 @@ public:
|
|||
* @brief The delegate for the actual edge set implementation
|
||||
*/
|
||||
class DB_PUBLIC EdgePairsDelegate
|
||||
: public tl::UniqueId
|
||||
: public ShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ Edges::Edges (EdgesDelegate *delegate)
|
|||
}
|
||||
|
||||
Edges::Edges (const Edges &other)
|
||||
: gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ())
|
||||
: db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@
|
|||
#include "dbEdgesDelegate.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbCellVariants.h"
|
||||
|
||||
#include "gsiObject.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -215,7 +214,7 @@ class Edges;
|
|||
*/
|
||||
|
||||
class DB_PUBLIC Edges
|
||||
: public gsi::ObjectBase
|
||||
: public db::ShapeCollection
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
@ -359,6 +358,14 @@ public:
|
|||
*/
|
||||
explicit Edges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges = true, bool merged_semantics = true);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
ShapeCollectionDelegateBase *get_delegate () const
|
||||
{
|
||||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying delegate object
|
||||
*/
|
||||
|
|
@ -1301,6 +1308,7 @@ public:
|
|||
|
||||
private:
|
||||
friend class EdgePairs;
|
||||
friend class Texts;
|
||||
|
||||
EdgesDelegate *mp_delegate;
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ EdgesDelegate::EdgesDelegate ()
|
|||
}
|
||||
|
||||
EdgesDelegate::EdgesDelegate (const EdgesDelegate &other)
|
||||
: tl::UniqueId ()
|
||||
: ShapeCollectionDelegateBase ()
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include "dbEdge.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdgePairRelations.h"
|
||||
#include "tlUniqueId.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -181,7 +181,7 @@ public:
|
|||
* @brief The delegate for the actual edge set implementation
|
||||
*/
|
||||
class DB_PUBLIC EdgesDelegate
|
||||
: public tl::UniqueId
|
||||
: public ShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbCommon.h"
|
||||
#include "dbRegionDelegate.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
#include "dbEmptyTexts.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
|
|
@ -107,11 +108,14 @@ public:
|
|||
virtual RegionDelegate *selected_not_interacting (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_interacting (const Edges &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_interacting (const Edges &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_interacting (const Texts &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_overlapping (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); }
|
||||
virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); }
|
||||
virtual TextsDelegate *pull_interacting (const Texts &) const { return new EmptyTexts (); }
|
||||
virtual RegionDelegate *pull_overlapping (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbEmptyTexts.h"
|
||||
#include "dbEmptyRegion.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
#include "dbTexts.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
EmptyTexts::EmptyTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EmptyTexts::EmptyTexts (const EmptyTexts &other)
|
||||
: TextsDelegate (other)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::clone () const
|
||||
{
|
||||
return new EmptyTexts (*this);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
EmptyTexts::polygons (db::Coord) const
|
||||
{
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
EmptyTexts::edges () const
|
||||
{
|
||||
return new EmptyEdges ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::add_in_place (const Texts &other)
|
||||
{
|
||||
return add (other);
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::add (const Texts &other) const
|
||||
{
|
||||
return other.delegate ()->clone ();
|
||||
}
|
||||
|
||||
bool
|
||||
EmptyTexts::equals (const Texts &other) const
|
||||
{
|
||||
return other.empty ();
|
||||
}
|
||||
|
||||
bool
|
||||
EmptyTexts::less (const Texts &other) const
|
||||
{
|
||||
return other.empty () ? false : true;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
EmptyTexts::pull_interacting (const Region &) const
|
||||
{
|
||||
return new EmptyRegion ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::selected_interacting (const Region &) const
|
||||
{
|
||||
return new EmptyTexts ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
EmptyTexts::selected_not_interacting (const Region &) const
|
||||
{
|
||||
return new EmptyTexts ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbEmptyTexts
|
||||
#define HDR_dbEmptyTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbTextsDelegate.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief The delegate for the actual edge set implementation
|
||||
*/
|
||||
class DB_PUBLIC EmptyTexts
|
||||
: public TextsDelegate
|
||||
{
|
||||
public:
|
||||
EmptyTexts ();
|
||||
EmptyTexts (const EmptyTexts &other);
|
||||
|
||||
virtual TextsDelegate *clone () const;
|
||||
|
||||
virtual std::string to_string (size_t) const { return std::string (); }
|
||||
|
||||
virtual TextsIteratorDelegate *begin () const { return 0; }
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); }
|
||||
|
||||
virtual bool empty () const { return true; }
|
||||
virtual size_t size () const { return 0; }
|
||||
|
||||
virtual Box bbox () const { return Box (); }
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &) { return this; }
|
||||
virtual TextsDelegate *filtered (const TextFilterBase &) const { return new EmptyTexts (); }
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const;
|
||||
virtual EdgesDelegate *edges () const;
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other);
|
||||
virtual TextsDelegate *add (const Texts &other) const;
|
||||
|
||||
virtual TextsDelegate *in (const Texts &, bool) const { return new EmptyTexts (); }
|
||||
|
||||
virtual const db::Text *nth (size_t) const { tl_assert (false); }
|
||||
virtual bool has_valid_texts () const { return true; }
|
||||
|
||||
virtual const db::RecursiveShapeIterator *iter () const { return 0; }
|
||||
|
||||
virtual bool equals (const Texts &other) const;
|
||||
virtual bool less (const Texts &other) const;
|
||||
|
||||
virtual void insert_into (Layout *, db::cell_index_type, unsigned int) const { }
|
||||
virtual void insert_into_as_polygons (Layout *, db::cell_index_type, unsigned int, db::Coord) const { }
|
||||
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const;
|
||||
virtual TextsDelegate *selected_interacting (const Region &) const;
|
||||
virtual TextsDelegate *selected_not_interacting (const Region &) const;
|
||||
|
||||
private:
|
||||
EmptyTexts &operator= (const EmptyTexts &other);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbFlatTexts.h"
|
||||
#include "dbEmptyTexts.h"
|
||||
#include "dbTexts.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// FlatTexts implementation
|
||||
|
||||
FlatTexts::FlatTexts ()
|
||||
: AsIfFlatTexts (), m_texts (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
FlatTexts::~FlatTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
FlatTexts::FlatTexts (const FlatTexts &other)
|
||||
: AsIfFlatTexts (other), m_texts (false)
|
||||
{
|
||||
m_texts = other.m_texts;
|
||||
}
|
||||
|
||||
FlatTexts::FlatTexts (const db::Shapes &texts)
|
||||
: AsIfFlatTexts (), m_texts (texts)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void FlatTexts::invalidate_cache ()
|
||||
{
|
||||
invalidate_bbox ();
|
||||
}
|
||||
|
||||
void FlatTexts::reserve (size_t n)
|
||||
{
|
||||
m_texts.reserve (db::Text::tag (), n);
|
||||
}
|
||||
|
||||
TextsIteratorDelegate *FlatTexts::begin () const
|
||||
{
|
||||
return new FlatTextsIterator (m_texts.get_layer<db::Text, db::unstable_layer_tag> ().begin (), m_texts.get_layer<db::Text, db::unstable_layer_tag> ().end ());
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> FlatTexts::begin_iter () const
|
||||
{
|
||||
return std::make_pair (db::RecursiveShapeIterator (m_texts), db::ICplxTrans ());
|
||||
}
|
||||
|
||||
bool FlatTexts::empty () const
|
||||
{
|
||||
return m_texts.empty ();
|
||||
}
|
||||
|
||||
size_t FlatTexts::size () const
|
||||
{
|
||||
return m_texts.size ();
|
||||
}
|
||||
|
||||
Box FlatTexts::compute_bbox () const
|
||||
{
|
||||
m_texts.update_bbox ();
|
||||
return m_texts.bbox ();
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
FlatTexts::filter_in_place (const TextFilterBase &filter)
|
||||
{
|
||||
text_iterator_type pw = m_texts.get_layer<db::Text, db::unstable_layer_tag> ().begin ();
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
if (filter.selected (*p)) {
|
||||
if (pw == m_texts.get_layer<db::Text, db::unstable_layer_tag> ().end ()) {
|
||||
m_texts.get_layer<db::Text, db::unstable_layer_tag> ().insert (*p);
|
||||
pw = m_texts.get_layer<db::Text, db::unstable_layer_tag> ().end ();
|
||||
} else {
|
||||
m_texts.get_layer<db::Text, db::unstable_layer_tag> ().replace (pw++, *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_texts.get_layer<db::Text, db::unstable_layer_tag> ().erase (pw, m_texts.get_layer<db::Text, db::unstable_layer_tag> ().end ());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
TextsDelegate *FlatTexts::add (const Texts &other) const
|
||||
{
|
||||
std::auto_ptr<FlatTexts> new_texts (new FlatTexts (*this));
|
||||
new_texts->invalidate_cache ();
|
||||
|
||||
FlatTexts *other_flat = dynamic_cast<FlatTexts *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
new_texts->raw_texts ().insert (other_flat->raw_texts ().get_layer<db::Text, db::unstable_layer_tag> ().begin (), other_flat->raw_texts ().get_layer<db::Text, db::unstable_layer_tag> ().end ());
|
||||
|
||||
} else {
|
||||
|
||||
size_t n = new_texts->raw_texts ().size ();
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
++n;
|
||||
}
|
||||
|
||||
new_texts->raw_texts ().reserve (db::Text::tag (), n);
|
||||
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
new_texts->raw_texts ().insert (*p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new_texts.release ();
|
||||
}
|
||||
|
||||
TextsDelegate *FlatTexts::add_in_place (const Texts &other)
|
||||
{
|
||||
invalidate_cache ();
|
||||
|
||||
FlatTexts *other_flat = dynamic_cast<FlatTexts *> (other.delegate ());
|
||||
if (other_flat) {
|
||||
|
||||
m_texts.insert (other_flat->raw_texts ().get_layer<db::Text, db::unstable_layer_tag> ().begin (), other_flat->raw_texts ().get_layer<db::Text, db::unstable_layer_tag> ().end ());
|
||||
|
||||
} else {
|
||||
|
||||
size_t n = m_texts.size ();
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
++n;
|
||||
}
|
||||
|
||||
m_texts.reserve (db::Text::tag (), n);
|
||||
|
||||
for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) {
|
||||
m_texts.insert (*p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
const db::Text *FlatTexts::nth (size_t n) const
|
||||
{
|
||||
return n < m_texts.size () ? &m_texts.get_layer<db::Text, db::unstable_layer_tag> ().begin () [n] : 0;
|
||||
}
|
||||
|
||||
bool FlatTexts::has_valid_texts () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator *FlatTexts::iter () const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
db::Shapes &out = layout->cell (into_cell).shapes (into_layer);
|
||||
for (TextsIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
db::Box box = p->box ();
|
||||
box.enlarge (db::Vector (enl, enl));
|
||||
out.insert (db::SimplePolygon (box));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
layout->cell (into_cell).shapes (into_layer).insert (m_texts);
|
||||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert (const db::Text &t)
|
||||
{
|
||||
m_texts.insert (t);
|
||||
invalidate_cache ();
|
||||
}
|
||||
|
||||
void
|
||||
FlatTexts::insert (const db::Shape &shape)
|
||||
{
|
||||
if (shape.is_text ()) {
|
||||
|
||||
db::Text t;
|
||||
shape.text (t);
|
||||
insert (t);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbFlatTexts
|
||||
#define HDR_dbFlatTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatTexts.h"
|
||||
#include "dbShapes.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief An iterator delegate for the flat text set
|
||||
*/
|
||||
class DB_PUBLIC FlatTextsIterator
|
||||
: public TextsIteratorDelegate
|
||||
{
|
||||
public:
|
||||
typedef db::layer<db::Text, db::unstable_layer_tag> edge_pair_layer_type;
|
||||
typedef edge_pair_layer_type::iterator iterator_type;
|
||||
|
||||
FlatTextsIterator (iterator_type from, iterator_type to)
|
||||
: m_from (from), m_to (to)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual bool at_end () const
|
||||
{
|
||||
return m_from == m_to;
|
||||
}
|
||||
|
||||
virtual void increment ()
|
||||
{
|
||||
++m_from;
|
||||
}
|
||||
|
||||
virtual const value_type *get () const
|
||||
{
|
||||
return m_from.operator-> ();
|
||||
}
|
||||
|
||||
virtual TextsIteratorDelegate *clone () const
|
||||
{
|
||||
return new FlatTextsIterator (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Texts;
|
||||
|
||||
iterator_type m_from, m_to;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The delegate for the actual text set implementation
|
||||
*/
|
||||
class DB_PUBLIC FlatTexts
|
||||
: public AsIfFlatTexts
|
||||
{
|
||||
public:
|
||||
typedef db::Text value_type;
|
||||
|
||||
typedef db::layer<db::Text, db::unstable_layer_tag> text_layer_type;
|
||||
typedef text_layer_type::iterator text_iterator_type;
|
||||
|
||||
FlatTexts ();
|
||||
FlatTexts (const db::Shapes &texts);
|
||||
|
||||
FlatTexts (const FlatTexts &other);
|
||||
|
||||
virtual ~FlatTexts ();
|
||||
|
||||
TextsDelegate *clone () const
|
||||
{
|
||||
return new FlatTexts (*this);
|
||||
}
|
||||
|
||||
void reserve (size_t);
|
||||
|
||||
virtual TextsIteratorDelegate *begin () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
|
||||
virtual bool empty () const;
|
||||
virtual size_t size () const;
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter);
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other);
|
||||
virtual TextsDelegate *add (const Texts &other) const;
|
||||
|
||||
virtual const db::Text *nth (size_t n) const;
|
||||
virtual bool has_valid_texts () const;
|
||||
|
||||
virtual const db::RecursiveShapeIterator *iter () const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const;
|
||||
|
||||
void insert (const db::Text &text);
|
||||
void insert (const db::Shape &shape);
|
||||
|
||||
template <class T>
|
||||
void insert (const db::Shape &shape, const T &trans)
|
||||
{
|
||||
if (shape.is_edge_pair ()) {
|
||||
|
||||
db::Text t;
|
||||
shape.text (t);
|
||||
t.transform (trans);
|
||||
insert (t);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void insert_seq (const Iter &seq)
|
||||
{
|
||||
for (Iter i = seq; ! i.at_end (); ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
void transform (const Trans &trans)
|
||||
{
|
||||
if (! trans.is_unity ()) {
|
||||
for (text_iterator_type p = m_texts.template get_layer<db::Text, db::unstable_layer_tag> ().begin (); p != m_texts.template get_layer<db::Text, db::unstable_layer_tag> ().end (); ++p) {
|
||||
m_texts.get_layer<db::Text, db::unstable_layer_tag> ().replace (p, p->transformed (trans));
|
||||
}
|
||||
invalidate_cache ();
|
||||
}
|
||||
}
|
||||
|
||||
db::Shapes &raw_texts () { return m_texts; }
|
||||
|
||||
protected:
|
||||
virtual Box compute_bbox () const;
|
||||
void invalidate_cache ();
|
||||
|
||||
private:
|
||||
friend class AsIfFlatTexts;
|
||||
|
||||
FlatTexts &operator= (const FlatTexts &other);
|
||||
|
||||
mutable db::Shapes m_texts;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
#include "dbPolygonTools.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbNetShape.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlTimer.h"
|
||||
|
|
@ -43,9 +44,9 @@ namespace db
|
|||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
template <class Container, class Shape, class Trans> void insert_transformed (db::Layout &layout, Container &shapes, const Shape &s, const Trans &t);
|
||||
template <class Shape, class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t);
|
||||
|
||||
template <class Container, class Trans> void insert_transformed (db::Layout &layout, Container &shapes, const db::PolygonRef &s, const Trans &t)
|
||||
template <class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::PolygonRef &s, const Trans &t)
|
||||
{
|
||||
db::Polygon poly = s.obj ();
|
||||
poly.transform (s.trans ());
|
||||
|
|
@ -55,7 +56,32 @@ template <class Container, class Trans> void insert_transformed (db::Layout &lay
|
|||
shapes.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
}
|
||||
|
||||
template <class Container, class Trans> void insert_transformed (db::Layout & /*layout*/, Container &shapes, const db::Edge &s, const Trans &t)
|
||||
template <class Trans> void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::NetShape &s, const Trans &t)
|
||||
{
|
||||
if (s.type () == db::NetShape::Polygon) {
|
||||
|
||||
db::PolygonRef pr = s.polygon_ref ();
|
||||
db::Polygon poly = pr.obj ();
|
||||
poly.transform (pr.trans ());
|
||||
if (! t.is_unity ()) {
|
||||
poly.transform (t);
|
||||
}
|
||||
shapes.insert (db::PolygonRef (poly, layout.shape_repository ()));
|
||||
|
||||
} else if (s.type () == db::NetShape::Text) {
|
||||
|
||||
db::TextRef tr = s.text_ref ();
|
||||
db::Text text = tr.obj ();
|
||||
text.transform (tr.trans ());
|
||||
if (! t.is_unity ()) {
|
||||
text.transform (t);
|
||||
}
|
||||
shapes.insert (db::TextRef (text, layout.shape_repository ()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Trans> void insert_transformed (db::Layout & /*layout*/, db::Shapes &shapes, const db::Edge &s, const Trans &t)
|
||||
{
|
||||
shapes.insert (s.transformed (t));
|
||||
}
|
||||
|
|
@ -237,6 +263,20 @@ interaction_test (const db::PolygonRef &a, const db::PolygonRef &b, const db::un
|
|||
}
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
static bool
|
||||
interaction_test (const db::NetShape &a, const db::NetShape &b, const Trans &trans, db::Connectivity::edge_connectivity_type)
|
||||
{
|
||||
return a.interacts_with_transformed (b, trans);
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static bool
|
||||
interaction_test (const db::NetShape &a, const db::NetShape &b, const db::unit_trans<C> &, db::Connectivity::edge_connectivity_type)
|
||||
{
|
||||
return a.interacts_with (b);
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
static bool
|
||||
interaction_test (const db::Edge &a, const db::Edge &b, const Trans &trans, db::Connectivity::edge_connectivity_type ec)
|
||||
|
|
@ -272,6 +312,8 @@ bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::NetShape> (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::UnitTrans &trans) const;
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::NetShape> (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::ICplxTrans &trans) const;
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::PolygonRef> (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::UnitTrans &trans) const;
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::PolygonRef> (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::ICplxTrans &trans) const;
|
||||
template DB_PUBLIC bool Connectivity::interacts<db::Edge> (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::UnitTrans &trans) const;
|
||||
|
|
@ -630,8 +672,10 @@ size_t local_cluster<T>::split (double max_area_ratio, Iter &output) const
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC local_cluster<db::NetShape>;
|
||||
template class DB_PUBLIC local_cluster<db::PolygonRef>;
|
||||
template class DB_PUBLIC local_cluster<db::Edge>;
|
||||
template DB_PUBLIC size_t local_cluster<db::NetShape>::split<std::back_insert_iterator<std::list<local_cluster<db::NetShape> > > > (double, std::back_insert_iterator<std::list<local_cluster<db::NetShape> > > &) const;
|
||||
template DB_PUBLIC size_t local_cluster<db::PolygonRef>::split<std::back_insert_iterator<std::list<local_cluster<db::PolygonRef> > > > (double, std::back_insert_iterator<std::list<local_cluster<db::PolygonRef> > > &) const;
|
||||
template DB_PUBLIC size_t local_cluster<db::Edge>::split<std::back_insert_iterator<std::list<local_cluster<db::Edge> > > > (double, std::back_insert_iterator<std::list<local_cluster<db::Edge> > > &) const;
|
||||
|
||||
|
|
@ -747,10 +791,10 @@ namespace
|
|||
|
||||
template <class T, class BoxTree>
|
||||
struct cluster_building_receiver
|
||||
: public db::box_scanner_receiver<T, std::pair<unsigned int, unsigned int> >
|
||||
: public db::box_scanner_receiver<T, std::pair<unsigned int, size_t> >
|
||||
{
|
||||
typedef typename local_cluster<T>::id_type id_type;
|
||||
typedef std::pair<const T *, std::pair<unsigned int, unsigned int> > shape_value;
|
||||
typedef std::pair<const T *, std::pair<unsigned int, size_t> > shape_value;
|
||||
typedef std::vector<shape_value> shape_vector;
|
||||
typedef std::set<size_t> global_nets;
|
||||
typedef std::pair<shape_vector, global_nets> cluster_value;
|
||||
|
|
@ -778,7 +822,7 @@ struct cluster_building_receiver
|
|||
}
|
||||
}
|
||||
|
||||
void add (const T *s1, std::pair<unsigned int, unsigned int> p1, const T *s2, std::pair<unsigned int, unsigned int> p2)
|
||||
void add (const T *s1, std::pair<unsigned int, size_t> p1, const T *s2, std::pair<unsigned int, size_t> p2)
|
||||
{
|
||||
if (! mp_conn->interacts (*s1, p1.first, *s2, p2.first)) {
|
||||
return;
|
||||
|
|
@ -824,7 +868,7 @@ struct cluster_building_receiver
|
|||
}
|
||||
}
|
||||
|
||||
void finish (const T *s, std::pair<unsigned int, unsigned> p)
|
||||
void finish (const T *s, std::pair<unsigned int, size_t> p)
|
||||
{
|
||||
// if the shape has not been handled yet, insert a single cluster with only this shape
|
||||
typename std::map<const T *, typename std::list<cluster_value>::iterator>::iterator ic = m_shape_to_clusters.find (s);
|
||||
|
|
@ -886,22 +930,108 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct addressable_shape_delivery
|
||||
{
|
||||
const T *operator () (const db::Shape &shape)
|
||||
{
|
||||
typename T::tag object_tag;
|
||||
return shape.basic_ptr (object_tag);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct addressable_shape_delivery<db::NetShape>
|
||||
{
|
||||
const NetShape *operator () (const db::Shape &shape)
|
||||
{
|
||||
if (shape.type () == db::Shape::TextRef) {
|
||||
m_heap.push_back (db::NetShape (shape.text_ref ()));
|
||||
return &m_heap.back ();
|
||||
} else if (shape.type () == db::Shape::PolygonRef) {
|
||||
m_heap.push_back (db::NetShape (shape.polygon_ref ()));
|
||||
return &m_heap.back ();
|
||||
} else {
|
||||
tl_assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<NetShape> m_heap;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct attr_accessor
|
||||
{
|
||||
size_t operator() (const db::Shape &shape) const
|
||||
{
|
||||
return shape.prop_id ();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct attr_accessor<db::NetShape>
|
||||
{
|
||||
size_t operator() (const db::Shape &shape) const
|
||||
{
|
||||
// NOTE: the attribute is
|
||||
// * odd: a StringRef pointer's value
|
||||
// * even: a Property ID times 2
|
||||
if (shape.type () == db::Shape::TextRef) {
|
||||
return db::text_ref_to_attr (&shape.text_ref ().obj ());
|
||||
} else {
|
||||
return db::prop_id_to_attr (shape.prop_id ());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct get_shape_flags { };
|
||||
|
||||
template <>
|
||||
struct get_shape_flags<db::Edge>
|
||||
{
|
||||
db::ShapeIterator::flags_type operator() () const
|
||||
{
|
||||
return db::ShapeIterator::Edges;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_shape_flags<db::PolygonRef>
|
||||
{
|
||||
db::ShapeIterator::flags_type operator() () const
|
||||
{
|
||||
return db::ShapeIterator::Polygons;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct get_shape_flags<db::NetShape>
|
||||
{
|
||||
db::ShapeIterator::flags_type operator() () const
|
||||
{
|
||||
return db::ShapeIterator::flags_type (db::ShapeIterator::Polygons | db::ShapeIterator::Texts);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
local_clusters<T>::build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence, bool report_progress)
|
||||
local_clusters<T>::build_clusters (const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence, bool report_progress)
|
||||
{
|
||||
static std::string desc = tl::to_string (tr ("Building local clusters"));
|
||||
|
||||
db::box_scanner<T, std::pair<unsigned int, unsigned int> > bs (report_progress, desc);
|
||||
typename T::tag object_tag;
|
||||
db::box_scanner<T, std::pair<unsigned int, size_t> > bs (report_progress, desc);
|
||||
db::box_convert<T> bc;
|
||||
addressable_shape_delivery<T> heap;
|
||||
attr_accessor<T> attr;
|
||||
db::ShapeIterator::flags_type shape_flags = get_shape_flags<T> () ();
|
||||
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
const db::Shapes &shapes = cell.shapes (*l);
|
||||
for (db::Shapes::shape_iterator s = shapes.begin (shape_flags); ! s.at_end (); ++s) {
|
||||
bs.insert (s->basic_ptr (object_tag), std::make_pair (*l, (unsigned int) s->prop_id ()));
|
||||
bs.insert (heap (*s), std::make_pair (*l, attr (*s)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -916,9 +1046,9 @@ local_clusters<T>::build_clusters (const db::Cell &cell, db::ShapeIterator::flag
|
|||
|
||||
template <class T>
|
||||
void
|
||||
local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<unsigned int> &attr_equivalence)
|
||||
local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<size_t> &attr_equivalence)
|
||||
{
|
||||
tl::equivalence_clusters<unsigned int> eq;
|
||||
tl::equivalence_clusters<size_t> eq;
|
||||
|
||||
// collect all local attributes (the ones which are present in attr_equivalence) into "eq"
|
||||
// and form equivalences for multi-attribute clusters.
|
||||
|
|
@ -939,18 +1069,18 @@ local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<unsig
|
|||
|
||||
// identify the layout clusters joined into one attribute cluster and join them
|
||||
|
||||
std::map<tl::equivalence_clusters<unsigned int>::cluster_id_type, std::set<size_t> > c2c;
|
||||
std::map<tl::equivalence_clusters<size_t>::cluster_id_type, std::set<size_t> > c2c;
|
||||
|
||||
for (const_iterator c = begin (); c != end (); ++c) {
|
||||
for (typename local_cluster<T>::attr_iterator a = c->begin_attr (); a != c->end_attr (); ++a) {
|
||||
tl::equivalence_clusters<unsigned int>::cluster_id_type cl = attr_equivalence.cluster_id (*a);
|
||||
tl::equivalence_clusters<size_t>::cluster_id_type cl = attr_equivalence.cluster_id (*a);
|
||||
if (cl > 0) {
|
||||
c2c [cl].insert (c->id ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<tl::equivalence_clusters<unsigned int>::cluster_id_type, std::set<size_t> >::const_iterator c = c2c.begin (); c != c2c.end (); ++c) {
|
||||
for (std::map<tl::equivalence_clusters<size_t>::cluster_id_type, std::set<size_t> >::const_iterator c = c2c.begin (); c != c2c.end (); ++c) {
|
||||
if (c->second.size () > 1) {
|
||||
std::set<size_t>::const_iterator cl0 = c->second.begin ();
|
||||
std::set<size_t>::const_iterator cl = cl0;
|
||||
|
|
@ -962,6 +1092,7 @@ local_clusters<T>::apply_attr_equivalences (const tl::equivalence_clusters<unsig
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC local_clusters<db::NetShape>;
|
||||
template class DB_PUBLIC local_clusters<db::PolygonRef>;
|
||||
template class DB_PUBLIC local_clusters<db::Edge>;
|
||||
|
||||
|
|
@ -984,6 +1115,7 @@ connected_clusters_iterator<T>::connected_clusters_iterator (const connected_clu
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC connected_clusters_iterator<db::NetShape>;
|
||||
template class DB_PUBLIC connected_clusters_iterator<db::PolygonRef>;
|
||||
template class DB_PUBLIC connected_clusters_iterator<db::Edge>;
|
||||
|
||||
|
|
@ -1053,6 +1185,7 @@ connected_clusters<T>::find_cluster_with_connection (const ClusterInstance &inst
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC connected_clusters<db::NetShape>;
|
||||
template class DB_PUBLIC connected_clusters<db::PolygonRef>;
|
||||
template class DB_PUBLIC connected_clusters<db::Edge>;
|
||||
|
||||
|
|
@ -1133,11 +1266,11 @@ void hier_clusters<T>::clear ()
|
|||
|
||||
template <class T>
|
||||
void
|
||||
hier_clusters<T>::build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||
hier_clusters<T>::build (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||
{
|
||||
clear ();
|
||||
cell_clusters_box_converter<T> cbc (layout, *this);
|
||||
do_build (cbc, layout, cell, shape_flags, conn, attr_equivalence, breakout_cells);
|
||||
do_build (cbc, layout, cell, conn, attr_equivalence, breakout_cells);
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
@ -1939,7 +2072,7 @@ hier_clusters<T>::propagate_cluster_inst (const db::Layout &layout, const db::Ce
|
|||
|
||||
template <class T>
|
||||
void
|
||||
hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||
hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > *attr_equivalence, const std::set<db::cell_index_type> *breakout_cells)
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity, tl::to_string (tr ("Computing shape clusters")));
|
||||
|
||||
|
|
@ -1957,8 +2090,8 @@ hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layou
|
|||
|
||||
// look for the net label joining spec - for the top cell the "top_cell_index" entry is looked for.
|
||||
// If there is no such entry or the cell is not the top cell, look for the entry by cell index.
|
||||
std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> >::const_iterator ae;
|
||||
const tl::equivalence_clusters<unsigned int> *ec = 0;
|
||||
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> >::const_iterator ae;
|
||||
const tl::equivalence_clusters<size_t> *ec = 0;
|
||||
if (attr_equivalence) {
|
||||
if (*c == cell.cell_index ()) {
|
||||
ae = attr_equivalence->find (top_cell_index);
|
||||
|
|
@ -1974,7 +2107,7 @@ hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layou
|
|||
}
|
||||
}
|
||||
|
||||
build_local_cluster (layout, layout.cell (*c), shape_flags, conn, ec);
|
||||
build_local_cluster (layout, layout.cell (*c), conn, ec);
|
||||
|
||||
++progress;
|
||||
|
||||
|
|
@ -2021,7 +2154,7 @@ hier_clusters<T>::do_build (cell_clusters_box_converter<T> &cbc, const db::Layou
|
|||
|
||||
template <class T>
|
||||
void
|
||||
hier_clusters<T>::build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence)
|
||||
hier_clusters<T>::build_local_cluster (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence)
|
||||
{
|
||||
std::string msg = tl::to_string (tr ("Computing local clusters for cell: ")) + std::string (layout.cell_name (cell.cell_index ()));
|
||||
if (tl::verbosity () >= m_base_verbosity + 20) {
|
||||
|
|
@ -2030,7 +2163,7 @@ hier_clusters<T>::build_local_cluster (const db::Layout &layout, const db::Cell
|
|||
tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 20, msg);
|
||||
|
||||
connected_clusters<T> &local = m_per_cell_clusters [cell.cell_index ()];
|
||||
local.build_clusters (cell, shape_flags, conn, attr_equivalence, true);
|
||||
local.build_clusters (cell, conn, attr_equivalence, true);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
|
@ -2336,6 +2469,7 @@ hier_clusters<T>::return_to_hierarchy (db::Layout &layout, const std::map<unsign
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC hier_clusters<db::NetShape>;
|
||||
template class DB_PUBLIC hier_clusters<db::PolygonRef>;
|
||||
template class DB_PUBLIC hier_clusters<db::Edge>;
|
||||
|
||||
|
|
@ -2460,6 +2594,7 @@ void recursive_cluster_shape_iterator<T>::down (db::cell_index_type ci, typename
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC recursive_cluster_shape_iterator<db::NetShape>;
|
||||
template class DB_PUBLIC recursive_cluster_shape_iterator<db::PolygonRef>;
|
||||
template class DB_PUBLIC recursive_cluster_shape_iterator<db::Edge>;
|
||||
|
||||
|
|
@ -2533,6 +2668,7 @@ void recursive_cluster_iterator<T>::down (db::cell_index_type ci, typename db::l
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC recursive_cluster_iterator<db::NetShape>;
|
||||
template class DB_PUBLIC recursive_cluster_iterator<db::PolygonRef>;
|
||||
template class DB_PUBLIC recursive_cluster_iterator<db::Edge>;
|
||||
|
||||
|
|
@ -2614,6 +2750,7 @@ incoming_cluster_connections<T>::ensure_computed_parent (db::cell_index_type ci)
|
|||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC incoming_cluster_connections<db::NetShape>;
|
||||
template class DB_PUBLIC incoming_cluster_connections<db::PolygonRef>;
|
||||
template class DB_PUBLIC incoming_cluster_connections<db::Edge>;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "dbCell.h"
|
||||
#include "dbInstElement.h"
|
||||
#include "tlEquivalenceClusters.h"
|
||||
#include "tlAssert.h"
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
|
@ -505,7 +506,7 @@ public:
|
|||
* cluster joining may happen in this case, because multi-attribute
|
||||
* assignment might create connections too.
|
||||
*/
|
||||
void build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence = 0, bool report_progress = false);
|
||||
void build_clusters (const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence = 0, bool report_progress = false);
|
||||
|
||||
/**
|
||||
* @brief Creates and inserts a new clusters
|
||||
|
|
@ -540,7 +541,7 @@ private:
|
|||
tree_type m_clusters;
|
||||
size_t m_next_dummy_id;
|
||||
|
||||
void apply_attr_equivalences (const tl::equivalence_clusters<unsigned int> &attr_equivalence);
|
||||
void apply_attr_equivalences (const tl::equivalence_clusters<size_t> &attr_equivalence);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -998,7 +999,7 @@ public:
|
|||
/**
|
||||
* @brief Builds a hierarchy of clusters from a cell hierarchy and given connectivity
|
||||
*/
|
||||
void build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence = 0, const std::set<cell_index_type> *breakout_cells = 0);
|
||||
void build (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > *attr_equivalence = 0, const std::set<cell_index_type> *breakout_cells = 0);
|
||||
|
||||
/**
|
||||
* @brief Gets the connected clusters for a given cell
|
||||
|
|
@ -1036,10 +1037,10 @@ public:
|
|||
size_t propagate_cluster_inst (const db::Layout &layout, const Cell &cell, const ClusterInstance &ci, db::cell_index_type parent_ci, bool with_self);
|
||||
|
||||
private:
|
||||
void build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters<unsigned int> *attr_equivalence);
|
||||
void build_local_cluster (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters<size_t> *attr_equivalence);
|
||||
void build_hier_connections (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::set<cell_index_type> *breakout_cells, instance_interaction_cache_type &instance_interaction_cache);
|
||||
void build_hier_connections_for_cells (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const std::vector<db::cell_index_type> &cells, const db::Connectivity &conn, const std::set<cell_index_type> *breakout_cells, tl::RelativeProgress &progress, instance_interaction_cache_type &instance_interaction_cache);
|
||||
void do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > *attr_equivalence, const std::set<cell_index_type> *breakout_cells);
|
||||
void do_build (cell_clusters_box_converter<T> &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map<cell_index_type, tl::equivalence_clusters<size_t> > *attr_equivalence, const std::set<cell_index_type> *breakout_cells);
|
||||
|
||||
std::map<db::cell_index_type, connected_clusters<T> > m_per_cell_clusters;
|
||||
int m_base_verbosity;
|
||||
|
|
@ -1335,6 +1336,49 @@ private:
|
|||
void ensure_computed_parent (db::cell_index_type ci) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper function generating an attribute ID from a property ID
|
||||
* This function is used to provide a generic attribute wrapping a property ID and a text ID.
|
||||
*/
|
||||
inline size_t prop_id_to_attr (db::properties_id_type id)
|
||||
{
|
||||
return size_t (id) * 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the attribute is a property ID
|
||||
*/
|
||||
inline bool is_prop_id_attr (size_t attr)
|
||||
{
|
||||
return (attr & 1) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the property ID from an attribute
|
||||
*/
|
||||
inline db::properties_id_type prop_id_from_attr (size_t attr)
|
||||
{
|
||||
return attr / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A helper function generating an attribute from a StringRef
|
||||
*/
|
||||
inline size_t text_ref_to_attr (const db::Text *tr)
|
||||
{
|
||||
return size_t (tr) + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the text value from an attribute ID
|
||||
*/
|
||||
inline const char *text_from_attr (size_t attr)
|
||||
{
|
||||
tl_assert ((attr & 1) != 0);
|
||||
const db::Text *t = reinterpret_cast<const db::Text *> (attr - 1);
|
||||
return t->string ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -633,8 +633,11 @@ shape_interactions<TS, TI>::intruder_shape (unsigned int id) const
|
|||
|
||||
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::PolygonRef>;
|
||||
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Edge>;
|
||||
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::TextRef>;
|
||||
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::TextRef, db::TextRef>;
|
||||
template class DB_PUBLIC shape_interactions<db::TextRef, db::PolygonRef>;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Helper classes for the LocalProcessor
|
||||
|
|
@ -656,6 +659,12 @@ inline unsigned int shape_flags<db::Edge> ()
|
|||
return db::ShapeIterator::Edges;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned int shape_flags<db::TextRef> ()
|
||||
{
|
||||
return db::ShapeIterator::Texts;
|
||||
}
|
||||
|
||||
template <class TS, class TI>
|
||||
struct interaction_registration_shape2shape
|
||||
: db::box_scanner_receiver2<TS, unsigned int, TI, unsigned int>
|
||||
|
|
@ -850,8 +859,11 @@ instances_interact (const db::Layout *layout1, const db::CellInstArray *inst1, u
|
|||
|
||||
// not very strong, but already useful: the cells interact if there is a layer1 in cell1
|
||||
// in the common box and a layer2 in the cell2 in the common box
|
||||
if (! db::RecursiveShapeIterator (*layout1, cell1, layer1, tni1 * cbox, true).at_end () &&
|
||||
! db::RecursiveShapeIterator (*layout2, cell2, layer2, tni2 * cbox, true).at_end ()) {
|
||||
// NOTE: don't use overlap mode for the RecursiveShapeIterator as this would not capture dot-like
|
||||
// objects like texts. Instead safe-shrink the search box and use touching mode ("false" for the last
|
||||
// argument)
|
||||
if (! db::RecursiveShapeIterator (*layout1, cell1, layer1, safe_box_enlarged (tni1 * cbox, -1, -1), false).at_end () &&
|
||||
! db::RecursiveShapeIterator (*layout2, cell2, layer2, safe_box_enlarged (tni2 * cbox, -1, -1), false).at_end ()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -929,7 +941,9 @@ instance_shape_interacts (const db::Layout *layout, const db::CellInstArray *ins
|
|||
|
||||
// not very strong, but already useful: the cells interact if there is a layer in cell
|
||||
// in the common box
|
||||
if (! db::RecursiveShapeIterator (*layout, cell, layer, tni * cbox, true).at_end ()) {
|
||||
// NOTE: don't use overlapping mode here, because this will not select point-like objects as texts or
|
||||
// dot edges. Instead safe-shrink the search box and use touching mode.
|
||||
if (! db::RecursiveShapeIterator (*layout, cell, layer, safe_box_enlarged (tni * cbox, -1, -1), false).at_end ()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1743,11 +1757,15 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
template class DB_PUBLIC local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::Edge, db::PolygonRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::Edge, db::Edge>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::TextRef, db::PolygonRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::TextRef, db::TextRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::PolygonRef, db::EdgePair>;
|
||||
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::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>;
|
||||
template class DB_PUBLIC local_processor<db::TextRef, db::PolygonRef, db::PolygonRef>;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -704,4 +704,22 @@ void EdgePairBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeReceiver (db::Layout *layout)
|
||||
: mp_layout (layout)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void TextBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target)
|
||||
{
|
||||
if (shape.is_text ()) {
|
||||
// NOTE: we intentionally skip all the text attributes (font etc.) here because in the context
|
||||
// of a text collections we're only interested in the locations.
|
||||
db::Text t (shape.text_string (), shape.text_trans ());
|
||||
target->insert (db::TextRef (t.transformed (trans), mp_layout->shape_repository ()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,6 +189,23 @@ public:
|
|||
virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An text-generating shape receiver that feeds a shapes array after turning the shapes into texts
|
||||
*/
|
||||
class DB_PUBLIC TextBuildingHierarchyBuilderShapeReceiver
|
||||
: public HierarchyBuilderShapeReceiver
|
||||
{
|
||||
public:
|
||||
TextBuildingHierarchyBuilderShapeReceiver (db::Layout *layout);
|
||||
|
||||
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
|
||||
virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A class building a hierarchy from a recursive shape iterator in push mode
|
||||
*
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@
|
|||
#include "dbLibraryManager.h"
|
||||
#include "dbLibrary.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbTexts.h"
|
||||
#include "tlTimer.h"
|
||||
#include "tlLog.h"
|
||||
#include "tlInternational.h"
|
||||
|
|
@ -661,6 +664,12 @@ Layout::insert (db::cell_index_type cell, int layer, const db::EdgePairs &edge_p
|
|||
edge_pairs.insert_into (this, cell, layer);
|
||||
}
|
||||
|
||||
void
|
||||
Layout::insert (db::cell_index_type cell, int layer, const db::Texts &texts)
|
||||
{
|
||||
texts.insert_into (this, cell, layer);
|
||||
}
|
||||
|
||||
void
|
||||
Layout::flatten (const db::Cell &source_cell, db::Cell &target_cell, const db::ICplxTrans &t, int levels)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ class LayerMapping;
|
|||
class Region;
|
||||
class Edges;
|
||||
class EdgePairs;
|
||||
class Texts;
|
||||
|
||||
template <class Coord> class generic_repository;
|
||||
typedef generic_repository<db::Coord> GenericRepository;
|
||||
|
|
@ -557,6 +558,14 @@ public:
|
|||
return m_string_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessor to the string repository (const version)
|
||||
*/
|
||||
const StringRepository &string_repository () const
|
||||
{
|
||||
return m_string_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessor to the shape repository
|
||||
*/
|
||||
|
|
@ -565,6 +574,14 @@ public:
|
|||
return m_shape_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessor to the shape repository (const version)
|
||||
*/
|
||||
const GenericRepository &shape_repository () const
|
||||
{
|
||||
return m_shape_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accessor to the properties repository
|
||||
*/
|
||||
|
|
@ -1123,6 +1140,15 @@ public:
|
|||
*/
|
||||
void insert (db::cell_index_type cell, int layer, const db::EdgePairs &edge_pairs);
|
||||
|
||||
/**
|
||||
* @brief Inserts a text collection (potentially hierarchical) into the given cell and layer
|
||||
*
|
||||
* If the text collection is flat (conceptionally), it will be put into the cell.
|
||||
* If the text collection is hierarchical, a cell hierarchy will be built below the
|
||||
* given cell.
|
||||
*/
|
||||
void insert (db::cell_index_type cell, int layer, const db::Texts &texts);
|
||||
|
||||
/**
|
||||
* @brief Delete a cell plus all subcells
|
||||
*
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "dbCommon.h"
|
||||
#include "dbLayoutToNetlist.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbDeepTexts.h"
|
||||
#include "dbShapeRepository.h"
|
||||
#include "dbCellMapping.h"
|
||||
#include "dbLayoutToNetlistWriter.h"
|
||||
|
|
@ -172,17 +173,17 @@ db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::st
|
|||
return region.release ();
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n)
|
||||
db::Texts *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n)
|
||||
{
|
||||
db::RecursiveShapeIterator si (m_iter);
|
||||
si.set_layer (layer_index);
|
||||
si.shape_flags (db::ShapeIterator::Texts);
|
||||
|
||||
std::auto_ptr <db::Region> region (new db::Region (si, dss ()));
|
||||
std::auto_ptr <db::Texts> texts (new db::Texts (si, dss ()));
|
||||
if (! n.empty ()) {
|
||||
register_layer (*region, n);
|
||||
register_layer (*texts, n);
|
||||
}
|
||||
return region.release ();
|
||||
return texts.release ();
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const std::string &n)
|
||||
|
|
@ -206,7 +207,7 @@ void LayoutToNetlist::link_nets (const db::Net *net, const db::Net *with)
|
|||
return;
|
||||
}
|
||||
|
||||
connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ());
|
||||
connected_clusters<db::NetShape> &clusters = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ());
|
||||
clusters.join_cluster_with (net->cluster_id (), with->cluster_id ());
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +222,7 @@ size_t LayoutToNetlist::link_net_to_parent_circuit (const Net *subcircuit_net, C
|
|||
db::CplxTrans dbu_trans (internal_layout ()->dbu ());
|
||||
db::ICplxTrans trans = dbu_trans.inverted () * dtrans * dbu_trans;
|
||||
|
||||
connected_clusters<db::PolygonRef> &parent_net_clusters = m_net_clusters.clusters_per_cell (parent_circuit->cell_index ());
|
||||
connected_clusters<db::NetShape> &parent_net_clusters = m_net_clusters.clusters_per_cell (parent_circuit->cell_index ());
|
||||
|
||||
size_t id = parent_net_clusters.insert_dummy ();
|
||||
|
||||
|
|
@ -236,7 +237,7 @@ void LayoutToNetlist::ensure_netlist ()
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::Region *> &layers)
|
||||
void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::ShapeCollection *> &layers)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
|
@ -262,7 +263,7 @@ void LayoutToNetlist::connect (const db::Region &l)
|
|||
m_conn.connect (dl.layer ());
|
||||
}
|
||||
|
||||
void LayoutToNetlist::connect (const db::Region &a, const db::Region &b)
|
||||
void LayoutToNetlist::connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
|
@ -283,7 +284,7 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b)
|
|||
m_conn.connect (dla.layer (), dlb.layer ());
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string &gn)
|
||||
void LayoutToNetlist::connect_global_impl (const db::ShapeCollection &l, const std::string &gn)
|
||||
{
|
||||
if (m_netlist_extracted) {
|
||||
throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted")));
|
||||
|
|
@ -296,7 +297,7 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string &
|
|||
db::DeepLayer dl = deep_layer_of (l);
|
||||
m_dlrefs.insert (dl);
|
||||
|
||||
return m_conn.connect_global (dl.layer (), gn);
|
||||
m_conn.connect_global (dl.layer (), gn);
|
||||
}
|
||||
|
||||
const std::string &LayoutToNetlist::global_net_name (size_t id) const
|
||||
|
|
@ -393,42 +394,6 @@ void LayoutToNetlist::ensure_layout () const
|
|||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::register_layer (const db::Region ®ion, const std::string &n)
|
||||
{
|
||||
if (m_named_regions.find (n) != m_named_regions.end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n);
|
||||
}
|
||||
|
||||
db::DeepLayer dl;
|
||||
|
||||
if (m_is_flat) {
|
||||
|
||||
dl = dss ().create_from_flat (region, true);
|
||||
|
||||
} else {
|
||||
|
||||
db::DeepRegion *delegate = dynamic_cast<db::DeepRegion *> (region.delegate());
|
||||
if (! delegate) {
|
||||
|
||||
dl = dss ().create_from_flat (region, true);
|
||||
|
||||
} else {
|
||||
|
||||
if (is_persisted (region)) {
|
||||
std::string prev_name = name (region);
|
||||
m_named_regions.erase (prev_name);
|
||||
}
|
||||
|
||||
dl = delegate->deep_layer ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_named_regions [n] = dl;
|
||||
m_name_of_layer [dl.layer ()] = n;
|
||||
}
|
||||
|
||||
std::string LayoutToNetlist::make_new_name (const std::string &stem)
|
||||
{
|
||||
int m = std::numeric_limits<int>::max () / 2 + 1;
|
||||
|
|
@ -452,16 +417,6 @@ std::string LayoutToNetlist::make_new_name (const std::string &stem)
|
|||
return name;
|
||||
}
|
||||
|
||||
std::string LayoutToNetlist::name (const db::Region ®ion) const
|
||||
{
|
||||
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (layer_of (region));
|
||||
if (n != m_name_of_layer.end ()) {
|
||||
return n->second;
|
||||
} else {
|
||||
return std::string ();
|
||||
}
|
||||
}
|
||||
|
||||
std::string LayoutToNetlist::name (unsigned int l) const
|
||||
{
|
||||
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (l);
|
||||
|
|
@ -472,11 +427,6 @@ std::string LayoutToNetlist::name (unsigned int l) const
|
|||
}
|
||||
}
|
||||
|
||||
bool LayoutToNetlist::is_persisted (const db::Region ®ion) const
|
||||
{
|
||||
return m_name_of_layer.find (layer_of (region)) != m_name_of_layer.end ();
|
||||
}
|
||||
|
||||
db::Region *LayoutToNetlist::layer_by_name (const std::string &name)
|
||||
{
|
||||
std::map<std::string, db::DeepLayer>::const_iterator l = m_named_regions.find (name);
|
||||
|
|
@ -497,12 +447,71 @@ db::Region *LayoutToNetlist::layer_by_index (unsigned int index)
|
|||
}
|
||||
}
|
||||
|
||||
db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) const
|
||||
static db::DeepLayer dss_create_from_flat (db::DeepShapeStore &dss, const db::ShapeCollection &coll)
|
||||
{
|
||||
const db::DeepRegion *dr = dynamic_cast<const db::DeepRegion *> (region.delegate ());
|
||||
const db::Region *region = dynamic_cast<const db::Region *> (&coll);
|
||||
const db::Texts *texts = dynamic_cast<const db::Texts *> (&coll);
|
||||
if (region) {
|
||||
return dss.create_from_flat (*region, true);
|
||||
} else if (texts) {
|
||||
return dss.create_from_flat (*texts);
|
||||
} else {
|
||||
tl_assert (false);
|
||||
}
|
||||
}
|
||||
|
||||
std::string LayoutToNetlist::name (const ShapeCollection &coll) const
|
||||
{
|
||||
std::map<unsigned int, std::string>::const_iterator n = m_name_of_layer.find (layer_of (coll));
|
||||
if (n != m_name_of_layer.end ()) {
|
||||
return n->second;
|
||||
} else {
|
||||
return std::string ();
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutToNetlist::register_layer (const ShapeCollection &collection, const std::string &n)
|
||||
{
|
||||
if (m_named_regions.find (n) != m_named_regions.end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n);
|
||||
}
|
||||
|
||||
db::DeepLayer dl;
|
||||
|
||||
if (m_is_flat) {
|
||||
|
||||
dl = dss_create_from_flat (dss (), collection);
|
||||
|
||||
} else {
|
||||
|
||||
db::DeepShapeCollectionDelegateBase *delegate = collection.get_delegate ()->deep ();
|
||||
if (! delegate) {
|
||||
|
||||
dl = dss_create_from_flat (dss (), collection);
|
||||
|
||||
} else {
|
||||
|
||||
if (is_persisted (collection)) {
|
||||
std::string prev_name = name (collection);
|
||||
m_named_regions.erase (prev_name);
|
||||
}
|
||||
|
||||
dl = delegate->deep_layer ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_named_regions [n] = dl;
|
||||
m_name_of_layer [dl.layer ()] = n;
|
||||
}
|
||||
|
||||
db::DeepLayer LayoutToNetlist::deep_layer_of (const db::ShapeCollection &coll) const
|
||||
{
|
||||
const db::DeepShapeCollectionDelegateBase *dr = coll.get_delegate ()->deep ();
|
||||
if (! dr) {
|
||||
|
||||
std::pair<bool, db::DeepLayer> lff = dss ().layer_for_flat (region);
|
||||
std::pair<bool, db::DeepLayer> lff = dss ().layer_for_flat (coll);
|
||||
if (lff.first) {
|
||||
return lff.second;
|
||||
} else {
|
||||
|
|
@ -514,11 +523,6 @@ db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) const
|
|||
}
|
||||
}
|
||||
|
||||
unsigned int LayoutToNetlist::layer_of (const db::Region ®ion) const
|
||||
{
|
||||
return deep_layer_of (region).layer ();
|
||||
}
|
||||
|
||||
db::CellMapping LayoutToNetlist::make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector<const db::Net *> *nets, bool with_device_cells)
|
||||
{
|
||||
std::set<db::cell_index_type> device_cells;
|
||||
|
|
@ -613,49 +617,84 @@ namespace
|
|||
}
|
||||
|
||||
template <class Tr>
|
||||
static bool deliver_shape (const db::PolygonRef &, StopOnFirst, const Tr &, db::properties_id_type)
|
||||
static bool deliver_shape (const db::NetShape &, StopOnFirst, const Tr &, db::properties_id_type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class Tr>
|
||||
static bool deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr, db::properties_id_type /*propid*/)
|
||||
static bool deliver_shape (const db::NetShape &s, db::Region ®ion, const Tr &tr, db::properties_id_type /*propid*/)
|
||||
{
|
||||
if (pr.obj ().is_box ()) {
|
||||
region.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr));
|
||||
} else {
|
||||
region.insert (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
if (s.type () == db::NetShape::Polygon) {
|
||||
|
||||
db::PolygonRef pr = s.polygon_ref ();
|
||||
|
||||
if (pr.obj ().is_box ()) {
|
||||
region.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr));
|
||||
} else {
|
||||
region.insert (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Tr>
|
||||
static bool deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const Tr &tr, db::properties_id_type propid)
|
||||
static bool deliver_shape (const db::NetShape &s, db::Shapes &shapes, const Tr &tr, db::properties_id_type propid)
|
||||
{
|
||||
if (pr.obj ().is_box ()) {
|
||||
if (propid) {
|
||||
shapes.insert (db::BoxWithProperties (pr.obj ().box ().transformed (pr.trans ()).transformed (tr), propid));
|
||||
if (s.type () == db::NetShape::Polygon) {
|
||||
|
||||
db::PolygonRef pr = s.polygon_ref ();
|
||||
|
||||
if (pr.obj ().is_box ()) {
|
||||
if (propid) {
|
||||
shapes.insert (db::BoxWithProperties (pr.obj ().box ().transformed (pr.trans ()).transformed (tr), propid));
|
||||
} else {
|
||||
shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr));
|
||||
}
|
||||
} else {
|
||||
shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr));
|
||||
db::Layout *layout = shapes.layout ();
|
||||
if (layout) {
|
||||
db::PolygonRef polygon_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ());
|
||||
if (propid) {
|
||||
shapes.insert (db::PolygonRefWithProperties (polygon_ref, propid));
|
||||
} else {
|
||||
shapes.insert (polygon_ref);
|
||||
}
|
||||
} else {
|
||||
db::Polygon polygon (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
if (propid) {
|
||||
shapes.insert (db::PolygonWithProperties (polygon, propid));
|
||||
} else {
|
||||
shapes.insert (polygon);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
} else if (s.type () == db::NetShape::Text) {
|
||||
|
||||
db::TextRef pr = s.text_ref ();
|
||||
|
||||
db::Layout *layout = shapes.layout ();
|
||||
if (layout) {
|
||||
db::PolygonRef polygon_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ());
|
||||
db::TextRef text_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ());
|
||||
if (propid) {
|
||||
shapes.insert (db::PolygonRefWithProperties (polygon_ref, propid));
|
||||
shapes.insert (db::TextRefWithProperties (text_ref, propid));
|
||||
} else {
|
||||
shapes.insert (polygon_ref);
|
||||
shapes.insert (text_ref);
|
||||
}
|
||||
} else {
|
||||
db::Polygon polygon (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
db::Text text (pr.obj ().transformed (pr.trans ()).transformed (tr));
|
||||
if (propid) {
|
||||
shapes.insert (db::PolygonWithProperties (polygon, propid));
|
||||
shapes.insert (db::TextWithProperties (text, propid));
|
||||
} else {
|
||||
shapes.insert (polygon);
|
||||
shapes.insert (text);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -759,7 +798,7 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &
|
|||
|
||||
if (net_cell_name_prefix) {
|
||||
|
||||
const db::connected_clusters<db::PolygonRef> &ccl = m_net_clusters.clusters_per_cell (ci);
|
||||
const db::connected_clusters<db::NetShape> &ccl = m_net_clusters.clusters_per_cell (ci);
|
||||
|
||||
bool any_connections = circuit_cell_name_prefix && ! ccl.connections_for_cluster (cid).empty ();
|
||||
if (! any_connections) {
|
||||
|
|
@ -805,8 +844,8 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &
|
|||
db::ICplxTrans tr_wo_mag = tr * db::ICplxTrans (1.0 / tr.mag ());
|
||||
db::ICplxTrans tr_mag (tr.mag ());
|
||||
|
||||
const db::connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (ci);
|
||||
typedef db::connected_clusters<db::PolygonRef>::connections_type connections_type;
|
||||
const db::connected_clusters<db::NetShape> &clusters = m_net_clusters.clusters_per_cell (ci);
|
||||
typedef db::connected_clusters<db::NetShape>::connections_type connections_type;
|
||||
const connections_type &connections = clusters.connections_for_cluster (cid);
|
||||
for (connections_type::const_iterator c = connections.begin (); c != connections.end (); ++c) {
|
||||
|
||||
|
|
@ -1007,13 +1046,13 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoi
|
|||
return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point);
|
||||
}
|
||||
|
||||
size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::PolygonRef> &test_cluster, std::vector<db::InstElement> &rev_inst_path)
|
||||
size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::NetShape> &test_cluster, std::vector<db::InstElement> &rev_inst_path)
|
||||
{
|
||||
db::Box local_box = trans * test_cluster.bbox ();
|
||||
|
||||
const db::local_clusters<db::PolygonRef> &lcc = net_clusters ().clusters_per_cell (cell->cell_index ());
|
||||
for (db::local_clusters<db::PolygonRef>::touching_iterator i = lcc.begin_touching (local_box); ! i.at_end (); ++i) {
|
||||
const db::local_cluster<db::PolygonRef> &lc = *i;
|
||||
const db::local_clusters<db::NetShape> &lcc = net_clusters ().clusters_per_cell (cell->cell_index ());
|
||||
for (db::local_clusters<db::NetShape>::touching_iterator i = lcc.begin_touching (local_box); ! i.at_end (); ++i) {
|
||||
const db::local_cluster<db::NetShape> &lc = *i;
|
||||
if (lc.interacts (test_cluster, trans, m_conn)) {
|
||||
return lc.id ();
|
||||
}
|
||||
|
|
@ -1053,7 +1092,7 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin
|
|||
// Prepare a test cluster
|
||||
db::Box box (point - db::Vector (1, 1), point + db::Vector (1, 1));
|
||||
db::GenericRepository sr;
|
||||
db::local_cluster<db::PolygonRef> test_cluster;
|
||||
db::local_cluster<db::NetShape> test_cluster;
|
||||
test_cluster.add (db::PolygonRef (db::Polygon (box), sr), layer);
|
||||
|
||||
std::vector<db::InstElement> inst_path;
|
||||
|
|
@ -1155,12 +1194,12 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg
|
|||
|
||||
for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) {
|
||||
|
||||
const connected_clusters<db::PolygonRef> &clusters = m_net_clusters.clusters_per_cell (*cid);
|
||||
const connected_clusters<db::NetShape> &clusters = m_net_clusters.clusters_per_cell (*cid);
|
||||
if (clusters.empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (connected_clusters<db::PolygonRef>::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
for (connected_clusters<db::NetShape>::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
if (! clusters.is_root (*c)) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -240,13 +240,13 @@ public:
|
|||
* derived by boolean operations for example.
|
||||
* Named regions are persisted inside the LayoutToNetlist object.
|
||||
*/
|
||||
void register_layer (const db::Region ®ion, const std::string &name);
|
||||
void register_layer (const ShapeCollection &collection, const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Gets the name of the given region
|
||||
* Returns an empty string if the region does not have a name.
|
||||
* @brief Gets the name of the given collection
|
||||
* Returns an empty string if the collection does not have a name.
|
||||
*/
|
||||
std::string name (const db::Region ®ion) const;
|
||||
std::string name (const ShapeCollection &coll) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the name of the given layer by index
|
||||
|
|
@ -272,7 +272,11 @@ public:
|
|||
* Persisted regions have a name and are kept inside the LayoutToNetlist
|
||||
* object.
|
||||
*/
|
||||
bool is_persisted (const db::Region ®ion) const;
|
||||
template <class Collection>
|
||||
bool is_persisted (const Collection &coll) const
|
||||
{
|
||||
return m_name_of_layer.find (layer_of (coll)) != m_name_of_layer.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the region (layer) with the given name
|
||||
|
|
@ -329,10 +333,10 @@ public:
|
|||
db::Region *make_layer (unsigned int layer_index, const std::string &name = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Creates a new region representing an original layer taking texts only
|
||||
* @brief Creates a new text collection representing an original layer taking texts only
|
||||
* See "make_layer" for details.
|
||||
*/
|
||||
db::Region *make_text_layer (unsigned int layer_index, const std::string &name = std::string ());
|
||||
db::Texts *make_text_layer (unsigned int layer_index, const std::string &name = std::string ());
|
||||
|
||||
/**
|
||||
* @brief Creates a new region representing an original layer taking polygons and texts
|
||||
|
|
@ -346,13 +350,13 @@ public:
|
|||
* This method will run device extraction for the given extractor. The layer map is specific
|
||||
* for the extractor and uses the region objects derived with "make_layer" and it's variants.
|
||||
*
|
||||
* In addition, derived regions can be passed too. Certain limitations apply. It's safe to use
|
||||
* In addition, derived regions/text collections can be passed too. Certain limitations apply. It's safe to use
|
||||
* boolean operations for deriving layers. Other operations are applicable as long as they are
|
||||
* capable of delivering hierarchical layers.
|
||||
*
|
||||
* If errors occur, the device extractor will contain theses errors.
|
||||
*/
|
||||
void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::Region *> &layers);
|
||||
void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map<std::string, db::ShapeCollection *> &layers);
|
||||
|
||||
/**
|
||||
* @brief Defines an intra-layer connection for the given layer.
|
||||
|
|
@ -367,13 +371,46 @@ public:
|
|||
* @brief Defines an inter-layer connection for the given layers.
|
||||
* The conditions mentioned with intra-layer "connect" apply for this method too.
|
||||
*/
|
||||
void connect (const db::Region &a, const db::Region &b);
|
||||
void connect (const db::Region &a, const db::Region &b)
|
||||
{
|
||||
connect_impl (a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Defines an inter-layer connection for the given layers.
|
||||
* As one layer is a texts layer, this connection will basically add net labels.
|
||||
*/
|
||||
void connect (const db::Region &a, const db::Texts &b)
|
||||
{
|
||||
connect_impl (a, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Defines an inter-layer connection for the given layers.
|
||||
* As one layer is a texts layer, this connection will basically add net labels.
|
||||
*/
|
||||
void connect (const db::Texts &a, const db::Region &b)
|
||||
{
|
||||
connect_impl (b, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects the given layer with a global net with the given name
|
||||
* Returns the global net ID
|
||||
*/
|
||||
size_t connect_global (const db::Region &l, const std::string &gn);
|
||||
void connect_global (const db::Region &l, const std::string &gn)
|
||||
{
|
||||
connect_global_impl (l, gn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Connects the given text layer with a global net with the given name
|
||||
* Returns the global net ID
|
||||
*/
|
||||
void connect_global (const db::Texts &l, const std::string &gn)
|
||||
{
|
||||
connect_global_impl (l, gn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the global net name for a given global net ID
|
||||
|
|
@ -470,7 +507,11 @@ public:
|
|||
* This method is required to derive the internal layer index - for example for
|
||||
* investigating the cluster tree.
|
||||
*/
|
||||
unsigned int layer_of (const db::Region ®ion) const;
|
||||
template <class Collection>
|
||||
unsigned int layer_of (const Collection &coll) const
|
||||
{
|
||||
return deep_layer_of (coll).layer ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a cell mapping for copying shapes from the internal layout to the given target layout.
|
||||
|
|
@ -522,7 +563,7 @@ public:
|
|||
* NOTE: the layer and cell indexes used inside this structure refer to the
|
||||
* internal layout.
|
||||
*/
|
||||
const db::hier_clusters<db::PolygonRef> &net_clusters () const
|
||||
const db::hier_clusters<db::NetShape> &net_clusters () const
|
||||
{
|
||||
return m_net_clusters;
|
||||
}
|
||||
|
|
@ -530,7 +571,7 @@ public:
|
|||
/**
|
||||
* @brief Gets the hierarchical shape clusters derived in the net extraction (non-conver version)
|
||||
*/
|
||||
db::hier_clusters<db::PolygonRef> &net_clusters ()
|
||||
db::hier_clusters<db::NetShape> &net_clusters ()
|
||||
{
|
||||
return m_net_clusters;
|
||||
}
|
||||
|
|
@ -744,7 +785,7 @@ private:
|
|||
tl::weak_ptr<db::DeepShapeStore> mp_dss;
|
||||
unsigned int m_layout_index;
|
||||
db::Connectivity m_conn;
|
||||
db::hier_clusters<db::PolygonRef> m_net_clusters;
|
||||
db::hier_clusters<db::NetShape> m_net_clusters;
|
||||
std::auto_ptr<db::Netlist> mp_netlist;
|
||||
std::set<db::DeepLayer> m_dlrefs;
|
||||
std::map<std::string, db::DeepLayer> m_named_regions;
|
||||
|
|
@ -786,15 +827,17 @@ private:
|
|||
|
||||
void init ();
|
||||
void ensure_netlist ();
|
||||
size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<db::PolygonRef> &test_cluster, std::vector<db::InstElement> &rev_inst_path);
|
||||
size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster<NetShape> &test_cluster, std::vector<db::InstElement> &rev_inst_path);
|
||||
void build_net_rec (const db::Net &net, db::Layout &target, cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map<unsigned int, const db::Region *> &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const;
|
||||
void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map<unsigned int, const db::Region *> &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const;
|
||||
void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map<unsigned int, const db::Region *> &lmap, const Net *net, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const;
|
||||
db::DeepLayer deep_layer_of (const db::Region ®ion) const;
|
||||
db::DeepLayer deep_layer_of (const ShapeCollection &coll) const;
|
||||
void ensure_layout () const;
|
||||
std::string make_new_name (const std::string &stem = std::string ());
|
||||
db::properties_id_type make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const;
|
||||
db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector<const db::Net *> *nets, bool with_device_cells);
|
||||
void connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b);
|
||||
void connect_global_impl (const db::ShapeCollection &l, const std::string &gn);
|
||||
|
||||
// implementation of NetlistManipulationCallbacks
|
||||
virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string LongKeys::device_key ("device");
|
||||
DB_PUBLIC std::string LongKeys::polygon_key ("polygon");
|
||||
DB_PUBLIC std::string LongKeys::rect_key ("rect");
|
||||
DB_PUBLIC std::string LongKeys::text_key ("text");
|
||||
DB_PUBLIC std::string LongKeys::terminal_key ("terminal");
|
||||
DB_PUBLIC std::string LongKeys::abstract_key ("abstract");
|
||||
DB_PUBLIC std::string LongKeys::param_key ("param");
|
||||
|
|
@ -56,7 +57,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string LongKeys::scale_key ("scale");
|
||||
DB_PUBLIC std::string LongKeys::pin_key ("pin");
|
||||
|
||||
// A, B, C, D, E, F, G, I, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
|
||||
// A, B, C, D, E, F, G, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y
|
||||
DB_PUBLIC std::string ShortKeys::version_key ("V");
|
||||
DB_PUBLIC std::string ShortKeys::description_key ("B");
|
||||
DB_PUBLIC std::string ShortKeys::top_key ("W");
|
||||
|
|
@ -72,6 +73,7 @@ namespace l2n_std_format
|
|||
DB_PUBLIC std::string ShortKeys::device_key ("D");
|
||||
DB_PUBLIC std::string ShortKeys::polygon_key ("Q");
|
||||
DB_PUBLIC std::string ShortKeys::rect_key ("R");
|
||||
DB_PUBLIC std::string ShortKeys::text_key ("J");
|
||||
DB_PUBLIC std::string ShortKeys::terminal_key ("T");
|
||||
DB_PUBLIC std::string ShortKeys::abstract_key ("A");
|
||||
DB_PUBLIC std::string ShortKeys::param_key ("E");
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ namespace db
|
|||
* "*" for <x> or <y> means take previous
|
||||
* rect(<layer> [coord] [coord]) - defines a rectangle [short key: R]
|
||||
* coordinates are bottom/left and top/right
|
||||
* text(<layer> [text] [coord]) - defines a rectangle [short key: J]
|
||||
*
|
||||
* [coord]
|
||||
*
|
||||
|
|
@ -177,6 +178,7 @@ namespace l2n_std_format
|
|||
static std::string subcircuit_key;
|
||||
static std::string polygon_key;
|
||||
static std::string rect_key;
|
||||
static std::string text_key;
|
||||
static std::string terminal_key;
|
||||
static std::string abstract_key;
|
||||
static std::string param_key;
|
||||
|
|
@ -209,6 +211,7 @@ namespace l2n_std_format
|
|||
static std::string subcircuit_key;
|
||||
static std::string polygon_key;
|
||||
static std::string rect_key;
|
||||
static std::string text_key;
|
||||
static std::string terminal_key;
|
||||
static std::string abstract_key;
|
||||
static std::string param_key;
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ LayoutToNetlistStandardReader::skip ()
|
|||
|
||||
void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n)
|
||||
{
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read")));
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_path);
|
||||
|
||||
try {
|
||||
read_netlist (0, l2n);
|
||||
|
|
@ -445,8 +445,7 @@ LayoutToNetlistStandardReader::read_property (db::NetlistObject *obj)
|
|||
br.done ();
|
||||
}
|
||||
|
||||
std::pair<unsigned int, db::PolygonRef>
|
||||
LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n)
|
||||
std::pair<unsigned int, NetShape> LayoutToNetlistStandardReader::read_geometry(db::LayoutToNetlist *l2n)
|
||||
{
|
||||
std::string lname;
|
||||
|
||||
|
|
@ -482,6 +481,22 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n)
|
|||
poly.assign_hull (pt.begin (), pt.end ());
|
||||
return std::make_pair (lid, db::PolygonRef (poly, l2n->internal_layout ()->shape_repository ()));
|
||||
|
||||
} else if (test (skeys::text_key) || test (lkeys::text_key)) {
|
||||
|
||||
Brace br (this);
|
||||
|
||||
read_word_or_quoted (lname);
|
||||
unsigned int lid = l2n->layer_of (layer_by_name (l2n, lname));
|
||||
|
||||
std::string text;
|
||||
read_word_or_quoted (text);
|
||||
|
||||
db::Point pt = read_point ();
|
||||
|
||||
br.done ();
|
||||
|
||||
return std::make_pair (lid, db::TextRef (db::Text (text, db::Trans (pt - db::Point ())), l2n->internal_layout ()->shape_repository ()));
|
||||
|
||||
} else if (at_end ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Unexpected end of file (polygon or rect expected)")));
|
||||
} else {
|
||||
|
|
@ -524,7 +539,7 @@ LayoutToNetlistStandardReader::read_polygon ()
|
|||
}
|
||||
|
||||
void
|
||||
LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell)
|
||||
LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::NetShape> &lc, db::Cell &cell)
|
||||
{
|
||||
m_ref = db::Point ();
|
||||
|
||||
|
|
@ -532,9 +547,9 @@ LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &b
|
|||
if (test (skeys::property_key) || test (lkeys::property_key)) {
|
||||
read_property (obj);
|
||||
} else {
|
||||
std::pair<unsigned int, db::PolygonRef> pr = read_geometry (l2n);
|
||||
std::pair<unsigned int, db::NetShape> pr = read_geometry (l2n);
|
||||
lc.add (pr.second, pr.first);
|
||||
cell.shapes (pr.first).insert (pr.second);
|
||||
pr.second.insert_into (cell.shapes (pr.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -561,8 +576,8 @@ LayoutToNetlistStandardReader::read_net (db::Netlist * /*netlist*/, db::LayoutTo
|
|||
|
||||
if (l2n) {
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
db::connected_clusters<db::NetShape> &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ());
|
||||
db::local_cluster<db::NetShape> &lc = *cc.insert ();
|
||||
net->set_cluster_id (lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ());
|
||||
|
|
@ -1025,8 +1040,8 @@ LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n,
|
|||
|
||||
if (l2n) {
|
||||
|
||||
db::connected_clusters<db::PolygonRef> &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ());
|
||||
db::local_cluster<db::PolygonRef> &lc = *cc.insert ();
|
||||
db::connected_clusters<db::NetShape> &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ());
|
||||
db::local_cluster<db::NetShape> &lc = *cc.insert ();
|
||||
dm->set_cluster_id_for_terminal (tid, lc.id ());
|
||||
|
||||
db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ());
|
||||
|
|
|
|||
|
|
@ -139,11 +139,11 @@ protected:
|
|||
void read_subcircuit (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map<db::CellInstArray, std::list<Connections> > &connections);
|
||||
bool read_trans_part (db::DCplxTrans &tr);
|
||||
void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceAbstract *dm, db::DeviceClass *dc);
|
||||
std::pair<unsigned int, db::PolygonRef> read_geometry (db::LayoutToNetlist *l2n);
|
||||
std::pair<unsigned int, db::NetShape> read_geometry(db::LayoutToNetlist *l2n);
|
||||
void read_property (db::NetlistObject *obj);
|
||||
db::Polygon read_polygon ();
|
||||
db::Box read_rect ();
|
||||
void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<db::PolygonRef> &lc, db::Cell &cell);
|
||||
void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster<NetShape> &lc, db::Cell &cell);
|
||||
db::Point read_point ();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -397,30 +397,49 @@ void std_writer_impl<Keys>::reset_geometry_ref ()
|
|||
}
|
||||
|
||||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative)
|
||||
void std_writer_impl<Keys>::write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative)
|
||||
{
|
||||
db::ICplxTrans t = tr * db::ICplxTrans (s->trans ());
|
||||
if (s->type () == db::NetShape::Polygon) {
|
||||
|
||||
const db::Polygon &poly = s->obj ();
|
||||
if (poly.is_box ()) {
|
||||
db::PolygonRef pr = s->polygon_ref ();
|
||||
db::ICplxTrans t = tr * db::ICplxTrans (pr.trans ());
|
||||
|
||||
db::Box box = t * poly.box ();
|
||||
*mp_stream << Keys::rect_key << "(" << lname;
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p1 (), m_ref, relative);
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p2 (), m_ref, relative);
|
||||
*mp_stream << ")";
|
||||
const db::Polygon &poly = pr.obj ();
|
||||
if (poly.is_box ()) {
|
||||
|
||||
} else {
|
||||
db::Box box = t * poly.box ();
|
||||
*mp_stream << Keys::rect_key << "(" << lname;
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p1 (), m_ref, relative);
|
||||
*mp_stream << " ";
|
||||
write_point (*mp_stream, box.p2 (), m_ref, relative);
|
||||
*mp_stream << ")";
|
||||
|
||||
*mp_stream << Keys::polygon_key << "(" << lname;
|
||||
if (poly.holes () > 0) {
|
||||
db::SimplePolygon sp = db::polygon_to_simple_polygon (poly);
|
||||
write_points (*mp_stream, sp, t, m_ref, relative);
|
||||
} else {
|
||||
write_points (*mp_stream, poly, t, m_ref, relative);
|
||||
|
||||
*mp_stream << Keys::polygon_key << "(" << lname;
|
||||
if (poly.holes () > 0) {
|
||||
db::SimplePolygon sp = db::polygon_to_simple_polygon (poly);
|
||||
write_points (*mp_stream, sp, t, m_ref, relative);
|
||||
} else {
|
||||
write_points (*mp_stream, poly, t, m_ref, relative);
|
||||
}
|
||||
*mp_stream << ")";
|
||||
|
||||
}
|
||||
|
||||
} else if (s->type () == db::NetShape::Text) {
|
||||
|
||||
*mp_stream << Keys::text_key << "(" << lname;
|
||||
|
||||
db::TextRef txtr = s->text_ref ();
|
||||
db::ICplxTrans t = tr * db::ICplxTrans (txtr.trans ());
|
||||
|
||||
*mp_stream << " " << tl::to_word_or_quoted_string (txtr.obj ().string ()) << " ";
|
||||
|
||||
db::Point pt = t * (db::Point () + txtr.obj ().trans ().disp ());
|
||||
write_point (*mp_stream, pt, m_ref, relative);
|
||||
|
||||
*mp_stream << ")";
|
||||
|
||||
}
|
||||
|
|
@ -435,7 +454,7 @@ bool std_writer_impl<Keys>::new_cell (cell_index_type ci) const
|
|||
template <class Keys>
|
||||
void std_writer_impl<Keys>::write (const db::Net &net, unsigned int id, const std::string &indent)
|
||||
{
|
||||
const db::hier_clusters<db::PolygonRef> &clusters = mp_l2n->net_clusters ();
|
||||
const db::hier_clusters<db::NetShape> &clusters = mp_l2n->net_clusters ();
|
||||
const db::Circuit *circuit = net.circuit ();
|
||||
const db::Connectivity &conn = mp_l2n->connectivity ();
|
||||
|
||||
|
|
@ -450,7 +469,7 @@ void std_writer_impl<Keys>::write (const db::Net &net, unsigned int id, const st
|
|||
db::cell_index_type cci = circuit->cell_index ();
|
||||
db::cell_index_type prev_ci = cci;
|
||||
|
||||
for (db::recursive_cluster_shape_iterator<db::PolygonRef> si (clusters, *l, cci, net.cluster_id (), this); ! si.at_end (); ) {
|
||||
for (db::recursive_cluster_shape_iterator<db::NetShape> si (clusters, *l, cci, net.cluster_id (), this); ! si.at_end (); ) {
|
||||
|
||||
// NOTE: we don't recursive into circuits which will later be output. However, as circuits may
|
||||
// vanish in "purge" but the clusters will still be there we need to recursive into clusters from
|
||||
|
|
@ -570,7 +589,7 @@ void std_writer_impl<Keys>::write (const db::DeviceAbstract &device_abstract, co
|
|||
{
|
||||
const std::vector<db::DeviceTerminalDefinition> &td = device_abstract.device_class ()->terminal_definitions ();
|
||||
|
||||
const db::hier_clusters<db::PolygonRef> &clusters = mp_l2n->net_clusters ();
|
||||
const db::hier_clusters<db::NetShape> &clusters = mp_l2n->net_clusters ();
|
||||
const db::Connectivity &conn = mp_l2n->connectivity ();
|
||||
|
||||
for (std::vector<db::DeviceTerminalDefinition>::const_iterator t = td.begin (); t != td.end (); ++t) {
|
||||
|
|
@ -587,8 +606,8 @@ void std_writer_impl<Keys>::write (const db::DeviceAbstract &device_abstract, co
|
|||
continue;
|
||||
}
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid);
|
||||
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
|
||||
const db::local_cluster<db::NetShape> &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid);
|
||||
for (db::local_cluster<db::NetShape>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
|
||||
|
||||
*mp_stream << indent << indent2;
|
||||
write (s.operator-> (), db::ICplxTrans (), name_for_layer (mp_l2n, *l), true);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class DeviceAbstract;
|
|||
class Net;
|
||||
class Netlist;
|
||||
class LayoutToNetlist;
|
||||
class NetShape;
|
||||
|
||||
namespace l2n_std_format
|
||||
{
|
||||
|
|
@ -75,7 +76,7 @@ private:
|
|||
void write (const db::SubCircuit &subcircuit, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
|
||||
void write (const db::Device &device, std::map<const Net *, unsigned int> &net2id, const std::string &indent);
|
||||
void write (const db::DeviceAbstract &device_abstract, const std::string &indent);
|
||||
void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
|
||||
void write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative);
|
||||
void write (const db::DCplxTrans &trans);
|
||||
void reset_geometry_ref ();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbNetShape.h"
|
||||
#include "dbShapes.h"
|
||||
#include "dbPolygonTools.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
NetShape::NetShape ()
|
||||
: m_ptr (0), m_dx (0), m_dy (0)
|
||||
{ }
|
||||
|
||||
NetShape::NetShape (const db::PolygonRef &pr)
|
||||
{
|
||||
m_ptr = size_t (&pr.obj ()) + 1;
|
||||
m_dx = pr.trans ().disp ().x ();
|
||||
m_dy = pr.trans ().disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::NetShape (const db::Polygon &poly, db::GenericRepository &repo)
|
||||
{
|
||||
db::PolygonRef pr (poly, repo);
|
||||
m_ptr = size_t (&pr.obj ()) + 1;
|
||||
m_dx = pr.trans ().disp ().x ();
|
||||
m_dy = pr.trans ().disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::NetShape (const db::TextRef &tr)
|
||||
{
|
||||
m_ptr = size_t (&tr.obj ());
|
||||
m_dx = tr.trans ().disp ().x ();
|
||||
m_dy = tr.trans ().disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::NetShape (const db::Text &text, db::GenericRepository &repo)
|
||||
{
|
||||
db::TextRef tr (text, repo);
|
||||
m_ptr = size_t (&tr.obj ());
|
||||
m_dx = tr.trans ().disp ().x ();
|
||||
m_dy = tr.trans ().disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::shape_type NetShape::type () const
|
||||
{
|
||||
if (m_ptr == 0) {
|
||||
return None;
|
||||
} else if ((m_ptr & 1) != 0) {
|
||||
return Polygon;
|
||||
} else {
|
||||
return Text;
|
||||
}
|
||||
}
|
||||
|
||||
db::PolygonRef NetShape::polygon_ref () const
|
||||
{
|
||||
if ((size_t (m_ptr) & 1) != 0) {
|
||||
return db::PolygonRef (reinterpret_cast<db::Polygon *> (m_ptr - 1), db::Disp (db::Vector (m_dx, m_dy)));
|
||||
}
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
db::TextRef NetShape::text_ref () const
|
||||
{
|
||||
if ((size_t (m_ptr) & 1) == 0) {
|
||||
return db::TextRef (reinterpret_cast<db::Text *> (m_ptr), db::Disp (db::Vector (m_dx, m_dy)));
|
||||
}
|
||||
tl_assert (false);
|
||||
}
|
||||
|
||||
void NetShape::transform (const db::Disp &tr)
|
||||
{
|
||||
m_dx += tr.disp ().x ();
|
||||
m_dy += tr.disp ().y ();
|
||||
}
|
||||
|
||||
NetShape::box_type NetShape::bbox () const
|
||||
{
|
||||
if ((m_ptr & 1) != 0) {
|
||||
return polygon_ref ().box ();
|
||||
} else if (m_ptr != 0) {
|
||||
return text_ref ().box ();
|
||||
} else {
|
||||
return box_type ();
|
||||
}
|
||||
}
|
||||
|
||||
void NetShape::insert_into (db::Shapes &shapes) const
|
||||
{
|
||||
if ((m_ptr & 1) != 0) {
|
||||
shapes.insert (polygon_ref ());
|
||||
} else if (m_ptr != 0) {
|
||||
shapes.insert (text_ref ());
|
||||
}
|
||||
}
|
||||
|
||||
void NetShape::insert_into (db::Shapes &shapes, db::properties_id_type pi) const
|
||||
{
|
||||
if ((m_ptr & 1) != 0) {
|
||||
shapes.insert (db::PolygonRefWithProperties (polygon_ref (), pi));
|
||||
} else if (m_ptr != 0) {
|
||||
shapes.insert (db::TextRefWithProperties (text_ref (), pi));
|
||||
}
|
||||
}
|
||||
|
||||
bool NetShape::interacts_with (const db::NetShape &other) const
|
||||
{
|
||||
if (m_ptr == 0 || other.m_ptr == 0 || ! bbox ().touches (other.bbox ())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_ptr & 1) != 0) {
|
||||
|
||||
if ((other.m_ptr & 1) != 0) {
|
||||
|
||||
// Polygon vs. polygon
|
||||
db::PolygonRef pr_other = other.polygon_ref ();
|
||||
db::PolygonRef pr = polygon_ref ();
|
||||
db::Polygon p = pr_other.obj ().transformed (pr.trans ().inverted () * pr_other.trans ());
|
||||
return db::interact_pp (pr.obj (), p);
|
||||
|
||||
} else {
|
||||
|
||||
// NOTE: we assume that the text ref's target is at 0,0
|
||||
db::PolygonRef pr = polygon_ref ();
|
||||
db::Point pt = db::Point (other.m_dx, other.m_dy) - pr.trans ().disp ();
|
||||
return db::inside_poly (pr.obj ().begin_edge (), pt) >= 0;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ((other.m_ptr & 1) == 0) {
|
||||
|
||||
// Text vs. text
|
||||
return m_dx == other.m_dx && m_dy == other.m_dy;
|
||||
|
||||
} else {
|
||||
|
||||
// NOTE: we assume that the text ref's target is at 0,0
|
||||
db::PolygonRef pr_other = other.polygon_ref ();
|
||||
db::Point pt = db::Point (m_dx, m_dy) - pr_other.trans ().disp ();
|
||||
return db::inside_poly (pr_other.obj ().begin_edge (), pt) >= 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Tr>
|
||||
bool NetShape::interacts_with_transformed (const db::NetShape &other, const Tr &trans) const
|
||||
{
|
||||
if (m_ptr == 0 || other.m_ptr == 0 || ! bbox ().touches (other.bbox ().transformed (trans))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_ptr & 1) != 0) {
|
||||
|
||||
if ((other.m_ptr & 1) != 0) {
|
||||
|
||||
// Polygon vs. polygon
|
||||
db::PolygonRef pr_other = other.polygon_ref ();
|
||||
db::PolygonRef pr = polygon_ref ();
|
||||
db::Polygon p = pr_other.obj ().transformed (Tr (pr.trans ().inverted ()) * trans * Tr (pr_other.trans ()));
|
||||
return db::interact_pp (pr.obj (), p);
|
||||
|
||||
} else {
|
||||
|
||||
// NOTE: we assume that the text ref's target is at 0,0
|
||||
db::PolygonRef pr = polygon_ref ();
|
||||
db::Point pt = trans * db::Point (other.m_dx, other.m_dy) - pr.trans ().disp ();
|
||||
return db::inside_poly (pr.obj ().begin_edge (), pt) >= 0;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ((other.m_ptr & 1) == 0) {
|
||||
|
||||
// Text vs. text
|
||||
db::Point pt = trans * db::Point (other.m_dx, other.m_dy);
|
||||
return db::Point (m_dx, m_dy) == pt;
|
||||
|
||||
} else {
|
||||
|
||||
// NOTE: we assume that the text ref's target is at 0,0
|
||||
db::PolygonRef pr_other = other.polygon_ref ();
|
||||
db::Point pt = trans.inverted () * db::Point (m_dx, m_dy) - pr_other.trans ().disp ();
|
||||
return db::inside_poly (pr_other.obj ().begin_edge (), pt) >= 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template bool NetShape::interacts_with_transformed<db::ICplxTrans> (const db::NetShape &other, const db::ICplxTrans &trans) const;
|
||||
template bool NetShape::interacts_with_transformed<db::Trans> (const db::NetShape &other, const db::Trans &trans) const;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbNetShape
|
||||
#define HDR_dbNetShape
|
||||
|
||||
#include "dbPolygon.h"
|
||||
#include "dbText.h"
|
||||
#include "dbShapeRepository.h"
|
||||
#include "dbBoxConvert.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
class Shapes;
|
||||
|
||||
/**
|
||||
* @brief Provides a union of a PolygonRef and a TextRef
|
||||
*
|
||||
* This object is used in the netlist extractor and represents either a polygon or a text.
|
||||
* The TextRef shall utilize a StringRef to represent the string.
|
||||
*/
|
||||
class DB_PUBLIC NetShape
|
||||
{
|
||||
public:
|
||||
enum shape_type { None, Text, Polygon };
|
||||
|
||||
typedef db::Point point_type;
|
||||
typedef db::Box box_type;
|
||||
typedef db::Coord coord_type;
|
||||
typedef db::Disp trans_type;
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
NetShape ();
|
||||
|
||||
/**
|
||||
* @brief A NetShape object representing a PolygonRef
|
||||
*/
|
||||
NetShape (const db::PolygonRef &pr);
|
||||
|
||||
/**
|
||||
* @brief A NetShape object representing a Polygon from the given shape repository
|
||||
*/
|
||||
NetShape (const db::Polygon &poly, db::GenericRepository &repo);
|
||||
|
||||
/**
|
||||
* @brief A NetShape object representing a TextRef
|
||||
*/
|
||||
NetShape (const db::TextRef &tr);
|
||||
|
||||
/**
|
||||
* @brief A NetShape object representing a Text from the given shape repository
|
||||
*/
|
||||
NetShape (const db::Text &text, db::GenericRepository &repo);
|
||||
|
||||
/**
|
||||
* @brief Gets a code indicating the type of object stored herein
|
||||
*/
|
||||
shape_type type () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the PolygonRef object
|
||||
* Asserts if the object stored is not a polygon.
|
||||
*/
|
||||
db::PolygonRef polygon_ref () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the TextRef object
|
||||
* Asserts if the object stored is not a text.
|
||||
*/
|
||||
db::TextRef text_ref () const;
|
||||
|
||||
/**
|
||||
* @brief In-place transformation
|
||||
*/
|
||||
void transform (const db::Disp &tr);
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (const NetShape &net_shape) const
|
||||
{
|
||||
return m_ptr == net_shape.m_ptr && m_dx == net_shape.m_dx && m_dy == net_shape.m_dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (const NetShape &net_shape) const
|
||||
{
|
||||
return ! operator== (net_shape);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Less operator
|
||||
*/
|
||||
bool operator< (const NetShape &net_shape) const
|
||||
{
|
||||
if (m_ptr != net_shape.m_ptr) {
|
||||
return m_ptr < net_shape.m_ptr;
|
||||
}
|
||||
if (m_dx != net_shape.m_dx) {
|
||||
return m_dx < net_shape.m_dx;
|
||||
}
|
||||
return m_dy < net_shape.m_dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the bounding box of the object
|
||||
*/
|
||||
box_type bbox () const;
|
||||
|
||||
/**
|
||||
* @brief Inserts the object into a Shapes collection
|
||||
*/
|
||||
void insert_into (db::Shapes &shapes) const;
|
||||
|
||||
/**
|
||||
* @brief Inserts the object into a Shapes collection with the given properties ID
|
||||
*/
|
||||
void insert_into (db::Shapes &shapes, db::properties_id_type pi) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the object interacts with another NetShape object
|
||||
*/
|
||||
bool interacts_with (const db::NetShape &other) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the object interacts with another NetShape object after transforming it
|
||||
*/
|
||||
template <class Tr>
|
||||
bool interacts_with_transformed (const db::NetShape &other, const Tr &trans) const;
|
||||
|
||||
public:
|
||||
size_t m_ptr;
|
||||
coord_type m_dx, m_dy;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A box converter implementation for NetShape
|
||||
*/
|
||||
template <>
|
||||
struct box_convert<db::NetShape>
|
||||
{
|
||||
typedef db::NetShape::box_type box_type;
|
||||
typedef db::NetShape::coord_type coord_type;
|
||||
typedef db::complex_bbox_tag complexity;
|
||||
|
||||
box_type operator() (const db::NetShape &net_shape) const
|
||||
{
|
||||
return net_shape.bbox ();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -119,9 +119,12 @@ void NetlistDeviceExtractor::initialize (db::Netlist *nl)
|
|||
setup ();
|
||||
}
|
||||
|
||||
static void insert_into_region (const db::PolygonRef &s, const db::ICplxTrans &tr, db::Region ®ion)
|
||||
static void insert_into_region (const db::NetShape &s, const db::ICplxTrans &tr, db::Region ®ion)
|
||||
{
|
||||
region.insert (s.obj ().transformed (tr * db::ICplxTrans (s.trans ())));
|
||||
if (s.type () == db::NetShape::Polygon) {
|
||||
db::PolygonRef pr = s.polygon_ref ();
|
||||
region.insert (pr.obj ().transformed (tr * db::ICplxTrans (pr.trans ())));
|
||||
}
|
||||
}
|
||||
|
||||
void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layout_index, const NetlistDeviceExtractor::input_layers &layer_map, db::Netlist &nl, hier_clusters_type &clusters, double device_scaling)
|
||||
|
|
@ -161,10 +164,10 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo
|
|||
}
|
||||
|
||||
tl_assert (l->second != 0);
|
||||
db::DeepRegion *dr = dynamic_cast<db::DeepRegion *> (l->second->delegate ());
|
||||
db::DeepShapeCollectionDelegateBase *dr = l->second->get_delegate ()->deep ();
|
||||
if (dr == 0) {
|
||||
|
||||
std::pair<bool, db::DeepLayer> alias = dss.layer_for_flat (tl::id_of (l->second->delegate ()));
|
||||
std::pair<bool, db::DeepLayer> alias = dss.layer_for_flat (tl::id_of (l->second->get_delegate ()));
|
||||
if (alias.first) {
|
||||
// use deep layer alias for a given flat one (if found)
|
||||
layers.push_back (alias.second.layer ());
|
||||
|
|
@ -207,8 +210,7 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
{
|
||||
tl_assert (layers.size () == m_layer_definitions.size ());
|
||||
|
||||
typedef db::PolygonRef shape_type;
|
||||
db::ShapeIterator::flags_type shape_iter_flags = db::ShapeIterator::Polygons;
|
||||
typedef db::NetShape shape_type;
|
||||
|
||||
mp_layout = &layout;
|
||||
m_layers = layers;
|
||||
|
|
@ -247,7 +249,7 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db:
|
|||
|
||||
db::Connectivity device_conn = get_connectivity (layout, layers);
|
||||
db::hier_clusters<shape_type> device_clusters;
|
||||
device_clusters.build (layout, cell, shape_iter_flags, device_conn, 0, breakout_cells);
|
||||
device_clusters.build (layout, cell, device_conn, 0, breakout_cells);
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Extracting devices")));
|
||||
|
||||
|
|
@ -365,12 +367,12 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache)
|
|||
DeviceCellKey key;
|
||||
|
||||
for (geometry_per_terminal_type::const_iterator t = d->second.second.begin (); t != d->second.second.end (); ++t) {
|
||||
std::map<unsigned int, std::set<db::PolygonRef> > > = key.geometry [t->first];
|
||||
std::map<unsigned int, std::set<db::NetShape> > > = key.geometry [t->first];
|
||||
for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) {
|
||||
std::set<db::PolygonRef> &gl = gt [l->first];
|
||||
for (std::vector<db::PolygonRef>::const_iterator p = l->second.begin (); p != l->second.end (); ++p) {
|
||||
db::PolygonRef pr = *p;
|
||||
pr.transform (db::PolygonRef::trans_type (-disp));
|
||||
std::set<db::NetShape> &gl = gt [l->first];
|
||||
for (std::vector<db::NetShape>::const_iterator p = l->second.begin (); p != l->second.end (); ++p) {
|
||||
db::NetShape pr = *p;
|
||||
pr.transform (db::NetShape::trans_type (-disp));
|
||||
gl.insert (pr);
|
||||
}
|
||||
}
|
||||
|
|
@ -411,10 +413,10 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache)
|
|||
for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) {
|
||||
|
||||
db::Shapes &shapes = device_cell.shapes (l->first);
|
||||
for (std::vector<db::PolygonRef>::const_iterator s = l->second.begin (); s != l->second.end (); ++s) {
|
||||
db::PolygonRef pr = *s;
|
||||
pr.transform (db::PolygonRef::trans_type (-disp));
|
||||
shapes.insert (db::PolygonRefWithProperties (pr, pi));
|
||||
for (std::vector<db::NetShape>::const_iterator s = l->second.begin (); s != l->second.end (); ++s) {
|
||||
db::NetShape pr = *s;
|
||||
pr.transform (db::NetShape::trans_type (-disp));
|
||||
pr.insert_into (shapes, pi);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -542,10 +544,10 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id
|
|||
|
||||
std::pair<db::Device *, geometry_per_terminal_type> &dd = m_new_devices[device->id ()];
|
||||
dd.first = device;
|
||||
std::vector<db::PolygonRef> &geo = dd.second[terminal_id][layer_index];
|
||||
std::vector<db::NetShape> &geo = dd.second[terminal_id][layer_index];
|
||||
|
||||
for (db::Region::const_iterator p = region.begin_merged (); !p.at_end (); ++p) {
|
||||
geo.push_back (db::PolygonRef (*p, mp_layout->shape_repository ()));
|
||||
geo.push_back (db::NetShape (*p, mp_layout->shape_repository ()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -555,7 +557,7 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id
|
|||
tl_assert (geometry_index < m_layers.size ());
|
||||
unsigned int layer_index = m_layers [geometry_index];
|
||||
|
||||
db::PolygonRef pr (polygon, mp_layout->shape_repository ());
|
||||
db::NetShape pr (polygon, mp_layout->shape_repository ());
|
||||
std::pair<db::Device *, geometry_per_terminal_type> &dd = m_new_devices[device->id ()];
|
||||
dd.first = device;
|
||||
dd.second[terminal_id][layer_index].push_back (pr);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbNetShape.h"
|
||||
|
||||
#include "gsiObject.h"
|
||||
|
||||
|
|
@ -204,8 +205,8 @@ public:
|
|||
typedef error_list::const_iterator error_iterator;
|
||||
typedef std::vector<db::NetlistDeviceExtractorLayerDefinition> layer_definitions;
|
||||
typedef layer_definitions::const_iterator layer_definitions_iterator;
|
||||
typedef std::map<std::string, db::Region *> input_layers;
|
||||
typedef db::hier_clusters<db::PolygonRef> hier_clusters_type;
|
||||
typedef std::map<std::string, db::ShapeCollection *> input_layers;
|
||||
typedef db::hier_clusters<db::NetShape> hier_clusters_type;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
|
|
@ -260,8 +261,6 @@ public:
|
|||
* the nets later to associate nets with device terminals.
|
||||
*
|
||||
* The definition of the input layers is device class specific.
|
||||
*
|
||||
* NOTE: The extractor expects "PolygonRef" type layers.
|
||||
*/
|
||||
void extract (Layout &layout, Cell &cell, const std::vector<unsigned int> &layers, Netlist *netlist, hier_clusters_type &clusters, double device_scaling = 1.0, const std::set<cell_index_type> *breakout_cells = 0);
|
||||
|
||||
|
|
@ -521,11 +520,11 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
std::map<size_t, std::map<unsigned int, std::set<db::PolygonRef> > > geometry;
|
||||
std::map<size_t, std::map<unsigned int, std::set<db::NetShape> > > geometry;
|
||||
std::map<size_t, double> parameters;
|
||||
};
|
||||
|
||||
typedef std::map<unsigned int, std::vector<db::PolygonRef> > geometry_per_layer_type;
|
||||
typedef std::map<unsigned int, std::vector<db::NetShape> > geometry_per_layer_type;
|
||||
typedef std::map<size_t, geometry_per_layer_type> geometry_per_terminal_type;
|
||||
|
||||
tl::weak_ptr<db::Netlist> m_netlist;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "dbNetlistExtractor.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbNetlistDeviceExtractor.h"
|
||||
#include "dbShapeRepository.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
namespace db
|
||||
|
|
@ -50,9 +51,9 @@ void NetlistExtractor::set_include_floating_subcircuits (bool f)
|
|||
}
|
||||
|
||||
static void
|
||||
build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<unsigned int> &eq)
|
||||
build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters<size_t> &eq)
|
||||
{
|
||||
std::map<std::string, std::set<unsigned int> > prop_by_name;
|
||||
std::map<std::string, std::set<size_t> > prop_by_name;
|
||||
tl::GlobPattern jn_pattern (joined_net_names);
|
||||
|
||||
for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) {
|
||||
|
|
@ -60,15 +61,23 @@ build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type
|
|||
if (p->first == net_name_id) {
|
||||
std::string nn = p->second.to_string ();
|
||||
if (jn_pattern.match (nn)) {
|
||||
prop_by_name [nn].insert (i->first);
|
||||
prop_by_name [nn].insert (db::prop_id_to_attr (i->first));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::set<unsigned int> >::const_iterator pn = prop_by_name.begin (); pn != prop_by_name.end (); ++pn) {
|
||||
std::set<unsigned int>::const_iterator p = pn->second.begin ();
|
||||
std::set<unsigned int>::const_iterator p0 = p;
|
||||
const db::repository<db::Text> &text_repository = layout->shape_repository ().repository (db::object_tag<db::Text> ());
|
||||
for (db::repository<db::Text>::iterator t = text_repository.begin (); t != text_repository.end (); ++t) {
|
||||
std::string nn = t->string ();
|
||||
if (jn_pattern.match (nn)) {
|
||||
prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ()));
|
||||
}
|
||||
}
|
||||
|
||||
for (std::map<std::string, std::set<size_t> >::const_iterator pn = prop_by_name.begin (); pn != prop_by_name.end (); ++pn) {
|
||||
std::set<size_t>::const_iterator p = pn->second.begin ();
|
||||
std::set<size_t>::const_iterator p0 = p;
|
||||
while (p != pn->second.end ()) {
|
||||
eq.same (*p0, *p);
|
||||
++p;
|
||||
|
|
@ -93,9 +102,9 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
m_terminal_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::terminal_id_property_name ());
|
||||
m_device_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::device_id_property_name ());
|
||||
|
||||
// the big part: actually extract the nets
|
||||
// build an attribute equivalence map which lists the "attribute IDs" which are identical in terms of net names
|
||||
|
||||
std::map<db::cell_index_type, tl::equivalence_clusters<unsigned int> > net_name_equivalence;
|
||||
std::map<db::cell_index_type, tl::equivalence_clusters<size_t> > net_name_equivalence;
|
||||
if (m_text_annot_name_id.first) {
|
||||
if (! m_joined_net_names.empty ()) {
|
||||
build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]);
|
||||
|
|
@ -107,7 +116,10 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
}
|
||||
}
|
||||
}
|
||||
mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn, &net_name_equivalence);
|
||||
|
||||
// the big part: actually extract the nets
|
||||
|
||||
mp_clusters->build (*mp_layout, *mp_cell, conn, &net_name_equivalence);
|
||||
|
||||
// reverse lookup for Circuit vs. cell index
|
||||
std::map<db::cell_index_type, db::Circuit *> circuits;
|
||||
|
|
@ -181,7 +193,7 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) {
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &lc = clusters.cluster_by_id (*c);
|
||||
const db::local_cluster<db::NetShape> &lc = clusters.cluster_by_id (*c);
|
||||
if (clusters.connections_for_cluster (*c).empty () && lc.empty ()) {
|
||||
// this is an entirely empty cluster so we skip it.
|
||||
// Such clusters are left over when joining clusters.
|
||||
|
|
@ -204,8 +216,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo
|
|||
|
||||
// add the global names as second priority
|
||||
if (net_names.empty ()) {
|
||||
const db::local_cluster<db::PolygonRef>::global_nets &gn = lc.get_global_nets ();
|
||||
for (db::local_cluster<db::PolygonRef>::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) {
|
||||
const db::local_cluster<db::NetShape>::global_nets &gn = lc.get_global_nets ();
|
||||
for (db::local_cluster<db::NetShape>::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) {
|
||||
net_names.insert (conn.global_net_name (*g));
|
||||
}
|
||||
}
|
||||
|
|
@ -250,7 +262,13 @@ NetlistExtractor::make_device_abstract_connections (db::DeviceAbstract *dm, cons
|
|||
|
||||
for (local_cluster_type::attr_iterator a = dc->begin_attr (); a != dc->end_attr (); ++a) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
if (! db::is_prop_id_attr (*a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::properties_id_type pi = db::prop_id_from_attr (*a);
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (j->first == m_terminal_annot_name_id.second) {
|
||||
dm->set_cluster_id_for_terminal (j->second.to<size_t> (), dc->id ());
|
||||
|
|
@ -282,13 +300,23 @@ void NetlistExtractor::collect_labels (const connected_clusters_type &clusters,
|
|||
const local_cluster_type &lc = clusters.cluster_by_id (cid);
|
||||
for (local_cluster_type::attr_iterator a = lc.begin_attr (); a != lc.end_attr (); ++a) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
if (db::is_prop_id_attr (*a)) {
|
||||
|
||||
db::properties_id_type pi = db::prop_id_from_attr (*a);
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
|
||||
if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) {
|
||||
net_names.insert (j->second.to_string ());
|
||||
}
|
||||
|
||||
if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) {
|
||||
net_names.insert (j->second.to_string ());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
net_names.insert (db::text_from_attr (*a));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -343,13 +371,19 @@ void NetlistExtractor::connect_devices (db::Circuit *circuit,
|
|||
continue;
|
||||
}
|
||||
|
||||
const db::local_cluster<db::PolygonRef> &dc = mp_clusters->clusters_per_cell (inst_cell_index).cluster_by_id (i->id ());
|
||||
const db::local_cluster<db::NetShape> &dc = mp_clusters->clusters_per_cell (inst_cell_index).cluster_by_id (i->id ());
|
||||
|
||||
// connect the net to the terminal of the device: take the terminal ID from the properties on the
|
||||
// device cluster
|
||||
for (local_cluster_type::attr_iterator a = dc.begin_attr (); a != dc.end_attr (); ++a) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a);
|
||||
if (! db::is_prop_id_attr (*a)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::properties_id_type pi = db::prop_id_from_attr (*a);
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi);
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) {
|
||||
|
||||
if (m_terminal_annot_name_id.first && j->first == m_terminal_annot_name_id.second) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
#include "dbHierNetworkProcessor.h"
|
||||
#include "dbNetShape.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
@ -71,9 +72,9 @@ class DeviceAbstract;
|
|||
class DB_PUBLIC NetlistExtractor
|
||||
{
|
||||
public:
|
||||
typedef db::hier_clusters<db::PolygonRef> hier_clusters_type;
|
||||
typedef db::connected_clusters<db::PolygonRef> connected_clusters_type;
|
||||
typedef db::local_cluster<db::PolygonRef> local_cluster_type;
|
||||
typedef db::hier_clusters<db::NetShape> hier_clusters_type;
|
||||
typedef db::connected_clusters<db::NetShape> connected_clusters_type;
|
||||
typedef db::local_cluster<db::NetShape> local_cluster_type;
|
||||
|
||||
/**
|
||||
* @brief NetExtractor constructor
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbOriginalLayerTexts.h"
|
||||
#include "dbTexts.h"
|
||||
#include "tlInternational.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// OriginalLayerTexts implementation
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class OriginalLayerTextsIterator
|
||||
: public TextsIteratorDelegate
|
||||
{
|
||||
public:
|
||||
OriginalLayerTextsIterator (const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans)
|
||||
: m_rec_iter (iter), m_iter_trans (trans)
|
||||
{
|
||||
set ();
|
||||
}
|
||||
|
||||
virtual bool at_end () const
|
||||
{
|
||||
return m_rec_iter.at_end ();
|
||||
}
|
||||
|
||||
virtual void increment ()
|
||||
{
|
||||
inc ();
|
||||
set ();
|
||||
}
|
||||
|
||||
virtual const value_type *get () const
|
||||
{
|
||||
return &m_text;
|
||||
}
|
||||
|
||||
virtual TextsIteratorDelegate *clone () const
|
||||
{
|
||||
return new OriginalLayerTextsIterator (*this);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Texts;
|
||||
|
||||
db::RecursiveShapeIterator m_rec_iter;
|
||||
db::ICplxTrans m_iter_trans;
|
||||
db::Text m_text;
|
||||
|
||||
void set ()
|
||||
{
|
||||
while (! m_rec_iter.at_end () && ! m_rec_iter.shape ().is_text ()) {
|
||||
++m_rec_iter;
|
||||
}
|
||||
if (! m_rec_iter.at_end ()) {
|
||||
m_rec_iter.shape ().text (m_text);
|
||||
m_text.transform (m_iter_trans * m_rec_iter.trans ());
|
||||
}
|
||||
}
|
||||
|
||||
void inc ()
|
||||
{
|
||||
if (! m_rec_iter.at_end ()) {
|
||||
++m_rec_iter;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
OriginalLayerTexts::OriginalLayerTexts ()
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
OriginalLayerTexts::OriginalLayerTexts (const OriginalLayerTexts &other)
|
||||
: AsIfFlatTexts (other),
|
||||
m_iter (other.m_iter),
|
||||
m_iter_trans (other.m_iter_trans)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
OriginalLayerTexts::OriginalLayerTexts (const RecursiveShapeIterator &si)
|
||||
: AsIfFlatTexts (), m_iter (si)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
OriginalLayerTexts::OriginalLayerTexts (const RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
: AsIfFlatTexts (), m_iter (si), m_iter_trans (trans)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
OriginalLayerTexts::~OriginalLayerTexts ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
TextsDelegate *
|
||||
OriginalLayerTexts::clone () const
|
||||
{
|
||||
return new OriginalLayerTexts (*this);
|
||||
}
|
||||
|
||||
TextsIteratorDelegate *
|
||||
OriginalLayerTexts::begin () const
|
||||
{
|
||||
return new OriginalLayerTextsIterator (m_iter, m_iter_trans);
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans>
|
||||
OriginalLayerTexts::begin_iter () const
|
||||
{
|
||||
return std::make_pair (m_iter, m_iter_trans);
|
||||
}
|
||||
|
||||
bool
|
||||
OriginalLayerTexts::empty () const
|
||||
{
|
||||
return m_iter.at_end ();
|
||||
}
|
||||
|
||||
const db::Text *
|
||||
OriginalLayerTexts::nth (size_t) const
|
||||
{
|
||||
throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat collections")));
|
||||
}
|
||||
|
||||
bool
|
||||
OriginalLayerTexts::has_valid_texts () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const db::RecursiveShapeIterator *
|
||||
OriginalLayerTexts::iter () const
|
||||
{
|
||||
return &m_iter;
|
||||
}
|
||||
|
||||
bool
|
||||
OriginalLayerTexts::equals (const Texts &other) const
|
||||
{
|
||||
const OriginalLayerTexts *other_delegate = dynamic_cast<const OriginalLayerTexts *> (other.delegate ());
|
||||
if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) {
|
||||
return true;
|
||||
} else {
|
||||
return AsIfFlatTexts::equals (other);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
OriginalLayerTexts::less (const Texts &other) const
|
||||
{
|
||||
const OriginalLayerTexts *other_delegate = dynamic_cast<const OriginalLayerTexts *> (other.delegate ());
|
||||
if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) {
|
||||
return false;
|
||||
} else {
|
||||
return AsIfFlatTexts::less (other);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OriginalLayerTexts::init ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbOriginalLayerTexts
|
||||
#define HDR_dbOriginalLayerTexts
|
||||
|
||||
#include "dbCommon.h"
|
||||
|
||||
#include "dbAsIfFlatTexts.h"
|
||||
#include "dbShapes.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief An original layer text collection based on a RecursiveShapeIterator
|
||||
*/
|
||||
class DB_PUBLIC OriginalLayerTexts
|
||||
: public AsIfFlatTexts
|
||||
{
|
||||
public:
|
||||
OriginalLayerTexts ();
|
||||
OriginalLayerTexts (const OriginalLayerTexts &other);
|
||||
OriginalLayerTexts (const RecursiveShapeIterator &si);
|
||||
OriginalLayerTexts (const RecursiveShapeIterator &si, const db::ICplxTrans &trans);
|
||||
virtual ~OriginalLayerTexts ();
|
||||
|
||||
TextsDelegate *clone () const;
|
||||
|
||||
virtual TextsIteratorDelegate *begin () const;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const;
|
||||
|
||||
virtual bool empty () const;
|
||||
|
||||
virtual const db::Text *nth (size_t n) const;
|
||||
virtual bool has_valid_texts () const;
|
||||
|
||||
virtual const db::RecursiveShapeIterator *iter () const;
|
||||
|
||||
virtual bool equals (const Texts &other) const;
|
||||
virtual bool less (const Texts &other) const;
|
||||
|
||||
private:
|
||||
OriginalLayerTexts &operator= (const OriginalLayerTexts &other);
|
||||
|
||||
mutable db::RecursiveShapeIterator m_iter;
|
||||
db::ICplxTrans m_iter_trans;
|
||||
|
||||
void init ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbCommon.h"
|
||||
|
||||
#include "dbPolygon.h"
|
||||
#include "dbText.h"
|
||||
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
|
@ -346,6 +347,18 @@ bool interact_pe (const Polygon &poly, const Edge &edge)
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determines whether the text is inside the polygon
|
||||
*/
|
||||
template <class Polygon, class Text>
|
||||
bool interact_pt (const Polygon &poly, const Text &text)
|
||||
{
|
||||
typedef typename Text::point_type point_type;
|
||||
point_type p;
|
||||
p += text.trans ().disp ();
|
||||
return (poly.box ().contains (p) && db::inside_poly (poly.begin_edge (), p) >= 0);
|
||||
}
|
||||
|
||||
// Some specializations that map all combinations to template versions
|
||||
inline bool interact (const db::Box &box1, const db::Box &box2) { return box1.touches (box2); }
|
||||
inline bool interact (const db::DBox &box1, const db::DBox &box2) { return box1.touches (box2); }
|
||||
|
|
@ -365,6 +378,10 @@ inline bool interact (const db::DPolygon &poly1, const db::DPolygon &poly
|
|||
inline bool interact (const db::DSimplePolygon &poly1, const db::DPolygon &poly2) { return interact_pp (poly1, poly2); }
|
||||
inline bool interact (const db::DPolygon &poly1, const db::DSimplePolygon &poly2) { return interact_pp (poly1, poly2); }
|
||||
inline bool interact (const db::DSimplePolygon &poly1, const db::DSimplePolygon &poly2) { return interact_pp (poly1, poly2); }
|
||||
inline bool interact (const db::Polygon &poly, const db::Text &text) { return interact_pt (poly, text); }
|
||||
inline bool interact (const db::SimplePolygon &poly, const db::Text &text) { return interact_pt (poly, text); }
|
||||
inline bool interact (const db::DPolygon &poly, const db::DText &text) { return interact_pt (poly, text); }
|
||||
inline bool interact (const db::DSimplePolygon &poly, const db::DText &text) { return interact_pt (poly, text); }
|
||||
|
||||
/**
|
||||
* @brief Extract a corner radius from a contour
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ Region::Region (RegionDelegate *delegate)
|
|||
}
|
||||
|
||||
Region::Region (const Region &other)
|
||||
: gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ())
|
||||
: db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@
|
|||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbPolygonGenerators.h"
|
||||
#include "dbCellVariants.h"
|
||||
|
||||
#include "gsiObject.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -216,7 +215,7 @@ private:
|
|||
* Polygons inside the region may contain holes if the region is merged.
|
||||
*/
|
||||
class DB_PUBLIC Region
|
||||
: public gsi::ObjectBase
|
||||
: public db::ShapeCollection
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
@ -351,6 +350,14 @@ public:
|
|||
*/
|
||||
explicit Region (DeepShapeStore &dss);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
ShapeCollectionDelegateBase *get_delegate () const
|
||||
{
|
||||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying delegate object
|
||||
*/
|
||||
|
|
@ -1322,6 +1329,52 @@ public:
|
|||
return Region (mp_delegate->selected_not_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which overlap or touch texts from the text collection
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Region &select_interacting (const Texts &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_interacting (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which do not overlap or touch texts from the text collection
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Region &select_not_interacting (const Texts &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_not_interacting (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which overlap or touch texts from the text collection
|
||||
*
|
||||
* This method is an out-of-place version of select_interacting.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Region selected_interacting (const Texts &other) const
|
||||
{
|
||||
return Region (mp_delegate->selected_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of this which do not overlap or touch texts from the text collection
|
||||
*
|
||||
* This method is an out-of-place version of select_not_interacting.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Region selected_not_interacting (const Texts &other) const
|
||||
{
|
||||
return Region (mp_delegate->selected_not_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of this region which overlap polygons from the other region
|
||||
*
|
||||
|
|
@ -1388,6 +1441,16 @@ public:
|
|||
return Edges (mp_delegate->pull_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all texts of "other" which are interacting (touching or overlapping with) polygons of this region
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Texts pull_interacting (const Texts &other) const
|
||||
{
|
||||
return Texts (mp_delegate->pull_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons of "other" which are interacting (touching or overlapping with) polygons of this region
|
||||
*
|
||||
|
|
@ -1612,6 +1675,7 @@ public:
|
|||
private:
|
||||
friend class Edges;
|
||||
friend class EdgePairs;
|
||||
friend class Texts;
|
||||
|
||||
RegionDelegate *mp_delegate;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ RegionDelegate::RegionDelegate ()
|
|||
}
|
||||
|
||||
RegionDelegate::RegionDelegate (const RegionDelegate &other)
|
||||
: tl::UniqueId ()
|
||||
: ShapeCollectionDelegateBase ()
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@
|
|||
|
||||
#include "dbPolygon.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdgePairRelations.h"
|
||||
#include "tlUniqueId.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -182,7 +183,7 @@ public:
|
|||
* @brief The delegate for the actual region implementation
|
||||
*/
|
||||
class DB_PUBLIC RegionDelegate
|
||||
: public tl::UniqueId
|
||||
: public db::ShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
|
|
@ -294,12 +295,15 @@ public:
|
|||
virtual RegionDelegate *selected_not_interacting (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_interacting (const Edges &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_interacting (const Edges &other) const = 0;
|
||||
virtual RegionDelegate *selected_interacting (const Texts &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &other) const = 0;
|
||||
virtual RegionDelegate *selected_overlapping (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &other) const = 0;
|
||||
virtual RegionDelegate *pull_inside (const Region &other) const = 0;
|
||||
virtual RegionDelegate *pull_interacting (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0;
|
||||
virtual RegionDelegate *pull_overlapping (const Region &other) const = 0;
|
||||
virtual TextsDelegate *pull_interacting (const Texts &other) const = 0;
|
||||
virtual RegionDelegate *in (const Region &other, bool invert) const = 0;
|
||||
|
||||
virtual const db::Polygon *nth (size_t n) const = 0;
|
||||
|
|
|
|||
|
|
@ -350,6 +350,62 @@ region_to_edge_interaction_filter_base<OutputType>::fill_output ()
|
|||
template class region_to_edge_interaction_filter_base<db::Polygon>;
|
||||
template class region_to_edge_interaction_filter_base<db::Edge>;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// RegionToTextInteractionFilterBase implementation
|
||||
|
||||
template <class OutputType, class TextType>
|
||||
region_to_text_interaction_filter_base<OutputType, TextType>::region_to_text_interaction_filter_base (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
template <class OutputType, class TextType>
|
||||
void
|
||||
region_to_text_interaction_filter_base<OutputType, TextType>::preset (const OutputType *s)
|
||||
{
|
||||
m_seen.insert (s);
|
||||
}
|
||||
|
||||
template <class OutputType, class TextType>
|
||||
void
|
||||
region_to_text_interaction_filter_base<OutputType, TextType>::add (const db::Polygon *p, size_t, const TextType *t, size_t)
|
||||
{
|
||||
const OutputType *o = 0;
|
||||
tl::select (o, p, t);
|
||||
|
||||
if ((m_seen.find (o) == m_seen.end ()) != m_inverse) {
|
||||
|
||||
// A polygon and an text interact if the text is either inside completely
|
||||
// of at least one text of the polygon intersects with the text
|
||||
db::Point pt = db::box_convert<TextType> () (*t).p1 ();
|
||||
if (p->box ().contains (pt) && db::inside_poly (p->begin_edge (), pt) >= 0) {
|
||||
if (m_inverse) {
|
||||
m_seen.erase (o);
|
||||
} else {
|
||||
m_seen.insert (o);
|
||||
put (*o);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class OutputType, class TextType>
|
||||
void
|
||||
region_to_text_interaction_filter_base<OutputType, TextType>::fill_output ()
|
||||
{
|
||||
for (typename std::set<const OutputType *>::const_iterator s = m_seen.begin (); s != m_seen.end (); ++s) {
|
||||
put (**s);
|
||||
}
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class region_to_text_interaction_filter_base<db::Polygon, db::TextRef>;
|
||||
template class region_to_text_interaction_filter_base<db::Polygon, db::Text>;
|
||||
template class region_to_text_interaction_filter_base<db::Text, db::Text>;
|
||||
template class region_to_text_interaction_filter_base<db::TextRef, db::TextRef>;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Polygon snapping
|
||||
|
||||
|
|
|
|||
|
|
@ -524,6 +524,52 @@ private:
|
|||
OutputContainer *mp_output;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the region to text interaction functionality
|
||||
*/
|
||||
template <class OutputType, class TextType>
|
||||
class DB_PUBLIC region_to_text_interaction_filter_base
|
||||
: public db::box_scanner_receiver2<db::Polygon, size_t, TextType, size_t>
|
||||
{
|
||||
public:
|
||||
region_to_text_interaction_filter_base (bool inverse);
|
||||
|
||||
void preset (const OutputType *s);
|
||||
void add (const db::Polygon *p, size_t, const TextType *e, size_t);
|
||||
void fill_output ();
|
||||
|
||||
protected:
|
||||
virtual void put (const OutputType &s) const = 0;
|
||||
|
||||
private:
|
||||
std::set<const OutputType *> m_seen;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the region to text interaction functionality
|
||||
*/
|
||||
template <class OutputContainer, class TextType, class OutputType = typename OutputContainer::value_type>
|
||||
class DB_PUBLIC_TEMPLATE region_to_text_interaction_filter
|
||||
: public region_to_text_interaction_filter_base<OutputType, TextType>
|
||||
{
|
||||
public:
|
||||
region_to_text_interaction_filter (OutputContainer &output, bool inverse)
|
||||
: region_to_text_interaction_filter_base<OutputType, TextType> (inverse), mp_output (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void put (const OutputType &poly) const
|
||||
{
|
||||
mp_output->insert (poly);
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
};
|
||||
|
||||
template <class C>
|
||||
static inline C snap_to_grid (C c, C g)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _HDR_dbShapeCollection
|
||||
#define _HDR_dbShapeCollection
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "tlUniqueId.h"
|
||||
#include "gsiObject.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A base class for the deep collection delegates
|
||||
*/
|
||||
class DB_PUBLIC DeepShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
DeepShapeCollectionDelegateBase () { }
|
||||
|
||||
DeepShapeCollectionDelegateBase (const DeepShapeCollectionDelegateBase &other)
|
||||
{
|
||||
m_deep_layer = other.m_deep_layer.copy ();
|
||||
}
|
||||
|
||||
DeepShapeCollectionDelegateBase &operator= (const DeepShapeCollectionDelegateBase &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_deep_layer = other.m_deep_layer.copy ();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const db::DeepLayer &deep_layer () const
|
||||
{
|
||||
return m_deep_layer;
|
||||
}
|
||||
|
||||
db::DeepLayer &deep_layer ()
|
||||
{
|
||||
return m_deep_layer;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void set_deep_layer (const db::DeepLayer &dl)
|
||||
{
|
||||
m_deep_layer = dl;
|
||||
}
|
||||
|
||||
private:
|
||||
db::DeepLayer m_deep_layer;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A base class for the shape collection delegates
|
||||
*/
|
||||
class DB_PUBLIC ShapeCollectionDelegateBase
|
||||
: public tl::UniqueId
|
||||
{
|
||||
public:
|
||||
ShapeCollectionDelegateBase () { }
|
||||
virtual ~ShapeCollectionDelegateBase () { }
|
||||
|
||||
virtual DeepShapeCollectionDelegateBase *deep () { return 0; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A base class for the shape collections such as Region, Edges, EdgePairs etc.
|
||||
*/
|
||||
class DB_PUBLIC ShapeCollection
|
||||
: public gsi::ObjectBase
|
||||
{
|
||||
public:
|
||||
ShapeCollection () { }
|
||||
virtual ~ShapeCollection () { }
|
||||
|
||||
virtual ShapeCollectionDelegateBase *get_delegate () const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
template<> struct type_traits<db::ShapeCollection> : public tl::type_traits<void>
|
||||
{
|
||||
// mark "NetlistDeviceExtractor" as having a default ctor and no copy ctor
|
||||
typedef tl::false_tag has_copy_constructor;
|
||||
typedef tl::false_tag has_default_constructor;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -176,6 +176,15 @@ public:
|
|||
return m_text_repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the repository by tag
|
||||
*/
|
||||
template <class Sh>
|
||||
const db::repository<Sh> &repository (db::object_tag<Sh> tag) const
|
||||
{
|
||||
return const_cast<generic_repository<C> *> (this)->repository (tag);
|
||||
}
|
||||
|
||||
void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
db::mem_stat (stat, purpose, cat, m_polygon_repository, no_self, parent);
|
||||
|
|
|
|||
|
|
@ -234,6 +234,20 @@ Shapes::swap (Shapes &d)
|
|||
m_layers.swap (d.m_layers);
|
||||
}
|
||||
|
||||
static
|
||||
Shapes::shape_type safe_insert_text (Shapes &shapes, const Shapes::shape_type &shape, tl::func_delegate_base <db::properties_id_type> &pm)
|
||||
{
|
||||
// for texts referring to a string repository we go the safe way and
|
||||
// simply instantiate and re-insert the text:
|
||||
Shapes::shape_type::text_type p;
|
||||
shape.text (p);
|
||||
if (! shape.has_prop_id ()) {
|
||||
return shapes.insert (p);
|
||||
} else {
|
||||
return shapes.insert (db::object_with_properties<Shapes::shape_type::text_type> (p, pm (shape.prop_id ())));
|
||||
}
|
||||
}
|
||||
|
||||
Shapes::shape_type
|
||||
Shapes::do_insert (const Shapes::shape_type &shape, const Shapes::unit_trans_type & /*t*/, tl::func_delegate_base <db::properties_id_type> &pm)
|
||||
{
|
||||
|
|
@ -352,19 +366,23 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Shapes::unit_trans_typ
|
|||
case shape_type::ShortBoxArray:
|
||||
return (insert_by_tag (shape_type::short_box_array_type::tag (), shape, pm));
|
||||
case shape_type::Text:
|
||||
case shape_type::TextRef:
|
||||
case shape_type::TextPtrArrayMember:
|
||||
{
|
||||
// because texts can refer to a string repository we go the safe way and
|
||||
// simply instantiate and re-insert the text:
|
||||
shape_type::text_type p;
|
||||
shape.text (p);
|
||||
if (! shape.has_prop_id ()) {
|
||||
return insert (p);
|
||||
if (shape.text ().string_ref () != 0) {
|
||||
return safe_insert_text (*this, shape, pm);
|
||||
} else {
|
||||
return insert (db::object_with_properties<shape_type::text_type> (p, pm (shape.prop_id ())));
|
||||
return (insert_by_tag (shape_type::text_type::tag (), shape, pm));
|
||||
}
|
||||
}
|
||||
case shape_type::TextRef:
|
||||
{
|
||||
if (shape.text_ref ().obj ().string_ref () != 0) {
|
||||
return safe_insert_text (*this, shape, pm);
|
||||
} else {
|
||||
return (insert_by_tag (shape_type::text_ref_type::tag (), shape, pm));
|
||||
}
|
||||
}
|
||||
case shape_type::TextPtrArrayMember:
|
||||
return safe_insert_text (*this, shape, pm);
|
||||
case shape_type::TextPtrArray:
|
||||
tl_assert (layout () != 0); // cannot translate the array members
|
||||
return insert_array_by_tag (shape_type::text_ptr_array_type::tag (), shape, shape_repository (), pm);
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@ inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int
|
|||
class DB_PUBLIC StringRepository
|
||||
{
|
||||
public:
|
||||
typedef std::set<StringRef *> string_refs_type;
|
||||
typedef string_refs_type::const_iterator iterator;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
|
|
@ -216,6 +219,22 @@ public:
|
|||
return m_string_refs.size ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates over the string refs (begin)
|
||||
*/
|
||||
iterator begin () const
|
||||
{
|
||||
return m_string_refs.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates over the string refs (end)
|
||||
*/
|
||||
iterator end () const
|
||||
{
|
||||
return m_string_refs.end ();
|
||||
}
|
||||
|
||||
void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const
|
||||
{
|
||||
if (! no_self) {
|
||||
|
|
@ -559,6 +578,21 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the StringRef object is there is one
|
||||
*
|
||||
* If the string is a plain text kept internally, this method returns 0.
|
||||
*/
|
||||
const StringRef *string_ref () const
|
||||
{
|
||||
size_t p = (size_t) mp_ptr;
|
||||
if (p & 1) {
|
||||
return reinterpret_cast<const StringRef *> (p - 1);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The transformation write accessor
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,212 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbCommon.h"
|
||||
|
||||
#include "dbTexts.h"
|
||||
#include "dbEmptyTexts.h"
|
||||
#include "dbFlatTexts.h"
|
||||
#include "dbDeepTexts.h"
|
||||
#include "dbOriginalLayerTexts.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
#include "tlVariant.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
Texts::Texts ()
|
||||
: mp_delegate (new EmptyTexts ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Texts::~Texts ()
|
||||
{
|
||||
delete mp_delegate;
|
||||
mp_delegate = 0;
|
||||
}
|
||||
|
||||
Texts::Texts (TextsDelegate *delegate)
|
||||
: mp_delegate (delegate)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Texts::Texts (const Texts &other)
|
||||
: db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ())
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
Texts &Texts::operator= (const Texts &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
set_delegate (other.mp_delegate->clone ());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Texts::Texts (const RecursiveShapeIterator &si)
|
||||
{
|
||||
mp_delegate = new OriginalLayerTexts (si);
|
||||
}
|
||||
|
||||
Texts::Texts (const RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
mp_delegate = new OriginalLayerTexts (si, trans);
|
||||
}
|
||||
|
||||
Texts::Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||
{
|
||||
mp_delegate = new DeepTexts (si, dss);
|
||||
}
|
||||
|
||||
Texts::Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||
{
|
||||
mp_delegate = new DeepTexts (si, dss, trans);
|
||||
}
|
||||
|
||||
template <class Sh>
|
||||
void Texts::insert (const Sh &shape)
|
||||
{
|
||||
flat_texts ()->insert (shape);
|
||||
}
|
||||
|
||||
template DB_PUBLIC void Texts::insert (const db::Text &);
|
||||
|
||||
void Texts::insert (const db::Shape &shape)
|
||||
{
|
||||
flat_texts ()->insert (shape);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Texts::insert (const db::Shape &shape, const T &trans)
|
||||
{
|
||||
flat_texts ()->insert (shape, trans);
|
||||
}
|
||||
|
||||
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::ICplxTrans &);
|
||||
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::Trans &);
|
||||
template DB_PUBLIC void Texts::insert (const db::Shape &, const db::Disp &);
|
||||
|
||||
void Texts::clear ()
|
||||
{
|
||||
set_delegate (new EmptyTexts ());
|
||||
}
|
||||
|
||||
void Texts::reserve (size_t n)
|
||||
{
|
||||
flat_texts ()->reserve (n);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Texts &Texts::transform (const T &trans)
|
||||
{
|
||||
flat_texts ()->transform (trans);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template DB_PUBLIC Texts &Texts::transform (const db::ICplxTrans &);
|
||||
template DB_PUBLIC Texts &Texts::transform (const db::Trans &);
|
||||
template DB_PUBLIC Texts &Texts::transform (const db::Disp &);
|
||||
|
||||
const db::RecursiveShapeIterator &
|
||||
Texts::iter () const
|
||||
{
|
||||
static db::RecursiveShapeIterator def_iter;
|
||||
const db::RecursiveShapeIterator *i = mp_delegate->iter ();
|
||||
return *(i ? i : &def_iter);
|
||||
}
|
||||
|
||||
void Texts::polygons (Region &output, db::Coord e) const
|
||||
{
|
||||
output.set_delegate (mp_delegate->polygons (e));
|
||||
}
|
||||
|
||||
void Texts::edges (Edges &output) const
|
||||
{
|
||||
output.set_delegate (mp_delegate->edges ());
|
||||
}
|
||||
|
||||
void Texts::set_delegate (TextsDelegate *delegate)
|
||||
{
|
||||
if (delegate != mp_delegate) {
|
||||
delete mp_delegate;
|
||||
mp_delegate = delegate;
|
||||
}
|
||||
}
|
||||
|
||||
FlatTexts *Texts::flat_texts ()
|
||||
{
|
||||
FlatTexts *texts = dynamic_cast<FlatTexts *> (mp_delegate);
|
||||
if (! texts) {
|
||||
texts = new FlatTexts ();
|
||||
if (mp_delegate) {
|
||||
texts->TextsDelegate::operator= (*mp_delegate);
|
||||
texts->insert_seq (begin ());
|
||||
}
|
||||
set_delegate (texts);
|
||||
}
|
||||
|
||||
return texts;
|
||||
}
|
||||
|
||||
void Texts::pull_interacting (Region &output, const Region &other) const
|
||||
{
|
||||
output = Region (mp_delegate->pull_interacting (other));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Texts &b)
|
||||
{
|
||||
db::Text ep;
|
||||
|
||||
if (! ex.try_read (ep)) {
|
||||
return false;
|
||||
}
|
||||
b.insert (ep);
|
||||
|
||||
while (ex.test (";")) {
|
||||
ex.read (ep);
|
||||
b.insert (ep);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Texts &b)
|
||||
{
|
||||
if (! test_extractor_impl (ex, b)) {
|
||||
ex.error (tl::to_string (tr ("Expected an edge pair collection specification")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,724 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbTexts
|
||||
#define HDR_dbTexts
|
||||
|
||||
#include "dbTextsDelegate.h"
|
||||
#include "dbShape.h"
|
||||
#include "dbRecursiveShapeIterator.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class TextFilterBase;
|
||||
class FlatTexts;
|
||||
class EmptyTexts;
|
||||
class Edges;
|
||||
class Region;
|
||||
class DeepShapeStore;
|
||||
class TransformationReducer;
|
||||
|
||||
/**
|
||||
* @brief An text set iterator
|
||||
*
|
||||
* The iterator delivers the texts of the text set
|
||||
*/
|
||||
class DB_PUBLIC TextsIterator
|
||||
{
|
||||
public:
|
||||
typedef TextsIteratorDelegate::value_type value_type;
|
||||
typedef const value_type &reference;
|
||||
typedef const value_type *pointer;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
typedef void difference_type;
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
TextsIterator ()
|
||||
: mp_delegate (0)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructor from a delegate
|
||||
* The iterator will take ownership over the delegate
|
||||
*/
|
||||
TextsIterator (TextsIteratorDelegate *delegate)
|
||||
: mp_delegate (delegate)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~TextsIterator ()
|
||||
{
|
||||
delete mp_delegate;
|
||||
mp_delegate = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor and assignment
|
||||
*/
|
||||
TextsIterator (const TextsIterator &other)
|
||||
: mp_delegate (0)
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assignment
|
||||
*/
|
||||
TextsIterator &operator= (const TextsIterator &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
delete mp_delegate;
|
||||
mp_delegate = other.mp_delegate ? other.mp_delegate->clone () : 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Returns true, if the iterator is at the end
|
||||
*/
|
||||
bool at_end () const
|
||||
{
|
||||
return mp_delegate == 0 || mp_delegate->at_end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increment
|
||||
*/
|
||||
TextsIterator &operator++ ()
|
||||
{
|
||||
if (mp_delegate) {
|
||||
mp_delegate->increment ();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access
|
||||
*/
|
||||
reference operator* () const
|
||||
{
|
||||
const value_type *value = operator-> ();
|
||||
tl_assert (value != 0);
|
||||
return *value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access
|
||||
*/
|
||||
pointer operator-> () const
|
||||
{
|
||||
return mp_delegate ? mp_delegate->get () : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
TextsIteratorDelegate *mp_delegate;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class allowing delivery of addressable texts
|
||||
*
|
||||
* In some applications (i.e. box scanner), texts need to be taken
|
||||
* by address. The text set cannot always deliver adressable edges.
|
||||
* This class help providing this ability by keeping a temporary copy
|
||||
* if required.
|
||||
*/
|
||||
|
||||
class DB_PUBLIC AddressableTextDelivery
|
||||
{
|
||||
public:
|
||||
AddressableTextDelivery ()
|
||||
: m_iter (), m_valid (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
AddressableTextDelivery (const TextsIterator &iter, bool valid)
|
||||
: m_iter (iter), m_valid (valid)
|
||||
{
|
||||
if (! m_valid && ! m_iter.at_end ()) {
|
||||
m_heap.push_back (*m_iter);
|
||||
}
|
||||
}
|
||||
|
||||
bool at_end () const
|
||||
{
|
||||
return m_iter.at_end ();
|
||||
}
|
||||
|
||||
AddressableTextDelivery &operator++ ()
|
||||
{
|
||||
++m_iter;
|
||||
if (! m_valid && ! m_iter.at_end ()) {
|
||||
m_heap.push_back (*m_iter);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const db::Text *operator-> () const
|
||||
{
|
||||
if (m_valid) {
|
||||
return m_iter.operator-> ();
|
||||
} else {
|
||||
return &m_heap.back ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
TextsIterator m_iter;
|
||||
bool m_valid;
|
||||
std::list<db::Text> m_heap;
|
||||
};
|
||||
|
||||
class Texts;
|
||||
|
||||
/**
|
||||
* @brief A base class for text filters
|
||||
*/
|
||||
class DB_PUBLIC TextFilterBase
|
||||
{
|
||||
public:
|
||||
TextFilterBase () { }
|
||||
virtual ~TextFilterBase () { }
|
||||
|
||||
virtual bool selected (const db::Text &text) const = 0;
|
||||
virtual const TransformationReducer *vars () const = 0;
|
||||
virtual bool wants_variants () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A set of texts
|
||||
*
|
||||
* Texts are convenient objects describing labels (a point and a text).
|
||||
*
|
||||
* Text sets are created from a text-delivering recursive shape iterator for example. Text sets
|
||||
* can be converted to polygons (representing a small box around the text's point) or to dot-like
|
||||
* edges representing the point of the text.
|
||||
*/
|
||||
class DB_PUBLIC Texts
|
||||
: public db::ShapeCollection
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
typedef db::coord_traits<db::Coord> coord_traits;
|
||||
typedef db::Text edge_pair_type;
|
||||
typedef db::Vector vector_type;
|
||||
typedef db::Point point_type;
|
||||
typedef db::Box box_type;
|
||||
typedef coord_traits::distance_type distance_type;
|
||||
typedef TextsIterator const_iterator;
|
||||
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*
|
||||
* This constructor creates an empty text set.
|
||||
*/
|
||||
Texts ();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~Texts ();
|
||||
|
||||
/**
|
||||
* @brief Constructor from a delegate
|
||||
*
|
||||
* The region will take ownership of the delegate.
|
||||
*/
|
||||
Texts (TextsDelegate *delegate);
|
||||
|
||||
/**
|
||||
* @brief Copy constructor
|
||||
*/
|
||||
Texts (const Texts &other);
|
||||
|
||||
/**
|
||||
* @brief Assignment
|
||||
*/
|
||||
Texts &operator= (const Texts &other);
|
||||
|
||||
/**
|
||||
* @brief Constructor from an object
|
||||
*
|
||||
* Creates an text set representing a single instance of that object
|
||||
*/
|
||||
explicit Texts (const db::Text &s)
|
||||
: mp_delegate (0)
|
||||
{
|
||||
insert (s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructor from an object
|
||||
*
|
||||
* Creates an text set representing a single instance of that object
|
||||
*/
|
||||
explicit Texts (const db::Shape &s)
|
||||
: mp_delegate (0)
|
||||
{
|
||||
insert (s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sequence constructor
|
||||
*
|
||||
* Creates an edge set from a sequence of objects. The objects need to be texts.
|
||||
* This version accepts iterators of the begin ... end style.
|
||||
*/
|
||||
template <class Iter>
|
||||
explicit Texts (const Iter &b, const Iter &e)
|
||||
: mp_delegate (0)
|
||||
{
|
||||
reserve (e - b);
|
||||
for (Iter i = b; i != e; ++i) {
|
||||
insert (*i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructor from a RecursiveShapeIterator
|
||||
*
|
||||
* Creates an text set from a recursive shape iterator. This allows one to feed an text set
|
||||
* from a hierarchy of cells.
|
||||
*/
|
||||
explicit Texts (const RecursiveShapeIterator &si);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a RecursiveShapeIterator with a transformation
|
||||
*
|
||||
* Creates an text set from a recursive shape iterator. This allows one to feed an text set
|
||||
* from a hierarchy of cells. The transformation is useful to scale to a specific
|
||||
* DBU for example.
|
||||
*/
|
||||
explicit Texts (const RecursiveShapeIterator &si, const db::ICplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a RecursiveShapeIterator providing a deep representation
|
||||
*
|
||||
* This version will create a hierarchical text collection. The DeepShapeStore needs to be provided
|
||||
* during the lifetime of the collection and acts as a heap for optimized data.
|
||||
*/
|
||||
explicit Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss);
|
||||
|
||||
/**
|
||||
* @brief Constructor from a RecursiveShapeIterator providing a deep representation with transformation
|
||||
*/
|
||||
explicit Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans);
|
||||
|
||||
/**
|
||||
* @brief Implementation of the ShapeCollection interface
|
||||
*/
|
||||
ShapeCollectionDelegateBase *get_delegate () const
|
||||
{
|
||||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the underlying delegate object
|
||||
*/
|
||||
TextsDelegate *delegate () const
|
||||
{
|
||||
return mp_delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterator of the text set
|
||||
*
|
||||
* The iterator delivers the edges of the text set.
|
||||
* It follows the at_end semantics.
|
||||
*/
|
||||
const_iterator begin () const
|
||||
{
|
||||
return TextsIterator (mp_delegate->begin ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivers a RecursiveShapeIterator pointing to the texts plus the necessary transformation
|
||||
*/
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const
|
||||
{
|
||||
return mp_delegate->begin_iter ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts the given shape (working object) into the text set
|
||||
*/
|
||||
template <class Sh>
|
||||
void insert (const Sh &shape);
|
||||
|
||||
/**
|
||||
* @brief Insert a shape reference into the text set
|
||||
*/
|
||||
void insert (const db::Shape &shape);
|
||||
|
||||
/**
|
||||
* @brief Insert a transformed shape into the text set
|
||||
*/
|
||||
template <class T>
|
||||
void insert (const db::Shape &shape, const T &trans);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the edge pair set is empty
|
||||
*/
|
||||
bool empty () const
|
||||
{
|
||||
return mp_delegate->empty ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of texts in the text set
|
||||
*/
|
||||
size_t size () const
|
||||
{
|
||||
return mp_delegate->size ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a string representing the text set
|
||||
*
|
||||
* nmax specifies how many texts are included (set to std::numeric_limits<size_t>::max() for "all".
|
||||
*/
|
||||
std::string to_string (size_t nmax = 10) const
|
||||
{
|
||||
return mp_delegate->to_string (nmax);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears the text set
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Reserve memory for the given number of texts
|
||||
*/
|
||||
void reserve (size_t n);
|
||||
|
||||
/**
|
||||
* @brief Returns the bounding box of the text set
|
||||
*/
|
||||
Box bbox () const
|
||||
{
|
||||
return mp_delegate->bbox ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Filters the texts
|
||||
*
|
||||
* This method will keep all texts for which the filter returns true.
|
||||
*/
|
||||
Texts &filter (const TextFilterBase &filter)
|
||||
{
|
||||
set_delegate (mp_delegate->filter_in_place (filter));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the filtered texts
|
||||
*
|
||||
* This method will return a new text set with only those texts which
|
||||
* conform to the filter criterion.
|
||||
*/
|
||||
Texts filtered (const TextFilterBase &filter) const
|
||||
{
|
||||
return Texts (mp_delegate->filtered (filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all polygons of the other region set which include the texts of this text collection
|
||||
*
|
||||
* Merged semantics applies for the other region. Merged polygons will be selected from the other region
|
||||
* if merged semantics is enabled.
|
||||
*/
|
||||
void pull_interacting (Region &output, const Region &other) const;
|
||||
|
||||
/**
|
||||
* @brief Selects all texts of this text set which are inside the polygons from the region
|
||||
*/
|
||||
Texts &select_interacting (const Region &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_interacting (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all texts of this text set which are inside the polygons from the region
|
||||
*
|
||||
* This method is an out-of-place version of select_interacting.
|
||||
*/
|
||||
Texts selected_interacting (const Region &other) const
|
||||
{
|
||||
return Texts (mp_delegate->selected_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects all texts of this text set which are not inside the polygons from the region
|
||||
*/
|
||||
Texts &select_not_interacting (const Region &other)
|
||||
{
|
||||
set_delegate (mp_delegate->selected_not_interacting (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all texts of this text set which are not inside the polygons from the region
|
||||
*
|
||||
* This method is an out-of-place version of select_not_interacting.
|
||||
*/
|
||||
Texts selected_not_interacting (const Region &other) const
|
||||
{
|
||||
return Texts (mp_delegate->selected_not_interacting (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Transforms the text set
|
||||
*/
|
||||
template <class T>
|
||||
Texts &transform (const T &trans);
|
||||
|
||||
/**
|
||||
* @brief Returns the transformed text set
|
||||
*/
|
||||
template <class T>
|
||||
Texts transformed (const T &trans) const
|
||||
{
|
||||
Texts d (*this);
|
||||
d.transform (trans);
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swaps with the other text set
|
||||
*/
|
||||
void swap (db::Texts &other)
|
||||
{
|
||||
std::swap (other.mp_delegate, mp_delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Joining of text set
|
||||
*
|
||||
* This method joins the text sets.
|
||||
*/
|
||||
Texts operator+ (const Texts &other) const
|
||||
{
|
||||
return Texts (mp_delegate->add (other));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief In-place text set joining
|
||||
*/
|
||||
Texts &operator+= (const Texts &other)
|
||||
{
|
||||
set_delegate (mp_delegate->add_in_place (other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all texts which are in the other text set
|
||||
*
|
||||
* This method will return all texts which are part of another text set.
|
||||
* The match is done exactly.
|
||||
* The "invert" flag can be used to invert the sense, i.e. with
|
||||
* "invert" set to true, this method will return all texts not
|
||||
* in the other text set.
|
||||
*/
|
||||
Texts in (const Texts &other, bool invert = false) const
|
||||
{
|
||||
return Texts (mp_delegate->in (other, invert));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the nth text
|
||||
*
|
||||
* This operation is available only for flat regions - i.e. such for which
|
||||
* "has_valid_texts" is true.
|
||||
*/
|
||||
const db::Text *nth (size_t n) const
|
||||
{
|
||||
return mp_delegate->nth (n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forces flattening of the text collection
|
||||
*
|
||||
* This method will turn any edge pair collection into a flat one.
|
||||
*/
|
||||
void flatten ()
|
||||
{
|
||||
flat_texts ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the text set has valid texts stored within itself
|
||||
*
|
||||
* If the region has valid texts, it is permissable to use the text's addresses
|
||||
* from the iterator. Furthermore, the random access operator nth() is available.
|
||||
*/
|
||||
bool has_valid_texts () const
|
||||
{
|
||||
return mp_delegate->has_valid_texts ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an addressable delivery for texts
|
||||
*
|
||||
* This object allows accessing the texts by address, even if they
|
||||
* are not delivered from a container. The magic is a heap object
|
||||
* inside the delivery object. Hence, the deliver object must persist
|
||||
* as long as the addresses are required.
|
||||
*/
|
||||
AddressableTextDelivery addressable_texts () const
|
||||
{
|
||||
return AddressableTextDelivery (begin (), has_valid_texts ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the internal iterator
|
||||
*
|
||||
* This method is intended for users who know what they are doing
|
||||
*/
|
||||
const db::RecursiveShapeIterator &iter () const;
|
||||
|
||||
/**
|
||||
* @brief Equality
|
||||
*/
|
||||
bool operator== (const db::Texts &other) const
|
||||
{
|
||||
return mp_delegate->equals (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inequality
|
||||
*/
|
||||
bool operator!= (const db::Texts &other) const
|
||||
{
|
||||
return ! mp_delegate->equals (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Less operator
|
||||
*/
|
||||
bool operator< (const db::Texts &other) const
|
||||
{
|
||||
return mp_delegate->less (other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts to polygons
|
||||
*
|
||||
* Note: because of the include hierarchy we can't use a direct return value.
|
||||
*
|
||||
* The output container is not cleared by this method but polygons are rather
|
||||
* appended.
|
||||
*
|
||||
* The given extension is applied in all directions rendering a square of 2*e
|
||||
* width and height. The center of the boxes will be the position of the texts.
|
||||
*/
|
||||
void polygons (Region &output, db::Coord e = 1) const;
|
||||
|
||||
/**
|
||||
* @brief Returns individual, dot-like edges
|
||||
*
|
||||
* Note: because of the include hierarchy we can't use a direct return value.
|
||||
*
|
||||
* The returned edges will be dot-like (identical points) and represent the
|
||||
* position of the text.
|
||||
*/
|
||||
void edges (Edges &output) const;
|
||||
|
||||
/**
|
||||
* @brief Enable progress reporting
|
||||
*
|
||||
* @param progress_text The description text of the progress object
|
||||
*/
|
||||
void enable_progress (const std::string &progress_desc = std::string ())
|
||||
{
|
||||
mp_delegate->enable_progress (progress_desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable progress reporting
|
||||
*/
|
||||
void disable_progress ()
|
||||
{
|
||||
mp_delegate->disable_progress ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts the edge pair collection into the given layout, cell and layer
|
||||
* If the text collection is a hierarchical region, the hierarchy is copied into the
|
||||
* layout's hierarchy.
|
||||
*/
|
||||
void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
return mp_delegate->insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts the edge pair collection into the given layout, cell and layer as polygons with the given enlargement
|
||||
* If the text collection is a hierarchical region, the hierarchy is copied into the
|
||||
* layout's hierarchy.
|
||||
*/
|
||||
void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const
|
||||
{
|
||||
return mp_delegate->insert_into_as_polygons (layout, into_cell, into_layer, enl);
|
||||
}
|
||||
|
||||
private:
|
||||
TextsDelegate *mp_delegate;
|
||||
|
||||
void set_delegate (TextsDelegate *delegate);
|
||||
FlatTexts *flat_texts ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
/**
|
||||
* @brief The type traits for the box type
|
||||
*/
|
||||
template <>
|
||||
struct type_traits <db::Texts> : public type_traits<void>
|
||||
{
|
||||
typedef true_tag supports_extractor;
|
||||
typedef true_tag supports_to_string;
|
||||
typedef true_tag has_less_operator;
|
||||
typedef true_tag has_equal_operator;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbTextsDelegate.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
TextsDelegate::TextsDelegate ()
|
||||
{
|
||||
m_report_progress = false;
|
||||
}
|
||||
|
||||
TextsDelegate::TextsDelegate (const TextsDelegate &other)
|
||||
: db::ShapeCollectionDelegateBase ()
|
||||
{
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
TextsDelegate &
|
||||
TextsDelegate::operator= (const TextsDelegate &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_report_progress = other.m_report_progress;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TextsDelegate::~TextsDelegate ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void TextsDelegate::enable_progress (const std::string &progress_desc)
|
||||
{
|
||||
m_report_progress = true;
|
||||
m_progress_desc = progress_desc;
|
||||
}
|
||||
|
||||
void TextsDelegate::disable_progress ()
|
||||
{
|
||||
m_report_progress = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_dbTextsDelegate
|
||||
#define HDR_dbTextsDelegate
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbShapeCollection.h"
|
||||
#include "dbText.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
class RecursiveShapeIterator;
|
||||
class Texts;
|
||||
class Region;
|
||||
class TextFilterBase;
|
||||
class RegionDelegate;
|
||||
class EdgesDelegate;
|
||||
class Layout;
|
||||
|
||||
/**
|
||||
* @brief The edge pair set iterator delegate
|
||||
*/
|
||||
class DB_PUBLIC TextsIteratorDelegate
|
||||
{
|
||||
public:
|
||||
TextsIteratorDelegate () { }
|
||||
virtual ~TextsIteratorDelegate () { }
|
||||
|
||||
typedef db::Text value_type;
|
||||
|
||||
virtual bool at_end () const = 0;
|
||||
virtual void increment () = 0;
|
||||
virtual const value_type *get () const = 0;
|
||||
virtual TextsIteratorDelegate *clone () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The delegate for the actual edge set implementation
|
||||
*/
|
||||
class DB_PUBLIC TextsDelegate
|
||||
: public ShapeCollectionDelegateBase
|
||||
{
|
||||
public:
|
||||
typedef db::Coord coord_type;
|
||||
typedef db::coord_traits<db::Coord> coord_traits;
|
||||
typedef db::Text edge_pair_type;
|
||||
typedef db::Vector vector_type;
|
||||
typedef db::Point point_type;
|
||||
typedef db::Box box_type;
|
||||
|
||||
TextsDelegate ();
|
||||
virtual ~TextsDelegate ();
|
||||
|
||||
TextsDelegate (const TextsDelegate &other);
|
||||
TextsDelegate &operator= (const TextsDelegate &other);
|
||||
|
||||
virtual TextsDelegate *clone () const = 0;
|
||||
|
||||
void enable_progress (const std::string &progress_desc);
|
||||
void disable_progress ();
|
||||
|
||||
// dummy features to harmonize the interface of region, edges and edge pair delegates
|
||||
void set_merged_semantics (bool) { }
|
||||
bool merged_semantics () const { return false; }
|
||||
void set_is_merged (bool) { }
|
||||
bool is_merged () const { return false; }
|
||||
|
||||
virtual std::string to_string (size_t nmax) const = 0;
|
||||
|
||||
virtual TextsIteratorDelegate *begin () const = 0;
|
||||
virtual std::pair<db::RecursiveShapeIterator, db::ICplxTrans> begin_iter () const = 0;
|
||||
|
||||
virtual bool empty () const = 0;
|
||||
virtual size_t size () const = 0;
|
||||
|
||||
virtual Box bbox () const = 0;
|
||||
|
||||
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter) = 0;
|
||||
virtual TextsDelegate *filtered (const TextFilterBase &filter) const = 0;
|
||||
|
||||
virtual RegionDelegate *polygons (db::Coord e) const = 0;
|
||||
virtual EdgesDelegate *edges () const = 0;
|
||||
|
||||
virtual TextsDelegate *add_in_place (const Texts &other) = 0;
|
||||
virtual TextsDelegate *add (const Texts &other) const = 0;
|
||||
|
||||
virtual TextsDelegate *in (const Texts &other, bool invert) const = 0;
|
||||
|
||||
virtual const db::Text *nth (size_t n) const = 0;
|
||||
virtual bool has_valid_texts () const = 0;
|
||||
|
||||
virtual const db::RecursiveShapeIterator *iter () const = 0;
|
||||
|
||||
virtual bool equals (const Texts &other) const = 0;
|
||||
virtual bool less (const Texts &other) const = 0;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const = 0;
|
||||
virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const = 0;
|
||||
|
||||
virtual RegionDelegate *pull_interacting (const Region &) const = 0;
|
||||
virtual TextsDelegate *selected_interacting (const Region &other) const = 0;
|
||||
virtual TextsDelegate *selected_not_interacting (const Region &other) const = 0;
|
||||
|
||||
protected:
|
||||
const std::string &progress_desc () const
|
||||
{
|
||||
return m_progress_desc;
|
||||
}
|
||||
|
||||
bool report_progress () const
|
||||
{
|
||||
return m_report_progress;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_report_progress;
|
||||
std::string m_progress_desc;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbTextsUtils.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// .. nothing yet ..
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#ifndef HDR_dbTextsUtils
|
||||
#define HDR_dbTextsUtils
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "tlGlobPattern.h"
|
||||
#include "tlSelect.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief An text filter filtering by a string
|
||||
*
|
||||
* It will filter all texts for which the string is equal to "text".
|
||||
* There is an "invert" flag which allows selecting all texts not
|
||||
* matching the criterion.
|
||||
*/
|
||||
|
||||
struct DB_PUBLIC TextStringFilter
|
||||
: public TextFilterBase
|
||||
{
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param text The text string to match
|
||||
* @param inverse If set to true, only polygons not matching this criterion will be filtered
|
||||
*/
|
||||
TextStringFilter (const std::string &text, bool inverse)
|
||||
: m_text (text), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the text matches the criterion
|
||||
*/
|
||||
virtual bool selected (const db::Text &text) const
|
||||
{
|
||||
return (text.string () == m_text) != m_inverse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This filter is not sensitive to hierarchy
|
||||
*/
|
||||
virtual const TransformationReducer *vars () const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Requires merged input
|
||||
*/
|
||||
virtual bool requires_raw_input () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wants to build variants
|
||||
*/
|
||||
virtual bool wants_variants () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_text;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An text filter filtering by a glob-style pattern
|
||||
*
|
||||
* It will filter all texts for which the string matches the given glob-style pattern.
|
||||
* There is an "invert" flag which allows selecting all texts not
|
||||
* matching the criterion.
|
||||
*/
|
||||
|
||||
struct DB_PUBLIC TextPatternFilter
|
||||
: public TextFilterBase
|
||||
{
|
||||
/**
|
||||
* @brief Constructor
|
||||
*
|
||||
* @param text The text pattern to match
|
||||
* @param inverse If set to true, only polygons not matching this criterion will be filtered
|
||||
*/
|
||||
TextPatternFilter (const std::string &text, bool inverse)
|
||||
: m_pattern (text), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the text matches the criterion
|
||||
*/
|
||||
virtual bool selected (const db::Text &text) const
|
||||
{
|
||||
return m_pattern.match (text.string ()) != m_inverse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This filter is not sensitive to hierarchy
|
||||
*/
|
||||
virtual const TransformationReducer *vars () const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Requires merged input
|
||||
*/
|
||||
virtual bool requires_raw_input () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wants to build variants
|
||||
*/
|
||||
virtual bool wants_variants () const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
tl::GlobPattern m_pattern;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the text ref to region interaction functionality which acts as an text receiver
|
||||
*
|
||||
* Note: This special scanner uses pointers to two different objects: texts and polygons.
|
||||
* It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate
|
||||
* pointers to edges.
|
||||
*
|
||||
* There is a special box converter which is able to sort that out as well.
|
||||
*/
|
||||
template <class OutputContainer, class TextType, class OutputType = typename OutputContainer::value_type>
|
||||
class text_to_region_interaction_filter
|
||||
: public db::box_scanner_receiver2<TextType, size_t, db::Polygon, size_t>
|
||||
{
|
||||
public:
|
||||
text_to_region_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void add (const db::TextRef *t, size_t, const db::Polygon *p, size_t)
|
||||
{
|
||||
const OutputType *tt = 0;
|
||||
tl::select (tt, t, p);
|
||||
|
||||
if (m_seen.find (tt) == m_seen.end ()) {
|
||||
if (db::interact (*p, t->obj ().transformed (t->trans ()))) {
|
||||
m_seen.insert (tt);
|
||||
mp_output->insert (*tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add (const db::Text *t, size_t, const db::Polygon *p, size_t)
|
||||
{
|
||||
const OutputType *tt = 0;
|
||||
tl::select (tt, t, p);
|
||||
|
||||
if (m_seen.find (tt) == m_seen.end ()) {
|
||||
if (db::interact (*p, *t)) {
|
||||
m_seen.insert (tt);
|
||||
mp_output->insert (*tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const OutputType *> m_seen;
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
@ -164,6 +164,34 @@ private:
|
|||
const db::ICplxTrans m_trans;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the generic implementation of the text collection insert functionality
|
||||
*/
|
||||
class TextsInserter
|
||||
{
|
||||
public:
|
||||
TextsInserter (db::Texts *texts, const db::ICplxTrans &trans)
|
||||
: mp_texts (texts), m_trans (trans)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void operator() (const T &)
|
||||
{
|
||||
// .. discard anything except Texts ..
|
||||
}
|
||||
|
||||
void operator() (const db::Text &t)
|
||||
{
|
||||
mp_texts->insert (t.transformed (m_trans));
|
||||
}
|
||||
|
||||
private:
|
||||
db::Texts *mp_texts;
|
||||
const db::ICplxTrans m_trans;
|
||||
};
|
||||
|
||||
class TileLayoutOutputReceiver
|
||||
: public db::TileOutputReceiver
|
||||
{
|
||||
|
|
@ -271,6 +299,26 @@ private:
|
|||
db::EdgePairs *mp_edge_pairs;
|
||||
};
|
||||
|
||||
class TileTextsOutputReceiver
|
||||
: public db::TileOutputReceiver
|
||||
{
|
||||
public:
|
||||
TileTextsOutputReceiver (db::Texts *texts)
|
||||
: mp_texts (texts)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void put (size_t /*ix*/, size_t /*iy*/, const db::Box &tile, size_t /*id*/, const tl::Variant &obj, double /*dbu*/, const db::ICplxTrans &trans, bool clip)
|
||||
{
|
||||
TextsInserter inserter (mp_texts, trans);
|
||||
insert_var (inserter, obj, tile, clip);
|
||||
}
|
||||
|
||||
private:
|
||||
db::Texts *mp_texts;
|
||||
};
|
||||
|
||||
class TilingProcessorJob
|
||||
: public tl::JobBase
|
||||
{
|
||||
|
|
@ -395,6 +443,7 @@ private:
|
|||
TilingProcessorJob *mp_job;
|
||||
|
||||
void do_perform (const TilingProcessorTask *task);
|
||||
void make_input_var (const TilingProcessor::InputSpec &is, const db::RecursiveShapeIterator *iter, tl::Eval &eval, double sf);
|
||||
};
|
||||
|
||||
class TilingProcessorReceiverFunction
|
||||
|
|
@ -452,6 +501,24 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void
|
||||
TilingProcessorWorker::make_input_var (const TilingProcessor::InputSpec &is, const db::RecursiveShapeIterator *iter, tl::Eval &eval, double sf)
|
||||
{
|
||||
if (! iter) {
|
||||
iter = &is.iter;
|
||||
}
|
||||
|
||||
if (is.type == TilingProcessor::TypeRegion) {
|
||||
eval.set_var (is.name, tl::Variant (db::Region (*iter, db::ICplxTrans (sf) * is.trans, is.merged_semantics)));
|
||||
} else if (is.type == TilingProcessor::TypeEdges) {
|
||||
eval.set_var (is.name, tl::Variant (db::Edges (*iter, db::ICplxTrans (sf) * is.trans, is.merged_semantics)));
|
||||
} else if (is.type == TilingProcessor::TypeEdgePairs) {
|
||||
eval.set_var (is.name, tl::Variant (db::EdgePairs (*iter, db::ICplxTrans (sf) * is.trans)));
|
||||
} else if (is.type == TilingProcessor::TypeTexts) {
|
||||
eval.set_var (is.name, tl::Variant (db::Texts (*iter, db::ICplxTrans (sf) * is.trans)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task)
|
||||
{
|
||||
|
|
@ -492,11 +559,7 @@ TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task)
|
|||
|
||||
if (! mp_job->has_tiles ()) {
|
||||
|
||||
if (i->region) {
|
||||
eval.set_var (i->name, tl::Variant (db::Region (i->iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics)));
|
||||
} else {
|
||||
eval.set_var (i->name, tl::Variant (db::Edges (i->iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics)));
|
||||
}
|
||||
make_input_var (*i, 0, eval, sf);
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -509,11 +572,7 @@ TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task)
|
|||
iter.confine_region (region_dbu);
|
||||
}
|
||||
|
||||
if (i->region) {
|
||||
eval.set_var (i->name, tl::Variant (db::Region (iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics)));
|
||||
} else {
|
||||
eval.set_var (i->name, tl::Variant (db::Edges (iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics)));
|
||||
}
|
||||
make_input_var (*i, &iter, eval, sf);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -559,7 +618,7 @@ TilingProcessor::TilingProcessor ()
|
|||
}
|
||||
|
||||
void
|
||||
TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans, bool as_region, bool merged_semantics)
|
||||
TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans, Type type, bool merged_semantics)
|
||||
{
|
||||
if (m_inputs.empty () && iter.layout ()) {
|
||||
m_dbu = iter.layout ()->dbu ();
|
||||
|
|
@ -568,7 +627,7 @@ TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterato
|
|||
m_inputs.back ().name = name;
|
||||
m_inputs.back ().iter = iter;
|
||||
m_inputs.back ().trans = trans;
|
||||
m_inputs.back ().region = as_region;
|
||||
m_inputs.back ().type = type;
|
||||
m_inputs.back ().merged_semantics = merged_semantics;
|
||||
}
|
||||
|
||||
|
|
@ -699,7 +758,17 @@ TilingProcessor::output (const std::string &name, db::EdgePairs &edge_pairs)
|
|||
m_outputs.back ().receiver = new TileEdgePairsOutputReceiver (&edge_pairs);
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
TilingProcessor::output (const std::string &name, db::Texts &texts)
|
||||
{
|
||||
m_top_eval.set_var (name, m_outputs.size ());
|
||||
m_outputs.push_back (OutputSpec ());
|
||||
m_outputs.back ().name = name;
|
||||
m_outputs.back ().id = 0;
|
||||
m_outputs.back ().receiver = new TileTextsOutputReceiver (&texts);
|
||||
}
|
||||
|
||||
void
|
||||
TilingProcessor::output (const std::string &name, db::Edges &edges)
|
||||
{
|
||||
m_top_eval.set_var (name, m_outputs.size ());
|
||||
|
|
|
|||
|
|
@ -346,6 +346,20 @@ void insert (X &inserter, const db::EdgePairs &data, const db::Box &tile, bool c
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
* The inserter is an object having an operator() that takes the object.
|
||||
* This function is responsible for preparing (i.e. clipping) and delivering the output.
|
||||
*/
|
||||
template <class X>
|
||||
void insert (X &inserter, const db::Texts &data, const db::Box &tile, bool clip)
|
||||
{
|
||||
for (db::Texts::const_iterator o = data.begin (); ! o.at_end (); ++o) {
|
||||
insert (inserter, *o, tile, clip);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivery of tiling processor output
|
||||
* This utility is put between the container and the receiver.
|
||||
|
|
@ -364,6 +378,9 @@ bool insert_var (X &inserter, const tl::Variant &obj, const db::Box &tile, bool
|
|||
} else if (obj.is_user<db::Edges> ()) {
|
||||
insert (inserter, obj.to_user<db::Edges> (), tile, clip);
|
||||
return true;
|
||||
} else if (obj.is_user<db::Texts> ()) {
|
||||
insert (inserter, obj.to_user<db::Texts> (), tile, clip);
|
||||
return true;
|
||||
} else if (obj.is_user<db::Box> ()) {
|
||||
insert (inserter, obj.to_user<db::Box> (), tile, clip);
|
||||
return true;
|
||||
|
|
@ -417,6 +434,8 @@ bool insert_var (X &inserter, const tl::Variant &obj, const db::Box &tile, bool
|
|||
class DB_PUBLIC TilingProcessor
|
||||
{
|
||||
public:
|
||||
enum Type { TypeRegion, TypeEdges, TypeEdgePairs, TypeTexts };
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
|
|
@ -441,7 +460,7 @@ public:
|
|||
* The transformation can be used to convert between database units.
|
||||
* If "as_region" is false, the input is taken as edge input.
|
||||
*/
|
||||
void input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans = db::ICplxTrans (), bool as_region = true, bool merged_semantics = true);
|
||||
void input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans = db::ICplxTrans (), Type type = TypeRegion, bool merged_semantics = true);
|
||||
|
||||
/**
|
||||
* @brief Specifies the output
|
||||
|
|
@ -489,6 +508,14 @@ public:
|
|||
*/
|
||||
void output (const std::string &name, db::EdgePairs &edge_pairs);
|
||||
|
||||
/**
|
||||
* @brief Specifies output to an text collection
|
||||
*
|
||||
* This version will specify output to a Texts object.
|
||||
* Only texts will be stored.
|
||||
*/
|
||||
void output (const std::string &name, db::Texts &texts);
|
||||
|
||||
/**
|
||||
* @brief Specifies output to an edge collection
|
||||
*
|
||||
|
|
@ -624,11 +651,11 @@ private:
|
|||
|
||||
struct InputSpec
|
||||
{
|
||||
InputSpec () : region (false), merged_semantics (false) { }
|
||||
InputSpec () : type (TilingProcessor::TypeRegion), merged_semantics (false) { }
|
||||
std::string name;
|
||||
db::RecursiveShapeIterator iter;
|
||||
db::ICplxTrans trans;
|
||||
bool region;
|
||||
TilingProcessor::Type type;
|
||||
bool merged_semantics;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -179,7 +179,9 @@ static size_t id (const db::EdgePairs *ep)
|
|||
return tl::id_of (ep->delegate ());
|
||||
}
|
||||
|
||||
Class<db::EdgePairs> decl_EdgePairs ("db", "EdgePairs",
|
||||
extern Class<db::ShapeCollection> decl_dbShapeCollection;
|
||||
|
||||
Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
||||
constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -412,7 +412,9 @@ static size_t id (const db::Edges *e)
|
|||
return tl::id_of (e->delegate ());
|
||||
}
|
||||
|
||||
Class<db::Edges> dec_Edges ("db", "Edges",
|
||||
extern Class<db::ShapeCollection> decl_dbShapeCollection;
|
||||
|
||||
Class<db::Edges> dec_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||
constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
|
|
@ -426,13 +428,13 @@ Class<db::Edges> dec_Edges ("db", "Edges",
|
|||
constructor ("new", &new_a1, gsi::arg ("array"),
|
||||
"@brief Constructor from a polygon array\n"
|
||||
"\n"
|
||||
"This constructor creates a region from an array of polygons.\n"
|
||||
"This constructor creates an edge collection from an array of polygons.\n"
|
||||
"The edges form the contours of the polygons.\n"
|
||||
) +
|
||||
constructor ("new", &new_a2, gsi::arg ("array"),
|
||||
"@brief Constructor from an edge array\n"
|
||||
"\n"
|
||||
"This constructor creates a region from an array of edges.\n"
|
||||
"This constructor creates an edge collection from an array of edges.\n"
|
||||
) +
|
||||
constructor ("new", &new_b, gsi::arg ("box"),
|
||||
"@brief Box constructor\n"
|
||||
|
|
@ -859,7 +861,7 @@ Class<db::Edges> dec_Edges ("db", "Edges",
|
|||
method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
|
||||
"@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 region\n"
|
||||
"@return A new edge collection containing the edges overlapping or touching edges from the other edge collection\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
|
|
@ -867,7 +869,7 @@ Class<db::Edges> dec_Edges ("db", "Edges",
|
|||
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the edges of this edge collection which do not overlap or touch edges from the other edge collection\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching edges from the other region\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching edges from the other edge collection\n"
|
||||
"\n"
|
||||
"This method does not merge the edges before they are selected. If you want to select coherent "
|
||||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
|
|
@ -889,7 +891,7 @@ Class<db::Edges> dec_Edges ("db", "Edges",
|
|||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the edges from this region which overlap or touch polygons from the region\n"
|
||||
"@brief Returns the edges from this edge collection which overlap or touch polygons from the region\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges overlapping or touching polygons from the region\n"
|
||||
"\n"
|
||||
|
|
@ -897,7 +899,7 @@ Class<db::Edges> dec_Edges ("db", "Edges",
|
|||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the edges from this region which do not overlap or touch polygons from the region\n"
|
||||
"@brief Returns the edges from this edge collection which do not overlap or touch polygons from the region\n"
|
||||
"\n"
|
||||
"@return A new edge collection containing the edges not overlapping or touching polygons from the region\n"
|
||||
"\n"
|
||||
|
|
@ -905,7 +907,7 @@ Class<db::Edges> dec_Edges ("db", "Edges",
|
|||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this region which overlap or touch polygons from the region\n"
|
||||
"@brief Selects the edges from this edge collection which overlap or touch polygons from the region\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
|
|
@ -913,7 +915,7 @@ Class<db::Edges> dec_Edges ("db", "Edges",
|
|||
"edges, make sure the edge collection is merged before this method is used.\n"
|
||||
) +
|
||||
method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the edges from this region which do not overlap or touch polygons from the region\n"
|
||||
"@brief Selects the edges from this edge collection which do not overlap or touch polygons from the region\n"
|
||||
"\n"
|
||||
"@return The edge collection after the edges have been selected (self)\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@
|
|||
#include "dbPCellDeclaration.h"
|
||||
#include "dbHash.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
|
|
@ -1188,6 +1191,30 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.26.\n"
|
||||
) +
|
||||
gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, int, const db::EdgePairs &)) &db::Layout::insert,
|
||||
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("edge_pairs"),
|
||||
"@brief Inserts an edge pair collection into the given cell and layer\n"
|
||||
"If the edge pair collection is (conceptionally) flat, it will be inserted into the cell's shapes "
|
||||
"list as a flat sequence of edge pairs.\n"
|
||||
"If the edge pair collection is deep (hierarchical), it will create a subhierarchy below the given "
|
||||
"cell and it's edge pairs will be put into the respective cells. Suitable subcells will be picked "
|
||||
"for inserting the edge pairs. If a hierarchy already exists below the given cell, the algorithm will "
|
||||
"try to reuse this hierarchy.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, int, const db::Texts &)) &db::Layout::insert,
|
||||
gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("texts"),
|
||||
"@brief Inserts an text collection into the given cell and layer\n"
|
||||
"If the text collection is (conceptionally) flat, it will be inserted into the cell's shapes "
|
||||
"list as a flat sequence of texts.\n"
|
||||
"If the text collection is deep (hierarchical), it will create a subhierarchy below the given "
|
||||
"cell and it's texts will be put into the respective cells. Suitable subcells will be picked "
|
||||
"for inserting the texts. If a hierarchy already exists below the given cell, the algorithm will "
|
||||
"try to reuse this hierarchy.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("flatten", &flatten, gsi::arg ("cell_index"), gsi::arg ("levels"), gsi::arg ("prune"),
|
||||
"@brief Flattens the given cell\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
gsi::method ("original_file=", &db::LayoutToNetlist::set_original_file,
|
||||
"@brief Sets the original file name of the database\n"
|
||||
) +
|
||||
gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (const db::Region ®ion) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
|
||||
gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (const db::ShapeCollection ®ion) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
|
||||
"@brief Gets the name of the given layer\n"
|
||||
) +
|
||||
gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (unsigned int) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
|
||||
|
|
@ -254,6 +254,13 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"\n"
|
||||
"If required, the system will assign a name automatically."
|
||||
) +
|
||||
gsi::method ("register", (void (db::LayoutToNetlist::*) (const db::Texts &texts, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n"),
|
||||
"@brief Names the given layer\n"
|
||||
"This method behaves like the one provided for Regions but accepts Texts. "
|
||||
"Texts (hierarchical text collections) are useful to represent labels for naming nets.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("layer_names", &l2n_layer_names,
|
||||
"@brief Returns a list of names of the layer kept inside the LayoutToNetlist object."
|
||||
) +
|
||||
|
|
@ -266,12 +273,20 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"Only named layers can be retrieved with this method. "
|
||||
"The returned object is a copy which represents the named layer."
|
||||
) +
|
||||
gsi::method ("is_persisted?", &db::LayoutToNetlist::is_persisted, gsi::arg ("layer"),
|
||||
gsi::method ("is_persisted?", &db::LayoutToNetlist::is_persisted<db::Region>, gsi::arg ("layer"),
|
||||
"@brief Returns true, if the given layer is a persisted region.\n"
|
||||
"Persisted layers are kept inside the LayoutToNetlist object and are not released "
|
||||
"if their object is destroyed. Named layers are persisted, unnamed layers are not. "
|
||||
"Only persisted, named layers can be put into \\connect."
|
||||
) +
|
||||
gsi::method ("is_persisted?", &db::LayoutToNetlist::is_persisted<db::Texts>, gsi::arg ("layer"),
|
||||
"@brief Returns true, if the given layer is a persisted texts collection.\n"
|
||||
"Persisted layers are kept inside the LayoutToNetlist object and are not released "
|
||||
"if their object is destroyed. Named layers are persisted, unnamed layers are not. "
|
||||
"Only persisted, named layers can be put into \\connect.\n"
|
||||
"\n"
|
||||
"The variant for Texts collections has been added in version 0.27."
|
||||
) +
|
||||
gsi::factory ("make_layer", (db::Region *(db::LayoutToNetlist::*) (const std::string &)) &db::LayoutToNetlist::make_layer, gsi::arg ("name", std::string ()),
|
||||
"@brief Creates a new, empty hierarchical region\n"
|
||||
"\n"
|
||||
|
|
@ -291,6 +306,8 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"See \\make_layer for details.\n"
|
||||
"\n"
|
||||
"The name is optional. If given, the layer will already be named accordingly (see \\register).\n"
|
||||
"\n"
|
||||
"Starting with version 0.27, this method returns a \\Texts object."
|
||||
) +
|
||||
gsi::factory ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()),
|
||||
"@brief Creates a new region representing an original layer taking polygons and texts\n"
|
||||
|
|
@ -321,11 +338,32 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"@brief Defines an inter-layer connection for the given layers.\n"
|
||||
"The conditions mentioned with intra-layer \\connect apply for this method too.\n"
|
||||
) +
|
||||
gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Region &, const db::Texts &)) &db::LayoutToNetlist::connect, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief Defines an inter-layer connection for the given layers.\n"
|
||||
"The conditions mentioned with intra-layer \\connect apply for this method too.\n"
|
||||
"As one argument is a (hierarchical) text collection, this method is used to attach net labels to polygons.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Texts &, const db::Region &)) &db::LayoutToNetlist::connect, gsi::arg ("a"), gsi::arg ("b"),
|
||||
"@brief Defines an inter-layer connection for the given layers.\n"
|
||||
"The conditions mentioned with intra-layer \\connect apply for this method too.\n"
|
||||
"As one argument is a (hierarchical) text collection, this method is used to attach net labels to polygons.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("connect_global", (void (db::LayoutToNetlist::*) (const db::Region &, const std::string &)) &db::LayoutToNetlist::connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"),
|
||||
"@brief Defines a connection of the given layer with a global net.\n"
|
||||
"This method returns the ID of the global net. Use \\global_net_name to get "
|
||||
"the name back from the ID."
|
||||
) +
|
||||
gsi::method ("connect_global", (void (db::LayoutToNetlist::*) (const db::Texts &, const std::string &)) &db::LayoutToNetlist::connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"),
|
||||
"@brief Defines a connection of the given text layer with a global net.\n"
|
||||
"This method returns the ID of the global net. Use \\global_net_name to get "
|
||||
"the name back from the ID."
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("global_net_name", &db::LayoutToNetlist::global_net_name, gsi::arg ("global_net_id"),
|
||||
"@brief Gets the global net name for the given global net ID."
|
||||
) +
|
||||
|
|
@ -378,11 +416,18 @@ Class<db::LayoutToNetlist> decl_dbLayoutToNetlist ("db", "LayoutToNetlist",
|
|||
"Usually it should not be required to obtain the internal cell. If you need to do so, make sure not to modify the cell as\n"
|
||||
"the functionality of the netlist extractor depends on it."
|
||||
) +
|
||||
gsi::method ("layer_of", &db::LayoutToNetlist::layer_of, gsi::arg ("l"),
|
||||
gsi::method ("layer_of", &db::LayoutToNetlist::layer_of<db::Region>, gsi::arg ("l"),
|
||||
"@brief Gets the internal layer for a given extraction layer\n"
|
||||
"This method is required to derive the internal layer index - for example for\n"
|
||||
"investigating the cluster tree.\n"
|
||||
) +
|
||||
gsi::method ("layer_of", &db::LayoutToNetlist::layer_of<db::Texts>, gsi::arg ("l"),
|
||||
"@brief Gets the internal layer for a given text collection\n"
|
||||
"This method is required to derive the internal layer index - for example for\n"
|
||||
"investigating the cluster tree.\n"
|
||||
"\n"
|
||||
"The variant for Texts collections has been added in version 0.27.\n"
|
||||
) +
|
||||
gsi::method ("cell_mapping_into", (db::CellMapping (db::LayoutToNetlist::*) (db::Layout &, db::Cell &, bool)) &db::LayoutToNetlist::cell_mapping_into, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("with_device_cells", false),
|
||||
"@brief Creates a cell mapping for copying shapes from the internal layout to the given target layout.\n"
|
||||
"If 'with_device_cells' is true, cells will be produced for devices. These are cells not corresponding to circuits, so they are disabled normally.\n"
|
||||
|
|
|
|||
|
|
@ -607,7 +607,9 @@ static size_t id (const db::Region *r)
|
|||
int td_simple ();
|
||||
int po_any ();
|
||||
|
||||
Class<db::Region> decl_Region ("db", "Region",
|
||||
extern Class<db::ShapeCollection> decl_dbShapeCollection;
|
||||
|
||||
Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
||||
constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
|
|
@ -1509,6 +1511,42 @@ Class<db::Region> decl_Region ("db", "Region",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.25\n"
|
||||
) +
|
||||
method ("interacting", (db::Region (db::Region::*) (const db::Texts &) const) &db::Region::selected_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the polygons of this region which overlap or touch texts\n"
|
||||
"\n"
|
||||
"@return A new region containing the polygons overlapping or touching texts\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
method ("not_interacting", (db::Region (db::Region::*) (const db::Texts &) const) &db::Region::selected_not_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the polygons of this region which do not overlap or touch texts\n"
|
||||
"\n"
|
||||
"@return A new region containing the polygons not overlapping or touching texts\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
method ("select_interacting", (db::Region &(db::Region::*) (const db::Texts &)) &db::Region::select_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the polygons of this region which overlap or touch texts\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
method ("select_not_interacting", (db::Region &(db::Region::*) (const db::Texts &)) &db::Region::select_not_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the polygons of this region which do not overlap or touch texts\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (self)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
method ("overlapping", &db::Region::selected_overlapping, gsi::arg ("other"),
|
||||
"@brief Returns the polygons of this region which overlap polygons from the other region\n"
|
||||
"\n"
|
||||
|
|
@ -1580,6 +1618,16 @@ Class<db::Region> decl_Region ("db", "Region",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.26.1\n"
|
||||
) +
|
||||
method ("pull_interacting", static_cast<db::Texts (db::Region::*) (const db::Texts &) const> (&db::Region::pull_interacting), gsi::arg ("other"),
|
||||
"@brief Returns all texts of \"other\" which are interacting with polygons of this region\n"
|
||||
"See \\pull_inside for a description of the \"pull_...\" methods.\n"
|
||||
"\n"
|
||||
"@return The text collection after the texts have been selected (from other)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27\n"
|
||||
) +
|
||||
method ("is_box?", &db::Region::is_box,
|
||||
"@brief Returns true, if the region is a simple box\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "gsiDecl.h"
|
||||
#include "dbShapeCollection.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
Class<db::ShapeCollection> decl_dbShapeCollection ("db", "ShapeCollection",
|
||||
gsi::Methods (),
|
||||
"@brief A base class for the shape collections (\\Region, \\Edges, \\EdgePairs and \\Texts)\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.27."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -419,6 +419,29 @@ static void insert_edge_pairs_with_dtrans (db::Shapes *sh, const db::EdgePairs &
|
|||
}
|
||||
}
|
||||
|
||||
static void insert_texts (db::Shapes *sh, const db::Texts &r)
|
||||
{
|
||||
for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (*s);
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_texts_with_trans (db::Shapes *sh, const db::Texts &r, const db::ICplxTrans &trans)
|
||||
{
|
||||
for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (trans));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_texts_with_dtrans (db::Shapes *sh, const db::Texts &r, const db::DCplxTrans &trans)
|
||||
{
|
||||
db::CplxTrans dbu_trans (shapes_dbu (sh));
|
||||
db::ICplxTrans itrans = dbu_trans.inverted () * trans * dbu_trans;
|
||||
for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) {
|
||||
sh->insert (s->transformed (itrans));
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int s_all () { return db::ShapeIterator::All; }
|
||||
static unsigned int s_all_with_properties () { return db::ShapeIterator::AllWithProperties; }
|
||||
static unsigned int s_properties () { return db::ShapeIterator::Properties; }
|
||||
|
|
@ -599,7 +622,7 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
|
|||
"@param edges The edge pairs to insert\n"
|
||||
"@param trans The transformation to apply (displacement in micrometer units)\n"
|
||||
"\n"
|
||||
"This method inserts all edge pairs from the edge collection into this shape container.\n"
|
||||
"This method inserts all edge pairs from the edge pair collection into this shape container.\n"
|
||||
"Before an edge pair is inserted, the given transformation is applied.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.\n"
|
||||
|
|
@ -682,6 +705,34 @@ Class<db::Shapes> decl_Shapes ("db", "Shapes",
|
|||
"\n"
|
||||
"This method has been introduced in version 0.25.\n"
|
||||
) +
|
||||
gsi::method_ext ("insert", &insert_texts, gsi::arg ("texts"),
|
||||
"@brief Inserts the texts from the text collection into this shape container\n"
|
||||
"@param texts The texts to insert\n"
|
||||
"\n"
|
||||
"This method inserts all texts from the text collection into this shape container.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("insert", &insert_texts_with_trans, gsi::arg ("texts"), gsi::arg ("trans"),
|
||||
"@brief Inserts the texts from the text collection into this shape container with a transformation\n"
|
||||
"@param edges The texts to insert\n"
|
||||
"@param trans The transformation to apply\n"
|
||||
"\n"
|
||||
"This method inserts all texts from the text collection into this shape container.\n"
|
||||
"Before an text is inserted, the given transformation is applied.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("insert", &insert_texts_with_dtrans, gsi::arg ("texts"), gsi::arg ("trans"),
|
||||
"@brief Inserts the texts from the text collection into this shape container with a transformation (given in micrometer units)\n"
|
||||
"@param edges The text to insert\n"
|
||||
"@param trans The transformation to apply (displacement in micrometer units)\n"
|
||||
"\n"
|
||||
"This method inserts all texts from the text collection into this shape container.\n"
|
||||
"Before an text is inserted, the given transformation is applied.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
) +
|
||||
gsi::method_ext ("transform", &transform_shapes, gsi::arg ("trans"),
|
||||
"@brief Transforms all shapes with the given transformation\n"
|
||||
"This method will invalidate all references to shapes inside this collection.\n\n"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,518 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "gsiDecl.h"
|
||||
|
||||
#include "dbTexts.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbDeepTexts.h"
|
||||
#include "dbTextsUtils.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
static db::Texts *new_v ()
|
||||
{
|
||||
return new db::Texts ();
|
||||
}
|
||||
|
||||
static db::Texts *new_a (const std::vector<db::Text> &t)
|
||||
{
|
||||
return new db::Texts (t.begin (), t.end ());
|
||||
}
|
||||
|
||||
static db::Texts *new_text (const db::Text &t)
|
||||
{
|
||||
return new db::Texts (t);
|
||||
}
|
||||
|
||||
static db::Texts *new_shapes (const db::Shapes &s)
|
||||
{
|
||||
db::Texts *r = new db::Texts ();
|
||||
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::Texts); !i.at_end (); ++i) {
|
||||
r->insert (*i);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static db::Texts *new_si (const db::RecursiveShapeIterator &si)
|
||||
{
|
||||
return new db::Texts (si);
|
||||
}
|
||||
|
||||
static db::Texts *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
return new db::Texts (si, trans);
|
||||
}
|
||||
|
||||
static db::Texts *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss)
|
||||
{
|
||||
return new db::Texts (si, dss);
|
||||
}
|
||||
|
||||
static db::Texts *new_si2d (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const db::ICplxTrans &trans)
|
||||
{
|
||||
return new db::Texts (si, dss, trans);
|
||||
}
|
||||
|
||||
static std::string to_string0 (const db::Texts *r)
|
||||
{
|
||||
return r->to_string ();
|
||||
}
|
||||
|
||||
static std::string to_string1 (const db::Texts *r, size_t n)
|
||||
{
|
||||
return r->to_string (n);
|
||||
}
|
||||
|
||||
static db::Texts &move_p (db::Texts *r, const db::Vector &p)
|
||||
{
|
||||
r->transform (db::Disp (p));
|
||||
return *r;
|
||||
}
|
||||
|
||||
static db::Texts &move_xy (db::Texts *r, db::Coord x, db::Coord y)
|
||||
{
|
||||
r->transform (db::Disp (db::Vector (x, y)));
|
||||
return *r;
|
||||
}
|
||||
|
||||
static db::Texts moved_p (const db::Texts *r, const db::Vector &p)
|
||||
{
|
||||
return r->transformed (db::Disp (p));
|
||||
}
|
||||
|
||||
static db::Texts moved_xy (const db::Texts *r, db::Coord x, db::Coord y)
|
||||
{
|
||||
return r->transformed (db::Disp (db::Vector (x, y)));
|
||||
}
|
||||
|
||||
static db::Region polygons0 (const db::Texts *e, db::Coord d)
|
||||
{
|
||||
db::Region r;
|
||||
e->polygons (r, d);
|
||||
return r;
|
||||
}
|
||||
|
||||
static db::Region extents1 (const db::Texts *r, db::Coord dx, db::Coord dy)
|
||||
{
|
||||
db::Region e;
|
||||
e.reserve (r->size ());
|
||||
for (db::Texts::const_iterator i = r->begin (); ! i.at_end (); ++i) {
|
||||
e.insert (i->box ().enlarged (db::Vector (dx, dy)));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static db::Region extents0 (const db::Texts *r, db::Coord d)
|
||||
{
|
||||
return extents1 (r, d, d);
|
||||
}
|
||||
|
||||
static db::Edges edges (const db::Texts *ep)
|
||||
{
|
||||
db::Edges e;
|
||||
ep->edges (e);
|
||||
return e;
|
||||
}
|
||||
|
||||
static void insert_t (db::Texts *t, const db::Texts &a)
|
||||
{
|
||||
for (db::Texts::const_iterator p = a.begin (); ! p.at_end (); ++p) {
|
||||
t->insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_deep (const db::Texts *t)
|
||||
{
|
||||
return dynamic_cast<const db::DeepTexts *> (t->delegate ()) != 0;
|
||||
}
|
||||
|
||||
static size_t id (const db::Texts *t)
|
||||
{
|
||||
return tl::id_of (t->delegate ());
|
||||
}
|
||||
|
||||
static db::Texts with_text (const db::Texts *r, const std::string &text, bool inverse)
|
||||
{
|
||||
db::TextStringFilter f (text, inverse);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Texts with_match (const db::Texts *r, const std::string &pattern, bool inverse)
|
||||
{
|
||||
db::TextPatternFilter f (pattern, inverse);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Region pull_interacting (const db::Texts *r, const db::Region &other)
|
||||
{
|
||||
db::Region out;
|
||||
r->pull_interacting (out, other);
|
||||
return out;
|
||||
}
|
||||
|
||||
extern Class<db::ShapeCollection> decl_dbShapeCollection;
|
||||
|
||||
Class<db::Texts> decl_Texts (decl_dbShapeCollection, "db", "Texts",
|
||||
constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
"\n"
|
||||
"This constructor creates an empty text collection.\n"
|
||||
) +
|
||||
constructor ("new", &new_a, gsi::arg ("array"),
|
||||
"@brief Constructor from an text array\n"
|
||||
"\n"
|
||||
"This constructor creates an text collection from an array of \\Text objects.\n"
|
||||
) +
|
||||
constructor ("new", &new_text, gsi::arg ("text"),
|
||||
"@brief Constructor from a single edge pair object\n"
|
||||
"\n"
|
||||
"This constructor creates an text collection with a single text.\n"
|
||||
) +
|
||||
constructor ("new", &new_shapes, gsi::arg ("shapes"),
|
||||
"@brief Shapes constructor\n"
|
||||
"\n"
|
||||
"This constructor creates an text collection from a \\Shapes collection.\n"
|
||||
) +
|
||||
constructor ("new", &new_si, gsi::arg ("shape_iterator"),
|
||||
"@brief Constructor from a hierarchical shape set\n"
|
||||
"\n"
|
||||
"This constructor creates a text collection from the shapes delivered by the given recursive shape iterator.\n"
|
||||
"Only texts are taken from the shape set and other shapes are ignored.\n"
|
||||
"This method allows feeding the text collection from a hierarchy of cells.\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"layout = ... # a layout\n"
|
||||
"cell = ... # the index of the initial cell\n"
|
||||
"layer = ... # the index of the layer from where to take the shapes from\n"
|
||||
"r = RBA::Texts::new(layout.begin_shapes(cell, layer))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
constructor ("new", &new_si2, gsi::arg ("shape_iterator"), gsi::arg ("trans"),
|
||||
"@brief Constructor from a hierarchical shape set with a transformation\n"
|
||||
"\n"
|
||||
"This constructor creates a text collection from the shapes delivered by the given recursive shape iterator.\n"
|
||||
"Only texts are taken from the shape set and other shapes are ignored.\n"
|
||||
"The given transformation is applied to each text taken.\n"
|
||||
"This method allows feeding the text collection from a hierarchy of cells.\n"
|
||||
"The transformation is useful to scale to a specific database unit for example.\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"layout = ... # a layout\n"
|
||||
"cell = ... # the index of the initial cell\n"
|
||||
"layer = ... # the index of the layer from where to take the shapes from\n"
|
||||
"dbu = 0.1 # the target database unit\n"
|
||||
"r = RBA::Texts::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
constructor ("new", &new_sid, gsi::arg ("shape_iterator"), gsi::arg ("dss"),
|
||||
"@brief Creates a hierarchical text collection from an original layer\n"
|
||||
"\n"
|
||||
"This constructor creates a text collection from the shapes delivered by the given recursive shape iterator.\n"
|
||||
"This version will create a hierarchical text collection which supports hierarchical operations.\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"dss = RBA::DeepShapeStore::new\n"
|
||||
"layout = ... # a layout\n"
|
||||
"cell = ... # the index of the initial cell\n"
|
||||
"layer = ... # the index of the layer from where to take the shapes from\n"
|
||||
"r = RBA::Texts::new(layout.begin_shapes(cell, layer))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
constructor ("new", &new_si2d, gsi::arg ("shape_iterator"), gsi::arg ("dss"), gsi::arg ("trans"),
|
||||
"@brief Creates a hierarchical text collection from an original layer with a transformation\n"
|
||||
"\n"
|
||||
"This constructor creates a text collection from the shapes delivered by the given recursive shape iterator.\n"
|
||||
"This version will create a hierarchical text collection which supports hierarchical operations.\n"
|
||||
"The transformation is useful to scale to a specific database unit for example.\n"
|
||||
"\n"
|
||||
"@code\n"
|
||||
"dss = RBA::DeepShapeStore::new\n"
|
||||
"layout = ... # a layout\n"
|
||||
"cell = ... # the index of the initial cell\n"
|
||||
"layer = ... # the index of the layer from where to take the shapes from\n"
|
||||
"dbu = 0.1 # the target database unit\n"
|
||||
"r = RBA::Texts::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
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 "
|
||||
"and existing hierarchy will be reused.\n"
|
||||
) +
|
||||
method ("insert_into_as_polygons", &db::Texts::insert_into_as_polygons, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("e"),
|
||||
"@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 "
|
||||
"and existing hierarchy will be reused.\n"
|
||||
"\n"
|
||||
"The texts will be converted to polygons with the enlargement value given be 'e'. See \\polygon or \\extents for details.\n"
|
||||
) +
|
||||
method ("insert", (void (db::Texts::*) (const db::Text &)) &db::Texts::insert, gsi::arg ("text"),
|
||||
"@brief Inserts a text into the collection\n"
|
||||
) +
|
||||
method_ext ("is_deep?", &is_deep,
|
||||
"@brief Returns true if the edge pair collection is a deep (hierarchical) one\n"
|
||||
) +
|
||||
method_ext ("data_id", &id,
|
||||
"@brief Returns the data ID (a unique identifier for the underlying data storage)\n"
|
||||
) +
|
||||
method ("+", &db::Texts::operator+, gsi::arg ("other"),
|
||||
"@brief Returns the combined text collection of self and the other one\n"
|
||||
"\n"
|
||||
"@return The resulting text collection\n"
|
||||
"\n"
|
||||
"This operator adds the texts of the other collection to self and returns a new combined set.\n"
|
||||
) +
|
||||
method ("+=", &db::Texts::operator+=, gsi::arg ("other"),
|
||||
"@brief Adds the texts of the other text collection to self\n"
|
||||
"\n"
|
||||
"@return The text collection after modification (self)\n"
|
||||
"\n"
|
||||
"This operator adds the texts of the other collection to self.\n"
|
||||
) +
|
||||
method_ext ("move", &move_p, gsi::arg ("p"),
|
||||
"@brief Moves the text collection\n"
|
||||
"\n"
|
||||
"Moves the texts by the given offset and returns the \n"
|
||||
"moved text collection. The text collection is overwritten.\n"
|
||||
"\n"
|
||||
"@param p The distance to move the texts.\n"
|
||||
"\n"
|
||||
"@return The moved texts (self).\n"
|
||||
) +
|
||||
method_ext ("move", &move_xy, gsi::arg ("x"), gsi::arg ("y"),
|
||||
"@brief Moves the text collection\n"
|
||||
"\n"
|
||||
"Moves the edge pairs by the given offset and returns the \n"
|
||||
"moved texts. The edge pair collection is overwritten.\n"
|
||||
"\n"
|
||||
"@param x The x distance to move the texts.\n"
|
||||
"@param y The y distance to move the texts.\n"
|
||||
"\n"
|
||||
"@return The moved texts (self).\n"
|
||||
) +
|
||||
method_ext ("moved", &moved_p, gsi::arg ("p"),
|
||||
"@brief Returns the moved text collection (does not modify self)\n"
|
||||
"\n"
|
||||
"Moves the texts by the given offset and returns the \n"
|
||||
"moved texts. The text collection is not modified.\n"
|
||||
"\n"
|
||||
"@param p The distance to move the texts.\n"
|
||||
"\n"
|
||||
"@return The moved texts.\n"
|
||||
) +
|
||||
method_ext ("moved", &moved_xy, gsi::arg ("x"), gsi::arg ("y"),
|
||||
"@brief Returns the moved edge pair collection (does not modify self)\n"
|
||||
"\n"
|
||||
"Moves the texts by the given offset and returns the \n"
|
||||
"moved texts. The text collection is not modified.\n"
|
||||
"\n"
|
||||
"@param x The x distance to move the texts.\n"
|
||||
"@param y The y distance to move the texts.\n"
|
||||
"\n"
|
||||
"@return The moved texts.\n"
|
||||
) +
|
||||
method ("transformed", (db::Texts (db::Texts::*)(const db::Trans &) const) &db::Texts::transformed, gsi::arg ("t"),
|
||||
"@brief Transform the edge pair collection\n"
|
||||
"\n"
|
||||
"Transforms the texts with the given transformation.\n"
|
||||
"Does not modify the edge pair collection but returns the transformed texts.\n"
|
||||
"\n"
|
||||
"@param t The transformation to apply.\n"
|
||||
"\n"
|
||||
"@return The transformed texts.\n"
|
||||
) +
|
||||
method ("transformed|#transformed_icplx", (db::Texts (db::Texts::*)(const db::ICplxTrans &) const) &db::Texts::transformed, gsi::arg ("t"),
|
||||
"@brief Transform the text collection with a complex transformation\n"
|
||||
"\n"
|
||||
"Transforms the text with the given complex transformation.\n"
|
||||
"Does not modify the text collection but returns the transformed texts.\n"
|
||||
"\n"
|
||||
"@param t The transformation to apply.\n"
|
||||
"\n"
|
||||
"@return The transformed texts.\n"
|
||||
) +
|
||||
method ("transform", (db::Texts &(db::Texts::*)(const db::Trans &)) &db::Texts::transform, gsi::arg ("t"),
|
||||
"@brief Transform the text collection (modifies self)\n"
|
||||
"\n"
|
||||
"Transforms the text collection with the given transformation.\n"
|
||||
"This version modifies the text collection and returns a reference to self.\n"
|
||||
"\n"
|
||||
"@param t The transformation to apply.\n"
|
||||
"\n"
|
||||
"@return The transformed text collection.\n"
|
||||
) +
|
||||
method ("transform|#transform_icplx", (db::Texts &(db::Texts::*)(const db::ICplxTrans &)) &db::Texts::transform, gsi::arg ("t"),
|
||||
"@brief Transform the text collection with a complex transformation (modifies self)\n"
|
||||
"\n"
|
||||
"Transforms the text collection with the given transformation.\n"
|
||||
"This version modifies the text collection and returns a reference to self.\n"
|
||||
"\n"
|
||||
"@param t The transformation to apply.\n"
|
||||
"\n"
|
||||
"@return The transformed text collection.\n"
|
||||
) +
|
||||
method_ext ("insert", &insert_t, gsi::arg ("texts"),
|
||||
"@brief Inserts all texts from the other text collection into this collection\n"
|
||||
) +
|
||||
method_ext ("edges", &edges,
|
||||
"@brief Returns dot-like edges for the texts\n"
|
||||
"@return An edge collection containing the individual, dot-like edges\n"
|
||||
) +
|
||||
method_ext ("extents", &extents0, gsi::arg ("d", db::Coord (1)),
|
||||
"@brief Returns a region with the enlarged bounding boxes of the texts\n"
|
||||
"Text bounding boxes are point-like boxes which vanish unless an enlargement of >0 is specified.\n"
|
||||
"The bounding box is centered at the text's location.\n"
|
||||
"The boxes will not be merged, so it is possible to determine overlaps "
|
||||
"of these boxes for example.\n"
|
||||
) +
|
||||
method_ext ("extents", &extents1, gsi::arg ("dx"), gsi::arg ("dy"),
|
||||
"@brief Returns a region with the enlarged bounding boxes of the texts\n"
|
||||
"This method acts like the other version of \\extents, but allows giving different enlargements for x and y direction.\n"
|
||||
) +
|
||||
method_ext ("polygons", &polygons0, gsi::arg ("e", db::Coord (1)),
|
||||
"@brief Converts the edge pairs to polygons\n"
|
||||
"This method creates polygons from the texts. This is equivalent to calling \\extents."
|
||||
) +
|
||||
method_ext ("with_text", with_text, gsi::arg ("text"), gsi::arg ("inverse"),
|
||||
"@brief Filter the text by text string\n"
|
||||
"If \"inverse\" is false, this method returns the texts with the given string.\n"
|
||||
"If \"inverse\" is true, this method returns the texts not having the given string.\n"
|
||||
) +
|
||||
method_ext ("with_match", with_match, gsi::arg ("pattern"), gsi::arg ("inverse"),
|
||||
"@brief Filter the text by glob pattern\n"
|
||||
"\"pattern\" is a glob-style pattern (e.g. \"A*\" will select all texts starting with a capital \"A\").\n"
|
||||
"If \"inverse\" is false, this method returns the texts matching the pattern.\n"
|
||||
"If \"inverse\" is true, this method returns the texts not matching the pattern.\n"
|
||||
) +
|
||||
method ("interacting|&", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the texts from this text collection which are inside or on the edge of polygons from the given region\n"
|
||||
"\n"
|
||||
"@return A new text collection containing the texts inside or on the edge of polygons from the region\n"
|
||||
) +
|
||||
method ("not_interacting|-", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_not_interacting, gsi::arg ("other"),
|
||||
"@brief Returns the texts from this text collection which are not inside or on the edge of polygons from the given region\n"
|
||||
"\n"
|
||||
"@return A new text collection containing the texts not inside or on the edge of polygons from the region\n"
|
||||
) +
|
||||
method ("select_interacting", (db::Texts &(db::Texts::*) (const db::Region &)) &db::Texts::select_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the texts from this text collection which are inside or on the edge of polygons from the given region\n"
|
||||
"\n"
|
||||
"@return A text collection after the texts have been selected (self)\n"
|
||||
"\n"
|
||||
"In contrast to \\interacting, this method will modify self.\n"
|
||||
) +
|
||||
method ("select_not_interacting", (db::Texts &(db::Texts::*) (const db::Region &)) &db::Texts::select_not_interacting, gsi::arg ("other"),
|
||||
"@brief Selects the texts from this text collection which are not inside or on the edge of polygons from the given region\n"
|
||||
"\n"
|
||||
"@return A text collection after the texts have been selected (self)\n"
|
||||
"\n"
|
||||
"In contrast to \\interacting, this method will modify self.\n"
|
||||
) +
|
||||
method_ext ("pull_interacting", &pull_interacting, gsi::arg ("other"),
|
||||
"@brief Returns all polygons of \"other\" which are including texts of this text set\n"
|
||||
"The \"pull_...\" method is similar to \"select_...\" but works the opposite way: it "
|
||||
"selects shapes from the argument region rather than self. In a deep (hierarchical) context "
|
||||
"the output region will be hierarchically aligned with self, so the \"pull_...\" method "
|
||||
"provide a way for rehierarchisation.\n"
|
||||
"\n"
|
||||
"@return The region after the polygons have been selected (from other)\n"
|
||||
"\n"
|
||||
"Merged semantics applies for the polygon region.\n"
|
||||
) +
|
||||
method ("clear", &db::Texts::clear,
|
||||
"@brief Clears the text collection\n"
|
||||
) +
|
||||
method ("swap", &db::Texts::swap, gsi::arg ("other"),
|
||||
"@brief Swap the contents of this collection with the contents of another collection\n"
|
||||
"This method is useful to avoid excessive memory allocation in some cases. "
|
||||
"For managed memory languages such as Ruby, those cases will be rare. "
|
||||
) +
|
||||
method ("bbox", &db::Texts::bbox,
|
||||
"@brief Return the bounding box of the text collection\n"
|
||||
"The bounding box is the box enclosing all origins of all texts.\n"
|
||||
) +
|
||||
method ("is_empty?", &db::Texts::empty,
|
||||
"@brief Returns true if the collection is empty\n"
|
||||
) +
|
||||
method ("size", &db::Texts::size,
|
||||
"@brief Returns the number of texts in this collection\n"
|
||||
) +
|
||||
gsi::iterator ("each", &db::Texts::begin,
|
||||
"@brief Returns each text of the text collection\n"
|
||||
) +
|
||||
method ("[]", &db::Texts::nth, gsi::arg ("n"),
|
||||
"@brief Returns the nth text\n"
|
||||
"\n"
|
||||
"This method returns nil if the index is out of range. It is available for flat texts only - i.e. "
|
||||
"those for which \\has_valid_texts? is true. Use \\flatten to explicitly flatten an text collection.\n"
|
||||
"\n"
|
||||
"The \\each iterator is the more general approach to access the texts."
|
||||
) +
|
||||
method ("flatten", &db::Texts::flatten,
|
||||
"@brief Explicitly flattens an text collection\n"
|
||||
"\n"
|
||||
"If the collection is already flat (i.e. \\has_valid_texts? returns true), this method will "
|
||||
"not change the collection.\n"
|
||||
) +
|
||||
method ("has_valid_texts?", &db::Texts::has_valid_texts,
|
||||
"@brief Returns true if the text collection is flat and individual texts can be accessed randomly\n"
|
||||
) +
|
||||
method ("enable_progress", &db::Texts::enable_progress, gsi::arg ("label"),
|
||||
"@brief Enable progress reporting\n"
|
||||
"After calling this method, the text collection will report the progress through a progress bar while "
|
||||
"expensive operations are running.\n"
|
||||
"The label is a text which is put in front of the progress bar.\n"
|
||||
"Using a progress bar will imply a performance penalty of a few percent typically.\n"
|
||||
) +
|
||||
method ("disable_progress", &db::Texts::disable_progress,
|
||||
"@brief Disable progress reporting\n"
|
||||
"Calling this method will disable progress reporting. See \\enable_progress.\n"
|
||||
) +
|
||||
method_ext ("to_s", &to_string0,
|
||||
"@brief Converts the text collection to a string\n"
|
||||
"The length of the output is limited to 20 texts to avoid giant strings on large collections. "
|
||||
"For full output use \"to_s\" with a maximum count parameter.\n"
|
||||
) +
|
||||
method_ext ("to_s", &to_string1, gsi::arg ("max_count"),
|
||||
"@brief Converts the text collection to a string\n"
|
||||
"This version allows specification of the maximum number of texts contained in the string."
|
||||
),
|
||||
"@brief Texts (a collection of texts)\n"
|
||||
"\n"
|
||||
"Text objects are useful as labels for net names, to identify certain regions and to specify specific locations in general. "
|
||||
"Text collections provide a way to store - also in a hierarchical fashion - and manipulate a collection of text objects.\n"
|
||||
"\n"
|
||||
"Text objects can be turned into polygons by creating small boxes around the texts (\\polygons). Texts can also be turned into dot-like "
|
||||
"edges (\\edges). Texts can be filtered by string, either by matching against a fixed string (\\with_text) or a glob-style pattern (\\with_match).\n"
|
||||
"\n"
|
||||
"Text collections can be filtered geometrically against a polygon \\Region using \\interacting or \\non-interacting. "
|
||||
"Vice versa, texts can be used to select polygons from a \\Region using \\pull_interacting.\n"
|
||||
"\n"
|
||||
"Beside that, text collections can be transformed, flattened and combined, similar to \\EdgePairs.\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.27.\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -255,6 +255,11 @@ static void tp_output_edge_pairs (db::TilingProcessor *proc, const std::string &
|
|||
proc->output (name, edge_pairs);
|
||||
}
|
||||
|
||||
static void tp_output_texts (db::TilingProcessor *proc, const std::string &name, db::Texts &texts)
|
||||
{
|
||||
proc->output (name, texts);
|
||||
}
|
||||
|
||||
static void tp_output_double (db::TilingProcessor *proc, const std::string &name, double *v)
|
||||
{
|
||||
proc->output (name, 0, new DoubleCollectingTileOutputReceiver (v), db::ICplxTrans ());
|
||||
|
|
@ -311,25 +316,49 @@ static void tp_input7 (db::TilingProcessor *proc, const std::string &name, const
|
|||
static void tp_input8 (db::TilingProcessor *proc, const std::string &name, const db::Region ®ion)
|
||||
{
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = region.begin_iter ();
|
||||
proc->input (name, it.first, it.second, true /*as polygons*/, region.merged_semantics ());
|
||||
proc->input (name, it.first, it.second, db::TilingProcessor::TypeRegion, region.merged_semantics ());
|
||||
}
|
||||
|
||||
static void tp_input9 (db::TilingProcessor *proc, const std::string &name, const db::Region ®ion, const db::ICplxTrans &trans)
|
||||
{
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = region.begin_iter ();
|
||||
proc->input (name, it.first, trans * it.second, true /*as polygons*/, region.merged_semantics ());
|
||||
proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeRegion, region.merged_semantics ());
|
||||
}
|
||||
|
||||
static void tp_input10 (db::TilingProcessor *proc, const std::string &name, const db::Edges &edges)
|
||||
{
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = edges.begin_iter ();
|
||||
proc->input (name, it.first, it.second, false /*not as polygons*/, edges.merged_semantics ());
|
||||
proc->input (name, it.first, it.second, db::TilingProcessor::TypeEdges, edges.merged_semantics ());
|
||||
}
|
||||
|
||||
static void tp_input11 (db::TilingProcessor *proc, const std::string &name, const db::Edges &edges, const db::ICplxTrans &trans)
|
||||
{
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = edges.begin_iter ();
|
||||
proc->input (name, it.first, trans * it.second, false /*not as polygons*/, edges.merged_semantics ());
|
||||
proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeEdges, edges.merged_semantics ());
|
||||
}
|
||||
|
||||
static void tp_input12 (db::TilingProcessor *proc, const std::string &name, const db::EdgePairs &edge_pairs)
|
||||
{
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = edge_pairs.begin_iter ();
|
||||
proc->input (name, it.first, it.second, db::TilingProcessor::TypeEdgePairs);
|
||||
}
|
||||
|
||||
static void tp_input13 (db::TilingProcessor *proc, const std::string &name, const db::EdgePairs &edge_pairs, const db::ICplxTrans &trans)
|
||||
{
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = edge_pairs.begin_iter ();
|
||||
proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeEdgePairs);
|
||||
}
|
||||
|
||||
static void tp_input14 (db::TilingProcessor *proc, const std::string &name, const db::Texts &texts)
|
||||
{
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = texts.begin_iter ();
|
||||
proc->input (name, it.first, it.second, db::TilingProcessor::TypeTexts);
|
||||
}
|
||||
|
||||
static void tp_input15 (db::TilingProcessor *proc, const std::string &name, const db::Texts &texts, const db::ICplxTrans &trans)
|
||||
{
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = texts.begin_iter ();
|
||||
proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeTexts);
|
||||
}
|
||||
|
||||
Class<db::TilingProcessor> decl_TilingProcessor ("db", "TilingProcessor",
|
||||
|
|
@ -385,16 +414,16 @@ Class<db::TilingProcessor> decl_TilingProcessor ("db", "TilingProcessor",
|
|||
method_ext ("input", &tp_input8, gsi::arg ("name"), gsi::arg ("region"),
|
||||
"@brief Specifies input for the tiling processor\n"
|
||||
"This method will establish an input channel for the processor. This version receives input from a \\Region object. "
|
||||
"Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only "
|
||||
"regions and edges are used as input.\n"
|
||||
"Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless "
|
||||
"a layout object is specified as input too.\n"
|
||||
"\n"
|
||||
"The name specifies the variable under which the input can be used in the scripts."
|
||||
) +
|
||||
method_ext ("input", &tp_input9, gsi::arg ("name"), gsi::arg ("region"), gsi::arg ("trans"),
|
||||
"@brief Specifies input for the tiling processor\n"
|
||||
"This method will establish an input channel for the processor. This version receives input from a \\Region object. "
|
||||
"Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only "
|
||||
"regions and edges are used as input.\n"
|
||||
"Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless "
|
||||
"a layout object is specified as input too.\n"
|
||||
"\n"
|
||||
"The name specifies the variable under which the input can be used in the scripts."
|
||||
"\n"
|
||||
|
|
@ -403,22 +432,62 @@ Class<db::TilingProcessor> decl_TilingProcessor ("db", "TilingProcessor",
|
|||
method_ext ("input", &tp_input10, gsi::arg ("name"), gsi::arg ("edges"),
|
||||
"@brief Specifies input for the tiling processor\n"
|
||||
"This method will establish an input channel for the processor. This version receives input from an \\Edges object. "
|
||||
"Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only "
|
||||
"regions and edges are used as input.\n"
|
||||
"Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless "
|
||||
"a layout object is specified as input too.\n"
|
||||
"\n"
|
||||
"The name specifies the variable under which the input can be used in the scripts."
|
||||
) +
|
||||
method_ext ("input", &tp_input11, gsi::arg ("name"), gsi::arg ("edges"), gsi::arg ("trans"),
|
||||
"@brief Specifies input for the tiling processor\n"
|
||||
"This method will establish an input channel for the processor. This version receives input from an \\Edges object. "
|
||||
"Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only "
|
||||
"regions and edges are used as input.\n"
|
||||
"Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless "
|
||||
"a layout object is specified as input too.\n"
|
||||
"\n"
|
||||
"The name specifies the variable under which the input can be used in the scripts."
|
||||
"\n"
|
||||
"This variant allows one to specify an additional transformation too. It has been introduced in version 0.23.2.\n"
|
||||
"\n"
|
||||
) +
|
||||
method_ext ("input", &tp_input12, gsi::arg ("name"), gsi::arg ("edge_pairs"),
|
||||
"@brief Specifies input for the tiling processor\n"
|
||||
"This method will establish an input channel for the processor. This version receives input from an \\EdgePairs object. "
|
||||
"Edge pair collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless "
|
||||
"a layout object is specified as input too.\n"
|
||||
"\n"
|
||||
"The name specifies the variable under which the input can be used in the scripts."
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("input", &tp_input13, gsi::arg ("name"), gsi::arg ("edge_pairs"), gsi::arg ("trans"),
|
||||
"@brief Specifies input for the tiling processor\n"
|
||||
"This method will establish an input channel for the processor. This version receives input from an \\EdgePairs object. "
|
||||
"Edge pair collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless "
|
||||
"a layout object is specified as input too.\n"
|
||||
"\n"
|
||||
"The name specifies the variable under which the input can be used in the scripts."
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("input", &tp_input14, gsi::arg ("name"), gsi::arg ("texts"),
|
||||
"@brief Specifies input for the tiling processor\n"
|
||||
"This method will establish an input channel for the processor. This version receives input from an \\Texts object. "
|
||||
"Text collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless "
|
||||
"a layout object is specified as input too.\n"
|
||||
"\n"
|
||||
"The name specifies the variable under which the input can be used in the scripts."
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("input", &tp_input15, gsi::arg ("name"), gsi::arg ("texts"), gsi::arg ("trans"),
|
||||
"@brief Specifies input for the tiling processor\n"
|
||||
"This method will establish an input channel for the processor. This version receives input from an \\Texts object. "
|
||||
"Text collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless "
|
||||
"a layout object is specified as input too.\n"
|
||||
"\n"
|
||||
"The name specifies the variable under which the input can be used in the scripts."
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
) +
|
||||
method ("var", &db::TilingProcessor::var, gsi::arg ("name"), gsi::arg ("value"),
|
||||
"@brief Defines a variable for the tiling processor script\n"
|
||||
"\n"
|
||||
|
|
@ -525,6 +594,20 @@ Class<db::TilingProcessor> decl_TilingProcessor ("db", "TilingProcessor",
|
|||
"@param name The name of the channel\n"
|
||||
"@param edge_pairs The \\EdgePairs object to which the data is sent\n"
|
||||
) +
|
||||
method_ext ("output", &tp_output_texts, gsi::arg ("name"), gsi::arg ("texts"),
|
||||
"@brief Specifies output to an \\Texts object\n"
|
||||
"This method will establish an output channel to an \\Texts object. The output sent to that channel "
|
||||
"will be put into the specified edge pair collection.\n"
|
||||
"Only \\Text objects are accepted. Other objects are discarded.\n"
|
||||
"\n"
|
||||
"The name is the name which must be used in the _output function of the scripts in order to "
|
||||
"address that channel.\n"
|
||||
"\n"
|
||||
"@param name The name of the channel\n"
|
||||
"@param texts The \\Texts object to which the data is sent\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27."
|
||||
) +
|
||||
method_ext ("output", &tp_output_double, gsi::arg ("name"), gsi::arg ("sum"),
|
||||
"@brief Specifies output to single value\n"
|
||||
"This method will establish an output channel which sums up float data delivered by calling the _output function.\n"
|
||||
|
|
|
|||
|
|
@ -1598,6 +1598,59 @@ TEST(28b_snap)
|
|||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au28.gds");
|
||||
}
|
||||
|
||||
TEST(29_InteractionsWithTexts)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/deep_texts_l2.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));
|
||||
unsigned int l8 = ly.get_layer (db::LayerProperties (8, 0));
|
||||
|
||||
db::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
db::Region polygons8 (db::RecursiveShapeIterator (ly, top_cell, l8), dss);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
db::Region polygons;
|
||||
polygons = polygons8.selected_interacting (texts2);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), polygons);
|
||||
|
||||
polygons = polygons8.selected_not_interacting (texts2);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), polygons);
|
||||
|
||||
{
|
||||
db::Region polygons8_copy = polygons8;
|
||||
polygons8_copy.select_interacting (texts2);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), polygons8_copy);
|
||||
}
|
||||
|
||||
{
|
||||
db::Region polygons8_copy = polygons8;
|
||||
polygons8_copy.select_not_interacting (texts2);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), polygons8_copy);
|
||||
}
|
||||
|
||||
{
|
||||
db::Texts t = polygons8.pull_interacting (texts2);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), t);
|
||||
}
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au29.gds");
|
||||
}
|
||||
|
||||
TEST(100_Integration)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2020 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 "dbHierarchyBuilder.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbDeepShapeStore.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbTextsUtils.h"
|
||||
#include "tlUnitTest.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
TEST(1_Basics)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/deep_texts_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));
|
||||
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
|
||||
unsigned int l100 = ly.get_layer (db::LayerProperties (100, 0));
|
||||
|
||||
db::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
db::Texts texts3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
|
||||
db::Texts texts100 (db::RecursiveShapeIterator (ly, top_cell, l100), dss);
|
||||
|
||||
EXPECT_EQ (texts100.empty (), true);
|
||||
EXPECT_EQ (texts2.empty (), false);
|
||||
EXPECT_EQ (texts2.bbox ().to_string (), "(-520,0;24040,2800)");
|
||||
EXPECT_EQ (texts2.size (), size_t (40));
|
||||
EXPECT_EQ (texts2.to_string ().substr (0, 42), "('L2',r0 -520,0);('L2',r0 -520,2800);('L2'");
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
db::Region polygons;
|
||||
texts2.polygons (polygons);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), polygons);
|
||||
|
||||
polygons.clear ();
|
||||
texts3.polygons (polygons);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), polygons);
|
||||
|
||||
db::Edges edges;
|
||||
texts2.edges (edges);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), edges);
|
||||
|
||||
// NOTE: insert texts2 as layer 14/0 from a copy - this tests the ability to copy-construct an TC
|
||||
db::Texts texts2_copy (texts2);
|
||||
texts2_copy.insert_into_as_polygons (&target, target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), 1);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au1.gds");
|
||||
}
|
||||
|
||||
TEST(2_Interactions)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/deep_texts_l2.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));
|
||||
unsigned int l8 = ly.get_layer (db::LayerProperties (8, 0));
|
||||
|
||||
db::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
db::Region polygons8 (db::RecursiveShapeIterator (ly, top_cell, l8), dss);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
db::Region polygons;
|
||||
texts2.selected_interacting (polygons8).polygons (polygons);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), polygons);
|
||||
|
||||
polygons.clear ();
|
||||
texts2.selected_not_interacting (polygons8).polygons (polygons);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), polygons);
|
||||
|
||||
{
|
||||
db::Texts texts2_copy = texts2;
|
||||
texts2_copy.select_interacting (polygons8);
|
||||
polygons.clear ();
|
||||
texts2_copy.polygons (polygons);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), polygons);
|
||||
}
|
||||
|
||||
{
|
||||
db::Texts texts2_copy = texts2;
|
||||
texts2_copy.select_not_interacting (polygons8);
|
||||
polygons.clear ();
|
||||
texts2_copy.polygons (polygons);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), polygons);
|
||||
}
|
||||
|
||||
{
|
||||
db::Texts texts2_copy = texts2;
|
||||
db::Region polygons;
|
||||
texts2_copy.pull_interacting (polygons, polygons8);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), polygons);
|
||||
}
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au2.gds");
|
||||
}
|
||||
|
||||
TEST(3_Filtering)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/deep_texts_l3.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::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
|
||||
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 (10, 0)), texts2.filtered (db::TextStringFilter ("L2", false)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), texts2.filtered (db::TextStringFilter ("L2", true)));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), texts2.filtered (db::TextPatternFilter ("L*A", false)));
|
||||
|
||||
texts2.filter (db::TextPatternFilter ("L*A", true));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), texts2);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au3.gds");
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue