mirror of https://github.com/KLayout/klayout.git
'interact' between regions and texts.
This commit is contained in:
parent
08026e8b35
commit
4e7d0a81b8
|
|
@ -26,8 +26,11 @@
|
|||
#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>
|
||||
|
||||
|
|
@ -273,5 +276,99 @@ AsIfFlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into
|
|||
}
|
||||
}
|
||||
|
||||
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 (true));
|
||||
|
||||
if (! inverse) {
|
||||
|
||||
text_to_region_interaction_filter<FlatTexts> 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> > 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 (), true);
|
||||
|
||||
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> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
namespace db {
|
||||
|
||||
class Region;
|
||||
|
||||
/**
|
||||
* @brief Provides default flat implementations
|
||||
*/
|
||||
|
|
@ -69,6 +71,10 @@ 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;
|
||||
|
||||
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 ();
|
||||
|
|
@ -80,6 +86,8 @@ private:
|
|||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1285,7 +1285,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);
|
||||
}
|
||||
|
|
@ -1302,7 +1302,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);
|
||||
|
|
@ -1381,7 +1381,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ protected:
|
|||
|
||||
private:
|
||||
friend class DeepEdges;
|
||||
friend class DeepTexts;
|
||||
|
||||
DeepRegion &operator= (const DeepRegion &other);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,13 @@
|
|||
#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
|
||||
{
|
||||
|
|
@ -384,5 +389,210 @@ void DeepTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type int
|
|||
m_deep_layer.insert_into_as_polygons (layout, into_cell, into_layer, enl);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class Text2PolygonInteractingLocalOperation
|
||||
: public local_operation<db::Text, db::PolygonRef, db::Text>
|
||||
{
|
||||
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::Text, db::PolygonRef> &interactions, std::unordered_set<db::Text> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::Text, size_t, db::Polygon, size_t> scanner;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
for (shape_interactions<db::Text, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::Text, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
others.insert (interactions.intruder_shape (*j));
|
||||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::Text, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::Text &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::Text> interacting;
|
||||
text_to_region_interaction_filter<std::unordered_set<db::Text> > filter (interacting);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), db::box_convert<db::Polygon> ());
|
||||
|
||||
for (shape_interactions<db::Text, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::Text &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::Text> > filter (result);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), 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::Text, 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::Text, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::Text, size_t, db::Polygon, size_t> scanner;
|
||||
|
||||
std::set<db::PolygonRef> others;
|
||||
for (shape_interactions<db::Text, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::Text, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
others.insert (interactions.intruder_shape (*j));
|
||||
}
|
||||
}
|
||||
|
||||
for (shape_interactions<db::Text, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const db::Text &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> filter (inserter);
|
||||
scanner.process (filter, 1, db::box_convert<db::Text> (), 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::Text, db::PolygonRef, db::Text> 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::Text, 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ private:
|
|||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,5 +84,23 @@ 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 ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,10 @@ public:
|
|||
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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -635,6 +635,8 @@ 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::Edge, db::Edge>;
|
||||
template class DB_PUBLIC shape_interactions<db::Edge, db::PolygonRef>;
|
||||
template class DB_PUBLIC shape_interactions<db::Text, db::Text>;
|
||||
template class DB_PUBLIC shape_interactions<db::Text, db::PolygonRef>;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Helper classes for the LocalProcessor
|
||||
|
|
@ -656,6 +658,12 @@ inline unsigned int shape_flags<db::Edge> ()
|
|||
return db::ShapeIterator::Edges;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline unsigned int shape_flags<db::Text> ()
|
||||
{
|
||||
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 +858,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 +940,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;
|
||||
}
|
||||
|
||||
|
|
@ -1748,6 +1761,8 @@ 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::Text, db::PolygonRef, db::Text>;
|
||||
template class DB_PUBLIC local_processor<db::Text, db::PolygonRef, db::PolygonRef>;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -176,6 +176,11 @@ FlatTexts *Texts::flat_texts ()
|
|||
return texts;
|
||||
}
|
||||
|
||||
void Texts::pull_interacting (Region &output, const Region &other) const
|
||||
{
|
||||
output = Region (mp_delegate->pull_interacting (other));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
|
|
|
|||
|
|
@ -447,6 +447,52 @@ public:
|
|||
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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace db {
|
|||
|
||||
class RecursiveShapeIterator;
|
||||
class Texts;
|
||||
class Region;
|
||||
class TextFilterBase;
|
||||
class RegionDelegate;
|
||||
class EdgesDelegate;
|
||||
|
|
@ -118,6 +119,10 @@ public:
|
|||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "tlGlobPattern.h"
|
||||
#include "tlSelect.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
|
|
@ -149,6 +152,44 @@ private:
|
|||
bool m_inverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the text 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 OutputType = typename OutputContainer::value_type>
|
||||
class text_to_region_interaction_filter
|
||||
: public db::box_scanner_receiver2<db::Text, size_t, db::Polygon, size_t>
|
||||
{
|
||||
public:
|
||||
text_to_region_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -426,13 +426,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 +859,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 +867,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 +889,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 +897,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 +905,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 +913,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"
|
||||
|
|
|
|||
|
|
@ -165,6 +165,13 @@ static db::Texts with_match (const db::Texts *r, const std::string &pattern, boo
|
|||
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;
|
||||
}
|
||||
|
||||
Class<db::Texts> decl_Texts ("db", "Texts",
|
||||
constructor ("new", &new_v,
|
||||
"@brief Default constructor\n"
|
||||
|
|
@ -397,6 +404,41 @@ Class<db::Texts> decl_Texts ("db", "Texts",
|
|||
"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::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::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::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::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::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::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::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::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"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -83,3 +83,63 @@ TEST(1_Basics)
|
|||
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");
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue