'interact' between regions and texts.

This commit is contained in:
Matthias Koefferlein 2020-05-13 17:29:10 +02:00
parent 08026e8b35
commit 4e7d0a81b8
21 changed files with 588 additions and 14 deletions

View File

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

View File

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

View File

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

View File

@ -176,6 +176,7 @@ protected:
private:
friend class DeepEdges;
friend class DeepTexts;
DeepRegion &operator= (const DeepRegion &other);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

BIN
testdata/algo/deep_texts_au2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/deep_texts_l2.gds vendored Normal file

Binary file not shown.