From aa674484015b9ea795ba00a2fc60a62f20cd9c9c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 2 Feb 2025 23:47:02 +0100 Subject: [PATCH] WIP: polygon neighborhood --- src/db/db/db.pro | 3 + src/db/db/dbEdgeNeighborhood.h | 2 +- src/db/db/dbPolygonNeighborhood.cc | 209 ++++++++++++++++++++++ src/db/db/dbPolygonNeighborhood.h | 173 ++++++++++++++++++ src/db/db/gsiDeclDbEdgeNeighborhood.cc | 2 +- src/db/db/gsiDeclDbPolygonNeighborhood.cc | 144 +++++++++++++++ 6 files changed, 531 insertions(+), 2 deletions(-) create mode 100644 src/db/db/dbPolygonNeighborhood.cc create mode 100644 src/db/db/dbPolygonNeighborhood.h create mode 100644 src/db/db/gsiDeclDbPolygonNeighborhood.cc diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 98e7ef5da..1b0c205b2 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -76,6 +76,7 @@ SOURCES = \ dbPCellVariant.cc \ dbPoint.cc \ dbPolygon.cc \ + dbPolygonNeighborhood.cc \ dbPolygonTools.cc \ dbPolygonGenerators.cc \ dbPropertiesRepository.cc \ @@ -139,6 +140,7 @@ SOURCES = \ gsiDeclDbPath.cc \ gsiDeclDbPoint.cc \ gsiDeclDbPolygon.cc \ + gsiDeclDbPolygonNeighborhood.cc \ gsiDeclDbReader.cc \ gsiDeclDbRecursiveInstanceIterator.cc \ gsiDeclDbRecursiveShapeIterator.cc \ @@ -310,6 +312,7 @@ HEADERS = \ dbPCellVariant.h \ dbPoint.h \ dbPolygon.h \ + dbPolygonNeighborhood.h \ dbPolygonTools.h \ dbPolygonGenerators.h \ dbPropertiesRepository.h \ diff --git a/src/db/db/dbEdgeNeighborhood.h b/src/db/db/dbEdgeNeighborhood.h index c4c53fc04..e5e95adc4 100644 --- a/src/db/db/dbEdgeNeighborhood.h +++ b/src/db/db/dbEdgeNeighborhood.h @@ -158,7 +158,7 @@ class DB_PUBLIC EdgeNeighborhoodCompoundOperationNode : public CompoundRegionMultiInputOperationNode { public: - EdgeNeighborhoodCompoundOperationNode (const std::vector &children, EdgeNeighborhoodVisitor *visitor, const db::Coord bext, db::Coord eext, db::Coord din, db::Coord dout); + EdgeNeighborhoodCompoundOperationNode (const std::vector &children, EdgeNeighborhoodVisitor *visitor, db::Coord bext, db::Coord eext, db::Coord din, db::Coord dout); virtual ResultType result_type () const { diff --git a/src/db/db/dbPolygonNeighborhood.cc b/src/db/db/dbPolygonNeighborhood.cc new file mode 100644 index 000000000..21a7a9696 --- /dev/null +++ b/src/db/db/dbPolygonNeighborhood.cc @@ -0,0 +1,209 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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 "dbPolygonNeighborhood.h" +#include "dbBoxScanner.h" +#include "dbClip.h" + +namespace db +{ + +PolygonNeighborhoodVisitor::PolygonNeighborhoodVisitor () + : m_result_type (db::CompoundRegionOperationNode::ResultType::Edges) +{ + disconnect_outputs (); +} + +void +PolygonNeighborhoodVisitor::connect_output (Layout * /*layout*/, std::unordered_set *polygons) const +{ + disconnect_outputs (); + mp_polygons = polygons; +} + +void +PolygonNeighborhoodVisitor::connect_output (db::Layout *layout, std::unordered_set *polygons) const +{ + disconnect_outputs (); + mp_layout = layout; + mp_polygon_refs = polygons; +} + +void +PolygonNeighborhoodVisitor::connect_output (db::Layout * /*layout*/, std::unordered_set *edges) const +{ + disconnect_outputs (); + mp_edges = edges; +} + +void +PolygonNeighborhoodVisitor::connect_output (Layout * /*layout*/, std::unordered_set *edge_pairs) const +{ + disconnect_outputs (); + mp_edge_pairs = edge_pairs; +} + +void +PolygonNeighborhoodVisitor::disconnect_outputs () const +{ + mp_layout = 0; + mp_polygons = 0; + mp_polygon_refs = 0; + mp_edges = 0; + mp_edge_pairs = 0; +} + +void +PolygonNeighborhoodVisitor::output_polygon (const db::PolygonWithProperties &poly) +{ + if (mp_polygons) { + mp_polygons->insert (poly); + } else if (mp_polygon_refs) { + tl_assert (mp_layout != 0); + mp_polygon_refs->insert (db::PolygonRefWithProperties (db::PolygonRef (poly, mp_layout->shape_repository ()), poly.properties_id ())); + } else { + throw tl::Exception (tl::to_string (tr ("PolygonNeighborhoodVisitor is not configured for edge output (use 'result_type=Edges')"))); + } +} + +void +PolygonNeighborhoodVisitor::output_edge (const db::EdgeWithProperties &edge) +{ + if (mp_edges == 0) { + throw tl::Exception (tl::to_string (tr ("PolygonNeighborhoodVisitor is not configured for edge output (use 'result_type=Edges')"))); + } + mp_edges->insert (edge); +} + +void +PolygonNeighborhoodVisitor::output_edge_pair (const db::EdgePairWithProperties &edge_pair) +{ + if (mp_edge_pairs == 0) { + throw tl::Exception (tl::to_string (tr ("PolygonNeighborhoodVisitor is not configured for edge pair output (use 'result_type=EdgePairs')"))); + } + mp_edge_pairs->insert (edge_pair); +} + +// -------------------------------------------------------------------------------------------------- + +PolygonNeighborhoodCompoundOperationNode::PolygonNeighborhoodCompoundOperationNode (const std::vector &children, PolygonNeighborhoodVisitor *visitor, db::Coord dist) + : CompoundRegionMultiInputOperationNode (children), m_dist (dist), mp_visitor (visitor) +{ + tl_assert (visitor != 0); + visitor->keep (); +} + +db::Coord +PolygonNeighborhoodCompoundOperationNode::computed_dist () const +{ + return m_dist; +} + +std::string +PolygonNeighborhoodCompoundOperationNode::generated_description () const +{ + return tl::to_string (tr ("Polygon neighborhood collector")); +} + +void +PolygonNeighborhoodCompoundOperationNode::do_compute_local (CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase *proc) const +{ + compute_local_impl (cache, layout, cell, interactions, results, proc); +} + +void +PolygonNeighborhoodCompoundOperationNode::do_compute_local (CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase *proc) const +{ + compute_local_impl (cache, layout, cell, interactions, results, proc); +} + +void +PolygonNeighborhoodCompoundOperationNode::do_compute_local (CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase *proc) const +{ + compute_local_impl (cache, layout, cell, interactions, results, proc); +} + +void +PolygonNeighborhoodCompoundOperationNode::do_compute_local (CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase *proc) const +{ + compute_local_impl (cache, layout, cell, interactions, results, proc); +} + +void +PolygonNeighborhoodCompoundOperationNode::do_compute_local (CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase *proc) const +{ + compute_local_impl (cache, layout, cell, interactions, results, proc); +} + +void +PolygonNeighborhoodCompoundOperationNode::do_compute_local (CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase *proc) const +{ + compute_local_impl (cache, layout, cell, interactions, results, proc); +} + +template +void +PolygonNeighborhoodCompoundOperationNode::compute_local_impl (CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase *proc) const +{ + if (! mp_visitor) { + return; + } + tl_assert (interactions.num_subjects () == 1); + tl_assert (! results.empty ()); + + try { + + mp_visitor->connect_output (layout, &results.front ()); + + const T &pr = interactions.begin_subjects ()->second; + db::PolygonWithProperties subject (pr.instantiate (), pr.properties_id ()); + + PolygonNeighborhoodVisitor::neighbors_type neighbors; + + for (unsigned int i = 0; i < children (); ++i) { + + std::vector &n = neighbors [i]; + + std::vector > others; + others.push_back (std::unordered_set ()); + + shape_interactions computed_interactions; + child (i)->compute_local (cache, layout, cell, interactions_for_child (interactions, i, computed_interactions), others, proc); + + for (auto p = others.front ().begin (); p != others.front ().end (); ++p) { + n.push_back (db::PolygonWithProperties (p->instantiate (), p->properties_id ())); + } + + } + + const_cast (mp_visitor.get ())->neighbors (layout, cell, subject, neighbors); + + mp_visitor->disconnect_outputs (); + + } catch (...) { + mp_visitor->disconnect_outputs (); + throw; + } +} + +} + diff --git a/src/db/db/dbPolygonNeighborhood.h b/src/db/db/dbPolygonNeighborhood.h new file mode 100644 index 000000000..17bd13178 --- /dev/null +++ b/src/db/db/dbPolygonNeighborhood.h @@ -0,0 +1,173 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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_dbPolygonNeighborhood +#define HDR_dbPolygonNeighborhood + +#include "dbCommon.h" +#include "dbCompoundOperation.h" +#include "dbBoxScanner.h" +#include "dbMatrix.h" + +namespace db +{ + +/** + * @brief A visitor for the neighbors of an edge + */ +class DB_PUBLIC PolygonNeighborhoodVisitor + : public gsi::ObjectBase, public tl::Object +{ +public: + typedef std::pair position_interval_type; + typedef unsigned int input_key_type; + typedef std::vector neighbor_shapes_type; + typedef std::map neighbors_type; + + /** + * @brief Constructor + */ + PolygonNeighborhoodVisitor (); + + /** + * @brief Destructor + */ + virtual ~PolygonNeighborhoodVisitor () { } + + /** + * @brief Configure the polygon output + */ + void connect_output (db::Layout * /*layout*/, std::unordered_set *polygons) const; + + /** + * @brief Configure the polygon ref output + */ + void connect_output (db::Layout *layout, std::unordered_set *polygons) const; + + /** + * @brief Configure the edge output + */ + void connect_output (db::Layout * /*layout*/, std::unordered_set *edges) const; + + /** + * @brief Configure the edge pair output + */ + void connect_output (db::Layout * /*layout*/, std::unordered_set *edge_pairs) const; + + /** + * @brief Disconnects output + */ + void disconnect_outputs () const; + + /** + * @brief Event handler called when a new polygon is encountered + * This will report the central polygon and the neighbors. + */ + virtual void neighbors (const db::Layout * /*layout*/, const db::Cell * /*cell*/, const db::PolygonWithProperties & /*polygon*/, const neighbors_type & /*neighbors*/) { } + + /** + * @brief Sets the result type + */ + void set_result_type (db::CompoundRegionOperationNode::ResultType result_type) + { + m_result_type = result_type; + } + + /** + * @brief Gets the result type + */ + db::CompoundRegionOperationNode::ResultType result_type () const + { + return m_result_type; + } + + /** + * @brief Delivers a polygon + * This function is only permitted if the result type is Region. + */ + void output_polygon (const PolygonWithProperties &poly); + + /** + * @brief Delivers an edge + * This function is only permitted if the result type is Edges. + */ + void output_edge (const db::EdgeWithProperties &edge); + + /** + * @brief Delivers an edge pair object + * This function is only permitted if the result type is EdgePairs. + */ + void output_edge_pair (const db::EdgePairWithProperties &edge_pair); + +private: + db::CompoundRegionOperationNode::ResultType m_result_type; + mutable std::unordered_set *mp_polygons; + mutable std::unordered_set *mp_polygon_refs; + mutable std::unordered_set *mp_edges; + mutable std::unordered_set *mp_edge_pairs; + mutable db::Layout *mp_layout; +}; + +/** + * @brief A local operation for implementation of the neighborhood visitor + */ +class DB_PUBLIC PolygonNeighborhoodCompoundOperationNode + : public CompoundRegionMultiInputOperationNode +{ +public: + PolygonNeighborhoodCompoundOperationNode (const std::vector &children, PolygonNeighborhoodVisitor *visitor, db::Coord dist); + + virtual ResultType result_type () const + { + return mp_visitor ? mp_visitor->result_type () : 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 & /*interactions*/, std::vector > & /*results*/, const db::LocalProcessorBase * /*proc*/) const; + virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions & /*interactions*/, std::vector > & /*results*/, const db::LocalProcessorBase * /*proc*/) const; + virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions & /*interactions*/, std::vector > & /*results*/, const db::LocalProcessorBase * /*proc*/) const; + virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions & /*interactions*/, std::vector > & /*results*/, const db::LocalProcessorBase * /*proc*/) const; + virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions & /*interactions*/, std::vector > & /*results*/, const db::LocalProcessorBase * /*proc*/) const; + virtual void do_compute_local (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions & /*interactions*/, std::vector > & /*results*/, const db::LocalProcessorBase * /*proc*/) const; + +private: + db::Coord m_dist; + tl::weak_ptr mp_visitor; + + template + void compute_local_impl (CompoundRegionOperationCache * /*cache*/, db::Layout * /*layout*/, db::Cell * /*cell*/, const shape_interactions & /*interactions*/, std::vector > & /*results*/, const db::LocalProcessorBase * /*proc*/) const; +}; + +} + +#endif + diff --git a/src/db/db/gsiDeclDbEdgeNeighborhood.cc b/src/db/db/gsiDeclDbEdgeNeighborhood.cc index 526b54487..94b0a3961 100644 --- a/src/db/db/gsiDeclDbEdgeNeighborhood.cc +++ b/src/db/db/gsiDeclDbEdgeNeighborhood.cc @@ -224,7 +224,7 @@ Class decl_EdgeNeighborhoodVisitorImpl (decl_E ); // --------------------------------------------------------------------------------- -// EdgeProcessor binding +// PolygonNeighborhoodCompoundOperationNode binding static db::CompoundRegionOperationNode *new_edge_neighborhood (const std::vector &children, db::EdgeNeighborhoodVisitor *visitor, const db::Coord bext, db::Coord eext, db::Coord din, db::Coord dout) { diff --git a/src/db/db/gsiDeclDbPolygonNeighborhood.cc b/src/db/db/gsiDeclDbPolygonNeighborhood.cc new file mode 100644 index 000000000..bf5d373ca --- /dev/null +++ b/src/db/db/gsiDeclDbPolygonNeighborhood.cc @@ -0,0 +1,144 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 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 "dbPolygonNeighborhood.h" + +namespace gsi +{ + +// --------------------------------------------------------------------------------- +// EdgeFilter binding + +class PolygonNeighborhoodVisitorImpl + : public db::PolygonNeighborhoodVisitor +{ +public: + PolygonNeighborhoodVisitorImpl () { } + + void issue_neighbors (const db::Layout *, const db::Cell *, const db::PolygonWithProperties &, const db::PolygonNeighborhoodVisitor::neighbors_type &) + { + // just for signature + } + + void neighbors (const db::Layout *layout, const db::Cell *cell, const db::PolygonWithProperties &polygon, const db::PolygonNeighborhoodVisitor::neighbors_type &neighbors) + { + if (f_neighbors.can_issue ()) { + + // NOTE: as scripts are potentially thread unsafe, we lock here + tl::MutexLocker locker (&m_lock); + return f_neighbors.issue (&PolygonNeighborhoodVisitorImpl::issue_neighbors, layout, cell, polygon, neighbors); + + } + } + + gsi::Callback f_neighbors; + +private: + // No copying + PolygonNeighborhoodVisitorImpl &operator= (const PolygonNeighborhoodVisitorImpl &); + PolygonNeighborhoodVisitorImpl (const PolygonNeighborhoodVisitorImpl &); + + tl::Mutex m_lock; +}; + +Class decl_PolygonNeighborhoodVisitor ("db", "PolygonNeighborhoodVisitorBase", + "@hide" +); + +Class decl_PolygonNeighborhoodVisitorImpl (decl_PolygonNeighborhoodVisitor, "db", "PolygonNeighborhoodVisitor", + gsi::callback ("neighbors", &PolygonNeighborhoodVisitorImpl::issue_neighbors, &PolygonNeighborhoodVisitorImpl::f_neighbors, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("polygon"), gsi::arg ("neighborhood"), + "@brief Is called for each polygon with the neighbors\n" + "This method is called for every (merged) polygon on the input region. It delivers the polygon and the neighborhood. " + "The neighborhood is a collection of polygons (with properties) vs. input index.\n" + "It contains all polygons 'close to' the current polygon given by 'polygon'. 'Close to' does not necessarily refer to " + "being exactly in the vicinity, but may include other polygons just entering the bounding box of the current polygon." + ) + + gsi::method ("output", &PolygonNeighborhoodVisitorImpl::output_polygon, gsi::arg ("polygon"), + "@brief Outputs a polygon\n" + "Use this method from one of the callbacks (\\on_edge, \\begin_polygon, \\end_polygon) to deliver a polygon. " + "Note that you have to configure the result type as 'Region' on construction of the visitor before being able to do so.\n" + "\n" + "'output' expects an object in original space - i.e. of the input edge. \\to_original_trans gives you a suitable " + "transformation to bring objects from 'edge is horizontal' space into the original space." + ) + + gsi::method ("output", &PolygonNeighborhoodVisitorImpl::output_edge, gsi::arg ("edge"), + "@brief Outputs an edge\n" + "Use this method from one of the callbacks (\\on_edge, \\begin_polygon, \\end_polygon) to deliver a polygon. " + "Note that you have to configure the result type as 'Edges' on construction of the visitor before being able to do so." + "\n" + "'output' expects an object in original space - i.e. of the input edge. \\to_original_trans gives you a suitable " + "transformation to bring objects from 'edge is horizontal' space into the original space." + ) + + gsi::method ("output", &PolygonNeighborhoodVisitorImpl::output_edge_pair, gsi::arg ("edge_pair"), + "@brief Outputs an edge pair\n" + "Use this method from one of the callbacks (\\on_edge, \\begin_polygon, \\end_polygon) to deliver a polygon. " + "Note that you have to configure the result type as 'EdgePairs' on construction of the visitor before being able to do so." + "\n" + "'output' expects an object in original space - i.e. of the input edge. \\to_original_trans gives you a suitable " + "transformation to bring objects from 'edge is horizontal' space into the original space." + ) + + gsi::method ("result_type=", &PolygonNeighborhoodVisitorImpl::set_result_type, gsi::arg ("result_type"), + "@brief Configures the result type\n" + "Use this method to indicate what type of result you want to deliver. You can use the corresponding 'output' method then to " + "deliver result shapes from one the callbacks (\\on_edge, \\begin_polygon, \\end_polygon). Set this attribute when you create " + "the visitor object. This attribute does not need to be set if no output is indended to be delivered." + ) + + gsi::method ("result_type", &PolygonNeighborhoodVisitorImpl::result_type, + "@brief Gets the result type\n" + ), + "@brief A visitor for the neighborhood of polygons in the input\n" + "\n" + "Objects of this class are passed to \\PolygonNeighborhoodCompoundOperationNode constructor to handle " + "events on each edge of the primary input along with the neighborhood taken from the additional inputs.\n" + "\n" + "See \\neighbors for the description of the events delivered." + "\n" + "This class has been introduced in version 0.30.0.\n" +); + +// --------------------------------------------------------------------------------- +// PolygonNeighborhoodCompoundOperationNode binding + +static db::CompoundRegionOperationNode *new_edge_neighborhood (const std::vector &children, db::PolygonNeighborhoodVisitor *visitor, const db::Coord dist) +{ + return new db::PolygonNeighborhoodCompoundOperationNode (children, visitor, dist); +} + +gsi::ClassExt decl_CompoundRegionOperationNode_ext ( + gsi::constructor ("new_polygon_neighborhood", &new_edge_neighborhood, gsi::arg ("children"), gsi::arg ("visitor"), gsi::arg ("dist", 0), + "@brief Creates a new edge neighborhood collector\n" + "\n" + "@param children The inputs to use. The inputs are enumrated by base zero indexes in the visitor callback.\n" + "@param visitor The visitor object (see \\PolygonNeighborhoodVisitor) receiving the edge events.\n" + "@param dist The search distance in which to look up neighbors.\n" + "\n" + "This constructor has been introduced in version 0.30.0.\n" + ) +); + +} +