Merge pull request #563 from KLayout/issue-487

Fix #487 (True text object support for DRC/LVS)
This commit is contained in:
Matthias Köfferlein 2020-05-26 22:44:53 +02:00 committed by GitHub
commit ba46ffb276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
300 changed files with 10218 additions and 1101 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -185,10 +185,9 @@ protected:
virtual RegionDelegate *pull_generic (const Region &region) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, bool inverse) const;
private:
AsIfFlatEdges &operator= (const AsIfFlatEdges &other);
private:
mutable bool m_bbox_valid;
mutable db::Box m_bbox;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &region);
/**
* @brief Conversion operator from texts collection to DeepLayer
* This requires the texts to be a DeepTexts. Otherwise, this constructor will assert
*/
DeepLayer (const Texts &region);
/**
* @brief Conversion operator from edges collection to DeepLayer
* This requires the edges to be a DeepEdges. Otherwise, this constructor will assert
*/
DeepLayer (const Edges &region);
/**
* @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 &region);
/**
* @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 &region, 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 &region) 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
*

613
src/db/db/dbDeepTexts.cc Normal file
View File

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

100
src/db/db/dbDeepTexts.h Normal file
View File

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

View File

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

View File

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

View File

@ -34,7 +34,7 @@ EdgePairsDelegate::EdgePairsDelegate ()
}
EdgePairsDelegate::EdgePairsDelegate (const EdgePairsDelegate &other)
: tl::UniqueId ()
: ShapeCollectionDelegateBase ()
{
operator= (other);
}

View File

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

View File

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

View File

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

View File

@ -37,7 +37,7 @@ EdgesDelegate::EdgesDelegate ()
}
EdgesDelegate::EdgesDelegate (const EdgesDelegate &other)
: tl::UniqueId ()
: ShapeCollectionDelegateBase ()
{
operator= (other);
}

View File

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

View File

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

106
src/db/db/dbEmptyTexts.cc Normal file
View File

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

89
src/db/db/dbEmptyTexts.h Normal file
View File

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

220
src/db/db/dbFlatTexts.cc Normal file
View File

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

173
src/db/db/dbFlatTexts.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &region, 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 &region) 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 &region) 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 &region) 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 &region) const
}
}
unsigned int LayoutToNetlist::layer_of (const db::Region &region) 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 &region, const Tr &tr, db::properties_id_type /*propid*/)
static bool deliver_shape (const db::NetShape &s, db::Region &region, 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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

218
src/db/db/dbNetShape.cc Normal file
View File

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

178
src/db/db/dbNetShape.h Normal file
View File

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

View File

@ -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 &region)
static void insert_into_region (const db::NetShape &s, const db::ICplxTrans &tr, db::Region &region)
{
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> > &gt = key.geometry [t->first];
std::map<unsigned int, std::set<db::NetShape> > &gt = 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);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,7 +38,7 @@ RegionDelegate::RegionDelegate ()
}
RegionDelegate::RegionDelegate (const RegionDelegate &other)
: tl::UniqueId ()
: ShapeCollectionDelegateBase ()
{
operator= (other);
}

View File

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

View File

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

View File

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

View File

View File

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

View File

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

View File

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

View File

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

212
src/db/db/dbTexts.cc Normal file
View File

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

724
src/db/db/dbTexts.h Normal file
View File

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

View File

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

144
src/db/db/dbTextsDelegate.h Normal file
View File

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

31
src/db/db/dbTextsUtils.cc Normal file
View File

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

208
src/db/db/dbTextsUtils.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &region) const) &db::LayoutToNetlist::name, gsi::arg ("l"),
gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (const db::ShapeCollection &region) 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"

View File

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

View File

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

View File

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

518
src/db/db/gsiDeclDbTexts.cc Normal file
View File

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

View File

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

View File

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

View File

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