Implemented solution for #570 (deep Edges::extents)

While doing this, it was discovered that the problem also
persists for EdgePairs and Texts.

In order to provide a more generic solution, some refactoring
was applied.
This commit is contained in:
Matthias Koefferlein 2020-05-31 01:55:05 +02:00
parent eacd67df1c
commit 759f07ee4d
42 changed files with 557 additions and 418 deletions

View File

@ -196,7 +196,8 @@ SOURCES = \
dbOriginalLayerTexts.cc \
dbNetShape.cc \
dbShapeCollection.cc \
gsiDeclDbShapeCollection.cc
gsiDeclDbShapeCollection.cc \
dbShapeCollectionUtils.cc
HEADERS = \
dbArray.h \
@ -353,7 +354,8 @@ HEADERS = \
dbTextsUtils.h \
dbOriginalLayerTexts.h \
dbNetShape.h \
dbShapeCollection.h
dbShapeCollection.h \
dbShapeCollectionUtils.h
!equals(HAVE_QT, "0") {

View File

@ -125,6 +125,28 @@ void AsIfFlatEdgePairs::invalidate_bbox ()
m_bbox_valid = false;
}
RegionDelegate *
AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const
{
std::auto_ptr<FlatRegion> region (new FlatRegion ());
if (filter.result_must_not_be_merged ()) {
region->set_merged_semantics (false);
}
std::vector<db::Polygon> res_polygons;
for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) {
res_polygons.clear ();
filter.process (*e, res_polygons);
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
region->insert (*pr);
}
}
return region.release ();
}
EdgePairsDelegate *
AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const
{

View File

@ -51,6 +51,8 @@ public:
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const;
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
virtual EdgePairsDelegate *add_in_place (const EdgePairs &other)
{
return add (other);

View File

@ -152,6 +152,28 @@ AsIfFlatTexts::filtered (const TextFilterBase &filter) const
return new_texts.release ();
}
RegionDelegate *
AsIfFlatTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter) const
{
std::auto_ptr<FlatRegion> region (new FlatRegion ());
if (filter.result_must_not_be_merged ()) {
region->set_merged_semantics (false);
}
std::vector<db::Polygon> res_polygons;
for (TextsIterator e (begin ()); ! e.at_end (); ++e) {
res_polygons.clear ();
filter.process (*e, res_polygons);
for (std::vector<db::Polygon>::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) {
region->insert (*pr);
}
}
return region.release ();
}
RegionDelegate *
AsIfFlatTexts::polygons (db::Coord e) const
{

View File

@ -53,6 +53,8 @@ public:
virtual TextsDelegate *filtered (const TextFilterBase &) const;
virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &filter) const;
virtual TextsDelegate *add_in_place (const Texts &other)
{
return add (other);

View File

@ -57,6 +57,22 @@ db::Trans MagnificationReducer::reduce (const db::Trans &) const
// ------------------------------------------------------------------------------------------
db::ICplxTrans XYAnisotropyAndMagnificationReducer::reduce (const db::ICplxTrans &trans) const
{
double a = trans.angle ();
if (a > 180.0 - db::epsilon) {
a -= 180.0;
}
return db::ICplxTrans (trans.mag (), a, false, db::Vector ());
}
db::Trans XYAnisotropyAndMagnificationReducer::reduce (const db::Trans &trans) const
{
return db::Trans (trans.angle () % 2, false, db::Vector ());
}
// ------------------------------------------------------------------------------------------
db::ICplxTrans MagnificationAndOrientationReducer::reduce (const db::ICplxTrans &trans) const
{
db::ICplxTrans res (trans);

View File

@ -81,6 +81,18 @@ struct DB_PUBLIC MagnificationReducer
db::Trans reduce (const db::Trans &) const;
};
/**
* @brief A reducer for magnification and XYAnisotropy
*
* This reducer is used for cases where an x and y-value is given, e.g. anisotropic size.
*/
struct DB_PUBLIC XYAnisotropyAndMagnificationReducer
: public TransformationReducer
{
db::ICplxTrans reduce (const db::ICplxTrans &trans) const;
db::Trans reduce (const db::Trans &trans) const;
};
/**
* @brief A magnification and orientation reducer
*

View File

@ -240,6 +240,12 @@ EdgePairsDelegate *DeepEdgePairs::filtered (const EdgePairFilterBase &filter) co
return AsIfFlatEdgePairs::filtered (filter);
}
RegionDelegate *
DeepEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const
{
return shape_collection_processed_impl<db::EdgePair, db::Polygon, db::DeepRegion> (deep_layer (), filter);
}
RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const
{
db::DeepLayer new_layer = deep_layer ().derived ();

View File

@ -63,6 +63,7 @@ public:
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter);
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const;
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
virtual EdgePairsDelegate *add_in_place (const EdgePairs &other);
virtual EdgePairsDelegate *add (const EdgePairs &other) const;

View File

@ -525,146 +525,19 @@ EdgesDelegate *DeepEdges::process_in_place (const EdgeProcessorBase &filter)
EdgesDelegate *
DeepEdges::processed (const EdgeProcessorBase &filter) const
{
return processed_impl<db::Edge, db::DeepEdges> (filter);
return shape_collection_processed_impl<db::Edge, db::Edge, db::DeepEdges> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
}
EdgePairsDelegate *
DeepEdges::processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &filter) const
{
return processed_impl<db::EdgePair, db::DeepEdgePairs> (filter);
return shape_collection_processed_impl<db::Edge, db::EdgePair, db::DeepEdgePairs> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
}
RegionDelegate *
DeepEdges::processed_to_polygons (const EdgeToPolygonProcessorBase &filter) const
{
return processed_impl<db::Polygon, db::DeepRegion> (filter);
}
namespace
{
template <class Result> struct delivery;
template <>
struct delivery<db::Polygon>
{
delivery (db::Layout *layout, db::Shapes *shapes)
: mp_layout (layout), mp_shapes (shapes)
{ }
void put (const db::Polygon &result)
{
tl::MutexLocker locker (&mp_layout->lock ());
mp_shapes->insert (db::PolygonRef (result, mp_layout->shape_repository ()));
}
private:
db::Layout *mp_layout;
db::Shapes *mp_shapes;
};
template <class Result>
struct delivery
{
delivery (db::Layout *, db::Shapes *shapes)
: mp_shapes (shapes)
{ }
void put (const Result &result)
{
mp_shapes->insert (result);
}
private:
db::Shapes *mp_shapes;
};
}
template <class Result, class OutputContainer>
OutputContainer *
DeepEdges::processed_impl (const edge_processor<Result> &filter) const
{
const db::DeepLayer &edges = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
std::auto_ptr<VariantsCollectorBase> vars;
if (filter.vars ()) {
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
vars->collect (edges.layout (), edges.initial_cell ());
if (filter.wants_variants ()) {
const_cast<db::DeepLayer &> (edges).separate_variants (*vars);
}
}
db::Layout &layout = const_cast<db::Layout &> (edges.layout ());
std::vector<Result> heap;
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
std::auto_ptr<OutputContainer> res (new OutputContainer (edges.derived ()));
if (filter.result_must_not_be_merged ()) {
res->set_merged_semantics (false);
}
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (filter.requires_raw_input () ? edges.layer () : edges.layer ());
if (vars.get ()) {
const std::map<db::ICplxTrans, size_t> &vv = vars->variants (c->cell_index ());
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st;
if (vv.size () == 1) {
st = & c->shapes (res->deep_layer ().layer ());
} else {
st = & to_commit [c->cell_index ()] [v->first];
}
delivery<Result> delivery (&layout, st);
const db::ICplxTrans &tr = v->first;
db::ICplxTrans trinv = tr.inverted ();
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
heap.clear ();
filter.process (si->edge ().transformed (tr), heap);
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
delivery.put (i->transformed (trinv));
}
}
}
} else {
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
delivery<Result> delivery (&layout, &st);
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
filter.process (si->edge (), heap);
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
delivery.put (*i);
}
}
}
}
if (! to_commit.empty () && vars.get ()) {
res->deep_layer ().commit_shapes (*vars, to_commit);
}
if (filter.result_is_merged ()) {
res->set_is_merged (true);
}
return res.release ();
return shape_collection_processed_impl<db::Edge, db::Polygon, db::DeepRegion> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
}
EdgesDelegate *

View File

@ -149,9 +149,10 @@ public:
return this;
}
void set_is_merged (bool f);
protected:
virtual void merged_semantics_changed ();
void set_is_merged (bool f);
private:
friend class DeepRegion;

View File

@ -955,152 +955,19 @@ DeepRegion::process_in_place (const PolygonProcessorBase &filter)
EdgesDelegate *
DeepRegion::processed_to_edges (const PolygonToEdgeProcessorBase &filter) const
{
return processed_impl<db::Edge, db::DeepEdges> (filter);
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
{
return processed_impl<db::EdgePair, db::DeepEdgePairs> (filter);
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
{
return processed_impl<db::Polygon, db::DeepRegion> (filter);
}
namespace
{
template <class Result> struct delivery;
template <>
struct delivery<db::Polygon>
{
delivery (db::Layout *layout, db::Shapes *shapes)
: mp_layout (layout), mp_shapes (shapes)
{ }
void put (const db::Polygon &result)
{
tl::MutexLocker locker (&mp_layout->lock ());
mp_shapes->insert (db::PolygonRef (result, mp_layout->shape_repository ()));
}
private:
db::Layout *mp_layout;
db::Shapes *mp_shapes;
};
template <class Result>
struct delivery
{
delivery (db::Layout *, db::Shapes *shapes)
: mp_shapes (shapes)
{ }
void put (const Result &result)
{
mp_shapes->insert (result);
}
private:
db::Shapes *mp_shapes;
};
}
template <class Result, class OutputContainer>
OutputContainer *
DeepRegion::processed_impl (const polygon_processor<Result> &filter) const
{
const db::DeepLayer &polygons = filter.requires_raw_input () ? deep_layer () : merged_deep_layer ();
std::auto_ptr<VariantsCollectorBase> vars;
if (filter.vars ()) {
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
vars->collect (polygons.layout (), polygons.initial_cell ());
if (filter.wants_variants ()) {
const_cast<db::DeepLayer &> (polygons).separate_variants (*vars);
}
}
db::Layout &layout = const_cast<db::Layout &> (polygons.layout ());
std::vector<Result> heap;
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
std::auto_ptr<OutputContainer> res (new OutputContainer (polygons.derived ()));
if (filter.result_must_not_be_merged ()) {
res->set_merged_semantics (false);
}
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (polygons.layer ());
if (vars.get ()) {
const std::map<db::ICplxTrans, size_t> &vv = vars->variants (c->cell_index ());
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st;
if (vv.size () == 1) {
st = & c->shapes (res->deep_layer ().layer ());
} else {
st = & to_commit [c->cell_index ()] [v->first];
}
delivery<Result> delivery (&layout, st);
const db::ICplxTrans &tr = v->first;
db::ICplxTrans trinv = tr.inverted ();
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
db::Polygon poly;
si->polygon (poly);
poly.transform (tr);
heap.clear ();
filter.process (poly, heap);
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
delivery.put (i->transformed (trinv));
}
}
}
} else {
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
delivery<Result> delivery (&layout, &st);
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
db::Polygon poly;
si->polygon (poly);
heap.clear ();
filter.process (poly, heap);
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
delivery.put (*i);
}
}
}
}
if (! to_commit.empty () && vars.get ()) {
res->deep_layer ().commit_shapes (*vars, to_commit);
}
if (filter.result_is_merged ()) {
res->set_is_merged (true);
}
return res.release ();
return shape_collection_processed_impl<db::Polygon, db::Polygon, db::DeepRegion> (filter.requires_raw_input () ? deep_layer () : merged_deep_layer (), filter);
}
RegionDelegate *
@ -1318,29 +1185,6 @@ DeepRegion::sized (coord_type d, unsigned int mode) const
return res.release ();
}
namespace
{
struct XYAnisotropyAndMagnificationReducer
: public db::TransformationReducer
{
db::ICplxTrans reduce (const db::ICplxTrans &trans) const
{
double a = trans.angle ();
if (a > 180.0 - db::epsilon) {
a -= 180.0;
}
return db::ICplxTrans (trans.mag (), a, false, db::Vector ());
}
db::Trans reduce (const db::Trans &trans) const
{
return db::Trans (trans.angle () % 2, false, db::Vector ());
}
};
}
RegionDelegate *
DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
{

View File

@ -164,10 +164,11 @@ public:
return this;
}
void set_is_merged (bool f);
protected:
virtual void merged_semantics_changed ();
virtual void min_coherence_changed ();
void set_is_merged (bool f);
private:
friend class DeepEdges;

View File

@ -333,6 +333,12 @@ DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const
return res.release ();
}
RegionDelegate *
DeepTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter) const
{
return shape_collection_processed_impl<db::Text, db::Polygon, db::DeepRegion> (deep_layer (), filter);
}
RegionDelegate *DeepTexts::polygons (db::Coord e) const
{
db::DeepLayer new_layer = deep_layer ().derived ();

View File

@ -65,6 +65,8 @@ public:
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter);
virtual TextsDelegate *filtered (const TextFilterBase &) const;
virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &filter) const;
virtual TextsDelegate *add_in_place (const Texts &other);
virtual TextsDelegate *add (const Texts &other) const;

View File

@ -143,6 +143,11 @@ EdgePairs::iter () const
return *(i ? i : &def_iter);
}
void EdgePairs::processed (Region &output, const EdgePairToPolygonProcessorBase &filter) const
{
output = Region (mp_delegate->processed_to_polygons (filter));
}
void EdgePairs::polygons (Region &output, db::Coord e) const
{
output.set_delegate (mp_delegate->polygons (e));

View File

@ -465,6 +465,14 @@ public:
return EdgePairs (mp_delegate->filtered (filter));
}
/**
* @brief Processes the edge pairs into polygons
*
* This method will run the processor over all edge pairs and return a region
* with the outputs of the processor.
*/
void processed (Region &output, const EdgePairToPolygonProcessorBase &filter) const;
/**
* @brief Transforms the edge pair set
*/

View File

@ -27,6 +27,7 @@
#include "dbCommon.h"
#include "dbEdgePair.h"
#include "dbShapeCollection.h"
#include "dbShapeCollectionUtils.h"
namespace db {
@ -37,6 +38,8 @@ class RegionDelegate;
class EdgesDelegate;
class Layout;
typedef shape_collection_processor<db::EdgePair, db::Polygon> EdgePairToPolygonProcessorBase;
/**
* @brief The edge pair set iterator delegate
*/
@ -97,6 +100,7 @@ public:
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &filter) = 0;
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &filter) const = 0;
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const = 0;
virtual RegionDelegate *polygons (db::Coord e) const = 0;
virtual EdgesDelegate *edges () const = 0;

View File

@ -30,6 +30,7 @@
#include "dbEdgePairs.h"
#include "dbEdgePairRelations.h"
#include "dbShapeCollection.h"
#include "dbShapeCollectionUtils.h"
#include <list>
@ -128,32 +129,9 @@ public:
virtual bool wants_variants () const = 0;
};
/**
* @brief A edge processor base class
*/
class DB_PUBLIC EdgeProcessorBase
: public edge_processor<db::Edge>
{
// .. nothing yet ..
};
/**
* @brief An edge-to-polygon processor base class
*/
class DB_PUBLIC EdgeToPolygonProcessorBase
: public edge_processor<db::Polygon>
{
// .. nothing yet ..
};
/**
* @brief An edge-to-edge pair processor base class
*/
class DB_PUBLIC EdgeToEdgePairProcessorBase
: public edge_processor<db::EdgePair>
{
// .. nothing yet ..
};
typedef shape_collection_processor<db::Edge, db::Edge> EdgeProcessorBase;
typedef shape_collection_processor<db::Edge, db::Polygon> EdgeToPolygonProcessorBase;
typedef shape_collection_processor<db::Edge, db::EdgePair> EdgeToEdgePairProcessorBase;
class RecursiveShapeIterator;
class EdgeFilterBase;

View File

@ -53,6 +53,12 @@ EmptyEdgePairs::polygons (db::Coord) const
return new EmptyRegion ();
}
RegionDelegate *
EmptyEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase &) const
{
return new EmptyRegion ();
}
EdgesDelegate *
EmptyEdgePairs::edges () const
{

View File

@ -55,6 +55,7 @@ public:
virtual EdgePairsDelegate *filter_in_place (const EdgePairFilterBase &) { return this; }
virtual EdgePairsDelegate *filtered (const EdgePairFilterBase &) const { return new EmptyEdgePairs (); }
virtual RegionDelegate *processed_to_polygons (const EdgePairToPolygonProcessorBase &filter) const;
virtual RegionDelegate *polygons (db::Coord e) const;
virtual EdgesDelegate *edges () const;

View File

@ -54,6 +54,12 @@ EmptyTexts::polygons (db::Coord) const
return new EmptyRegion ();
}
RegionDelegate *
EmptyTexts::processed_to_polygons (const TextToPolygonProcessorBase &) const
{
return new EmptyRegion ();
}
EdgesDelegate *
EmptyTexts::edges () const
{

View File

@ -56,6 +56,8 @@ public:
virtual TextsDelegate *filter_in_place (const TextFilterBase &) { return this; }
virtual TextsDelegate *filtered (const TextFilterBase &) const { return new EmptyTexts (); }
virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &) const;
virtual RegionDelegate *polygons (db::Coord e) const;
virtual EdgesDelegate *edges () const;

View File

@ -135,32 +135,9 @@ public:
virtual bool wants_variants () const = 0;
};
/**
* @brief A polygon-to-polygon processor base class
*/
class DB_PUBLIC PolygonProcessorBase
: public polygon_processor<db::Polygon>
{
// .. nothing yet ..
};
/**
* @brief A polygon-to-edge processor base class
*/
class DB_PUBLIC PolygonToEdgeProcessorBase
: public polygon_processor<db::Edge>
{
// .. nothing yet ..
};
/**
* @brief A polygon-to-edge pair processor base class
*/
class DB_PUBLIC PolygonToEdgePairProcessorBase
: public polygon_processor<db::EdgePair>
{
// .. nothing yet ..
};
typedef shape_collection_processor<db::Polygon, db::Polygon> PolygonProcessorBase;
typedef shape_collection_processor<db::Polygon, db::Edge> PolygonToEdgeProcessorBase;
typedef shape_collection_processor<db::Polygon, db::EdgePair> PolygonToEdgePairProcessorBase;
/**
* @brief The region iterator delegate

View File

@ -87,28 +87,6 @@ void CornerDetectorCore::detect_corners (const db::Polygon &poly, const CornerPo
}
}
// -----------------------------------------------------------------------------------
// Extents implementation
void Extents::process (const db::Polygon &poly, std::vector<db::Polygon> &result) const
{
db::Box box = poly.box ().enlarged (db::Vector (m_dx, m_dy));
if (! box.empty ()) {
result.push_back (db::Polygon (box));
}
}
const TransformationReducer *Extents::vars () const
{
if (m_dx == 0 && m_dy == 0) {
return 0;
} else if (m_dx == m_dy) {
return & m_isotropic_reducer;
} else {
return & m_anisotropic_reducer;
}
}
// -----------------------------------------------------------------------------------
// RelativeExtents implementation

View File

@ -158,34 +158,6 @@ public:
// -----------------------------------------------------------------------------------
// Extents
/**
* @brief A processor delivering the extents (bounding box) of the merged polygons
* This processor allows over- or undersizing of the resulting box by a given amount
*/
class DB_PUBLIC Extents
: public db::PolygonProcessorBase
{
public:
Extents (db::Coord dx, db::Coord dy)
: m_dx (dx), m_dy (dy)
{
// .. nothing yet ..
}
void process (const db::Polygon &poly, std::vector<db::Polygon> &result) const;
virtual const TransformationReducer *vars () const;
virtual bool result_is_merged () const { return false; }
virtual bool result_must_not_be_merged () const { return false; }
virtual bool requires_raw_input () const { return false; }
virtual bool wants_variants () const { return true; }
private:
db::Coord m_dx, m_dy;
db::MagnificationAndOrientationReducer m_anisotropic_reducer;
db::MagnificationReducer m_isotropic_reducer;
};
/**
* @brief A processor delivering the relative extents (bounding box) of the merged polygons
* This processor allows over- or undersizing of the resulting box by a given amount and delivery

View File

@ -0,0 +1,23 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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 "dbShapeCollectionUtils.h"

View File

@ -0,0 +1,302 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2020 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_dbShapeCollectionUtils
#define HDR_dbShapeCollectionUtils
#include "dbCommon.h"
#include "dbShape.h"
#include "dbShapes.h"
#include "dbLayout.h"
#include "dbCellVariants.h"
#include "dbShapeCollection.h"
#include "dbDeepShapeStore.h"
#include <list>
namespace db {
/**
* @brief A template base class for edge processors
*
* A polygon processor can turn a edge into something else.
*/
template <class Shape, class Result>
class DB_PUBLIC_TEMPLATE shape_collection_processor
{
public:
/**
* @brief Constructor
*/
shape_collection_processor () { }
/**
* @brief Destructor
*/
virtual ~shape_collection_processor () { }
/**
* @brief Performs the actual processing
* This method will take the input edge from "edge" and puts the results into "res".
* "res" can be empty - in this case, the edge will be skipped.
*/
virtual void process (const Shape &shape, std::vector<Result> &res) const = 0;
/**
* @brief Returns the transformation reducer for building cell variants
* This method may return 0. In this case, not cell variants are built.
*/
virtual const TransformationReducer *vars () const = 0;
/**
* @brief Returns true, if the result of this operation can be regarded "merged" always.
*/
virtual bool result_is_merged () const = 0;
/**
* @brief Returns true, if the result of this operation must not be merged.
* This feature can be used, if the result represents "degenerated" objects such
* as point-like edges. These must not be merged. Otherwise they disappear.
*/
virtual bool result_must_not_be_merged () const = 0;
/**
* @brief Returns true, if the processor wants raw (not merged) input
*/
virtual bool requires_raw_input () const = 0;
/**
* @brief Returns true, if the processor wants to build variants
* If not true, the processor accepts shape propagation as variant resolution.
*/
virtual bool wants_variants () const = 0;
};
/**
* @brief A shape delivery class for the shape collection processor
*/
template <class Result> struct shape_collection_processor_delivery;
/**
* @brief A shape delivery implementation for polygons
*/
template <>
struct DB_PUBLIC shape_collection_processor_delivery<db::Polygon>
{
shape_collection_processor_delivery (db::Layout *layout, db::Shapes *shapes)
: mp_layout (layout), mp_shapes (shapes)
{ }
void put (const db::Polygon &result)
{
tl::MutexLocker locker (&mp_layout->lock ());
mp_shapes->insert (db::PolygonRef (result, mp_layout->shape_repository ()));
}
private:
db::Layout *mp_layout;
db::Shapes *mp_shapes;
};
/**
* @brief A shape delivery implementation for texts
*/
template <>
struct DB_PUBLIC shape_collection_processor_delivery<db::Text>
{
shape_collection_processor_delivery (db::Layout *layout, db::Shapes *shapes)
: mp_layout (layout), mp_shapes (shapes)
{ }
void put (const db::Text &result)
{
tl::MutexLocker locker (&mp_layout->lock ());
mp_shapes->insert (db::TextRef (result, mp_layout->shape_repository ()));
}
private:
db::Layout *mp_layout;
db::Shapes *mp_shapes;
};
/**
* @brief A generic delivery
*/
template <class Result>
struct DB_PUBLIC shape_collection_processor_delivery
{
shape_collection_processor_delivery (db::Layout *, db::Shapes *shapes)
: mp_shapes (shapes)
{ }
void put (const Result &result)
{
mp_shapes->insert (result);
}
private:
db::Shapes *mp_shapes;
};
/**
* @brief Provides a generic implementation of the shape collection processor
*/
template <class Shape, class Result, class OutputContainer>
DB_PUBLIC_TEMPLATE
OutputContainer *
shape_collection_processed_impl (const db::DeepLayer &input, const shape_collection_processor<Shape, Result> &filter)
{
std::auto_ptr<VariantsCollectorBase> vars;
if (filter.vars ()) {
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
vars->collect (input.layout (), input.initial_cell ());
if (filter.wants_variants ()) {
const_cast<db::DeepLayer &> (input).separate_variants (*vars);
}
}
db::Layout &layout = const_cast<db::Layout &> (input.layout ());
std::vector<Result> heap;
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
std::auto_ptr<OutputContainer> res (new OutputContainer (input.derived ()));
if (filter.result_must_not_be_merged ()) {
res->set_merged_semantics (false);
}
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (input.layer ());
if (vars.get ()) {
const std::map<db::ICplxTrans, size_t> &vv = vars->variants (c->cell_index ());
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
db::Shapes *st;
if (vv.size () == 1) {
st = & c->shapes (res->deep_layer ().layer ());
} else {
st = & to_commit [c->cell_index ()] [v->first];
}
shape_collection_processor_delivery<Result> delivery (&layout, st);
const db::ICplxTrans &tr = v->first;
db::ICplxTrans trinv = tr.inverted ();
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
Shape s;
si->instantiate (s);
s.transform (tr);
heap.clear ();
filter.process (s, heap);
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
delivery.put (i->transformed (trinv));
}
}
}
} else {
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
shape_collection_processor_delivery<Result> delivery (&layout, &st);
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
Shape s;
si->instantiate (s);
heap.clear ();
filter.process (s, heap);
for (typename std::vector<Result>::const_iterator i = heap.begin (); i != heap.end (); ++i) {
delivery.put (*i);
}
}
}
}
if (! to_commit.empty () && vars.get ()) {
res->deep_layer ().commit_shapes (*vars, to_commit);
}
if (filter.result_is_merged ()) {
res->set_is_merged (true);
}
return res.release ();
}
/**
* @brief A generic processor to compute the extents of an object
*/
template <class Shape>
class extents_processor
: public db::shape_collection_processor<Shape, db::Polygon>
{
public:
extents_processor (db::Coord dx, db::Coord dy)
: m_dx (dx), m_dy (dy)
{ }
virtual void process (const Shape &s, std::vector<db::Polygon> &res) const
{
db::box_convert<Shape> bc;
db::Box box = bc (s).enlarged (db::Vector (m_dx, m_dy));
if (! box.empty ()) {
res.push_back (db::Polygon (box));
}
}
virtual const db::TransformationReducer *vars () const
{
if (m_dx == 0 && m_dy == 0) {
return 0;
} else if (m_dx == m_dy) {
return & m_isotropic_reducer;
} else {
return & m_anisotropic_reducer;
}
}
virtual bool result_is_merged () const { return false; }
virtual bool requires_raw_input () const { return false; }
virtual bool result_must_not_be_merged () const { return false; }
virtual bool wants_variants () const { return true; }
private:
db::XYAnisotropyAndMagnificationReducer m_anisotropic_reducer;
db::MagnificationReducer m_isotropic_reducer;
db::Coord m_dx, m_dy;
};
}
#endif

View File

@ -176,6 +176,11 @@ FlatTexts *Texts::flat_texts ()
return texts;
}
void Texts::processed (Region &output, const TextToPolygonProcessorBase &filter) const
{
output = Region (mp_delegate->processed_to_polygons (filter));
}
void Texts::pull_interacting (Region &output, const Region &other) const
{
output = Region (mp_delegate->pull_interacting (other));

View File

@ -454,6 +454,14 @@ public:
return Texts (mp_delegate->filtered (filter));
}
/**
* @brief Processes the edges into polygons
*
* This method will run the processor over all edges and return a region
* with the outputs of the processor.
*/
void processed (Region &output, const TextToPolygonProcessorBase &filter) const;
/**
* @brief Selects all polygons of the other region set which include the texts of this text collection
*

View File

@ -26,6 +26,7 @@
#include "dbCommon.h"
#include "dbShapeCollection.h"
#include "dbShapeCollectionUtils.h"
#include "dbText.h"
namespace db {
@ -38,6 +39,8 @@ class RegionDelegate;
class EdgesDelegate;
class Layout;
typedef shape_collection_processor<db::Text, db::Polygon> TextToPolygonProcessorBase;
/**
* @brief The edge pair set iterator delegate
*/
@ -98,6 +101,7 @@ public:
virtual TextsDelegate *filter_in_place (const TextFilterBase &filter) = 0;
virtual TextsDelegate *filtered (const TextFilterBase &filter) const = 0;
virtual RegionDelegate *processed_to_polygons (const TextToPolygonProcessorBase &filter) const = 0;
virtual RegionDelegate *polygons (db::Coord e) const = 0;
virtual EdgesDelegate *edges () const = 0;

View File

@ -123,12 +123,9 @@ static db::Region polygons2 (const db::EdgePairs *e, db::Coord d)
static db::Region extents2 (const db::EdgePairs *r, db::Coord dx, db::Coord dy)
{
db::Region e;
e.reserve (r->size ());
for (db::EdgePairs::const_iterator i = r->begin (); ! i.at_end (); ++i) {
e.insert (i->bbox ().enlarged (db::Vector (dx, dy)));
}
return e;
db::Region output;
r->processed (output, db::extents_processor<db::EdgePair> (dx, dy));
return output;
}
static db::Region extents1 (const db::EdgePairs *r, db::Coord d)

View File

@ -325,12 +325,9 @@ static db::Region pull_interacting (const db::Edges *r, const db::Region &other)
static db::Region extents2 (const db::Edges *r, db::Coord dx, db::Coord dy)
{
db::Region e;
e.reserve (r->size ());
for (db::Edges::const_iterator i = r->begin (); ! i.at_end (); ++i) {
e.insert (i->bbox ().enlarged (db::Vector (dx, dy)));
}
return e;
db::Region output;
r->processed (output, db::extents_processor<db::Edge> (dx, dy));
return output;
}
static db::Region extents1 (const db::Edges *r, db::Coord d)

View File

@ -259,7 +259,7 @@ static db::Region moved_xy (const db::Region *r, db::Coord x, db::Coord y)
static db::Region extents2 (const db::Region *r, db::Coord dx, db::Coord dy)
{
return r->processed (db::Extents (dx, dy));
return r->processed (db::extents_processor<db::Polygon> (dx, dy));
}
static db::Region extents1 (const db::Region *r, db::Coord d)

View File

@ -116,12 +116,9 @@ static db::Region polygons0 (const db::Texts *e, db::Coord d)
static db::Region extents1 (const db::Texts *r, db::Coord dx, db::Coord dy)
{
db::Region e;
e.reserve (r->size ());
for (db::Texts::const_iterator i = r->begin (); ! i.at_end (); ++i) {
e.insert (i->box ().enlarged (db::Vector (dx, dy)));
}
return e;
db::Region output;
r->processed (output, db::extents_processor<db::Text> (dx, dy));
return output;
}
static db::Region extents0 (const db::Texts *r, db::Coord d)

View File

@ -1176,8 +1176,8 @@ TEST(21_Processors)
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r1.processed (db::CornersAsRectangles (-180.0, 180.0, 2000)));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r1.processed (db::CornersAsRectangles (0.0, 180.0, 2000)));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::Extents (0, 0)));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::Extents (1000, 2000)));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r1.processed (db::extents_processor<db::Polygon> (0, 0)));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r1.processed (db::extents_processor<db::Polygon> (1000, 2000)));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r1.processed (db::RelativeExtents (0, 0, 1.0, 1.0, 0, 0)));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), r1.processed (db::RelativeExtents (0.25, 0.4, 0.75, 0.6, 1000, 2000)));
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r1.processed (db::RelativeExtentsAsEdges (0, 0, 1.0, 1.0)));

View File

@ -1589,8 +1589,8 @@ TEST(100_Processors)
EXPECT_EQ (r.processed (db::CornersAsRectangles (-180.0, 180.0, 2)).to_string (), "(98,-2;98,2;102,2;102,-2);(-2,-2;-2,2;2,2;2,-2);(-2,198;-2,202;2,202;2,198);(98,198;98,202;102,202;102,198);(198,298;198,302;202,302;202,298);(-2,298;-2,302;2,302;2,298);(-2,398;-2,402;2,402;2,398);(98,398;98,402;102,402;102,398);(98,498;98,502;102,502;102,498);(198,498;198,502;202,502;202,498)");
EXPECT_EQ (r.processed (db::CornersAsRectangles (0.0, 180.0, 2)).to_string (), "(98,398;98,402;102,402;102,398)");
EXPECT_EQ (r.processed (db::Extents (0, 0)).to_string (), "(0,0;0,200;100,200;100,0);(0,300;0,500;200,500;200,300)");
EXPECT_EQ (r.processed (db::Extents (10, 20)).to_string (), "(-10,-20;-10,220;110,220;110,-20);(-10,280;-10,520;210,520;210,280)");
EXPECT_EQ (r.processed (db::extents_processor<db::Polygon> (0, 0)).to_string (), "(0,0;0,200;100,200;100,0);(0,300;0,500;200,500;200,300)");
EXPECT_EQ (r.processed (db::extents_processor<db::Polygon> (10, 20)).to_string (), "(-10,-20;-10,220;110,220;110,-20);(-10,280;-10,520;210,520;210,280)");
EXPECT_EQ (r.processed (db::RelativeExtents (0, 0, 1.0, 1.0, 0, 0)).to_string (), "(0,0;0,200;100,200;100,0);(0,300;0,500;200,500;200,300)");
EXPECT_EQ (r.processed (db::RelativeExtents (0.25, 0.4, 0.75, 0.6, 10, 20)).to_string (), "(15,60;15,140;85,140;85,60);(40,360;40,440;160,440;160,360)");
EXPECT_EQ (r.processed (db::RelativeExtentsAsEdges (0, 0, 1.0, 1.0)).to_string (), "(0,0;100,200);(0,300;200,500)");

View File

@ -714,3 +714,44 @@ TEST(15_issue548)
db::compare_layouts (_this, layout, au, db::NoNormalization);
}
// Edges::extents isn't deep-enabled
TEST(16_issue570)
{
std::string rs = tl::testsrc ();
rs += "/testdata/drc/drcSimpleTests_16.drc";
std::string input = tl::testsrc ();
input += "/testdata/drc/drcSimpleTests_16.gds";
std::string au = tl::testsrc ();
au += "/testdata/drc/drcSimpleTests_au16.gds";
std::string output = this->tmp_file ("tmp.gds");
{
// Set some variables
lym::Macro config;
config.set_text (tl::sprintf (
"$drc_test_source = '%s'\n"
"$drc_test_target = '%s'\n"
, input, output)
);
config.set_interpreter (lym::Macro::Ruby);
EXPECT_EQ (config.run (), 0);
}
lym::Macro drc;
drc.load_from (rs);
EXPECT_EQ (drc.run (), 0);
db::Layout layout;
{
tl::InputStream stream (output);
db::Reader reader (stream);
reader.read (layout);
}
db::compare_layouts (_this, layout, au, db::NoNormalization);
}

16
testdata/drc/drcSimpleTests_16.drc vendored Normal file
View File

@ -0,0 +1,16 @@
source($drc_test_source)
target($drc_test_target)
deep
input(2,0).output(2, 0)
input(3,0).output(3, 0)
input(4,0).output(4, 0)
input(9,0).output(9, 0)
input(2,0).edges.extents(10.nm, 10.nm).output(102, 0)
input(3,0).edges.extents(10.nm, 20.nm).output(103, 0)
input(4,0).edges.extents(20.nm, 10.nm).output(104, 0)
input(9,0).edges.extents(20.nm).output(109, 0)

BIN
testdata/drc/drcSimpleTests_16.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au16.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/ringo.gds vendored

Binary file not shown.