mirror of https://github.com/KLayout/klayout.git
commit
b3968c31e5
20
build.sh
20
build.sh
|
|
@ -560,6 +560,25 @@ else
|
|||
fi
|
||||
echo " Installation target: $BIN"
|
||||
echo " Build directory: $BUILD"
|
||||
echo ""
|
||||
echo " Build flags:"
|
||||
echo " HAVE_RUBY=$HAVE_RUBY"
|
||||
echo " HAVE_PYTHON=$HAVE_PYTHON"
|
||||
echo " HAVE_QTBINDINGS=$HAVE_QTBINDINGS"
|
||||
echo " HAVE_QT=$HAVE_QT"
|
||||
echo " HAVE_QT_UITOOLS=$HAVE_QT_UITOOLS"
|
||||
echo " HAVE_QT_NETWORK=$HAVE_QT_NETWORK"
|
||||
echo " HAVE_QT_SQL=$HAVE_QT_SQL"
|
||||
echo " HAVE_QT_SVG=$HAVE_QT_SVG"
|
||||
echo " HAVE_QT_PRINTSUPPORT=$HAVE_QT_PRINTSUPPORT"
|
||||
echo " HAVE_QT_MULTIMEDIA=$HAVE_QT_MULTIMEDIA"
|
||||
echo " HAVE_QT_DESIGNER=$HAVE_QT_DESIGNER"
|
||||
echo " HAVE_QT_XML=$HAVE_QT_XML"
|
||||
echo " HAVE_64BIT_COORD=$HAVE_64BIT_COORD"
|
||||
echo " HAVE_CURL=$HAVE_CURL"
|
||||
echo " HAVE_PNG=$HAVE_PNG"
|
||||
echo " HAVE_EXPAT=$HAVE_EXPAT"
|
||||
echo " RPATH=$RPATH"
|
||||
|
||||
mkdir -p $BUILD
|
||||
|
||||
|
|
@ -674,6 +693,7 @@ if [ $BUILD_EXPERT = 1 ]; then
|
|||
QMAKE_CXXFLAGS="$CXXFLAGS"
|
||||
QMAKE_CXXFLAGS_RELEASE=
|
||||
QMAKE_CXXFLAGS_DEBUG=
|
||||
QMAKE_LIBS="$LIBS"
|
||||
QMAKE_LFLAGS="$LDFLAGS"
|
||||
QMAKE_LFLAGS_RELEASE=
|
||||
QMAKE_LFLAGS_DEBUG=
|
||||
|
|
|
|||
|
|
@ -514,6 +514,12 @@ AsIfFlatEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, c
|
|||
EdgesDelegate *
|
||||
AsIfFlatEdges::in (const Edges &other, bool invert) const
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return invert ? clone () : new EmptyEdges ();
|
||||
} else if (empty ()) {
|
||||
return new EmptyEdges ();
|
||||
}
|
||||
|
||||
std::set <db::Edge> op;
|
||||
for (EdgesIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
|
||||
op.insert (*o);
|
||||
|
|
@ -530,6 +536,34 @@ AsIfFlatEdges::in (const Edges &other, bool invert) const
|
|||
return new_region.release ();
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *>
|
||||
AsIfFlatEdges::in_and_out (const Edges &other) const
|
||||
{
|
||||
if (other.empty ()) {
|
||||
return std::make_pair (new EmptyEdges (), clone ());
|
||||
} else if (empty ()) {
|
||||
return std::make_pair (new EmptyEdges (), new EmptyEdges ());
|
||||
}
|
||||
|
||||
std::set <db::Edge> op;
|
||||
for (EdgesIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
|
||||
op.insert (*o);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatEdges> in (new FlatEdges (false));
|
||||
std::unique_ptr<FlatEdges> out (new FlatEdges (false));
|
||||
|
||||
for (EdgesIterator o (begin_merged ()); ! o.at_end (); ++o) {
|
||||
if (op.find (*o) != op.end ()) {
|
||||
in->insert (*o);
|
||||
} else {
|
||||
out->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair (in.release (), out.release ());
|
||||
}
|
||||
|
||||
size_t
|
||||
AsIfFlatEdges::count () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ public:
|
|||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Region &other) const;
|
||||
|
||||
virtual EdgesDelegate *in (const Edges &, bool) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const;
|
||||
|
||||
virtual bool equals (const Edges &other) const;
|
||||
virtual bool less (const Edges &other) const;
|
||||
|
|
|
|||
|
|
@ -148,25 +148,6 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
|
|||
return result.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::in (const Region &other, bool invert) const
|
||||
{
|
||||
std::set <db::Polygon> op;
|
||||
for (RegionIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
|
||||
op.insert (*o);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (false));
|
||||
|
||||
for (RegionIterator o (begin_merged ()); ! o.at_end (); ++o) {
|
||||
if ((op.find (*o) == op.end ()) == invert) {
|
||||
new_region->insert (*o);
|
||||
}
|
||||
}
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
bool
|
||||
AsIfFlatRegion::is_box () const
|
||||
{
|
||||
|
|
@ -401,7 +382,7 @@ private:
|
|||
}
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
AsIfFlatRegion::in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics ());
|
||||
|
||||
|
|
@ -409,6 +390,56 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOut
|
|||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
// shortcut
|
||||
if (empty ()) {
|
||||
if (output_mode == Positive || output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (clone (), clone ());
|
||||
}
|
||||
} else if (other.empty ()) {
|
||||
if (output_mode == Positive) {
|
||||
return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0);
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new EmptyRegion (), clone ());
|
||||
}
|
||||
}
|
||||
|
||||
std::set <db::Polygon> op;
|
||||
for (RegionIterator o (other.begin_merged ()); ! o.at_end (); ++o) {
|
||||
op.insert (*o);
|
||||
}
|
||||
|
||||
std::unique_ptr<FlatRegion> new_region (new FlatRegion (false));
|
||||
|
||||
for (RegionIterator o (begin_merged ()); ! o.at_end (); ++o) {
|
||||
if (op.find (*o) != op.end ()) {
|
||||
if (output_mode == Positive || output_mode == PositiveAndNegative) {
|
||||
oph.results () [0]->insert (*o);
|
||||
}
|
||||
} else {
|
||||
if (output_mode == Negative) {
|
||||
oph.results () [0]->insert (*o);
|
||||
} else if (output_mode == PositiveAndNegative) {
|
||||
oph.results () [1]->insert (*o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
}
|
||||
|
||||
min_count = std::max (size_t (1), min_count);
|
||||
|
||||
// shortcut
|
||||
|
|
@ -454,7 +485,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOut
|
|||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics ());
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
|
|
@ -500,7 +531,7 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOut
|
|||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
OutputPairHolder oph (output_mode, merged_semantics ());
|
||||
OutputPairHolder oph (output_mode, merged_semantics () || is_merged ());
|
||||
|
||||
if (output_mode == None) {
|
||||
return oph.region_pair ();
|
||||
|
|
@ -580,7 +611,7 @@ AsIfFlatRegion::pull_generic (const Edges &other) const
|
|||
std::vector<generic_shape_iterator<db::Edge> > others;
|
||||
others.push_back (other.begin_merged ());
|
||||
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges (merged_semantics ()));
|
||||
std::unique_ptr<FlatEdges> output (new FlatEdges (other.merged_semantics () || other.is_merged ()));
|
||||
std::vector<db::Shapes *> results;
|
||||
results.push_back (&output->raw_edges ());
|
||||
|
||||
|
|
@ -689,7 +720,7 @@ AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) cons
|
|||
std::vector<generic_shape_iterator<db::Polygon> > others;
|
||||
others.push_back (other.begin_merged ());
|
||||
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (merged_semantics ()));
|
||||
std::unique_ptr<FlatRegion> output (new FlatRegion (other.merged_semantics () || other.is_merged ()));
|
||||
std::vector<db::Shapes *> results;
|
||||
results.push_back (&output->raw_polygons ());
|
||||
|
||||
|
|
|
|||
|
|
@ -265,7 +265,15 @@ public:
|
|||
return pull_generic (other, 0, false);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *in (const Region &other, bool invert) const;
|
||||
virtual RegionDelegate *in (const Region &other, bool invert) const
|
||||
{
|
||||
return in_and_out_generic (other, invert ? Negative : Positive).first;
|
||||
}
|
||||
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> in_and_out (const Region &other) const
|
||||
{
|
||||
return in_and_out_generic (other, PositiveAndNegative);
|
||||
}
|
||||
|
||||
virtual bool equals (const Region &other) const;
|
||||
virtual bool less (const Region &other) const;
|
||||
|
|
@ -284,6 +292,7 @@ protected:
|
|||
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;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> in_and_out_generic (const Region &other, InteractingOutputMode output_mode) 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);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "dbLayoutUtils.h"
|
||||
#include "dbLocalOperation.h"
|
||||
#include "dbLocalOperationUtils.h"
|
||||
#include "dbRegionLocalOperations.h" // for db::ContainedEdgesLocalOperation
|
||||
#include "dbHierProcessor.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
|
||||
|
|
@ -1741,8 +1742,62 @@ EdgesDelegate *DeepEdges::pull_generic (const Edges &other) const
|
|||
|
||||
EdgesDelegate *DeepEdges::in (const Edges &other, bool invert) const
|
||||
{
|
||||
// TODO: is there a cheaper way?
|
||||
return AsIfFlatEdges::in (other, invert);
|
||||
std::unique_ptr<db::DeepEdges> dr_holder;
|
||||
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other edge collection isn't deep, turn into a top-level only deep edge collection to facilitate re-hierarchization
|
||||
dr_holder.reset (new db::DeepEdges (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
|
||||
std::vector<unsigned int> output_layers;
|
||||
output_layers.reserve (1);
|
||||
output_layers.push_back (dl_out.layer ());
|
||||
|
||||
db::ContainedEdgesLocalOperation op (invert ? Negative : Positive);
|
||||
|
||||
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (edges.store ()->threads ());
|
||||
|
||||
proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers);
|
||||
|
||||
return new db::DeepEdges (dl_out);
|
||||
}
|
||||
|
||||
std::pair<EdgesDelegate *, EdgesDelegate *> DeepEdges::in_and_out (const Edges &other) const
|
||||
{
|
||||
std::unique_ptr<db::DeepEdges> dr_holder;
|
||||
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
// if the other edge collection isn't deep, turn into a top-level only deep edge collection to facilitate re-hierarchization
|
||||
dr_holder.reset (new db::DeepEdges (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &edges = merged_deep_layer ();
|
||||
|
||||
DeepLayer dl_out (edges.derived ());
|
||||
DeepLayer dl_out2 (edges.derived ());
|
||||
|
||||
std::vector<unsigned int> output_layers;
|
||||
output_layers.reserve (2);
|
||||
output_layers.push_back (dl_out.layer ());
|
||||
output_layers.push_back (dl_out2.layer ());
|
||||
|
||||
db::ContainedEdgesLocalOperation op (PositiveAndNegative);
|
||||
|
||||
db::local_processor<db::Edge, db::Edge, db::Edge> proc (const_cast<db::Layout *> (&edges.layout ()), const_cast<db::Cell *> (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (edges.store ()->threads ());
|
||||
|
||||
proc.run (&op, edges.layer (), other_deep->merged_deep_layer ().layer (), output_layers);
|
||||
|
||||
return std::make_pair (new db::DeepEdges (dl_out), new db::DeepEdges (dl_out2));
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ public:
|
|||
virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const;
|
||||
|
||||
virtual EdgesDelegate *in (const Edges &, bool) const;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -555,6 +555,12 @@ DeepRegion::merged_deep_layer () const
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
DeepRegion::merged_polygons_available () const
|
||||
{
|
||||
return m_is_merged || m_merged_polygons_valid;
|
||||
}
|
||||
|
||||
void
|
||||
DeepRegion::ensure_merged_polygons_valid () const
|
||||
{
|
||||
|
|
@ -850,6 +856,10 @@ DeepRegion::is_box () const
|
|||
size_t
|
||||
DeepRegion::count () const
|
||||
{
|
||||
if (empty ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
|
|
@ -864,6 +874,10 @@ DeepRegion::count () const
|
|||
size_t
|
||||
DeepRegion::hier_count () const
|
||||
{
|
||||
if (empty ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t n = 0;
|
||||
|
||||
const db::Layout &layout = deep_layer ().layout ();
|
||||
|
|
@ -877,6 +891,10 @@ DeepRegion::hier_count () const
|
|||
DeepRegion::area_type
|
||||
DeepRegion::area (const db::Box &box) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (box.empty ()) {
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
|
@ -910,6 +928,10 @@ DeepRegion::area (const db::Box &box) const
|
|||
DeepRegion::perimeter_type
|
||||
DeepRegion::perimeter (const db::Box &box) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (box.empty ()) {
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
|
@ -955,6 +977,10 @@ DeepRegion::to_string (size_t nmax) const
|
|||
EdgePairsDelegate *
|
||||
DeepRegion::grid_check (db::Coord gx, db::Coord gy) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return new EmptyEdgePairs ();
|
||||
}
|
||||
|
||||
if (gx < 0 || gy < 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value")));
|
||||
}
|
||||
|
|
@ -1013,6 +1039,10 @@ DeepRegion::grid_check (db::Coord gx, db::Coord gy) const
|
|||
EdgePairsDelegate *
|
||||
DeepRegion::angle_check (double min, double max, bool inverse) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return new DeepEdgePairs (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
db::Layout &layout = const_cast<db::Layout &> (polygons.layout ());
|
||||
|
||||
|
|
@ -1037,6 +1067,10 @@ DeepRegion::angle_check (double min, double max, bool inverse) const
|
|||
RegionDelegate *
|
||||
DeepRegion::snapped (db::Coord gx, db::Coord gy)
|
||||
{
|
||||
if (empty ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
if (gx < 0 || gy < 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value")));
|
||||
}
|
||||
|
|
@ -1047,7 +1081,7 @@ DeepRegion::snapped (db::Coord gx, db::Coord gy)
|
|||
}
|
||||
|
||||
if (! gx) {
|
||||
return this;
|
||||
return clone ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
|
@ -1169,7 +1203,11 @@ public:
|
|||
EdgesDelegate *
|
||||
DeepRegion::edges (const EdgeFilterBase *filter) const
|
||||
{
|
||||
if (! filter && merged_semantics ()) {
|
||||
if (empty ()) {
|
||||
return new db::DeepEdges (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
if (! filter && merged_semantics () && ! merged_polygons_available ()) {
|
||||
|
||||
// Hierarchical edge detector - no pre-merge required
|
||||
|
||||
|
|
@ -1251,6 +1289,10 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
|
|||
RegionDelegate *
|
||||
DeepRegion::process_in_place (const PolygonProcessorBase &filter)
|
||||
{
|
||||
if (empty ()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: implement to be really in-place
|
||||
return processed (filter);
|
||||
}
|
||||
|
|
@ -1258,24 +1300,40 @@ DeepRegion::process_in_place (const PolygonProcessorBase &filter)
|
|||
EdgesDelegate *
|
||||
DeepRegion::processed_to_edges (const PolygonToEdgeProcessorBase &filter) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return new db::DeepEdges (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
return shape_collection_processed_impl<db::Polygon, db::Edge, db::DeepEdges> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
EdgePairsDelegate *
|
||||
DeepRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &filter) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
return shape_collection_processed_impl<db::Polygon, db::EdgePair, db::DeepEdgePairs> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::processed (const PolygonProcessorBase &filter) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
return shape_collection_processed_impl<db::Polygon, db::Polygon, db::DeepRegion> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::filter_in_place (const PolygonFilterBase &filter)
|
||||
{
|
||||
if (empty ()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: implement to be really in-place
|
||||
*this = *apply_filter (filter);
|
||||
return this;
|
||||
|
|
@ -1284,6 +1342,10 @@ DeepRegion::filter_in_place (const PolygonFilterBase &filter)
|
|||
RegionDelegate *
|
||||
DeepRegion::filtered (const PolygonFilterBase &filter) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
return apply_filter (filter);
|
||||
}
|
||||
|
||||
|
|
@ -1366,6 +1428,10 @@ DeepRegion::apply_filter (const PolygonFilterBase &filter) const
|
|||
RegionDelegate *
|
||||
DeepRegion::merged_in_place ()
|
||||
{
|
||||
if (empty ()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
// NOTE: this makes both layers share the same resource
|
||||
|
|
@ -1378,12 +1444,17 @@ DeepRegion::merged_in_place ()
|
|||
RegionDelegate *
|
||||
DeepRegion::merged_in_place (bool min_coherence, unsigned int min_wc)
|
||||
{
|
||||
// TODO: implement to be really in-place
|
||||
return merged (min_coherence, min_wc);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::merged () const
|
||||
{
|
||||
if (empty ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_merged_polygons.layout ());
|
||||
|
|
@ -1402,6 +1473,10 @@ DeepRegion::merged () const
|
|||
RegionDelegate *
|
||||
DeepRegion::merged (bool min_coherence, unsigned int min_wc) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return clone ();
|
||||
}
|
||||
|
||||
tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons");
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (deep_layer ().layout ());
|
||||
|
|
@ -1550,13 +1625,6 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
|
|||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::in (const Region &other, bool invert) const
|
||||
{
|
||||
// TODO: this can be optimized maybe ...
|
||||
return db::AsIfFlatRegion::in (other, invert);
|
||||
}
|
||||
|
||||
template <class TR, class Output>
|
||||
static
|
||||
Output *region_cop_impl (DeepRegion *region, db::CompoundRegionOperationNode &node)
|
||||
|
|
@ -1643,6 +1711,12 @@ DeepRegion::cop_to_edges (db::CompoundRegionOperationNode &node)
|
|||
EdgePairsDelegate *
|
||||
DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
||||
} else if (other && ! is_subject_regionptr (other) && other->empty () && ! options.negative) {
|
||||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
const db::DeepRegion *other_deep = 0;
|
||||
unsigned int other_layer = 0;
|
||||
bool other_is_merged = true;
|
||||
|
|
@ -1706,6 +1780,10 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
EdgePairsDelegate *
|
||||
DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return new db::DeepEdgePairs (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
|
||||
EdgeRelationFilter check (rel, d, options.metrics);
|
||||
|
|
@ -1796,11 +1874,82 @@ private:
|
|||
|
||||
}
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
DeepRegion::in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const
|
||||
{
|
||||
if (output_mode == None) {
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> ((RegionDelegate *) 0, (RegionDelegate *) 0);
|
||||
} else if (empty ()) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (clone (), clone ());
|
||||
} else {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
}
|
||||
} else if (other.empty ()) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_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-hierarchization
|
||||
dr_holder.reset (new db::DeepRegion (other, const_cast<db::DeepShapeStore &> (*deep_layer ().store ())));
|
||||
other_deep = dr_holder.get ();
|
||||
}
|
||||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
const db::DeepLayer &other_polygons = other_deep->merged_deep_layer ();
|
||||
|
||||
db::ContainedLocalOperation op (output_mode);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&polygons.layout ()), const_cast<db::Cell *> (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ());
|
||||
proc.set_description (progress_desc ());
|
||||
proc.set_report_progress (report_progress ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (polygons.store ()->threads ());
|
||||
|
||||
InteractingResultHolder orh (output_mode, merged_semantics (), polygons);
|
||||
|
||||
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
|
||||
|
||||
return orh.result_pair ();
|
||||
}
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
if (output_mode == None) {
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> (0, 0);
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> ((RegionDelegate *) 0, (RegionDelegate *) 0);
|
||||
} else if (empty ()) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (clone (), clone ());
|
||||
} else {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
}
|
||||
} else if (other.empty ()) {
|
||||
if (mode > 0 /*outside*/) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (clone (), new DeepRegion (deep_layer ().derived ()));
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
}
|
||||
} else {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
|
||||
|
|
@ -1818,7 +1967,8 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
|
|||
|
||||
const db::DeepLayer &polygons = merged_deep_layer ();
|
||||
// NOTE: on "inside" or with counting, the other polygons must be merged
|
||||
const db::DeepLayer &other_polygons = (mode < 0 || counting) ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
|
||||
bool other_needs_merged = (mode < 0 || counting);
|
||||
const db::DeepLayer &other_polygons = other_needs_merged ? other_deep->merged_deep_layer () : other_deep->deep_layer ();
|
||||
|
||||
db::InteractingLocalOperation op (mode, touching, output_mode, min_count, max_count, true);
|
||||
|
||||
|
|
@ -1832,7 +1982,7 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
|
|||
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
bool result_is_merged = (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ()));
|
||||
bool result_is_merged = (! split_after && (merged_semantics () || is_merged ()));
|
||||
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
|
||||
|
||||
proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ());
|
||||
|
|
@ -1843,6 +1993,24 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
|
|||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
if (output_mode == None) {
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> ((RegionDelegate *) 0, (RegionDelegate *) 0);
|
||||
} else if (empty ()) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (clone (), clone ());
|
||||
} else {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
}
|
||||
} else if (other.empty ()) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool counting = !(min_count == 1 && max_count == std::numeric_limits<size_t>::max ());
|
||||
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
|
|
@ -1870,7 +2038,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputM
|
|||
proc.set_max_vertex_count (polygons.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
bool result_is_merged = (! split_after && other.is_merged () && (merged_semantics () || is_merged ()));
|
||||
bool result_is_merged = (! split_after && (merged_semantics () || is_merged ()));
|
||||
InteractingResultHolder orh (output_mode, result_is_merged, polygons);
|
||||
|
||||
proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), orh.layers ());
|
||||
|
|
@ -1881,6 +2049,12 @@ DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputM
|
|||
RegionDelegate *
|
||||
DeepRegion::pull_generic (const Region &other, int mode, bool touching) const
|
||||
{
|
||||
if (empty ()) {
|
||||
return clone ();
|
||||
} else if (other.empty ()) {
|
||||
return new DeepRegion (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
bool split_after = false;
|
||||
|
||||
|
|
@ -1913,15 +2087,17 @@ DeepRegion::pull_generic (const Region &other, int mode, bool touching) const
|
|||
proc.run (&op, polygons.layer (), other_polygons.layer (), dl_out.layer ());
|
||||
|
||||
db::DeepRegion *res = new db::DeepRegion (dl_out);
|
||||
if (! split_after && ((mode < 0 && merged_semantics ()) || is_merged ()) && (other.merged_semantics () || other.is_merged ())) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
res->set_is_merged (! split_after && (other.merged_semantics () || other.is_merged ()));
|
||||
return res;
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
DeepRegion::pull_generic (const Edges &other) const
|
||||
{
|
||||
if (empty () || other.empty ()) {
|
||||
return new DeepEdges (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
std::unique_ptr<db::DeepEdges> dr_holder;
|
||||
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
|
|
@ -1953,6 +2129,10 @@ DeepRegion::pull_generic (const Edges &other) const
|
|||
TextsDelegate *
|
||||
DeepRegion::pull_generic (const Texts &other) const
|
||||
{
|
||||
if (empty () || other.empty ()) {
|
||||
return new DeepTexts (deep_layer ().derived ());
|
||||
}
|
||||
|
||||
std::unique_ptr<db::DeepTexts> dr_holder;
|
||||
const db::DeepTexts *other_deep = dynamic_cast<const db::DeepTexts *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
|
|
@ -1976,15 +2156,31 @@ DeepRegion::pull_generic (const Texts &other) const
|
|||
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;
|
||||
return new db::DeepTexts (dl_out);
|
||||
}
|
||||
|
||||
|
||||
std::pair<RegionDelegate *, RegionDelegate *>
|
||||
DeepRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const
|
||||
{
|
||||
if (output_mode == None) {
|
||||
return std::pair<RegionDelegate *, RegionDelegate *> ((RegionDelegate *) 0, (RegionDelegate *) 0);
|
||||
} else if (empty ()) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (clone (), clone ());
|
||||
} else {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
}
|
||||
} else if (other.empty ()) {
|
||||
if (output_mode == PositiveAndNegative) {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), clone ());
|
||||
} else if (output_mode == Negative) {
|
||||
return std::make_pair (clone (), (RegionDelegate *) 0);
|
||||
} else {
|
||||
return std::make_pair (new DeepRegion (deep_layer ().derived ()), (RegionDelegate *) 0);
|
||||
}
|
||||
}
|
||||
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
bool split_after = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -133,8 +133,6 @@ public:
|
|||
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const;
|
||||
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const;
|
||||
|
||||
virtual RegionDelegate *in (const Region &other, bool invert) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
virtual DeepShapeCollectionDelegateBase *deep ()
|
||||
|
|
@ -144,6 +142,7 @@ public:
|
|||
|
||||
void set_is_merged (bool f);
|
||||
|
||||
bool merged_polygons_available () const;
|
||||
const DeepLayer &merged_deep_layer () const;
|
||||
|
||||
protected:
|
||||
|
|
@ -158,6 +157,7 @@ protected:
|
|||
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;
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> in_and_out_generic (const Region &other, InteractingOutputMode output_mode) const;
|
||||
|
||||
private:
|
||||
friend class DeepEdges;
|
||||
|
|
|
|||
|
|
@ -1390,6 +1390,19 @@ public:
|
|||
return Edges (mp_delegate->in (other, invert));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all edges which are in the other edge set and which are not.
|
||||
*
|
||||
* This method is equivalent to calling in with invert = false and true, but more efficient.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Edges, Edges> in_and_out (const Edges &other) const
|
||||
{
|
||||
std::pair<db::EdgesDelegate *, db::EdgesDelegate *> p = mp_delegate->in_and_out (other);
|
||||
return std::pair<Edges, Edges> (Edges (p.first), Edges (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the nth edge
|
||||
*
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@ public:
|
|||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Edges &other) const = 0;
|
||||
|
||||
virtual EdgesDelegate *in (const Edges &other, bool invert) const = 0;
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const = 0;
|
||||
|
||||
virtual const db::Edge *nth (size_t n) const = 0;
|
||||
virtual bool has_valid_edges () const = 0;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ public:
|
|||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> selected_inside_pair (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
|
||||
virtual EdgesDelegate *in (const Edges &, bool) const { return new EmptyEdges (); }
|
||||
virtual std::pair<EdgesDelegate *, EdgesDelegate *> in_and_out (const Edges &) const { return std::make_pair (new EmptyEdges (), new EmptyEdges ()); }
|
||||
|
||||
virtual const db::Edge *nth (size_t) const { tl_assert (false); }
|
||||
virtual bool has_valid_edges () const { return true; }
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ public:
|
|||
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 (); }
|
||||
virtual std::pair<RegionDelegate *, RegionDelegate *> in_and_out (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); }
|
||||
|
||||
virtual bool has_valid_polygons () const { return true; }
|
||||
virtual bool has_valid_merged_polygons () const { return true; }
|
||||
|
|
|
|||
|
|
@ -1602,6 +1602,19 @@ public:
|
|||
return Region (mp_delegate->in (other, invert));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons which are in the other region plus the ones which are not
|
||||
*
|
||||
* This method is similar to calling in with inverse = false and true, but more efficient.
|
||||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
std::pair<Region, Region> in_and_out (const Region &other) const
|
||||
{
|
||||
std::pair<db::RegionDelegate *, db::RegionDelegate *> p = mp_delegate->in_and_out (other);
|
||||
return std::pair<Region, Region> (Region (p.first), Region (p.second));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Round corners (in-place)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -308,6 +308,7 @@ public:
|
|||
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 std::pair<RegionDelegate *, RegionDelegate *> in_and_out (const Region &other) const = 0;
|
||||
|
||||
virtual const db::Polygon *nth (size_t n) const = 0;
|
||||
virtual bool has_valid_polygons () const = 0;
|
||||
|
|
|
|||
|
|
@ -915,6 +915,81 @@ template class DB_PUBLIC interacting_local_operation<db::Polygon, db::Polygon, d
|
|||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
contained_local_operation<TS, TI, TR>::contained_local_operation (InteractingOutputMode output_mode)
|
||||
: m_output_mode (output_mode)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
db::Coord contained_local_operation<TS, TI, TR>::dist () const
|
||||
{
|
||||
return 1; // touching included for degenerated polygons and edges
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
void contained_local_operation<TS, TI, TR>::do_compute_local (db::Layout * /*layout*/, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
if (m_output_mode == None) {
|
||||
return;
|
||||
} else if (m_output_mode == Positive || m_output_mode == Negative) {
|
||||
tl_assert (results.size () == 1);
|
||||
} else {
|
||||
tl_assert (results.size () == 2);
|
||||
}
|
||||
|
||||
std::set<TI> others;
|
||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (typename shape_interactions<TS, TI>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
others.insert (interactions.intruder_shape (*j).second);
|
||||
}
|
||||
}
|
||||
|
||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
const TS &subject = interactions.subject_shape (i->first);
|
||||
if (others.find (subject) != others.end ()) {
|
||||
if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) {
|
||||
results [0].insert (subject);
|
||||
}
|
||||
} else {
|
||||
if (m_output_mode == Negative) {
|
||||
results [0].insert (subject);
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
results [1].insert (subject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
OnEmptyIntruderHint
|
||||
contained_local_operation<TS, TI, TR>::on_empty_intruder_hint () const
|
||||
{
|
||||
if (m_output_mode == Positive) {
|
||||
return OnEmptyIntruderHint::Drop;
|
||||
} else if (m_output_mode == Negative) {
|
||||
return OnEmptyIntruderHint::Copy;
|
||||
} else if (m_output_mode == PositiveAndNegative) {
|
||||
return OnEmptyIntruderHint::CopyToSecond;
|
||||
} else {
|
||||
return OnEmptyIntruderHint::Ignore;
|
||||
}
|
||||
}
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
std::string contained_local_operation<TS, TI, TR>::description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select polygons contained in other region"));
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC contained_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
|
||||
template class DB_PUBLIC contained_local_operation<db::Polygon, db::Polygon, db::Polygon>;
|
||||
template class DB_PUBLIC contained_local_operation<db::Edge, db::Edge, db::Edge>;
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
pull_local_operation<TS, TI, TR>::pull_local_operation (int mode, bool touching)
|
||||
: m_mode (mode), m_touching (touching)
|
||||
|
|
|
|||
|
|
@ -351,6 +351,26 @@ public:
|
|||
|
||||
typedef pull_with_text_local_operation<db::PolygonRef, db::TextRef, db::TextRef> PullWithTextLocalOperation;
|
||||
|
||||
template <class TS, class TI, class TR>
|
||||
class contained_local_operation
|
||||
: public local_operation<TS, TI, TR>
|
||||
{
|
||||
public:
|
||||
contained_local_operation (InteractingOutputMode output_mode);
|
||||
|
||||
virtual db::Coord dist () const;
|
||||
virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions<TS, TI> &interactions, std::vector<std::unordered_set<TR> > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const;
|
||||
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
|
||||
virtual std::string description () const;
|
||||
|
||||
private:
|
||||
InteractingOutputMode m_output_mode;
|
||||
};
|
||||
|
||||
typedef contained_local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef> ContainedLocalOperation;
|
||||
// the implementation is type-agnostic and can be used for edges too
|
||||
typedef contained_local_operation<db::Edge, db::Edge, db::Edge> ContainedEdgesLocalOperation;
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -35,7 +35,16 @@
|
|||
namespace gsi
|
||||
{
|
||||
|
||||
static db::Edges *new_v ()
|
||||
static inline std::vector<db::Edges> as_2edges_vector (const std::pair<db::Edges, db::Edges> &rp)
|
||||
{
|
||||
std::vector<db::Edges> res;
|
||||
res.reserve (2);
|
||||
res.push_back (db::Edges (const_cast<db::Edges &> (rp.first).take_delegate ()));
|
||||
res.push_back (db::Edges (const_cast<db::Edges &> (rp.second).take_delegate ()));
|
||||
return res;
|
||||
}
|
||||
|
||||
static db::Edges *new_v ()
|
||||
{
|
||||
return new db::Edges ();
|
||||
}
|
||||
|
|
@ -166,6 +175,11 @@ static db::Edges not_in (const db::Edges *r, const db::Edges &other)
|
|||
return r->in (other, true);
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> in_and_out (const db::Edges *r, const db::Edges &other)
|
||||
{
|
||||
return as_2edges_vector (r->in_and_out (other));
|
||||
}
|
||||
|
||||
static db::Edges &move_p (db::Edges *r, const db::Vector &p)
|
||||
{
|
||||
r->transform (db::Disp (p));
|
||||
|
|
@ -377,15 +391,6 @@ static size_t id (const db::Edges *e)
|
|||
return tl::id_of (e->delegate ());
|
||||
}
|
||||
|
||||
static inline std::vector<db::Edges> as_2edges_vector (const std::pair<db::Edges, db::Edges> &rp)
|
||||
{
|
||||
std::vector<db::Edges> res;
|
||||
res.reserve (2);
|
||||
res.push_back (db::Edges (const_cast<db::Edges &> (rp.first).take_delegate ()));
|
||||
res.push_back (db::Edges (const_cast<db::Edges &> (rp.second).take_delegate ()));
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::vector<db::Edges> andnot_with_edges (const db::Edges *r, const db::Edges &other)
|
||||
{
|
||||
return as_2edges_vector (r->andnot (other));
|
||||
|
|
@ -1633,16 +1638,24 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
) +
|
||||
method_ext ("members_of|#in", &in, gsi::arg ("other"),
|
||||
method_ext ("members_of|in", &in, gsi::arg ("other"),
|
||||
"@brief Returns all edges which are members of the other edge collection\n"
|
||||
"This method returns all edges in self which can be found in the other edge collection as well with exactly the same "
|
||||
"geometry."
|
||||
) +
|
||||
method_ext ("not_members_of|#not_in", ¬_in, gsi::arg ("other"),
|
||||
method_ext ("not_members_of|not_in", ¬_in, gsi::arg ("other"),
|
||||
"@brief Returns all edges which are not members of the other edge collection\n"
|
||||
"This method returns all edges in self which can not be found in the other edge collection with exactly the same "
|
||||
"geometry."
|
||||
) +
|
||||
method_ext ("in_and_out", &in_and_out, gsi::arg ("other"),
|
||||
"@brief Returns all polygons which are members and not members of the other region\n"
|
||||
"This method is equivalent to calling \\members_of and \\not_members_of, but delivers both results at the same time and "
|
||||
"is more efficient than two separate calls. "
|
||||
"The first element returned is the \\members_of part, the second is the \\not_members_of part.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.\n"
|
||||
) +
|
||||
method_ext ("is_deep?", &is_deep,
|
||||
"@brief Returns true if the edge collection is a deep (hierarchical) one\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -44,6 +44,15 @@
|
|||
namespace gsi
|
||||
{
|
||||
|
||||
static inline std::vector<db::Region> as_2region_vector (const std::pair<db::Region, db::Region> &rp)
|
||||
{
|
||||
std::vector<db::Region> res;
|
||||
res.reserve (2);
|
||||
res.push_back (db::Region (const_cast<db::Region &> (rp.first).take_delegate ()));
|
||||
res.push_back (db::Region (const_cast<db::Region &> (rp.second).take_delegate ()));
|
||||
return res;
|
||||
}
|
||||
|
||||
static db::Region *new_v ()
|
||||
{
|
||||
return new db::Region ();
|
||||
|
|
@ -430,6 +439,11 @@ static db::Region not_in (const db::Region *r, const db::Region &other)
|
|||
return r->in (other, true);
|
||||
}
|
||||
|
||||
static std::vector<db::Region> in_and_out (const db::Region *r, const db::Region &other)
|
||||
{
|
||||
return as_2region_vector (r->in_and_out (other));
|
||||
}
|
||||
|
||||
static db::Region rectangles (const db::Region *r)
|
||||
{
|
||||
db::RectangleFilter f (false, false);
|
||||
|
|
@ -605,15 +619,6 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other,
|
|||
);
|
||||
}
|
||||
|
||||
static inline std::vector<db::Region> as_2region_vector (const std::pair<db::Region, db::Region> &rp)
|
||||
{
|
||||
std::vector<db::Region> res;
|
||||
res.reserve (2);
|
||||
res.push_back (db::Region (const_cast<db::Region &> (rp.first).take_delegate ()));
|
||||
res.push_back (db::Region (const_cast<db::Region &> (rp.second).take_delegate ()));
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::vector<db::Region> andnot (const db::Region *r, const db::Region &other)
|
||||
{
|
||||
return as_2region_vector (r->andnot (other));
|
||||
|
|
@ -2186,16 +2191,24 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
"are taken from a hole-less representation (i.e. GDS2 file). Use explicit merge (\\merge method) "
|
||||
"in order to merge the polygons and detect holes.\n"
|
||||
) +
|
||||
method_ext ("members_of|#in", &in, gsi::arg ("other"),
|
||||
method_ext ("members_of|in", &in, gsi::arg ("other"),
|
||||
"@brief Returns all polygons which are members of the other region\n"
|
||||
"This method returns all polygons in self which can be found in the other region as well with exactly the same "
|
||||
"geometry."
|
||||
) +
|
||||
method_ext ("not_members_of|#not_in", ¬_in, gsi::arg ("other"),
|
||||
method_ext ("not_members_of|not_in", ¬_in, gsi::arg ("other"),
|
||||
"@brief Returns all polygons which are not members of the other region\n"
|
||||
"This method returns all polygons in self which can not be found in the other region with exactly the same "
|
||||
"geometry."
|
||||
) +
|
||||
method_ext ("in_and_out", &in_and_out, gsi::arg ("other"),
|
||||
"@brief Returns all polygons which are members and not members of the other region\n"
|
||||
"This method is equivalent to calling \\members_of and \\not_members_of, but delivers both results at the same time and "
|
||||
"is more efficient than two separate calls. "
|
||||
"The first element returned is the \\members_of part, the second is the \\not_members_of part.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.28.\n"
|
||||
) +
|
||||
method_ext ("rectangles", &rectangles,
|
||||
"@brief Returns all polygons which are rectangles\n"
|
||||
"This method returns all polygons in self which are rectangles."
|
||||
|
|
|
|||
|
|
@ -1182,3 +1182,113 @@ TEST(19_AndNotWithEdges)
|
|||
EXPECT_EQ (db::compare (eflat.andnot (ee).second, "(1500,2000;1500,2100);(1100,0;1100,1000);(0,0;0,1000);(100,0;100,3000);(1800,2500;1800,3500);(-1500,0;-1500,1000);(1700,1500;1600,2500)"), true);
|
||||
}
|
||||
|
||||
TEST(20_in)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/deep_region_l31.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 l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
|
||||
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty
|
||||
|
||||
db::Edges e1 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l1), dss)).edges ());
|
||||
db::Edges e2 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss)).edges ());
|
||||
db::Edges e3 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l3), dss)).edges ());
|
||||
|
||||
db::Edges e1r = e1;
|
||||
e1r.set_merged_semantics (false);
|
||||
db::Edges e2r = e2;
|
||||
e2r.set_merged_semantics (false);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), e1);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), e2);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e2.in (e1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2.in (e1, true));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), e2.in (e3));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), e2.in (e3, true));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), e3.in (e1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), e3.in (e1, true));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e2r.in (e1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e2r.in (e1, true));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e2.in (e1r));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e2.in (e1r, true));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e2r.in (e1r));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e2r.in (e1r, true));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au20.gds");
|
||||
}
|
||||
|
||||
TEST(20_in_and_out)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/deep_region_l31.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 l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
|
||||
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty
|
||||
|
||||
db::Edges e1 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l1), dss)).edges ());
|
||||
db::Edges e2 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l2), dss)).edges ());
|
||||
db::Edges e3 = db::Edges ((db::Region (db::RecursiveShapeIterator (ly, top_cell, l3), dss)).edges ());
|
||||
|
||||
db::Edges e1r = e1;
|
||||
e1r.set_merged_semantics (false);
|
||||
db::Edges e2r = e2;
|
||||
e2r.set_merged_semantics (false);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), e1);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), e2);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e2.in_and_out (e1).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2.in_and_out (e1).second);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), e2.in_and_out (e3).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), e2.in_and_out (e3).second);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), e3.in_and_out (e1).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), e3.in_and_out (e1).second);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), e2r.in_and_out (e1).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), e2r.in_and_out (e1).second);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), e2.in_and_out (e1r).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), e2.in_and_out (e1r).second);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), e2r.in_and_out (e1r).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), e2r.in_and_out (e1r).second);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au20.gds");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -880,8 +880,6 @@ TEST(14_Interacting)
|
|||
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
db::Region r6 (db::RecursiveShapeIterator (ly, top_cell, l6), dss);
|
||||
db::Region r1f (db::RecursiveShapeIterator (ly, top_cell, l1));
|
||||
db::Region r2f (db::RecursiveShapeIterator (ly, top_cell, l2));
|
||||
db::Region r6f (db::RecursiveShapeIterator (ly, top_cell, l6));
|
||||
db::Region r1r = r1;
|
||||
r1r.set_merged_semantics (false);
|
||||
db::Region r2r = r2;
|
||||
|
|
@ -889,6 +887,11 @@ TEST(14_Interacting)
|
|||
db::Region r6r = r6;
|
||||
r6r.set_merged_semantics (false);
|
||||
|
||||
db::Edges r1e = r1.edges ();
|
||||
db::Edges r1ef = r1f.edges ();
|
||||
db::Edges r1er = r1r.edges ();
|
||||
r1er.set_merged_semantics (false);
|
||||
|
||||
{
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
|
@ -947,22 +950,18 @@ TEST(14_Interacting)
|
|||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (66, 0)), r6r.selected_overlapping (r1r));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (67, 0)), r6r.selected_not_overlapping (r1r));
|
||||
|
||||
EXPECT_EQ (r2.selected_interacting (r1).is_merged (), false);
|
||||
EXPECT_EQ (r2.selected_interacting (r1.merged ()).is_merged (), true);
|
||||
EXPECT_EQ (r2.selected_inside (r1).is_merged (), true);
|
||||
EXPECT_EQ (r2.selected_interacting (r1).is_merged (), true);
|
||||
EXPECT_EQ (r2r.selected_interacting (r1).is_merged (), false);
|
||||
EXPECT_EQ (r2.selected_interacting (r1r).is_merged (), false);
|
||||
EXPECT_EQ (r2r.selected_interacting (r1r).is_merged (), false);
|
||||
EXPECT_EQ (r2r.selected_interacting (r1.merged ()).is_merged (), false);
|
||||
EXPECT_EQ (r2.selected_interacting (r1r).is_merged (), true);
|
||||
EXPECT_EQ (r2.selected_inside (r1).is_merged (), true);
|
||||
EXPECT_EQ (r2r.selected_inside (r1).is_merged (), false);
|
||||
EXPECT_EQ (r2.selected_inside (r1).is_merged (), true);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au14a.gds");
|
||||
}
|
||||
|
||||
db::Edges r1e = r1.edges ();
|
||||
db::Edges r1ef = r1f.edges ();
|
||||
db::Edges r1er = r1r.edges ();
|
||||
r1er.set_merged_semantics (false);
|
||||
|
||||
{
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
|
@ -976,8 +975,8 @@ TEST(14_Interacting)
|
|||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (32, 0)), r6r.selected_interacting (r1er));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (33, 0)), r6r.selected_not_interacting (r1er));
|
||||
|
||||
EXPECT_EQ (r6.selected_interacting (r1e).is_merged (), false);
|
||||
EXPECT_EQ (r6.selected_interacting (r1er).is_merged (), false);
|
||||
EXPECT_EQ (r6.selected_interacting (r1e).is_merged (), true);
|
||||
EXPECT_EQ (r6.selected_interacting (r1er).is_merged (), true);
|
||||
EXPECT_EQ (r6r.selected_interacting (r1e).is_merged (), false);
|
||||
EXPECT_EQ (r6r.selected_interacting (r1er).is_merged (), false);
|
||||
|
||||
|
|
@ -1470,6 +1469,16 @@ TEST(25_Pull)
|
|||
db::Region r6r = r6;
|
||||
r6r.set_merged_semantics (false);
|
||||
|
||||
db::Edges r1e = r1.edges ();
|
||||
db::Edges r1ef = r1f.edges ();
|
||||
db::Edges r1er = r1r.edges ();
|
||||
r1er.set_merged_semantics (false);
|
||||
|
||||
db::Edges r6e = r6.edges ();
|
||||
db::Edges r6ef = r6f.edges ();
|
||||
db::Edges r6er = r6r.edges ();
|
||||
r6er.set_merged_semantics (false);
|
||||
|
||||
{
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
|
@ -1499,8 +1508,8 @@ TEST(25_Pull)
|
|||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (62, 0)), r2r.pull_overlapping (r6r));
|
||||
|
||||
EXPECT_EQ (r2.pull_inside (r6).is_merged (), true);
|
||||
EXPECT_EQ (r2.pull_interacting (r6).is_merged (), false);
|
||||
EXPECT_EQ (r2r.pull_interacting (r6).is_merged (), false);
|
||||
EXPECT_EQ (r2.pull_interacting (r6).is_merged (), true);
|
||||
EXPECT_EQ (r2r.pull_interacting (r6).is_merged (), true);
|
||||
EXPECT_EQ (r2.pull_interacting (r6r).is_merged (), false);
|
||||
EXPECT_EQ (r2r.pull_interacting (r6r).is_merged (), false);
|
||||
|
||||
|
|
@ -1508,16 +1517,6 @@ TEST(25_Pull)
|
|||
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au25a.gds");
|
||||
}
|
||||
|
||||
db::Edges r1e = r1.edges ();
|
||||
db::Edges r1ef = r1f.edges ();
|
||||
db::Edges r1er = r1r.edges ();
|
||||
r1er.set_merged_semantics (false);
|
||||
|
||||
db::Edges r6e = r6.edges ();
|
||||
db::Edges r6ef = r6f.edges ();
|
||||
db::Edges r6er = r6r.edges ();
|
||||
r6er.set_merged_semantics (false);
|
||||
|
||||
{
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
|
@ -1800,7 +1799,7 @@ TEST(30a_interact_with_count_region)
|
|||
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
|
||||
|
||||
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
|
|
@ -1891,7 +1890,7 @@ TEST(30b_interact_with_count_edge)
|
|||
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
|
||||
|
||||
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
|
|
@ -1981,7 +1980,7 @@ TEST(30c_interact_with_count_text)
|
|||
EXPECT_EQ (r.selected_interacting (rr2, 2, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_interacting (rr2, 4, 5).to_string (), "");
|
||||
|
||||
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (empty).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr).to_string (), "");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)");
|
||||
|
|
@ -2018,6 +2017,115 @@ TEST(30c_interact_with_count_text)
|
|||
EXPECT_EQ (r.selected_not_interacting (rr, 3, 4).to_string (), "(0,0;0,200;100,200;100,0)");
|
||||
}
|
||||
|
||||
TEST(31_in)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/deep_region_l31.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 l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
|
||||
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty
|
||||
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
|
||||
db::Region r1r = r1;
|
||||
r1r.set_merged_semantics (false);
|
||||
db::Region r2r = r2;
|
||||
r2r.set_merged_semantics (false);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2.in (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.in (r1, true));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.in (r3, false));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.in (r3, true));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r3.in (r1, false));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r3.in (r1, true));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r2r.in (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r2r.in (r1, true));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), r2.in (r1r));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), r2.in (r1r, true));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), r2r.in (r1r));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), r2r.in (r1r, true));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au31.gds");
|
||||
}
|
||||
|
||||
TEST(31_in_and_out)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/deep_region_l31.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 l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0));
|
||||
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); // empty
|
||||
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
|
||||
|
||||
db::Region r1r = r1;
|
||||
r1r.set_merged_semantics (false);
|
||||
db::Region r2r = r2;
|
||||
r2r.set_merged_semantics (false);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (1, 0)), r1);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2.in_and_out (r1).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.in_and_out (r1).second);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.in_and_out (r3).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.in_and_out (r3).second);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r3.in_and_out (r1).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r3.in_and_out (r1).second);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r2r.in_and_out (r1).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r2r.in_and_out (r1).second);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (30, 0)), r2.in_and_out (r1r).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (31, 0)), r2.in_and_out (r1r).second);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (40, 0)), r2r.in_and_out (r1r).first);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (41, 0)), r2r.in_and_out (r1r).second);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_region_au31.gds");
|
||||
}
|
||||
|
||||
TEST(100_Integration)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
|
|
|||
|
|
@ -1121,6 +1121,42 @@ TEST(27)
|
|||
EXPECT_EQ (db::compare (e.selected_outside_differential (ee).second, "(1100,-1000;1100,2000);(1200,-1000;1200,0);(1300,-800;1300,-200);(1400,1000;1400,1100);(1500,1000;1500,2100);(1600,-800;1600,-200);(1900,1000;1900,2000)"), true);
|
||||
}
|
||||
|
||||
// Edges::in and Edges:in_and_out
|
||||
TEST(28)
|
||||
{
|
||||
db::Edges e;
|
||||
e.insert (db::Edge (0, 0, 0, 1000));
|
||||
e.insert (db::Edge (0, 1000, 0, 2000));
|
||||
e.insert (db::Edge (100, 0, 100, 1000));
|
||||
|
||||
db::Edges ee;
|
||||
ee.insert (db::Edge (0, 0, 0, 2000));
|
||||
ee.insert (db::Edge (100, 1000, 0, 2000));
|
||||
ee.insert (db::Edge (100, 0, 100, 1000));
|
||||
|
||||
EXPECT_EQ (db::compare (e.in (db::Edges ()), ""), true);
|
||||
EXPECT_EQ (db::compare (e.in (db::Edges (), true), "(0,0;0,1000);(0,1000;0,2000);(100,0;100,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.in_and_out (db::Edges ()).first, ""), true);
|
||||
EXPECT_EQ (db::compare (e.in_and_out (db::Edges ()).second, "(0,0;0,1000);(0,1000;0,2000);(100,0;100,1000)"), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().in (ee), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().in (ee, true), ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().in_and_out (ee).first, ""), true);
|
||||
EXPECT_EQ (db::compare (db::Edges ().in_and_out (ee).second, ""), true);
|
||||
EXPECT_EQ (db::compare (e.in (ee), "(0,0;0,2000);(100,0;100,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.in (ee, true), ""), true);
|
||||
EXPECT_EQ (db::compare (e.in_and_out (ee).first, "(0,0;0,2000);(100,0;100,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.in_and_out (ee).second, ""), true);
|
||||
EXPECT_EQ (db::compare (ee.in (e, true), "(100,1000;0,2000)"), true);
|
||||
EXPECT_EQ (db::compare (ee.in_and_out (e).second, "(100,1000;0,2000)"), true);
|
||||
|
||||
e.set_merged_semantics (false);
|
||||
ee.set_merged_semantics (false);
|
||||
|
||||
EXPECT_EQ (db::compare (e.in (ee), "(100,0;100,1000)"), true);
|
||||
EXPECT_EQ (db::compare (e.in (ee, true), "(0,0;0,1000);(0,1000;0,2000)"), true);
|
||||
EXPECT_EQ (db::compare (ee.in (e, true), "(0,0;0,2000);(100,1000;0,2000)"), true);
|
||||
}
|
||||
|
||||
// GitHub issue #72 (Edges/Region NOT issue)
|
||||
TEST(100)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1095,15 +1095,25 @@ TEST(19)
|
|||
r2.insert (db::Box (db::Point (0, 0), db::Point (20, 30)));
|
||||
|
||||
EXPECT_EQ (r1.in (r2, false).to_string (), "(0,0;0,30;20,30;20,0)");
|
||||
EXPECT_EQ (r1.in_and_out (r2).first.to_string (), "(0,0;0,30;20,30;20,0)");
|
||||
EXPECT_EQ (r1.in (r2, true).to_string (), "");
|
||||
EXPECT_EQ (r1.in (r1, false).to_string (), "(0,0;0,30;20,30;20,0)");
|
||||
EXPECT_EQ (r1.in (r1, true).to_string (), "");
|
||||
EXPECT_EQ (r1.in_and_out (r2).second.to_string (), "");
|
||||
EXPECT_EQ (r2.in (r1, true).to_string (), "");
|
||||
|
||||
r1.set_merged_semantics (false);
|
||||
r2.set_merged_semantics (false);
|
||||
|
||||
EXPECT_EQ (db::compare (r1.in (r2, false), "(0,0;0,20;20,20;20,0);(0,0;0,30;20,30;20,0)"), true);
|
||||
EXPECT_EQ (db::compare (r1.in_and_out (r2).first, "(0,0;0,20;20,20;20,0);(0,0;0,30;20,30;20,0)"), true);
|
||||
EXPECT_EQ (r1.in (r2, true).to_string (), "(0,0;0,20;10,20;10,0)");
|
||||
EXPECT_EQ (r1.in_and_out (r2).second.to_string (), "(0,0;0,20;10,20;10,0)");
|
||||
EXPECT_EQ (r2.in (r1, true).to_string (), "(0,0;0,10;20,10;20,0)");
|
||||
EXPECT_EQ (r1.in (db::Region (), false).to_string (), "");
|
||||
EXPECT_EQ (db::compare (r1.in (db::Region (), true), "(0,0;0,20;10,20;10,0);(0,0;0,20;20,20;20,0);(0,0;0,30;20,30;20,0)"), true);
|
||||
EXPECT_EQ (db::Region ().in (r1, false).to_string (), "");
|
||||
EXPECT_EQ (db::Region ().in (r1, true).to_string (), "");
|
||||
}
|
||||
|
||||
TEST(20)
|
||||
|
|
|
|||
|
|
@ -1342,6 +1342,44 @@ The following image shows the effect of the "in" method (input1: red, input2: bl
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="in_and_out"/><h2>"in_and_out" - Selects shapes or regions of self which are and which are not contained in the other layer</h2>
|
||||
<keyword name="in_and_out"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>(in, not_in) = layer.in_and_out(other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method is equivalent to calling <a href="#in">in</a> and <a href="#not_in">not_in</a>, but more
|
||||
efficient as it delivers both results in a single call.
|
||||
</p><p>
|
||||
This method is available for polygon, text and edge layers. Edges can be selected
|
||||
with respect to other edges or polygons. Texts can be selected with respect to
|
||||
polygons. Polygons can be selected with respect to edges, texts and other polygons.
|
||||
</p><p>
|
||||
The following image shows the effect of the "interacting" method (input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_interacting.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
If a single count is given, shapes from self are selected only if they do interact at least with the given
|
||||
number of (different) shapes from the other layer. If a min and max count is given, shapes from
|
||||
self are selected only if they interact with min_count or more, but a maximum of max_count different shapes
|
||||
from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_interacting2.png"/></td>
|
||||
<td><img src="/images/drc_interacting3.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/images/drc_interacting4.png"/></td>
|
||||
<td><img src="/images/drc_interacting5.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="insert"/><h2>"insert" - Inserts one or many objects into the layer</h2>
|
||||
<keyword name="insert"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1448,50 +1486,6 @@ method computing both inside and outside part in a single call.
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="interacting"/><h2>"interacting" - Selects shapes or regions of self which touch or overlap shapes from the other region</h2>
|
||||
<keyword name="interacting"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.interacting(other)</tt></li>
|
||||
<li><tt>layer.interacting(other, min_count)</tt></li>
|
||||
<li><tt>layer.interacting(other, min_count, max_count)</tt></li>
|
||||
<li><tt>layer.interacting(other, min_count .. max_count)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects all shapes or regions from self which touch or overlap shapes from the other
|
||||
region. Unless self is in raw mode (see <a href="#raw">raw</a>), coherent regions are selected from self,
|
||||
otherwise individual shapes are selected.
|
||||
It returns a new layer containing the selected shapes. A version which modifies self
|
||||
is <a href="#select_interacting">select_interacting</a>.
|
||||
</p><p>
|
||||
This method is available for polygon, text and edge layers. Edges can be selected
|
||||
with respect to other edges or polygons. Texts can be selected with respect to
|
||||
polygons. Polygons can be selected with respect to edges, texts and other polygons.
|
||||
</p><p>
|
||||
The following image shows the effect of the "interacting" method (input1: red, input2: blue):
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_interacting.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
If a single count is given, shapes from self are selected only if they do interact at least with the given
|
||||
number of (different) shapes from the other layer. If a min and max count is given, shapes from
|
||||
self are selected only if they interact with min_count or more, but a maximum of max_count different shapes
|
||||
from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions.
|
||||
</p><p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="/images/drc_interacting2.png"/></td>
|
||||
<td><img src="/images/drc_interacting3.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="/images/drc_interacting4.png"/></td>
|
||||
<td><img src="/images/drc_interacting5.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="intersections"/><h2>"intersections" - Returns the intersection points of intersecting edge segments for two edge collections</h2>
|
||||
<keyword name="intersections"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -2442,6 +2442,13 @@ CODE
|
|||
# @/tr
|
||||
# @/table
|
||||
|
||||
# %DRC%
|
||||
# @name in_and_out
|
||||
# @brief Selects shapes or regions of self which are and which are not contained in the other layer
|
||||
# @synopsis (in, not_in) = layer.in_and_out(other)
|
||||
# This method is equivalent to calling \in and \not_in, but more
|
||||
# efficient as it delivers both results in a single call.
|
||||
|
||||
# %DRC%
|
||||
# @name interacting
|
||||
# @brief Selects shapes or regions of self which touch or overlap shapes from the other region
|
||||
|
|
@ -2844,6 +2851,24 @@ CODE
|
|||
CODE
|
||||
end
|
||||
|
||||
%w(in_and_out).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other, *args)
|
||||
|
||||
@engine._context("#{f}") do
|
||||
|
||||
requires_same_type(other)
|
||||
requires_edges_or_region
|
||||
|
||||
res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data)
|
||||
[ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ]
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
%w(split_interacting).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(other, *args)
|
||||
|
|
|
|||
|
|
@ -1376,3 +1376,13 @@ TEST(57d_issue_1190)
|
|||
{
|
||||
run_test (_this, "57", true);
|
||||
}
|
||||
|
||||
TEST(58_in_and_out)
|
||||
{
|
||||
run_test (_this, "58", false);
|
||||
}
|
||||
|
||||
TEST(58d_in_and_out)
|
||||
{
|
||||
run_test (_this, "58", true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -422,7 +422,8 @@ void MacroCollection::scan ()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> dirs = tl::dir_entries (p, false /*with_files*/, true /*with_dirs*/, true /*without_dotfiles*/);
|
||||
// NOTE: we add files to capture symlinks to directories
|
||||
std::vector<std::string> dirs = tl::dir_entries (p, true /*with_files*/, true /*with_dirs*/, true /*without_dotfiles*/);
|
||||
for (auto f = dirs.begin (); f != dirs.end (); ++f) {
|
||||
|
||||
std::string fp = tl::combine_path (p, *f);
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
|
||||
l1e = l1.edges
|
||||
l2e = l2.edges
|
||||
|
||||
l2.in(l1).output(10, 0)
|
||||
l2.not_in(l1).output(11, 0)
|
||||
l2.in_and_out(l1).first.output(12, 0)
|
||||
l2.in_and_out(l1).last.output(13, 0)
|
||||
|
||||
l2e.in(l1e).output(20, 0)
|
||||
l2e.not_in(l1e).output(21, 0)
|
||||
l2e.in_and_out(l1e).first.output(22, 0)
|
||||
l2e.in_and_out(l1e).last.output(23, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue