This commit is contained in:
Matthias Koefferlein 2024-10-21 21:50:35 +02:00
parent a983603dbc
commit 422c88207c
5 changed files with 395 additions and 10 deletions

View File

@ -23,6 +23,7 @@ SOURCES = \
dbCommonReader.cc \
dbCompoundOperation.cc \
dbEdge.cc \
dbEdgeNeighborhood.cc \
dbEdgePair.cc \
dbEdgePairFilters.cc \
dbEdgePairRelations.cc \
@ -119,6 +120,7 @@ SOURCES = \
gsiDeclDbCommonStreamOptions.cc \
gsiDeclDbCompoundOperation.cc \
gsiDeclDbEdge.cc \
gsiDeclDbEdgeNeighborhood.cc \
gsiDeclDbEdgePair.cc \
gsiDeclDbEdgePairs.cc \
gsiDeclDbEdgeProcessor.cc \
@ -249,6 +251,7 @@ HEADERS = \
dbCommonReader.h \
dbCompoundOperation.h \
dbEdge.h \
dbEdgeNeighborhood.h \
dbEdgePair.h \
dbEdgePairFilters.h \
dbEdgePairRelations.h \

View File

@ -266,6 +266,7 @@ protected:
virtual db::Coord computed_dist () const = 0;
virtual std::string generated_description () const;
virtual bool wants_caching () const { return true; }
private:
std::string m_description;
@ -276,23 +277,32 @@ private:
{
// TODO: confine caching to those nodes which need it.
std::pair<bool, std::vector<std::unordered_set<TR> > *> cp = cache->get<TR> (this);
if (wants_caching ()) {
if (! cp.first) {
std::pair<bool, std::vector<std::unordered_set<TR> > *> cp = cache->get<TR> (this);
std::vector<std::unordered_set<TR> > uncached_results;
uncached_results.resize (results.size ());
if (! cp.first) {
do_compute_local (cache, layout, cell, interactions, uncached_results, proc);
std::vector<std::unordered_set<TR> > uncached_results;
uncached_results.resize (results.size ());
cp.second->swap (uncached_results);
do_compute_local (cache, layout, cell, interactions, uncached_results, proc);
cp.second->swap (uncached_results);
}
tl_assert (results.size () == cp.second->size ());
for (size_t r = 0; r < results.size (); ++r) {
results[r].insert ((*cp.second)[r].begin (), (*cp.second)[r].end ());
}
} else {
do_compute_local (cache, layout, cell, interactions, results, proc);
}
tl_assert (results.size () == cp.second->size ());
for (size_t r = 0; r < results.size (); ++r) {
results[r].insert ((*cp.second)[r].begin (), (*cp.second)[r].end ());
}
}
};

View File

@ -0,0 +1,107 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2024 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dbEdgeNeighborhood.h"
#include "dbBoxScanner.h"
namespace db
{
EdgeNeighborhoodCompoundOperationNode::EdgeNeighborhoodCompoundOperationNode (const std::vector<CompoundRegionOperationNode *> &children, EdgeNeighborhoodVisitor *visitor, db::Coord bext, db::Coord eext, db::Coord din, db::Coord dout)
: CompoundRegionMultiInputOperationNode (children), m_bext (bext), m_eext (eext), m_din (din), m_dout (dout), mp_visitor (visitor)
{
tl_assert (visitor != 0);
visitor->keep ();
}
db::Coord
EdgeNeighborhoodCompoundOperationNode::computed_dist () const
{
return std::max (std::max (m_bext, m_eext), std::max (m_din, m_dout));
}
std::string
EdgeNeighborhoodCompoundOperationNode::generated_description () const
{
return tl::to_string (tr ("Neighborhood collector"));
}
void
EdgeNeighborhoodCompoundOperationNode::do_collect_neighbors (db::box_scanner2<db::Edge, unsigned int, db::Polygon, unsigned int> &scanner, const db::Layout *layout, const db::Cell *cell) const
{
}
void
EdgeNeighborhoodCompoundOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, db::Cell *cell, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > & /*results*/, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (interactions.num_subjects () == 1);
db::box_scanner2<db::Edge, unsigned int, db::Polygon, unsigned int> scanner;
std::list<db::Edge> edges;
std::list<db::Polygon> polygons;
for (auto i = interactions.begin_intruders (); i != interactions.end_intruders (); ++i) {
db::PolygonRef pr (i->second.second);
polygons.push_back (pr.instantiate ());
scanner.insert2 (&polygons.back (), i->second.first);
}
const db::PolygonRef &pr = interactions.begin_subjects ()->second;
unsigned int ie = 0;
for (auto e = pr.begin_edge (); ! e.at_end (); ++e, ++ie) {
edges.push_back (*e);
scanner.insert1 (&edges.back (), ie);
}
do_collect_neighbors (scanner, layout, cell);
}
void
EdgeNeighborhoodCompoundOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout *layout, db::Cell *cell, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Edge> > & /*results*/, const db::LocalProcessorBase * /*proc*/) const
{
tl_assert (interactions.num_subjects () == 1);
db::box_scanner2<db::Edge, unsigned int, db::Polygon, unsigned int> scanner;
std::list<db::Edge> edges;
std::list<db::Polygon> polygons;
for (auto i = interactions.begin_intruders (); i != interactions.end_intruders (); ++i) {
polygons.push_back (i->second.second);
scanner.insert2 (&polygons.back (), i->second.first);
}
const db::Polygon &pr = interactions.begin_subjects ()->second;
unsigned int ie = 0;
for (auto e = pr.begin_edge (); ! e.at_end (); ++e, ++ie) {
edges.push_back (*e);
scanner.insert1 (&edges.back (), ie);
}
do_collect_neighbors (scanner, layout, cell);
}
}

View File

@ -0,0 +1,106 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2024 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef HDR_dbEdgeNeighborhood
#define HDR_dbEdgeNeighborhood
#include "dbCommon.h"
#include "dbCompoundOperation.h"
#include "dbBoxScanner.h"
namespace db
{
/**
* @brief A visitor for the neighbors of an edge
*/
class DB_PUBLIC EdgeNeighborhoodVisitor
: public gsi::ObjectBase, public tl::Object
{
public:
typedef std::pair<double, double> position_interval_type;
typedef unsigned int input_key_type;
typedef std::list<db::Polygon> neighbor_shapes_type;
typedef std::map<input_key_type, neighbor_shapes_type> neighbors_per_interval_type;
typedef std::vector<std::pair<position_interval_type, neighbors_per_interval_type> > neighbors_type;
/**
* @brief Constructor
*/
EdgeNeighborhoodVisitor () { }
/**
* @brief Destructor
*/
virtual ~EdgeNeighborhoodVisitor () { }
/**
* @brief Event handler for each edge plus it's neighborhood
*/
void on_edge (const db::Layout *layout, const db::Cell *cell, const db::Edge &edge, const neighbors_type &neighbors);
};
/**
* @brief A local operation for implementation of the neighborhood visitor
*/
class DB_PUBLIC EdgeNeighborhoodCompoundOperationNode
: public CompoundRegionMultiInputOperationNode
{
public:
EdgeNeighborhoodCompoundOperationNode (const std::vector<CompoundRegionOperationNode *> &children, EdgeNeighborhoodVisitor *visitor, const db::Coord bext, db::Coord eext, db::Coord din, db::Coord dout);
virtual ResultType result_type () const
{
return CompoundRegionOperationNode::Edges;
}
virtual bool wants_caching () const
{
return false;
}
protected:
virtual db::Coord computed_dist () const;
virtual std::string generated_description () const;
virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Polygon, db::Polygon> & /*interactions*/, std::vector<std::unordered_set<db::Edge> > & /*results*/, const db::LocalProcessorBase * /*proc*/) const;
virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::PolygonRef, db::PolygonRef> & /*interactions*/, std::vector<std::unordered_set<db::Edge> > & /*results*/, const db::LocalProcessorBase * /*proc*/) const;
// not implemented
virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Polygon, db::Polygon> & /*interactions*/, std::vector<std::unordered_set<db::Polygon> > & /*results*/, const db::LocalProcessorBase * /*proc*/) const { }
virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::Polygon, db::Polygon> & /*interactions*/, std::vector<std::unordered_set<db::EdgePair> > & /*results*/, const db::LocalProcessorBase * /*proc*/) const { }
virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::PolygonRef, db::PolygonRef> & /*interactions*/, std::vector<std::unordered_set<db::PolygonRef> > & /*results*/, const db::LocalProcessorBase * /*proc*/) const { }
virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions<db::PolygonRef, db::PolygonRef> & /*interactions*/, std::vector<std::unordered_set<db::EdgePair> > & /*results*/, const db::LocalProcessorBase * /*proc*/) const { }
private:
db::Coord m_bext, m_eext, m_din, m_dout;
tl::weak_ptr<EdgeNeighborhoodVisitor> mp_visitor;
void do_collect_neighbors (db::box_scanner2<db::Edge, unsigned int, db::Polygon, unsigned int> &scanner, const db::Layout *layout, const db::Cell *cell) const;
};
}
#endif

View File

@ -0,0 +1,159 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2024 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "gsiDecl.h"
#include "gsiEnums.h"
#include "tlThreads.h"
#include "dbEdgeNeighborhood.h"
namespace gsi
{
// ---------------------------------------------------------------------------------
// EdgeFilter binding
class EdgeNeighborhoodVisitorImpl
: public db::EdgeNeighborhoodVisitor
{
public:
EdgeNeighborhoodVisitorImpl () { }
void issue_on_edge (const db::Layout *, const db::Cell *, const db::Edge &, const tl::Variant &)
{
// just for signature
}
void on_edge (const db::Layout *layout, const db::Cell *cell, const db::Edge &edge, const db::EdgeNeighborhoodVisitor::neighbors_type &neighbors)
{
if (f_on_edge.can_issue ()) {
tl::Variant neighborhood = build_neighbors (neighbors);
// NOTE: as scripts are potentially thread unsafe, we lock here
tl::MutexLocker locker (&m_lock);
return f_on_edge.issue<EdgeNeighborhoodVisitorImpl, const db::Layout *, const db::Cell *, const db::Edge &, const tl::Variant &> (&EdgeNeighborhoodVisitorImpl::issue_on_edge, layout, cell, edge, neighborhood);
}
}
gsi::Callback f_on_edge;
static tl::Variant build_neighbors (const db::EdgeNeighborhoodVisitor::neighbors_type &neighbors)
{
tl::Variant result;
result.set_list ();
for (auto n = neighbors.begin (); n != neighbors.end (); ++n) {
tl::Variant row;
row.set_list ();
tl::Variant interval;
interval.set_list ();
interval.push (n->first.first);
interval.push (n->first.second);
row.push (interval);
tl::Variant nmap;
nmap.set_array ();
for (auto nn = n->second.begin (); nn != n->second.end (); ++nn) {
nmap.insert (tl::Variant (nn->first), tl::Variant (nn->second));
}
row.push (nmap);
result.push (row);
}
return result;
}
private:
// No copying
EdgeNeighborhoodVisitorImpl &operator= (const EdgeNeighborhoodVisitorImpl &);
EdgeNeighborhoodVisitorImpl (const EdgeNeighborhoodVisitorImpl &);
tl::Mutex m_lock;
};
Class<gsi::EdgeNeighborhoodVisitorImpl> decl_EdgeNeighborhoodVisitorImpl ("db", "EdgeNeighborhoodVisitor",
gsi::callback ("on_edge", &EdgeNeighborhoodVisitorImpl::issue_on_edge, &EdgeNeighborhoodVisitorImpl::f_on_edge, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("edge"), gsi::arg ("neighborhood"),
"@brief Is called for each edge with the edge neighbors\n"
"This method is called for every edge on the input region. It delivers the edge and the edge neighborhood. "
"The edge neighborhood is classified in intervals along the edge. The intervals are given by a range of "
"positions along the edge - 0.0 being the beginning of the edge and positive values towards the end of the edge. "
"For 'bext' and 'eext' larger than zero (see "
"\\EdgeNeighborhoodCompoundOperationNode), the position can be negative or larger than the edge length.\n"
"\n"
"The structure of the neighbors is:\n"
"\n"
"@code\n"
"[\n"
" [ [ from, to ], { input_index => polygons }\n"
"]\n"
"@/code\n"
"\n"
"'from' and 'to' are the positions of the interval, 'input_index' is the index of the input the neighbors are on "
"(see 'children' argument of \\EdgeNeighborhoodCompoundOperationNode constructor), 'prop_id' is the properties ID of "
"the neighbors and 'polygons' is a list of polygons describing the neighborhood.\n"
"The polygons are projected on the edge - i.e. they are in a coordinate system where the edge is horizonal and "
"goes from (0,0) to (length,0).\n"
"\n"
"The polygons are boxes for manhattan input and trapezoids in the general case.\n"
),
"@brief A visitor for the neighborhood of edges in the input\n"
"\n"
"Objects of this class are passed to \\EdgeNeighborhoodCompoundOperationNode constructor to handle "
"events on each edge of the primary input along with the neighborhood taken from the additional inputs.\n"
"\n"
"See \\on_edge for the description of the events delivered."
"\n"
"This class has been introduced in version 0.xx.\n" // @@@
);
// ---------------------------------------------------------------------------------
// EdgeProcessor binding
static db::CompoundRegionOperationNode *new_edge_neighborhood (const std::vector<db::CompoundRegionOperationNode *> &children, db::EdgeNeighborhoodVisitor *visitor, const db::Coord bext, db::Coord eext, db::Coord din, db::Coord dout)
{
return new db::EdgeNeighborhoodCompoundOperationNode (children, visitor, bext, eext, din, dout);
}
gsi::ClassExt<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode_ext (
gsi::constructor ("new_edge_neighborhood", &new_edge_neighborhood, gsi::arg ("children"), gsi::arg ("visitor"), gsi::arg ("bext", 0), gsi::arg ("eext", 0), gsi::arg ("din", 0), gsi::arg ("dout", 0),
"@brief Creates a new edge neighborhood collector\n"
"\n"
"@param children The inputs to use. The first one in the primary input, the others are neighbors.\n"
"@param visitor The visitor object (see \\EdgeNeighborhoodVisitor) receiving the edge events.\n"
"@param bext The search window extension to use at the edge beginning.\n"
"@param eext The search window extension to use at the edge beginning.\n"
"@param din The search window extension to use at the edge beginning.\n"
"@param dout The search window extension to use at the edge beginning.\n"
)
);
}