klayout/src/db/db/dbCell.cc

1096 lines
29 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2023 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 "dbCell.h"
#include "dbLayout.h"
#include "dbManager.h"
#include "dbBox.h"
#include "dbPCellVariant.h"
#include "dbLayoutUtils.h"
#include "dbLayerMapping.h"
#include "dbCellMapping.h"
#include <limits>
namespace db
{
struct CellOp
: public db::Op
{
CellOp () { }
virtual ~CellOp () { }
virtual void redo (db::Cell *) const = 0;
virtual void undo (db::Cell *) const = 0;
};
class SwapLayerOp
: public CellOp
{
public:
SwapLayerOp (unsigned int a, unsigned int b)
: m_a (a), m_b (b)
{ }
virtual void redo (db::Cell *cell) const
{
cell->swap (m_a, m_b);
}
virtual void undo (db::Cell *cell) const
{
cell->swap (m_a, m_b);
}
private:
unsigned int m_a, m_b;
};
struct SetCellPropId
: public CellOp
{
SetCellPropId (db::properties_id_type f, db::properties_id_type t)
: m_from (f), m_to (t)
{ }
virtual void redo (db::Cell *cell) const
{
cell->prop_id (m_to);
}
virtual void undo (db::Cell *cell) const
{
cell->prop_id (m_from);
}
private:
db::properties_id_type m_from, m_to;
};
Cell::box_type Cell::ms_empty_box = Cell::box_type ();
Cell::Cell (cell_index_type ci, db::Layout &l)
: db::Object (l.manager ()),
m_cell_index (ci), mp_layout (&l), m_instances (this), m_prop_id (0), m_hier_levels (0), m_bbox_needs_update (false), m_ghost_cell (false),
mp_last (0), mp_next (0)
{
// .. nothing yet
}
Cell::Cell (const Cell &d)
: db::Object (d),
gsi::ObjectBase (),
mp_layout (d.mp_layout), m_instances (this), m_prop_id (d.m_prop_id), m_hier_levels (d.m_hier_levels),
mp_last (0), mp_next (0)
{
m_cell_index = d.m_cell_index;
operator= (d);
}
Cell &
Cell::operator= (const Cell &d)
{
if (this != &d) {
// Note: the cell index is part of the cell's identity - hence we do not change it here. It's copied in
// the copy ctor however.
invalidate_hier ();
clear_shapes_no_invalidate ();
for (shapes_map::const_iterator s = d.m_shapes_map.begin (); s != d.m_shapes_map.end (); ++s) {
shapes (s->first) = s->second;
}
m_ghost_cell = d.m_ghost_cell;
m_instances = d.m_instances;
m_bbox = d.m_bbox;
m_bboxes = d.m_bboxes;
m_hier_levels = d.m_hier_levels;
m_prop_id = d.m_prop_id;
m_bbox_needs_update = d.m_bbox_needs_update;
}
return *this;
}
Cell::~Cell ()
{
clear_shapes ();
}
Cell *
Cell::clone (db::Layout &layout) const
{
Cell *new_cell = new Cell (cell_index (), layout);
*new_cell = *this;
return new_cell;
}
unsigned int
Cell::layers () const
{
if (m_shapes_map.empty ()) {
return 0;
} else {
shapes_map::const_iterator s = m_shapes_map.end ();
--s;
return s->first + 1;
}
}
bool
Cell::empty () const
{
if (! m_instances.empty ()) {
return false;
}
for (shapes_map::const_iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
if (! s->second.empty ()) {
return false;
}
}
return true;
}
void
Cell::clear (unsigned int index)
{
shapes_map::iterator s = m_shapes_map.find(index);
if (s != m_shapes_map.end() && ! s->second.empty ()) {
mp_layout->invalidate_bboxes (index); // HINT: must come before the change is done!
s->second.clear ();
m_bbox_needs_update = true;
}
}
void
Cell::clear (unsigned int index, unsigned int types)
{
shapes_map::iterator s = m_shapes_map.find(index);
if (s != m_shapes_map.end() && ! s->second.empty ()) {
mp_layout->invalidate_bboxes (index); // HINT: must come before the change is done!
s->second.clear (types);
m_bbox_needs_update = true;
}
}
Cell::shapes_type &
Cell::shapes (unsigned int index)
{
shapes_map::iterator s = m_shapes_map.find(index);
if (s == m_shapes_map.end()) {
s = m_shapes_map.insert (std::make_pair(index, shapes_type (0, this, mp_layout ? mp_layout->is_editable () : true))).first;
s->second.manager (manager ());
}
return s->second;
}
const Cell::shapes_type &
Cell::shapes (unsigned int index) const
{
shapes_map::const_iterator s = m_shapes_map.find(index);
if (s != m_shapes_map.end()) {
return s->second;
} else {
// Because of a gcc bug it seems to be not possible
// to instantiate a simple static object here:
static const shapes_type *empty_shapes = 0;
if (! empty_shapes) {
empty_shapes = new shapes_type ();
}
return *empty_shapes;
}
}
unsigned int
Cell::index_of_shapes (const Cell::shapes_type *shapes) const
{
for (shapes_map::const_iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
if (&s->second == shapes) {
return s->first;
}
}
return std::numeric_limits<unsigned int>::max ();
}
void
Cell::clear_shapes ()
{
mp_layout->invalidate_bboxes (std::numeric_limits<unsigned int>::max ()); // HINT: must come before the change is done!
clear_shapes_no_invalidate ();
}
void
Cell::update_relations ()
{
m_instances.update_relations (mp_layout, cell_index ());
}
bool
Cell::is_shape_bbox_dirty () const
{
if (m_bbox_needs_update) {
return true;
}
for (shapes_map::const_iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
if (s->second.is_bbox_dirty ()) {
return true;
}
}
return false;
}
bool
Cell::update_bbox (unsigned int layers)
{
unsigned int l;
// determine the bounding box
box_type org_bbox = m_bbox;
m_bbox = box_type ();
// save the original boxes for simple compare
box_map org_bboxes;
org_bboxes.swap (m_bboxes);
// compute the per-layer bboxes of the cell instances
// exploit the fact that these are sorted by instance,
// rotation and magnification.
for (instances_type::sorted_inst_iterator o = m_instances.begin_sorted_insts (); o != m_instances.end_sorted_insts (); ) {
const cell_inst_array_type *o1_inst = *o;
instances_type::sorted_inst_iterator oo = o;
while (++oo != m_instances.end_sorted_insts () && (*oo)->raw_equal (*o1_inst))
;
box_type raw_box;
while (o != oo) {
raw_box += (*o)->raw_bbox ();
++o;
}
for (l = 0; l < layers; ++l) {
// the per-layer bounding boxes
db::box_convert <cell_inst_type> bc (*mp_layout, l);
box_type lbox = o1_inst->bbox_from_raw_bbox (raw_box, bc);
if (! lbox.empty ()) {
m_bbox += lbox;
box_map::iterator b = m_bboxes.find (l);
if (b == m_bboxes.end ()) {
m_bboxes.insert (std::make_pair (l, lbox));
} else {
b->second += lbox;
}
}
}
}
// update the bboxes of the shapes lists
for (shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
s->second.reset_bbox_dirty ();
box_type sbox (s->second.bbox ());
if (! sbox.empty ()) {
m_bbox += sbox;
box_map::iterator b = m_bboxes.find (s->first);
if (b == m_bboxes.end ()) {
m_bboxes.insert (std::make_pair (s->first, sbox));
} else {
b->second += sbox;
}
}
}
// reset "dirty child instances" flag
m_bbox_needs_update = false;
// return true, if anything has changed with the box
return (org_bbox != m_bbox || org_bboxes != m_bboxes);
}
void
Cell::copy (unsigned int src, unsigned int dest)
{
if (src != dest) {
shapes (dest).insert (shapes (src));
} else {
// When duplicating the layer, first create a copy to avoid problems with non-stable containers
// Hint: using the assignment and not the copy ctor does not copy the db::Manager association.
db::Shapes shape_copy;
shape_copy = shapes (src);
shapes (dest).insert (shape_copy);
}
}
void
Cell::copy (unsigned int src, unsigned int dest, unsigned int types)
{
if (src != dest) {
shapes (dest).insert (shapes (src), types);
} else {
// When duplicating the layer, first create a copy to avoid problems with non-stable containers
// Hint: using the assignment and not the copy ctor does not copy the db::Manager association.
db::Shapes shape_copy;
shape_copy.insert (shapes (src), types);
shapes (dest).insert (shape_copy);
}
}
void
Cell::move (unsigned int src, unsigned int dest)
{
if (src != dest) {
copy (src, dest);
clear (src);
}
}
void
Cell::move (unsigned int src, unsigned int dest, unsigned int types)
{
if (src != dest) {
copy (src, dest, types);
clear (src, types);
}
}
void
Cell::swap (unsigned int i1, unsigned int i2)
{
if (i1 != i2) {
if (manager () && manager ()->transacting ()) {
manager ()->queue (this, new SwapLayerOp (i1, i2));
}
shapes (i1).swap (shapes (i2));
m_bbox_needs_update = true;
}
}
void
Cell::sort_shapes ()
{
for (shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
s->second.sort ();
}
}
void
Cell::prop_id (db::properties_id_type id)
{
if (m_prop_id != id) {
if (manager () && manager ()->transacting ()) {
manager ()->queue (this, new SetCellPropId (m_prop_id, id));
}
m_prop_id = id;
}
}
const Cell::box_type &
Cell::bbox () const
{
mp_layout->update ();
return m_bbox;
}
const Cell::box_type &
Cell::bbox (unsigned int l) const
{
mp_layout->update ();
box_map::const_iterator b = m_bboxes.find (l);
if (b != m_bboxes.end ()) {
return b->second;
} else {
return ms_empty_box;
}
}
Cell::const_iterator
Cell::begin () const
{
mp_layout->update ();
return m_instances.begin ();
}
Cell::overlapping_iterator
Cell::begin_overlapping (const box_type &b) const
{
mp_layout->update ();
return m_instances.begin_overlapping (b, mp_layout);
}
Cell::touching_iterator
Cell::begin_touching (const box_type &b) const
{
mp_layout->update ();
return m_instances.begin_touching (b, mp_layout);
}
Cell::parent_inst_iterator
Cell::begin_parent_insts () const
{
mp_layout->update ();
return m_instances.begin_parent_insts (mp_layout);
}
Cell::child_cell_iterator
Cell::begin_child_cells () const
{
mp_layout->update ();
return m_instances.begin_child_cells ();
}
size_t
Cell::child_cells () const
{
mp_layout->update ();
return m_instances.child_cells ();
}
size_t
Cell::parent_cells () const
{
mp_layout->update ();
return m_instances.parent_cells ();
}
Cell::parent_cell_iterator
Cell::begin_parent_cells () const
{
mp_layout->update ();
return m_instances.begin_parent_cells ();
}
Cell::parent_cell_iterator
Cell::end_parent_cells () const
{
mp_layout->update ();
return m_instances.end_parent_cells ();
}
bool
Cell::is_top () const
{
mp_layout->update ();
return m_instances.is_top ();
}
bool
Cell::is_leaf () const
{
return m_instances.empty ();
}
unsigned int
Cell::hierarchy_levels () const
{
mp_layout->update ();
return m_hier_levels;
}
static bool
has_shapes_touching_impl (const db::Cell &cell, unsigned int layer, const db::Box &box)
{
if (! cell.shapes (layer).begin_touching (box, db::ShapeIterator::All).at_end ()) {
return true;
}
for (db::Cell::touching_iterator i = cell.begin_touching (box); ! i.at_end (); ++i) {
for (db::CellInstArray::iterator ia = i->cell_inst ().begin_touching (box, db::box_convert<db::CellInst> (*cell.layout (), layer)); ! ia.at_end (); ++ia) {
db::Box cbox;
if (i->is_complex ()) {
cbox = i->complex_trans (*ia).inverted () * box;
} else {
cbox = (*ia).inverted () * box;
}
if (has_shapes_touching_impl (cell.layout ()->cell (i->cell_index ()), layer, cbox)) {
return true;
}
}
}
return false;
}
bool
Cell::has_shapes_touching (unsigned int layer, const db::Box &box) const
{
return has_shapes_touching_impl (*this, layer, box);
}
void
Cell::collect_caller_cells (std::set<cell_index_type> &callers) const
{
collect_caller_cells (callers, -1);
}
void
Cell::collect_caller_cells (std::set<cell_index_type> &callers, const std::set<cell_index_type> &cone, int levels) const
{
if (levels != 0) {
for (parent_cell_iterator cc = begin_parent_cells (); cc != end_parent_cells (); ++cc) {
if (cone.find (*cc) != cone.end () && callers.find (*cc) == callers.end () && mp_layout->is_valid_cell_index (*cc)) {
callers.insert (*cc);
mp_layout->cell (*cc).collect_caller_cells (callers, levels < 0 ? levels : levels - 1);
}
}
}
}
void
Cell::collect_caller_cells (std::set<cell_index_type> &callers, int levels) const
{
if (levels != 0) {
for (parent_cell_iterator cc = begin_parent_cells (); cc != end_parent_cells (); ++cc) {
if (callers.find (*cc) == callers.end () && mp_layout->is_valid_cell_index (*cc)) {
callers.insert (*cc);
mp_layout->cell (*cc).collect_caller_cells (callers, levels < 0 ? levels : levels - 1);
}
}
}
}
void
Cell::collect_called_cells (std::set<cell_index_type> &called) const
{
collect_called_cells (called, -1);
}
void
Cell::collect_called_cells (std::set<cell_index_type> &called, int levels) const
{
if (levels != 0) {
for (child_cell_iterator cc = begin_child_cells (); ! cc.at_end (); ++cc) {
if (called.find (*cc) == called.end () && mp_layout->is_valid_cell_index (*cc)) {
called.insert (*cc);
mp_layout->cell (*cc).collect_called_cells (called, levels < 0 ? levels : levels - 1);
}
}
}
}
void
Cell::invalidate_insts ()
{
mp_layout->invalidate_hier (); // HINT: must come before the change is done!
mp_layout->invalidate_bboxes (std::numeric_limits<unsigned int>::max ());
m_bbox_needs_update = true;
}
void
Cell::invalidate_hier ()
{
mp_layout->invalidate_hier (); // HINT: must come before the change is done!
}
void
Cell::redo (db::Op *op)
{
db::CellOp *cell_op = dynamic_cast<db::CellOp *> (op);
if (cell_op) {
// redo operation
cell_op->redo (this);
} else {
// other actions are only queued by the instance list - this is should be
// responsible for the handling of the latter.
// HACK: this is not really a nice concept, but it saves us a pointer to the manager.
m_instances.redo (op);
}
}
void
Cell::undo (db::Op *op)
{
db::CellOp *cell_op = dynamic_cast<db::CellOp *> (op);
if (cell_op) {
// undo operation
cell_op->undo (this);
} else {
// other actions are only queued by the instance list - this is should be
// responsible for the handling of the latter.
// HACK: this is not really a nice concept, but it saves us a pointer to the manager.
m_instances.undo (op);
}
}
void
Cell::mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
{
if (! no_self) {
stat->add (typeid (Cell), (void *) this, sizeof (Cell), sizeof (Cell), parent, purpose, cat);
}
db::mem_stat (stat, purpose, cat, m_bboxes, true, (void *) this);
db::mem_stat (stat, MemStatistics::Instances, cat, m_instances, true, (void *) this);
db::mem_stat (stat, MemStatistics::ShapesInfo, cat, m_shapes_map, true, (void *) this);
}
void
Cell::clear_shapes_no_invalidate ()
{
// Hint: we can't simply clear the map because of the undo stack
for (shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
s->second.clear ();
}
m_bbox_needs_update = true;
}
unsigned int
Cell::count_hier_levels () const
{
unsigned int l = 0;
for (const_iterator c = begin (); !c.at_end (); ++c) {
l = std::max (l, (unsigned int) mp_layout->cell (c->cell_index ()).m_hier_levels + 1);
}
return l;
}
void
Cell::count_parent_insts (std::vector <size_t> &count) const
{
m_instances.count_parent_insts (count);
}
void
Cell::clear_parent_insts (size_t sz)
{
m_instances.clear_parent_insts (sz);
}
void
Cell::sort_child_insts ()
{
m_instances.sort_child_insts ();
}
std::pair<bool, db::pcell_id_type>
Cell::is_pcell_instance (const instance_type &ref) const
{
return mp_layout->is_pcell_instance (ref.cell_index ());
}
std::map<std::string, tl::Variant>
Cell::get_named_pcell_parameters (const instance_type &ref) const
{
return mp_layout->get_named_pcell_parameters (ref.cell_index ());
}
tl::Variant
Cell::get_pcell_parameter (const instance_type &ref, const std::string &name) const
{
return mp_layout->get_pcell_parameter (ref.cell_index (), name);
}
const std::vector<tl::Variant> &
Cell::get_pcell_parameters (const instance_type &ref) const
{
return mp_layout->get_pcell_parameters (ref.cell_index ());
}
Cell::instance_type
Cell::change_pcell_parameters (const instance_type &ref, const std::vector<tl::Variant> &new_parameters)
{
cell_index_type new_cell_index = mp_layout->get_pcell_variant_cell (ref.cell_index (), new_parameters);
if (new_cell_index != ref.cell_index ()) {
CellInstArray new_cell_inst (ref.cell_inst ());
new_cell_inst.object () = db::CellInst (new_cell_index);
return m_instances.replace (ref, new_cell_inst);
} else {
return ref;
}
}
void
Cell::sort_inst_tree ()
{
m_instances.sort_inst_tree (mp_layout);
// update the number of hierarchy levels
m_hier_levels = count_hier_levels ();
}
std::string
Cell::get_basic_name () const
{
tl_assert (layout () != 0);
return layout ()->cell_name (cell_index ());
}
std::string
Cell::get_qualified_name () const
{
return get_basic_name ();
}
std::string
Cell::get_display_name () const
{
tl_assert (layout () != 0);
if (is_ghost_cell () && empty ()) {
return std::string ("(") + layout ()->cell_name (cell_index ()) + std::string (")");
} else {
return layout ()->cell_name (cell_index ());
}
}
void
Cell::set_name (const std::string &name)
{
tl_assert (layout () != 0);
layout ()->rename_cell (cell_index (), name.c_str ());
}
void
Cell::copy_shapes (const db::Cell &source_cell, const db::LayerMapping &layer_mapping)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
const db::Layout *source_layout = source_cell.layout ();
if (! source_layout) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
if (target_layout != source_layout) {
db::PropertyMapper pm (target_layout, source_layout);
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
shapes (lm->second).insert_transformed (source_cell.shapes (lm->first), trans, pm);
}
} else {
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
shapes (lm->second).insert (source_cell.shapes (lm->first));
}
}
}
void
Cell::copy_shapes (const db::Cell &source_cell)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
if (target_layout != source_cell.layout ()) {
if (! source_cell.layout ()) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
db::LayerMapping lm;
lm.create_full (*target_layout, *source_cell.layout ());
this->copy_shapes (source_cell, lm);
} else {
for (db::Layout::layer_iterator l = target_layout->begin_layers (); l != target_layout->end_layers (); ++l) {
shapes ((*l).first).insert (source_cell.shapes ((*l).first));
}
}
}
void
Cell::copy_instances (const db::Cell &source_cell)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot copy instances within the same cell")));
}
if (layout () != source_cell.layout ()) {
throw tl::Exception (tl::to_string (tr ("Cells do not reside in the same layout")));
}
for (db::Cell::const_iterator i = source_cell.begin (); ! i.at_end (); ++i) {
insert (*i);
}
}
std::vector<db::cell_index_type>
Cell::copy_tree (const db::Cell &source_cell)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
const db::Layout *source_layout = source_cell.layout ();
if (! source_layout) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
db::CellMapping cm;
std::vector <db::cell_index_type> new_cells = cm.create_single_mapping_full (*target_layout, cell_index (), *source_layout, source_cell.cell_index ());
db::LayerMapping lm;
lm.create_full (*target_layout, *source_cell.layout ());
std::vector <db::cell_index_type> source_cells;
source_cells.push_back (source_cell.cell_index ());
db::copy_shapes (*target_layout, *source_layout, trans, source_cells, cm.table (), lm.table ());
return new_cells;
}
void
Cell::copy_tree_shapes (const db::Cell &source_cell, const db::CellMapping &cm)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
const db::Layout *source_layout = source_cell.layout ();
if (! source_layout) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
db::LayerMapping lm;
lm.create_full (*target_layout, *source_cell.layout ());
std::vector <db::cell_index_type> source_cells;
source_cells.push_back (source_cell.cell_index ());
db::copy_shapes (*target_layout, *source_layout, trans, source_cells, cm.table (), lm.table ());
}
void
Cell::copy_tree_shapes (const db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot copy shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
const db::Layout *source_layout = source_cell.layout ();
if (! source_layout) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
std::vector <db::cell_index_type> source_cells;
source_cells.push_back (source_cell.cell_index ());
db::copy_shapes (*target_layout, *source_layout, trans, source_cells, cm.table (), lm.table ());
}
void
Cell::move_shapes (db::Cell &source_cell, const db::LayerMapping &layer_mapping)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot move shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
db::Layout *source_layout = source_cell.layout ();
if (! source_layout) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
if (target_layout != source_layout) {
db::PropertyMapper pm (target_layout, source_layout);
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
shapes (lm->second).insert_transformed (source_cell.shapes (lm->first), trans, pm);
source_cell.shapes (lm->first).clear ();
}
} else {
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
shapes (lm->second).insert (source_cell.shapes (lm->first));
source_cell.shapes (lm->first).clear ();
}
}
}
void
Cell::move_shapes (db::Cell &source_cell)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot move shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
if (target_layout != source_cell.layout ()) {
if (! source_cell.layout ()) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
db::LayerMapping lm;
lm.create_full (*target_layout, *source_cell.layout ());
move_shapes (source_cell, lm);
} else {
for (db::Layout::layer_iterator l = target_layout->begin_layers (); l != target_layout->end_layers (); ++l) {
shapes ((*l).first).insert (source_cell.shapes ((*l).first));
source_cell.shapes ((*l).first).clear ();
}
}
}
void
Cell::move_instances (db::Cell &source_cell)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot move instances within the same cell")));
}
if (layout () != source_cell.layout ()) {
throw tl::Exception (tl::to_string (tr ("Cells do not reside in the same layout")));
}
for (db::Cell::const_iterator i = source_cell.begin (); ! i.at_end (); ++i) {
insert (*i);
}
source_cell.clear_insts ();
}
std::vector<db::cell_index_type>
Cell::move_tree (db::Cell &source_cell)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot move shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
db::Layout *source_layout = source_cell.layout ();
if (! source_layout) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
db::PropertyMapper pm (target_layout, source_layout);
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
db::CellMapping cm;
std::vector <db::cell_index_type> new_cells = cm.create_single_mapping_full (*target_layout, cell_index (), *source_layout, source_cell.cell_index ());
db::LayerMapping lm;
lm.create_full (*target_layout, *source_cell.layout ());
std::vector <db::cell_index_type> source_cells;
source_cells.push_back (source_cell.cell_index ());
db::move_shapes (*target_layout, *source_layout, trans, source_cells, cm.table (), lm.table ());
source_layout->prune_subcells (source_cell.cell_index ());
return new_cells;
}
void
Cell::move_tree_shapes (db::Cell &source_cell, const db::CellMapping &cm)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot move shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
db::Layout *source_layout = source_cell.layout ();
if (! source_layout) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
db::PropertyMapper pm (target_layout, source_layout);
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
db::LayerMapping lm;
lm.create_full (*target_layout, *source_cell.layout ());
std::vector <db::cell_index_type> source_cells;
source_cells.push_back (source_cell.cell_index ());
db::move_shapes (*target_layout, *source_layout, trans, source_cells, cm.table (), lm.table ());
}
void
Cell::move_tree_shapes (db::Cell &source_cell, const db::CellMapping &cm, const db::LayerMapping &lm)
{
if (this == &source_cell) {
throw tl::Exception (tl::to_string (tr ("Cannot move shapes within the same cell")));
}
db::Layout *target_layout = layout ();
if (! target_layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside in a layout")));
}
db::Layout *source_layout = source_cell.layout ();
if (! source_layout) {
throw tl::Exception (tl::to_string (tr ("Source cell does not reside in a layout")));
}
db::PropertyMapper pm (target_layout, source_layout);
db::ICplxTrans trans (source_layout->dbu () / target_layout->dbu ());
std::vector <db::cell_index_type> source_cells;
source_cells.push_back (source_cell.cell_index ());
db::move_shapes (*target_layout, *source_layout, trans, source_cells, cm.table (), lm.table ());
}
}