mirror of https://github.com/KLayout/klayout.git
Added tests, Region#pull_interacting with texts
This commit is contained in:
parent
878a494abb
commit
7dab87b881
|
|
@ -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"
|
||||
|
|
@ -375,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 (false));
|
||||
region_to_text_interaction_filter<Shapes, db::Polygon> filter (output->raw_polygons (), 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
|
||||
{
|
||||
|
|
@ -468,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> filter (output->raw_texts (), false);
|
||||
|
||||
AddressablePolygonDelivery p (begin (), has_valid_merged_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
}
|
||||
|
||||
AddressableTextDelivery e (other.addressable_texts ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert2 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
|
||||
|
||||
return output.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -202,6 +202,16 @@ public:
|
|||
return selected_interacting_generic (other, true);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_interacting (const Texts &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, false);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, true);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *selected_overlapping (const Region &other) const
|
||||
{
|
||||
return selected_interacting_generic (other, 0, false, false);
|
||||
|
|
@ -227,6 +237,11 @@ public:
|
|||
return pull_generic (other);
|
||||
}
|
||||
|
||||
virtual TextsDelegate *pull_interacting (const Texts &other) const
|
||||
{
|
||||
return pull_generic (other);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *pull_overlapping (const Region &other) const
|
||||
{
|
||||
return pull_generic (other, 0, false);
|
||||
|
|
@ -247,8 +262,10 @@ 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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -1896,6 +1897,143 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct TextResultInserter
|
||||
{
|
||||
typedef db::Text value_type;
|
||||
|
||||
TextResultInserter (std::unordered_set<db::Text> &result)
|
||||
: mp_result (&result)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::Text &e)
|
||||
{
|
||||
(*mp_result).insert (e);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_set<db::Text> *mp_result;
|
||||
};
|
||||
|
||||
class PullWithTextLocalOperation
|
||||
: public local_operation<db::PolygonRef, db::Text, db::Text>
|
||||
{
|
||||
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::Text> &interactions, std::unordered_set<db::Text> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner;
|
||||
|
||||
TextResultInserter inserter (result);
|
||||
region_to_text_interaction_filter<TextResultInserter> filter (inserter, false);
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Text> ());
|
||||
}
|
||||
|
||||
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::Text, 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::Text> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
db::box_scanner2<db::Polygon, size_t, db::Text, size_t> scanner;
|
||||
|
||||
ResultInserter inserter (layout, result);
|
||||
region_to_text_interaction_filter<ResultInserter> 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::Text> ());
|
||||
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 *
|
||||
|
|
@ -2042,4 +2180,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::Text, db::Text> 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::Text, 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,8 +193,10 @@ 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;
|
||||
|
|
|
|||
|
|
@ -459,6 +459,36 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Edges &edges, const db::IC
|
|||
return dl;
|
||||
}
|
||||
|
||||
DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans)
|
||||
{
|
||||
// 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;
|
||||
|
||||
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 db::Region ®ion) const
|
||||
{
|
||||
return layer_for_flat (tl::id_of (region.delegate ()));
|
||||
|
|
|
|||
|
|
@ -338,7 +338,18 @@ public:
|
|||
* After a flat layer has been created for a region, it can be retrieved
|
||||
* from the region later with layer_for_flat (region).
|
||||
*/
|
||||
DeepLayer create_from_flat (const db::Edges ®ion, const db::ICplxTrans &trans = db::ICplxTrans ());
|
||||
DeepLayer create_from_flat (const db::Edges &edges, const db::ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief 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 region.
|
||||
|
|
|
|||
|
|
@ -96,6 +96,12 @@ DeepTexts::DeepTexts ()
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss)
|
||||
: AsIfFlatTexts ()
|
||||
{
|
||||
m_deep_layer = dss.create_from_flat (other);
|
||||
}
|
||||
|
||||
DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss)
|
||||
: AsIfFlatTexts (), m_deep_layer (dss.create_text_layer (si))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class DB_PUBLIC DeepTexts
|
|||
{
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 (); }
|
||||
|
||||
|
|
|
|||
|
|
@ -157,6 +157,29 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class shape_reference_translator<db::Text>
|
||||
{
|
||||
public:
|
||||
typedef db::Text shape_type;
|
||||
|
||||
shape_reference_translator (db::Layout * /*target_layout*/)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
const shape_type &operator() (const shape_type &s) const
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class Trans>
|
||||
shape_type operator() (const shape_type &s, const Trans &tr) const
|
||||
{
|
||||
return s.transformed (tr);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Ref, class Trans>
|
||||
class shape_reference_translator_with_trans_from_shape_ref
|
||||
{
|
||||
|
|
@ -633,6 +656,7 @@ 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::Text>;
|
||||
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>;
|
||||
|
|
@ -1756,6 +1780,8 @@ 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::Text, db::PolygonRef>;
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::Text, db::Text>;
|
||||
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>;
|
||||
|
|
|
|||
|
|
@ -1322,6 +1322,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 +1434,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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "dbPolygon.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdgePairRelations.h"
|
||||
#include "tlUniqueId.h"
|
||||
|
|
@ -294,12 +295,15 @@ public:
|
|||
virtual RegionDelegate *selected_not_interacting (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_interacting (const Edges &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_interacting (const Edges &other) const = 0;
|
||||
virtual RegionDelegate *selected_interacting (const Texts &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_interacting (const Texts &other) const = 0;
|
||||
virtual RegionDelegate *selected_overlapping (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &other) const = 0;
|
||||
virtual RegionDelegate *pull_inside (const Region &other) const = 0;
|
||||
virtual RegionDelegate *pull_interacting (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0;
|
||||
virtual RegionDelegate *pull_overlapping (const Region &other) const = 0;
|
||||
virtual TextsDelegate *pull_interacting (const Texts &other) const = 0;
|
||||
virtual RegionDelegate *in (const Region &other, bool invert) const = 0;
|
||||
|
||||
virtual const db::Polygon *nth (size_t n) const = 0;
|
||||
|
|
|
|||
|
|
@ -350,6 +350,61 @@ 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>
|
||||
region_to_text_interaction_filter_base<OutputType>::region_to_text_interaction_filter_base (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
template <class OutputType>
|
||||
void
|
||||
region_to_text_interaction_filter_base<OutputType>::preset (const OutputType *s)
|
||||
{
|
||||
m_seen.insert (s);
|
||||
}
|
||||
|
||||
template <class OutputType>
|
||||
void
|
||||
region_to_text_interaction_filter_base<OutputType>::add (const db::Polygon *p, size_t, const db::Text *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;
|
||||
pt += t->trans ().disp ();
|
||||
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>
|
||||
void
|
||||
region_to_text_interaction_filter_base<OutputType>::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>;
|
||||
template class region_to_text_interaction_filter_base<db::Text>;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Polygon snapping
|
||||
|
||||
|
|
|
|||
|
|
@ -524,6 +524,52 @@ private:
|
|||
OutputContainer *mp_output;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the region to text interaction functionality
|
||||
*/
|
||||
template <class OutputType>
|
||||
class DB_PUBLIC region_to_text_interaction_filter_base
|
||||
: public db::box_scanner_receiver2<db::Polygon, size_t, db::Text, 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 db::Text *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 OutputType = typename OutputContainer::value_type>
|
||||
class DB_PUBLIC_TEMPLATE region_to_text_interaction_filter
|
||||
: public region_to_text_interaction_filter_base<OutputType>
|
||||
{
|
||||
public:
|
||||
region_to_text_interaction_filter (OutputContainer &output, bool inverse)
|
||||
: region_to_text_interaction_filter_base<OutputType> (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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1509,6 +1509,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 +1616,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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1495,6 +1495,84 @@ TEST(33b_snap)
|
|||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au33.gds");
|
||||
}
|
||||
|
||||
TEST(34a)
|
||||
{
|
||||
db::Region r;
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "");
|
||||
r.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
|
||||
r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
|
||||
r.set_merged_semantics (false);
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
EXPECT_EQ (r.selected_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
db::Texts tt;
|
||||
tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30))));
|
||||
tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0))));
|
||||
EXPECT_EQ (r.selected_interacting (tt).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (300, 30))))).to_string (), "");
|
||||
db::Region rr = r;
|
||||
r.select_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10)))));
|
||||
EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
rr.select_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10)))));
|
||||
EXPECT_EQ (rr.to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
|
||||
r.clear ();
|
||||
r.insert(db::Box (db::Point (1000, 0), db::Point (6000, 4000)));
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000))))).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 2000))))).to_string (), "(1000,0;1000,4000;6000,4000;6000,0)");
|
||||
EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000)))).selected_interacting (r).to_string (), "");
|
||||
EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 2000)))).selected_interacting (r).to_string (), "('abc',r0 2000,2000)");
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000))))).to_string (), "");
|
||||
EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000)))).selected_interacting (r).to_string (), "");
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (1000, 2000))))).to_string (), "(1000,0;1000,4000;6000,4000;6000,0)");
|
||||
EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (1000, 2000)))).selected_interacting (r).to_string (), "('abc',r0 1000,2000)");
|
||||
}
|
||||
|
||||
TEST(34b)
|
||||
{
|
||||
db::Region r;
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "");
|
||||
r.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
|
||||
r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
|
||||
r.set_merged_semantics (true);
|
||||
r.set_min_coherence (true);
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
db::Texts tt;
|
||||
tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30))));
|
||||
tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0))));
|
||||
EXPECT_EQ (r.selected_interacting (tt).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)");
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), "");
|
||||
r.select_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10)))));
|
||||
EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,-100)");
|
||||
}
|
||||
|
||||
TEST(34c)
|
||||
{
|
||||
db::Region r;
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "");
|
||||
r.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
|
||||
r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
|
||||
r.set_merged_semantics (true);
|
||||
r.set_min_coherence (false);
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (0, 0))))).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), "");
|
||||
r.select_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10)))));
|
||||
EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
}
|
||||
|
||||
TEST(34d)
|
||||
{
|
||||
db::Region r;
|
||||
EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "");
|
||||
r.insert (db::Box (db::Point (0, 0), db::Point (100, 200)));
|
||||
r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0)));
|
||||
r.set_merged_semantics (true);
|
||||
r.set_min_coherence (false);
|
||||
EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "('abc',r0 30,30)");
|
||||
EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (0, 0))))).to_string (), "('abc',r0 0,0)");
|
||||
EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), "");
|
||||
}
|
||||
|
||||
TEST(100_Processors)
|
||||
{
|
||||
db::Region r;
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue