klayout/src/db/db/dbHierarchyBuilder.h

354 lines
14 KiB
C++

/*
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_dbHierarchyBuilder
#define HDR_dbHierarchyBuilder
#include "dbCommon.h"
#include "dbRecursiveShapeIterator.h"
#include "dbLayout.h"
#include <map>
#include <vector>
#include <set>
namespace db
{
/**
* @brief A helper function comparing two recursive shape iterators for compatibility with respect to hierarchy building
*
* This function will return -1, 0 or 1 depending on whether the two iterators
* can be used with the same builder (0) or whether they are less (-1) or greater (1).
*/
int DB_PUBLIC compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2);
/**
* @brief A class to receive shapes from the hierarchy builder
*
* This class can be reimplemented to implement clipping and/or
* simplification.
*/
class DB_PUBLIC HierarchyBuilderShapeReceiver
{
public:
HierarchyBuilderShapeReceiver () { }
virtual ~HierarchyBuilderShapeReceiver () { }
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0;
virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0;
virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0;
};
/**
* @brief A shape receiver that simply pushes into the target
*/
class DB_PUBLIC HierarchyBuilderShapeInserter
: public HierarchyBuilderShapeReceiver
{
public:
HierarchyBuilderShapeInserter () { }
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
tl::ident_map<db::Layout::properties_id_type> pm;
target->insert (shape, trans, pm);
}
virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
if (trans.is_ortho ()) {
target->insert (shape.transformed (trans));
} else {
db::Polygon poly (shape);
target->insert (poly.transformed (trans));
}
}
virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
if (trans.is_unity ()) {
target->insert (shape);
} else {
target->insert (shape.transformed (trans));
}
}
};
/**
* @brief A clipping shape receiver that forwards to another one
*/
class DB_PUBLIC ClippingHierarchyBuilderShapeReceiver
: public HierarchyBuilderShapeReceiver
{
public:
ClippingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0);
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
private:
void insert_clipped (const db::Box &box, const db::ICplxTrans &trans, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target);
void insert_clipped (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target);
static bool is_inside (const db::Box &box, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region);
static bool is_outside (const db::Box &box, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region);
HierarchyBuilderShapeReceiver *mp_pipe;
};
/**
* @brief A polygon reducing shape receiver that forwards to another one
*/
class DB_PUBLIC ReducingHierarchyBuilderShapeReceiver
: public HierarchyBuilderShapeReceiver
{
public:
ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0, double area_ratio = 3.0, size_t max_vertex_count = 16);
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
private:
void reduce (const db::Polygon &poly, const db::ICplxTrans &trans, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target);
HierarchyBuilderShapeReceiver *mp_pipe;
double m_area_ratio;
size_t m_max_vertex_count;
};
/**
* @brief A polygon reference generating shape receiver that feeds a shapes array after turning the shapes into PolygonRefs
*/
class DB_PUBLIC PolygonReferenceHierarchyBuilderShapeReceiver
: public HierarchyBuilderShapeReceiver
{
public:
PolygonReferenceHierarchyBuilderShapeReceiver (db::Layout *layout, int text_enlargement = -1, const tl::Variant &text_prop_name = tl::Variant ());
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
private:
db::Layout *mp_layout;
int m_text_enlargement;
bool m_make_text_prop;
db::property_names_id_type m_text_prop_id;
};
/**
* @brief An edge-generating shape receiver that feeds a shapes array after turning the shapes into edges
*/
class DB_PUBLIC EdgeBuildingHierarchyBuilderShapeReceiver
: public HierarchyBuilderShapeReceiver
{
public:
EdgeBuildingHierarchyBuilderShapeReceiver (bool as_edges);
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Box &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Polygon &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
private:
bool m_as_edges;
};
/**
* @brief An edge pair-generating shape receiver that feeds a shapes array after turning the shapes into edges
*/
class DB_PUBLIC EdgePairBuildingHierarchyBuilderShapeReceiver
: public HierarchyBuilderShapeReceiver
{
public:
EdgePairBuildingHierarchyBuilderShapeReceiver ();
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
};
/**
* @brief A class building a hierarchy from a recursive shape iterator in push mode
*
* This class is a RecursiveShapeReceiver which acts on the hierarchy events and
* uses them to rebuild a hierarchy in the target layout. In can be used multiple
* times and will reuse the hierarchy as far as possible.
*
* The hierarchy builder can form clip variants for cells and clip the shapes
* according to the selected region.
*
* NOTE: the hierarchy build should not be used in multiple passes with regions
* as the hierarchy is sampled in the first pass and the hierarchy builder will
* rely on precisely the same hierarchy arrangement. This is not given with
* region selections.
*/
class DB_PUBLIC HierarchyBuilder
: public db::RecursiveShapeReceiver
{
public:
typedef std::map<std::pair<db::cell_index_type, std::set<db::Box> >, db::cell_index_type> cell_map_type;
typedef std::map<db::cell_index_type, std::vector<db::cell_index_type> > original_target_to_variants_map_type;
typedef std::map<db::cell_index_type, db::cell_index_type> variant_to_original_target_map_type;
HierarchyBuilder (db::Layout *target, unsigned int target_layer, const db::ICplxTrans &trans = db::ICplxTrans (), HierarchyBuilderShapeReceiver *pipe = 0);
HierarchyBuilder (db::Layout *target, const db::ICplxTrans &trans = db::ICplxTrans (), HierarchyBuilderShapeReceiver *pipe = 0);
virtual ~HierarchyBuilder ();
/**
* @brief Installs a custom shape receiver
* The hierarchy builder will *NOT* take ownership of this object.
*/
void set_shape_receiver (HierarchyBuilderShapeReceiver *pipe);
virtual void begin (const RecursiveShapeIterator *iter);
virtual void end (const RecursiveShapeIterator *iter);
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box &region, const box_tree_type *complex_region);
virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell);
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region);
/**
* @brief Sets the target layer - shapes will be put there
*/
void set_target_layer (unsigned int target_layer)
{
m_target_layer = target_layer;
}
/**
* @brief Reset the builder - performs a new initial pass
*/
void reset ();
/**
* @brief Gets the initial cell the builder produced in the target layout
*/
db::Cell *initial_cell ()
{
return mp_initial_cell;
}
/**
* @brief Gets the target layout
*/
db::Layout *target ()
{
return mp_target.get ();
}
/**
* @brief Gets the recursive shape iterator the data was taken from
*/
const db::RecursiveShapeIterator &source () const
{
return m_source;
}
/**
* @brief Gets the iterator for the cell map
*/
cell_map_type::const_iterator begin_cell_map () const
{
return m_cell_map.begin ();
}
/**
* @brief Gets the iterator for the cell map (end)
*/
cell_map_type::const_iterator end_cell_map () const
{
return m_cell_map.end ();
}
/**
* @brief Unmaps an original cell/clip box version from the original-to-working copy cell map
*
* An unmapped cell is never again considered.
*/
void unmap (const cell_map_type::key_type &k)
{
m_cell_map.erase (k);
}
/**
* @brief Maps an original cell/clip box version to a original-to-working copy cell
*/
void map (const cell_map_type::key_type &k, db::cell_index_type ci)
{
m_cell_map [k] = ci;
}
/**
* @brief Marks a cell as a variant of another
*
* The first cell is either the original, non-variant target cell or itself a variant.
* The second cell will be registered as a variant of the first one.
*/
void register_variant (db::cell_index_type non_var, db::cell_index_type var);
/**
* @brief Unregisters a cell as a variant
*/
void unregister_variant (db::cell_index_type var);
/**
* @brief Gets a value indicating whether the given cell is a variant cell
*/
bool is_variant (db::cell_index_type ci) const
{
return m_variants_to_original_target_map.find (ci) != m_variants_to_original_target_map.end ();
}
/**
* @brief Gets the original target for a variant cell
*/
db::cell_index_type original_target_for_variant (db::cell_index_type ci) const;
private:
tl::weak_ptr<db::Layout> mp_target;
HierarchyBuilderShapeReceiver *mp_pipe;
bool m_initial_pass;
db::RecursiveShapeIterator m_source;
cell_map_type m_cell_map;
original_target_to_variants_map_type m_original_targets_to_variants_map;
variant_to_original_target_map_type m_variants_to_original_target_map;
std::set<cell_map_type::key_type> m_cells_seen;
std::set<db::cell_index_type> m_cells_to_be_filled;
cell_map_type::const_iterator m_cm_entry;
bool m_cm_new_entry;
unsigned int m_target_layer;
std::vector<std::pair<bool, std::vector<db::Cell *> > > m_cell_stack;
db::Cell *mp_initial_cell;
db::ICplxTrans m_trans;
};
}
#endif