Merge branch 'master' into devel

This commit is contained in:
Matthias Koefferlein 2025-08-15 14:21:13 +02:00
commit 5eb8c760d8
27 changed files with 413 additions and 155 deletions

View File

@ -192,7 +192,7 @@ RubySequoia = { 'exe': '/System/Library/Frameworks/Ruby.framework/Versions
# install with 'sudo port install ruby33'
# [Key Type Name] = 'MP33'
Ruby33MacPorts = { 'exe': '/opt/local/bin/ruby3.3',
'inc': '/opt/local/include/ruby-3.3.8',
'inc': '/opt/local/include/ruby-3.3.9',
'lib': '/opt/local/lib/libruby.3.3.dylib'
}

View File

@ -36,12 +36,7 @@ DB_PUBLIC db::Box cellinst_box_convert_impl (const db::CellInst &inst, const db:
} else if (allow_empty) {
return inst.bbox (*layout);
} else {
db::Box box = inst.bbox (*layout);
if (box.empty ()) {
return db::Box (db::Point (0, 0), db::Point (0, 0));
} else {
return box;
}
return inst.bbox_with_empty (*layout);
}
}
@ -52,11 +47,7 @@ DB_PUBLIC db::Box cell_box_convert_impl (const db::Cell &c, int layer, bool allo
} else if (allow_empty) {
return c.bbox ();
} else {
if (c.bbox ().empty ()) {
return db::Box (db::Point (0, 0), db::Point (0, 0));
} else {
return c.bbox ();
}
return c.bbox_with_empty ();
}
}

View File

@ -96,7 +96,7 @@ Cell::Cell (cell_index_type ci, db::Layout &l)
m_bbox_needs_update (false), m_locked (false), m_ghost_cell (false),
mp_last (0), mp_next (0)
{
// .. nothing yet
m_bbox_with_empty = box_type (box_type::point_type (), box_type::point_type ());
}
Cell::Cell (const Cell &d)
@ -128,6 +128,7 @@ Cell::operator= (const Cell &d)
m_locked = d.m_locked;
m_instances = d.m_instances;
m_bbox = d.m_bbox;
m_bbox_with_empty = d.m_bbox_with_empty;
m_bboxes = d.m_bboxes;
m_hier_levels = d.m_hier_levels;
m_prop_id = d.m_prop_id;
@ -282,6 +283,10 @@ Cell::update_bbox (unsigned int layers)
box_type org_bbox = m_bbox;
m_bbox = box_type ();
// determine the bounding box with empty cells
box_type org_bbox_with_empty = m_bbox_with_empty;
m_bbox_with_empty = box_type ();
// save the original boxes for simple compare
box_map org_bboxes;
org_bboxes.swap (m_bboxes);
@ -313,16 +318,21 @@ Cell::update_bbox (unsigned int layers)
m_bbox += lbox;
box_map::iterator b = m_bboxes.find (l);
if (b == m_bboxes.end ()) {
m_bboxes.insert (std::make_pair (l, lbox));
m_bboxes.insert (std::make_pair (l, lbox));
} else {
b->second += lbox;
b->second += lbox;
}
}
}
db::box_convert <cell_inst_type, false> bc_we (*mp_layout);
m_bbox_with_empty += o1_inst->bbox_from_raw_bbox (raw_box, bc_we);
}
box_type sbox_all;
// update the bboxes of the shapes lists
for (shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
@ -331,7 +341,7 @@ Cell::update_bbox (unsigned int layers)
box_type sbox (s->second.bbox ());
if (! sbox.empty ()) {
m_bbox += sbox;
sbox_all += sbox;
box_map::iterator b = m_bboxes.find (s->first);
if (b == m_bboxes.end ()) {
m_bboxes.insert (std::make_pair (s->first, sbox));
@ -342,12 +352,20 @@ Cell::update_bbox (unsigned int layers)
}
// combine shapes in all-layer boxes
m_bbox += sbox_all;
m_bbox_with_empty += sbox_all;
// no empty box
if (m_bbox_with_empty.empty ()) {
m_bbox_with_empty = box_type (box_type::point_type (), box_type::point_type ());
}
// 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);
return (org_bbox != m_bbox || org_bbox_with_empty != m_bbox_with_empty || org_bboxes != m_bboxes);
}
void
@ -442,6 +460,13 @@ Cell::prop_id (db::properties_id_type id)
}
}
const Cell::box_type &
Cell::bbox_with_empty () const
{
mp_layout->update ();
return m_bbox_with_empty;
}
const Cell::box_type &
Cell::bbox () const
{

View File

@ -536,6 +536,17 @@ public:
*/
const box_type &bbox () const;
/**
* @brief Retrieve the bounding box of the cell, including empty cells
*
* This method behaves like "bbox", but includes empty cells as single-point
* boxes (0,0;0,0). This bounding box is used for drawing and allows
* including empty cells.
*
* @return The bounding box that was computed by update_bbox
*/
const box_type &bbox_with_empty () const;
/**
* @brief Retrieve the per-layer bounding box of the cell
*
@ -1098,7 +1109,7 @@ private:
mutable db::Layout *mp_layout;
shapes_map m_shapes_map;
instances_type m_instances;
box_type m_bbox;
box_type m_bbox, m_bbox_with_empty;
box_map m_bboxes;
db::properties_id_type m_prop_id;

View File

@ -33,6 +33,12 @@ CellInst::bbox (const db::Layout &g) const
return g.cell (m_cell_index).bbox ();
}
CellInst::box_type
CellInst::bbox_with_empty (const db::Layout &g) const
{
return g.cell (m_cell_index).bbox_with_empty ();
}
CellInst::box_type
CellInst::bbox (const db::Layout &g, unsigned int l) const
{

View File

@ -90,6 +90,15 @@ public:
*/
box_type bbox (const Layout &g) const;
/**
* @brief Compute the bounding box, including empty cells
*
* This method computes the bbox of the cell instance.
* As a requirement, the cell's bounding box must have been
* computed before.
*/
box_type bbox_with_empty (const Layout &g) const;
/**
* @brief Compute the bounding box
*

View File

@ -85,7 +85,8 @@ struct DB_PUBLIC InstElement
*
* @param bc The bounding box converter for the cell instance (db::box_convert<db::CellInst>)
*/
db::Box bbox (const db::box_convert<db::CellInst> &bc) const
template <class BoxConvert>
db::Box bbox (const BoxConvert &bc) const
{
if (whole_array ()) {
// this is the whole array

View File

@ -907,6 +907,19 @@ Instance::bbox () const
}
}
Instance::box_type
Instance::bbox_with_empty () const
{
const db::Instances *i = instances ();
const db::Cell *c = i ? i->cell () : 0;
const db::Layout *g = c ? c->layout () : 0;
if (g) {
return bbox (db::box_convert<cell_inst_type, false> (*g));
} else {
return db::Instance::box_type ();
}
}
// -------------------------------------------------------------------------------------
// Instances implementation

View File

@ -338,6 +338,15 @@ public:
*/
cell_inst_array_type::box_type bbox () const;
/**
* @brief Returns the bounding box of this array, including empty instances
*
* This method uses the pointers provided internally to identify container and cell.
* In constrast to normal "bbox", this bounding box considers empty cells as
* point-like with a box of (0,0;0,0).
*/
cell_inst_array_type::box_type bbox_with_empty () const;
/**
* @brief Return the iterator for the instances of the array
*

View File

@ -1661,7 +1661,8 @@ Triangulation::refine (const TriangulationParameters &parameters)
Edge *edge = find_closest_edge (center, vstart, true /*inside only*/);
tl_assert (edge != 0);
if (! edge->is_segment () || edge->side_of (*vstart) * edge->side_of (center) >= 0) {
if ((! edge->is_segment () && (edge->side_of (center) < 0 ? edge->left () : edge->right ()) != 0 /*center is inside*/)
|| (edge->is_segment () && edge->side_of (*vstart) * edge->side_of (center) >= 0)) {
if (tl::verbosity () >= parameters.base_verbosity + 20) {
tl::info << "Inserting out-of-triangle center " << center << " of " << (*t)->to_string (true);

View File

@ -33,13 +33,18 @@ TEST(1)
db::Cell &c1 (g.cell (g.add_cell ()));
db::Cell &c2 (g.cell (g.add_cell ()));
EXPECT_EQ (c1.bbox (), db::Box ());
EXPECT_EQ (c1.bbox_with_empty (), db::Box (db::Point(), db::Point ()));
db::Box b (0, 100, 1000, 1200);
c1.shapes (0).insert (b);
EXPECT_EQ (c1.bbox (), b);
EXPECT_EQ (c1.bbox_with_empty (), b);
db::Box bb (0, -100, 2000, 2200);
c1.shapes (1).insert (bb);
EXPECT_EQ (c1.bbox (), b + bb);
EXPECT_EQ (c1.bbox_with_empty (), b + bb);
EXPECT_EQ (c1.bbox (0), b);
EXPECT_EQ (c1.bbox (1), bb);
@ -52,6 +57,7 @@ TEST(1)
EXPECT_EQ (c2.bbox (0), t * b);
EXPECT_EQ (c2.bbox (1), t * bb);
EXPECT_EQ (c1.bbox (), (b + bb));
EXPECT_EQ (c1.bbox_with_empty (), (b + bb));
// some basic testing of the instance trees
int n;
@ -715,6 +721,11 @@ TEST(3a)
db::Trans t (db::Vector (100, -100));
db::Instance inst = c0.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), t));
EXPECT_EQ (inst.to_string (), "cell_index=1 r0 100,-100");
EXPECT_EQ (inst.bbox ().to_string (), "()");
EXPECT_EQ (inst.bbox (db::box_convert<db::CellInst, false> (g)).to_string (), "(100,-100;100,-100)");
EXPECT_EQ (inst.bbox_with_empty ().to_string (), "(100,-100;100,-100)");
EXPECT_EQ (c0.bbox ().to_string (), "()");
EXPECT_EQ (c0.bbox_with_empty ().to_string (), "(100,-100;100,-100)");
inst = c0.transform (inst, db::Trans (5));
EXPECT_EQ (inst.to_string (), "cell_index=1 m45 -100,100");

View File

@ -5950,10 +5950,10 @@ CODE
bx = 0.0
by = 0.0
else
bx = [ fc_box.width, row_step.x ].max
by = [ fc_box.height, column_step.y ].max
bx = [ fc_box.width, row_step.x.abs + column_step.x.abs ].max + [ -fill_margin.x, 0 ].max
by = [ fc_box.height, row_step.y.abs + column_step.y.abs ].max + [ -fill_margin.y, 0 ].max
end
tp.tile_border(bx, by)
tp.tile_border(@engine.dbu * bx, @engine.dbu * by)
tp.threads = (@engine.threads || 1)
result_arg = "nil"

View File

@ -627,7 +627,7 @@ Service::selection_bbox ()
db::CplxTrans ctx_trans = db::CplxTrans (layout.dbu ()) * cv.context_trans () * r->trans ();
db::box_convert<db::CellInst> bc (layout);
db::box_convert<db::CellInst, false> bc (layout);
if (! r->is_cell_inst ()) {
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv_and_layer (r->cv_index (), r->layer ());
@ -1115,7 +1115,7 @@ Service::click_proximity (const db::DPoint &pos, lay::Editable::SelectionMode mo
lay::InstFinder finder (true, view ()->is_editable () && m_top_level_sel, view ()->is_editable () /*full arrays in editable mode*/, true /*enclose_inst*/, exclude, true /*visible layers*/);
// go through all cell views
std::set< std::pair<db::DCplxTrans, int> > variants = view ()->cv_transform_variants ();
std::set< std::pair<db::DCplxTrans, int> > variants = view ()->cv_transform_variants_with_empty();
for (std::set< std::pair<db::DCplxTrans, int> >::const_iterator v = variants.begin (); v != variants.end (); ++v) {
finder.find (view (), v->second, v->first, search_box);
}
@ -1164,7 +1164,7 @@ Service::transient_select (const db::DPoint &pos)
lay::InstFinder finder (true, view ()->is_editable () && m_top_level_sel, view ()->is_editable () /*full arrays in editable mode*/, true /*enclose instances*/, &m_previous_selection, true /*visible layers only*/);
// go through all transform variants
std::set< std::pair<db::DCplxTrans, int> > variants = view ()->cv_transform_variants ();
std::set< std::pair<db::DCplxTrans, int> > variants = view ()->cv_transform_variants_with_empty ();
for (std::set< std::pair<db::DCplxTrans, int> >::const_iterator v = variants.begin (); v != variants.end (); ++v) {
finder.find (view (), v->second, v->first, search_box);
}
@ -1185,7 +1185,7 @@ Service::transient_select (const db::DPoint &pos)
db::Instance inst = r->back ().inst_ptr;
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants (r->cv_index ());
std::vector<db::DCplxTrans> tv = mp_view->cv_transform_variants_with_empty (r->cv_index ());
if (view ()->is_editable ()) {
#if 0
@ -1498,7 +1498,7 @@ Service::select (const db::DBox &box, lay::Editable::SelectionMode mode)
lay::InstFinder finder (box.is_point (), view ()->is_editable () && m_top_level_sel, view ()->is_editable () /*full arrays in editable mode*/, true /*enclose_inst*/, exclude, true /*only visible layers*/);
// go through all cell views
std::set< std::pair<db::DCplxTrans, int> > variants = view ()->cv_transform_variants ();
std::set< std::pair<db::DCplxTrans, int> > variants = view ()->cv_transform_variants_with_empty ();
for (std::set< std::pair<db::DCplxTrans, int> >::const_iterator v = variants.begin (); v != variants.end (); ++v) {
finder.find (view (), v->second, v->first, search_box);
}
@ -1754,6 +1754,10 @@ Service::do_selection_to_view ()
// build the transformation variants cache
TransformationVariants tv (view ());
// prepare a default transformation for empty variants
std::vector<db::DCplxTrans> empty_tv;
empty_tv.push_back (db::DCplxTrans ());
// Build markers
for (EditableSelectionIterator r = begin_selection (); ! r.at_end (); ++r) {
@ -1769,39 +1773,39 @@ Service::do_selection_to_view ()
if (m_cell_inst_service) {
const std::vector<db::DCplxTrans> *tv_list = tv.per_cv (r->cv_index ());
if (tv_list != 0) {
if (tv_list == 0) {
tv_list = &empty_tv;
}
if (view ()->is_editable ()) {
if (view ()->is_editable ()) {
#if 0
// to show the content of the cell when the instance is selected:
lay::InstanceMarker *marker = new lay::InstanceMarker (view (), r->cv_index (), ! show_shapes_of_instances (), show_shapes_of_instances () ? max_shapes_of_instances () : 0);
// to show the content of the cell when the instance is selected:
lay::InstanceMarker *marker = new lay::InstanceMarker (view (), r->cv_index (), ! show_shapes_of_instances (), show_shapes_of_instances () ? max_shapes_of_instances () : 0);
#else
lay::InstanceMarker *marker = new lay::InstanceMarker (view (), r->cv_index ());
lay::InstanceMarker *marker = new lay::InstanceMarker (view (), r->cv_index ());
#endif
marker->set_vertex_shape (lay::ViewOp::Cross);
marker->set_vertex_size (9 /*cross vertex size*/);
if (r->seq () > 0 && m_indicate_secondary_selection) {
marker->set_dither_pattern (3);
}
marker->set (r->back ().inst_ptr, gt, *tv_list);
m_markers.push_back (std::make_pair (r.operator-> (), marker));
} else {
lay::Marker *marker = new lay::Marker (view (), r->cv_index ());
marker->set_vertex_shape (lay::ViewOp::Cross);
marker->set_vertex_size (9 /*cross vertex size*/);
if (r->seq () > 0 && m_indicate_secondary_selection) {
marker->set_dither_pattern (3);
}
db::box_convert<db::CellInst> bc (cv->layout ());
marker->set (bc (r->back ().inst_ptr.cell_inst ().object ()), gt * r->back ().inst_ptr.cell_inst ().complex_trans (*r->back ().array_inst), *tv_list);
m_markers.push_back (std::make_pair (r.operator-> (), marker));
marker->set_vertex_shape (lay::ViewOp::Cross);
marker->set_vertex_size (9 /*cross vertex size*/);
if (r->seq () > 0 && m_indicate_secondary_selection) {
marker->set_dither_pattern (3);
}
marker->set (r->back ().inst_ptr, gt, *tv_list);
m_markers.push_back (std::make_pair (r.operator-> (), marker));
} else {
lay::Marker *marker = new lay::Marker (view (), r->cv_index ());
marker->set_vertex_shape (lay::ViewOp::Cross);
marker->set_vertex_size (9 /*cross vertex size*/);
if (r->seq () > 0 && m_indicate_secondary_selection) {
marker->set_dither_pattern (3);
}
db::box_convert<db::CellInst> bc (cv->layout ());
marker->set (bc (r->back ().inst_ptr.cell_inst ().object ()), gt * r->back ().inst_ptr.cell_inst ().complex_trans (*r->back ().array_inst), *tv_list);
m_markers.push_back (std::make_pair (r.operator-> (), marker));
}

View File

@ -1686,7 +1686,7 @@ InstService::do_begin_edit (const db::DPoint &p)
std::pair<bool, db::cell_index_type> ci = make_cell (cv);
if (ci.first) {
// use the snapped lower left corner of the bbox unless the origin is inside the bbox
db::Box cell_bbox = cv->layout ().cell (ci.second).bbox ();
db::Box cell_bbox = cv->layout ().cell (ci.second).bbox_with_empty ();
if (! m_place_origin && ! cell_bbox.contains (db::Point ())) {
db::CplxTrans ct (1.0, m_angle, m_mirror, db::DVector ());
m_disp = db::DPoint () + (m_disp - snap (cell_bbox.transformed (ct).lower_left () * cv->layout ().dbu ()));
@ -1830,7 +1830,7 @@ InstService::do_mouse_move (const db::DPoint &p)
std::pair<bool, db::cell_index_type> ci = make_cell (cv);
if (ci.first) {
// use the snapped lower left corner of the bbox unless the origin is inside the bbox
db::Box cell_bbox = cv->layout ().cell (ci.second).bbox ();
db::Box cell_bbox = cv->layout ().cell (ci.second).bbox_with_empty ();
if (! m_place_origin && ! cell_bbox.contains (db::Point ())) {
db::CplxTrans ct (1.0, m_angle, m_mirror, db::DVector ());
m_disp = db::DPoint () + (m_disp - snap (cell_bbox.transformed (ct).lower_left () * cv->layout ().dbu ()));

View File

@ -100,13 +100,13 @@ Finder::start (lay::LayoutViewBase *view, unsigned int cv_index, const std::vect
if (layers.size () == 1) {
m_box_convert = db::box_convert <db::CellInst> (*mp_layout, (unsigned int) layers [0]);
m_cell_box_convert = db::box_convert <db::Cell> ((unsigned int) layers [0]);
m_box_convert = db::box_convert <db::CellInst, false> (*mp_layout, (unsigned int) layers [0]);
m_cell_box_convert = db::box_convert <db::Cell, false> ((unsigned int) layers [0]);
} else {
m_box_convert = db::box_convert <db::CellInst> (*mp_layout);
m_cell_box_convert = db::box_convert <db::Cell> ();
m_box_convert = db::box_convert <db::CellInst, false> (*mp_layout);
m_cell_box_convert = db::box_convert <db::Cell, false> ();
}
@ -217,7 +217,8 @@ Finder::do_find (const db::Cell &cell, int level, const db::DCplxTrans &vp, cons
} else if (level < m_max_level
&& (t * m_cell_box_convert (cell)).touches (m_scan_region)
&& (mp_view->select_inside_pcells_mode () || !cell.is_proxy ())
&& !mp_view->is_cell_hidden (cell.cell_index (), m_cv_index)) {
&& !mp_view->is_cell_hidden (cell.cell_index (), m_cv_index)
&& !cell.is_ghost_cell ()) {
db::ICplxTrans it = t.inverted ();
db::Box scan_box (it * m_scan_region);
@ -734,7 +735,7 @@ InstFinder::find (lay::LayoutViewBase *view, const db::DBox &region_mu)
progress.set_format ("");
mp_progress = &progress;
std::set< std::pair<db::DCplxTrans, int> > variants = view->cv_transform_variants ();
std::set< std::pair<db::DCplxTrans, int> > variants = view->cv_transform_variants_with_empty ();
for (std::set< std::pair<db::DCplxTrans, int> >::const_iterator v = variants.begin (); v != variants.end (); ++v) {
find (view, v->second, v->first, region_mu);
}
@ -828,7 +829,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
// just consider the instances exactly at the last level of
// hierarchy (this is where the boxes are drawn) or of cells that
// are hidden.
if (level == max_level () - 1 || inst_cell.is_proxy () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
if (level == max_level () - 1 || inst_cell.is_proxy () || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
db::box_convert <db::CellInst, false> bc (layout ());
for (db::CellInstArray::iterator p = cell_inst.begin_touching (search_box, bc); ! p.at_end (); ++p) {
@ -836,10 +837,11 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
++*mp_progress;
db::Box ibox;
if (inst_cell.bbox ().empty ()) {
ibox = db::Box (db::Point (0, 0), db::Point (0, 0));
} else if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
ibox = inst_cell.bbox ();
if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
ibox = inst_cell.bbox_with_empty ();
} else if (inst_cell.bbox ().empty ()) {
// empty cells cannot be found by visible layers, so we always select them here
ibox = inst_cell.bbox_with_empty ();
} else {
for (std::vector<int>::const_iterator l = m_visible_layer_indexes.begin (); l != m_visible_layer_indexes.end (); ++l) {
ibox += inst_cell.bbox (*l);
@ -903,7 +905,7 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
// just consider the instances exactly at the last level of
// hierarchy (this is where the boxes are drawn) or if of cells that
// are hidden.
if (level == max_level () - 1 || inst_cell.is_proxy () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
if (level == max_level () - 1 || inst_cell.is_proxy () || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
db::box_convert <db::CellInst, false> bc (layout ());
for (db::CellInstArray::iterator p = cell_inst.begin_touching (search_box, bc); ! p.at_end (); ++p) {
@ -914,10 +916,11 @@ InstFinder::visit_cell (const db::Cell &cell, const db::Box &search_box, const d
double d = std::numeric_limits<double>::max ();
db::Box ibox;
if (inst_cell.bbox ().empty ()) {
ibox = db::Box (db::Point (0, 0), db::Point (0, 0));
} else if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
ibox = inst_cell.bbox ();
if (! m_visible_layers || level == mp_view->get_max_hier_levels () - 1 || inst_cell.is_ghost_cell () || mp_view->is_cell_hidden (inst_cell.cell_index (), m_cv_index)) {
ibox = inst_cell.bbox_with_empty ();
} else if (inst_cell.bbox ().empty ()) {
// empty cells cannot be found by visible layers, so we always select them here
ibox = inst_cell.bbox_with_empty ();
} else {
for (std::vector<int>::const_iterator l = m_visible_layer_indexes.begin (); l != m_visible_layer_indexes.end (); ++l) {
ibox += inst_cell.bbox (*l);

View File

@ -218,8 +218,8 @@ private:
bool m_point_mode;
bool m_catch_all;
bool m_top_level_sel;
db::box_convert <db::CellInst> m_box_convert;
db::box_convert <db::Cell> m_cell_box_convert;
db::box_convert <db::CellInst, false> m_box_convert;
db::box_convert <db::Cell, false> m_cell_box_convert;
};
/**

View File

@ -790,7 +790,29 @@ LayerPropertiesNode::set_parent (const LayerPropertiesNode *parent)
mp_parent.reset (const_cast<LayerPropertiesNode *>(parent));
}
db::DBox
db::DBox
LayerPropertiesNode::overall_bbox () const
{
tl_assert (mp_view);
lay::CellView cv = mp_view->cellview (cellview_index ());
if (! cv.is_valid ()) {
return db::DBox ();
} else {
db::DBox b;
double dbu = cv->layout ().dbu ();
for (std::vector<db::DCplxTrans>::const_iterator t = trans ().begin (); t != trans ().end (); ++t) {
b += (*t * db::CplxTrans (dbu) * cv.context_trans ()) * cv.cell ()->bbox_with_empty ();
}
return b;
}
}
db::DBox
LayerPropertiesNode::bbox () const
{
tl_assert (mp_view);
@ -802,12 +824,7 @@ LayerPropertiesNode::bbox () const
} else if (is_cell_box_layer ()) {
db::DBox b;
double dbu = cv->layout ().dbu ();
for (std::vector<db::DCplxTrans>::const_iterator t = trans ().begin (); t != trans ().end (); ++t) {
b += (*t * db::CplxTrans (dbu) * cv.context_trans ()) * cv.cell ()->bbox ();
}
return b;
return overall_bbox ();
} else {

View File

@ -1182,7 +1182,17 @@ public:
* @return A bbox in micron units
*/
db::DBox bbox () const;
/**
* @brief Computes the overall box of this layer
*
* This is not a layer specific box, but an all-layer box,
* including transformations (if specified).
* This box is equivalent to the box delivered by
* a cell frame layer.
*/
db::DBox overall_bbox () const;
/**
* @brief Attach to a view
*

View File

@ -79,6 +79,9 @@ const double zoom_factor = 0.7;
// factor by which panning is faster in "fast" (+Shift) mode
const double fast_factor = 3.0;
// size of cross
const int mark_size = 9;
// -------------------------------------------------------------
struct OpHideShowCell
@ -3861,8 +3864,13 @@ LayoutViewBase::full_box () const
db::DBox bbox;
for (LayerPropertiesConstIterator l = get_properties ().begin_const_recursive (); ! l.at_end (); ++l) {
bbox += l->bbox ();
auto tv = cv_transform_variants_with_empty ();
for (auto i = tv.begin (); i != tv.end (); ++i) {
const lay::CellView &cv = cellview (i->second);
if (cv.is_valid ()) {
double dbu = cv->layout ().dbu ();
bbox += (i->first * db::CplxTrans (dbu) * cv.context_trans ()) * cv.cell ()->bbox_with_empty ();
}
}
for (lay::AnnotationShapes::iterator a = annotation_shapes ().begin (); ! a.at_end (); ++a) {
@ -4241,7 +4249,7 @@ LayoutViewBase::set_view_ops ()
// cell boxes
if (m_cell_box_visible) {
lay::ViewOp vop;
lay::ViewOp vop, vopv;
// context level
if (m_ctx_color.is_valid ()) {
@ -4249,12 +4257,15 @@ LayoutViewBase::set_view_ops ()
} else {
vop = lay::ViewOp (lay::LayerProperties::brighter (box_color.rgb (), brightness_for_context), lay::ViewOp::Copy, 0, 0, 0);
}
vopv = vop;
vopv.shape (lay::ViewOp::Cross);
vopv.width (mark_size);
// fill, frame, text, vertex
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vop);
view_ops.push_back (vop);
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vopv);
// child level
if (m_child_ctx_color.is_valid ()) {
@ -4262,21 +4273,27 @@ LayoutViewBase::set_view_ops ()
} else {
vop = lay::ViewOp (lay::LayerProperties::brighter (box_color.rgb (), brightness_for_context), lay::ViewOp::Copy, 0, 0, 0);
}
vopv = vop;
vopv.shape (lay::ViewOp::Cross);
vopv.width (mark_size);
// fill, frame, text, vertex
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vop);
view_ops.push_back (vop);
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vopv);
// current level
vop = lay::ViewOp (box_color.rgb (), lay::ViewOp::Copy, 0, 0, 0);
vopv = vop;
vopv.shape (lay::ViewOp::Cross);
vopv.width (mark_size);
// fill, frame, text, vertex
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vop);
view_ops.push_back (vop);
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
view_ops.push_back (vopv);
} else {
// invisible
@ -4487,7 +4504,7 @@ LayoutViewBase::set_view_ops ()
view_ops.push_back (lay::ViewOp (0, lay::ViewOp::Or, 0, 0, 0));
}
// vertex
view_ops.push_back (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, l->marked (true /*real*/) ? 9/*mark size*/ : 0)); // vertex
view_ops.push_back (lay::ViewOp (frame_color, mode, 0, 0, 0, lay::ViewOp::Cross, l->marked (true /*real*/) ? mark_size : 0)); // vertex
} else {
for (unsigned int i = 0; i < (unsigned int) planes_per_layer / 3; ++i) {
@ -5974,6 +5991,16 @@ LayoutViewBase::cv_transform_variants (int cv_index) const
return std::vector<db::DCplxTrans> (trns_variants.begin (), trns_variants.end ());
}
std::vector<db::DCplxTrans>
LayoutViewBase::cv_transform_variants_with_empty (int cv_index) const
{
std::vector<db::DCplxTrans> trns_variants = cv_transform_variants (cv_index);
if (trns_variants.empty ()) {
trns_variants.push_back (db::DCplxTrans ());
}
return trns_variants;
}
std::vector<db::DCplxTrans>
LayoutViewBase::cv_transform_variants (int cv_index, unsigned int layer) const
{
@ -6034,7 +6061,32 @@ LayoutViewBase::cv_transform_variants () const
return box_variants;
}
db::InstElement
std::set< std::pair<db::DCplxTrans, int> >
LayoutViewBase::cv_transform_variants_with_empty () const
{
std::set< std::pair<db::DCplxTrans, int> > box_variants = cv_transform_variants ();
// add a default box variant for the CVs not present in the layer list to
// draw boxes at least.
std::vector<bool> cv_present;
cv_present.resize (m_cellviews.size ());
for (auto bv = box_variants.begin (); bv != box_variants.end (); ++bv) {
if (bv->second >= 0 && bv->second < int (cv_present.size ())) {
cv_present[bv->second] = true;
}
}
for (auto i = cv_present.begin (); i != cv_present.end (); ++i) {
if (!*i) {
box_variants.insert (std::make_pair (db::DCplxTrans (), int (i - cv_present.begin ())));
}
}
return box_variants;
}
db::InstElement
LayoutViewBase::ascend (int index)
{
tl_assert (int (m_cellviews.size ()) > index && cellview_iter (index)->is_valid ());

View File

@ -1674,11 +1674,27 @@ public:
*/
std::set< std::pair<db::DCplxTrans, int> > cv_transform_variants () const;
/**
* @brief Get a list of cellview index and transform variants including empty cellviews
*
* This version delivers a unit-transformation variant for cell views for which
* no layer is present. This version is used for instance box drawing.
*/
std::set< std::pair<db::DCplxTrans, int> > cv_transform_variants_with_empty () const;
/**
* @brief Get the global transform variants for a given cellview index
*/
std::vector<db::DCplxTrans> cv_transform_variants (int cv_index) const;
/**
* @brief Get the global transform variants for a given cellview index including empty cellviews
*
* This version delivers a unit-transformation variant for cell views for which
* no layer is present. This version is used for instance box drawing.
*/
std::vector<db::DCplxTrans> cv_transform_variants_with_empty (int cv_index) const;
/**
* @brief Get the global transform variants for a given cellview index and layer
*/

View File

@ -53,7 +53,7 @@ void render_cell_inst (const db::Layout &layout, const db::CellInstArray &inst,
const db::Cell &cell = layout.cell (inst.object ().cell_index ());
std::string cell_name = layout.display_name (inst.object ().cell_index ());
db::Box cell_box = cell.bbox ();
db::Box cell_box = cell.bbox_with_empty ();
db::Vector a, b;
unsigned long amax = 0, bmax = 0;
@ -589,7 +589,12 @@ InstanceMarker::set_max_shapes (size_t s)
db::DBox
InstanceMarker::item_bbox () const
{
return db::DBox (m_inst.bbox ());
const db::Layout *ly = layout ();
if (! ly) {
return db::DBox ();
}
return db::DBox (m_inst.bbox_with_empty ());
}
// ------------------------------------------------------------------------
@ -1059,7 +1064,7 @@ Marker::item_bbox () const
} else if (m_type == Instance) {
const db::Layout *ly = layout ();
if (ly) {
return db::DBox (m_object.inst->bbox (db::box_convert <db::CellInst> (*ly)));
return db::DBox (m_object.inst->bbox (db::box_convert <db::CellInst, false> (*ly)));
}
}
return db::DBox ();

View File

@ -555,6 +555,18 @@ RedrawThreadWorker::setup (LayoutViewBase *view, RedrawThreadCanvas *canvas, con
m_hidden_cells = view->hidden_cells ();
// collect the ghost cells
m_ghost_cells.resize (view->cellviews ());
for (unsigned int i = 0; i < view->cellviews (); ++i) {
std::set <lay::LayoutViewBase::cell_index_type> &gc = m_ghost_cells [i];
const db::Layout &ly = view->cellview (i)->layout ();
for (auto c = ly.begin (); c != ly.end (); ++c) {
if (c->is_ghost_cell ()) {
gc.insert (c->cell_index ());
}
}
}
m_cellviews.clear ();
m_cellviews.reserve (view->cellviews ());
for (unsigned int i = 0; i < view->cellviews (); ++i) {
@ -563,7 +575,7 @@ RedrawThreadWorker::setup (LayoutViewBase *view, RedrawThreadCanvas *canvas, con
m_nlayers = mp_redraw_thread->num_layers ();
m_box_variants = view->cv_transform_variants ();
m_box_variants = view->cv_transform_variants_with_empty ();
}
void
@ -601,7 +613,7 @@ RedrawThreadWorker::test_snapshot (const UpdateSnapshotCallback *update_snapshot
}
void
RedrawThreadWorker::draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, const std::string &txt)
RedrawThreadWorker::draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, bool empty_cell, const std::string &txt)
{
lay::Renderer &r = *mp_renderer;
@ -616,15 +628,20 @@ RedrawThreadWorker::draw_cell (bool drawing_context, int level, const db::CplxTr
lay::CanvasPlane *fill = m_planes[0 + plane_group * (planes_per_layer / 3)];
lay::CanvasPlane *contour = m_planes[1 + plane_group * (planes_per_layer / 3)];
lay::CanvasPlane *vertices = m_planes[3 + plane_group * (planes_per_layer / 3)];
r.draw (box, trans, fill, contour, 0, 0);
if (empty_cell) {
r.draw (dbox, 0, contour, vertices, 0);
} else {
r.draw (dbox, fill, contour, 0, 0);
}
if (! txt.empty () && dbox.width () > m_min_size_for_label && dbox.height () > m_min_size_for_label) {
if (! txt.empty () && (empty_cell || (dbox.width () > m_min_size_for_label && dbox.height () > m_min_size_for_label))) {
// Hint: we render to contour because the texts plane is reserved for properties
r.draw (dbox, txt,
db::Font (m_box_font),
db::HAlignCenter,
db::VAlignCenter,
r.draw (dbox, txt,
db::Font (m_box_font),
db::HAlignCenter,
db::VAlignCenter,
// TODO: apply "real" transformation?
db::DFTrans (m_box_text_transform ? trans.fp_trans ().rot () : db::DFTrans::r0), 0, 0, 0, contour);
}
@ -633,10 +650,6 @@ RedrawThreadWorker::draw_cell (bool drawing_context, int level, const db::CplxTr
void
RedrawThreadWorker::draw_cell_properties (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, db::properties_id_type prop_id)
{
if (prop_id == 0 || ! m_show_properties) {
return;
}
lay::Renderer &r = *mp_renderer;
unsigned int plane_group = 2;
@ -648,7 +661,9 @@ RedrawThreadWorker::draw_cell_properties (bool drawing_context, int level, const
lay::CanvasPlane *texts = m_planes[2 + plane_group * (planes_per_layer / 3)];
r.draw_propstring (prop_id, (trans * box).p1 (), texts, trans);
if (prop_id != 0 && m_show_properties) {
r.draw_propstring (prop_id, (trans * box).p1 (), texts, trans);
}
}
static bool
@ -673,21 +688,28 @@ cells_in (const db::Layout *layout, const db::Cell &cell,
return false;
}
static bool
need_draw_box (const db::Layout *layout, const db::Cell &cell,
int level, int to_level,
const std::vector <std::set <db::cell_index_type> > &hidden_cells, unsigned int cv_index)
bool
RedrawThreadWorker::need_draw_box (const db::Layout *layout, const db::Cell &cell, int level)
{
if (level > to_level) {
if (level > m_to_level) {
return false;
}
if (hidden_cells.size () > cv_index && ! hidden_cells [cv_index].empty ()) {
if (m_ghost_cells.size () > (size_t) m_cv_index && ! m_ghost_cells [m_cv_index].empty ()) {
std::set <std::pair <int, db::cell_index_type> > cache;
if (cells_in (layout, cell, hidden_cells [cv_index], to_level - level, cache)) {
if (cells_in (layout, cell, m_ghost_cells [m_cv_index], m_to_level - level, cache)) {
return true;
}
}
return int (cell.hierarchy_levels ()) + level >= to_level;
if (m_hidden_cells.size () > (size_t) m_cv_index && ! m_hidden_cells [m_cv_index].empty ()) {
std::set <std::pair <int, db::cell_index_type> > cache;
if (cells_in (layout, cell, m_hidden_cells [m_cv_index], m_to_level - level, cache)) {
return true;
}
}
return int (cell.hierarchy_levels ()) + level >= m_to_level;
}
void
@ -701,7 +723,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
const db::Cell &cell = mp_layout->cell (ci);
// we will never come to a valid level ..
if (! need_draw_box (mp_layout, cell, level, m_to_level, m_hidden_cells, m_cv_index)) {
if (! need_draw_box (mp_layout, cell, level)) {
return;
}
if (cell_var_cached (ci, trans)) {
@ -720,36 +742,33 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
const db::Cell &cell = mp_layout->cell (ci);
// For small bboxes, the cell outline can be reduced ..
db::Box bbox = cell.bbox ();
db::Box bbox = cell.bbox_with_empty ();
bool empty_cell = cell.bbox ().empty ();
if (bbox.empty ()) {
// no shapes there and below ..
} else if (m_drop_small_cells && drop_cell (cell, trans)) {
if (m_drop_small_cells && drop_cell (cell, trans)) {
// small cell dropped
} else if (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ())) {
} else if (level == m_to_level || cell.is_ghost_cell () || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ())) {
// paint the box on this level
draw_cell (drawing_context, level, trans, bbox, mp_layout->display_name (ci));
draw_cell (drawing_context, level, trans, bbox, empty_cell, mp_layout->display_name (ci));
} else if (level < m_to_level) {
db::DBox dbbox = trans * bbox;
if (dbbox.width () < 1.5 && dbbox.height () < 1.5) {
if (!empty_cell && (dbbox.width () < 1.5 && dbbox.height () < 1.5)) {
if (need_draw_box (mp_layout, cell, level, m_to_level, m_hidden_cells, m_cv_index)) {
if (need_draw_box (mp_layout, cell, level)) {
// the cell is a very small box and we know there must be
// some level at which to draw the boundary: just draw it
// here and stop looking further down ..
draw_cell (drawing_context, level, trans, bbox, std::string ());
draw_cell (drawing_context, level, trans, bbox, empty_cell, std::string ());
}
} else {
db::box_convert <db::CellInst> bc (*mp_layout);
db::box_convert<db::CellInst, false> bc (*mp_layout);
// create a set of boxes to look into
db::Coord aw = db::coord_traits<db::Coord>::rounded (m_abstract_mode_width / mp_layout->dbu ());
@ -779,7 +798,8 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
const db::CellInstArray &cell_inst = inst->cell_inst ();
db::cell_index_type new_ci = cell_inst.object ().cell_index ();
db::Box new_cell_box = mp_layout->cell (new_ci).bbox ();
db::Box new_cell_box = cell_inst.bbox (bc);
bool empty_inst_cell = mp_layout->cell (new_ci).bbox ().empty ();
if (last_ci != new_ci) {
// Hint: don't use any_cell_box on partially visible cells because that will degrade performance
@ -796,7 +816,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
db::Vector a, b;
unsigned long amax, bmax;
bool simplify = false;
if (cell_inst.is_regular_array (a, b, amax, bmax)) {
if (cell_inst.is_regular_array (a, b, amax, bmax) && (amax > 1 || bmax > 1)) {
db::DBox inst_box;
if (cell_inst.is_complex ()) {
@ -816,9 +836,7 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
if (simplify) {
// The array can be simplified if there are levels below to draw
if (need_draw_box (mp_layout, mp_layout->cell (new_ci), level + 1, m_to_level, m_hidden_cells, m_cv_index)) {
db::box_convert <db::CellInst> bc (*mp_layout);
if (need_draw_box (mp_layout, mp_layout->cell (new_ci), level + 1)) {
unsigned int plane_group = 2;
if (drawing_context) {
@ -827,8 +845,13 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
plane_group = 1;
}
if (empty_inst_cell) {
lay::CanvasPlane *vertices = m_planes[3 + plane_group * (planes_per_layer / 3)];
r.draw (cell_inst.bbox (bc), trans, 0, 0, vertices, 0);
}
lay::CanvasPlane *contour = m_planes[1 + plane_group * (planes_per_layer / 3)];
r.draw (cell_inst.bbox (bc), trans, contour, 0, 0, 0);
r.draw (cell_inst.bbox (bc), trans, contour, contour, 0, 0);
}
@ -900,7 +923,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
const db::Cell &cell = mp_layout->cell (ci);
// we will never come to a valid level ..
if (! need_draw_box (mp_layout, cell, level, m_to_level, m_hidden_cells, m_cv_index)) {
if (! need_draw_box (mp_layout, cell, level)) {
return;
}
if (cell_var_cached (ci, trans)) {
@ -918,17 +941,14 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
const db::Cell &cell = mp_layout->cell (ci);
// For small bboxes, the cell outline can be reduced ..
db::Box bbox = cell.bbox ();
db::Box bbox = cell.bbox_with_empty ();
bool empty_cell = cell.bbox ().empty ();
if (bbox.empty ()) {
// no shapes there and below ..
} else if (m_drop_small_cells && drop_cell (cell, trans)) {
if (m_drop_small_cells && drop_cell (cell, trans)) {
// small cell dropped
} else if (level == m_to_level || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ())) {
} else if (level == m_to_level || cell.is_ghost_cell () || (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ())) {
// paint the box on this level
draw_cell_properties (drawing_context, level, trans, bbox, prop_id);
@ -936,13 +956,13 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
} else if (level < m_to_level) {
db::DBox dbbox = trans * bbox;
if (dbbox.width () < 1.5 && dbbox.height () < 1.5) {
if (!empty_cell && (dbbox.width () < 1.5 && dbbox.height () < 1.5)) {
// ignore cells which are small
} else {
db::box_convert <db::CellInst> bc (*mp_layout);
db::box_convert <db::CellInst, false> bc (*mp_layout);
// create a set of boxes to look into
db::Coord aw = db::coord_traits<db::Coord>::rounded (m_abstract_mode_width / mp_layout->dbu ());
@ -973,7 +993,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
db::properties_id_type cell_inst_prop = inst->prop_id ();
db::cell_index_type new_ci = cell_inst.object ().cell_index ();
db::Box new_cell_box = mp_layout->cell (new_ci).bbox ();
db::Box new_cell_box = cell_inst.bbox (bc);
if (last_ci != new_ci) {
// Hint: don't use any_cell_box on partially visible cells because that will degrade performance
@ -990,7 +1010,7 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
db::Vector a, b;
unsigned long amax, bmax;
bool simplify = false;
if (cell_inst.is_regular_array (a, b, amax, bmax)) {
if (cell_inst.is_regular_array (a, b, amax, bmax) && (amax > 1 || bmax > 1)) {
db::DBox inst_box;
if (cell_inst.is_complex ()) {
@ -1052,13 +1072,18 @@ RedrawThreadWorker::any_shapes (db::cell_index_type cell_index, unsigned int lev
}
}
// Ghost cells are not drawn either
const db::Cell &cell = mp_layout->cell (cell_index);
if (cell.is_ghost_cell ()) {
return false;
}
// the cache contains all cells that are visited already
RedrawThreadWorker::micro_instance_cache_t::const_iterator c = m_mi_cache.find (std::make_pair (cell_index, levels));
if (c == m_mi_cache.end ()) {
int ret = false;
const db::Cell &cell = mp_layout->cell (cell_index);
if (! cell.shapes (m_layer).begin (db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::Paths | db::ShapeIterator::Boxes | db::ShapeIterator::Points, mp_prop_sel, m_inv_prop_sel).at_end ()) {
ret = true;
} else if (levels > 1) {
@ -1089,13 +1114,18 @@ RedrawThreadWorker::any_cell_box (db::cell_index_type cell_index, unsigned int l
}
}
// ghost cells are also drawn
const db::Cell &cell = mp_layout->cell (cell_index);
if (cell.is_ghost_cell ()) {
return true;
}
// the cache contains all cells that are visited already
RedrawThreadWorker::micro_instance_cache_t::const_iterator c = m_mi_cell_box_cache.find (std::make_pair (cell_index, levels));
if (c == m_mi_cell_box_cache.end ()) {
int ret = false;
if (levels > 1) {
const db::Cell &cell = mp_layout->cell (cell_index);
for (db::Cell::child_cell_iterator cc = cell.begin_child_cells (); !cc.at_end () && !ret; ++cc) {
ret = any_cell_box (*cc, levels - 1);
}
@ -1125,13 +1155,18 @@ RedrawThreadWorker::any_text_shapes (db::cell_index_type cell_index, unsigned in
}
}
// Ghost cells are not drawn either
const db::Cell &cell = mp_layout->cell (cell_index);
if (cell.is_ghost_cell ()) {
return false;
}
// the cache contains all cells that are visited already
RedrawThreadWorker::micro_instance_cache_t::const_iterator c = m_mi_text_cache.find (std::make_pair (cell_index, levels));
if (c == m_mi_text_cache.end ()) {
bool ret = false;
const db::Cell &cell = mp_layout->cell (cell_index);
if (! cell.shapes (m_layer).begin (db::ShapeIterator::Texts, mp_prop_sel, m_inv_prop_sel).at_end () ||
(m_show_properties && ! cell.shapes (m_layer).begin (db::ShapeIterator::AllWithProperties, mp_prop_sel, m_inv_prop_sel).at_end ())) {
ret = true;
@ -1309,7 +1344,7 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
} else if (! bbox.empty ()) {
bool hidden = (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ());
bool hidden = cell.is_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (ci) != m_hidden_cells [m_cv_index].end ()));
bool need_to_dive = (level + 1 < m_to_level) && ! hidden;
db::Box cell_bbox = cell.bbox ();
@ -1443,7 +1478,7 @@ RedrawThreadWorker::draw_text_layer (bool drawing_context, db::cell_index_type c
++inst;
db::cell_index_type new_ci = cell_inst.object ().cell_index ();
bool hidden = (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (new_ci) != m_hidden_cells [m_cv_index].end ());
bool hidden = mp_layout->cell (new_ci).is_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (new_ci) != m_hidden_cells [m_cv_index].end ()));
db::Box cell_box = mp_layout->cell (new_ci).bbox (m_layer);
if (! cell_box.empty () && ! hidden) {
@ -1745,7 +1780,7 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
++inst;
db::cell_index_type new_ci = cell_inst.object ().cell_index ();
bool hidden = (m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (new_ci) != m_hidden_cells [m_cv_index].end ());
bool hidden = mp_layout->cell (new_ci).is_ghost_cell () || ((m_cv_index < int (m_hidden_cells.size ()) && m_hidden_cells [m_cv_index].find (new_ci) != m_hidden_cells [m_cv_index].end ()));
db::Box new_cell_box = mp_layout->cell (new_ci).bbox (m_layer);
if (! new_cell_box.empty () && ! hidden) {
@ -1902,7 +1937,7 @@ RedrawThreadWorker::draw_layer (int from_level, int to_level, db::cell_index_typ
db::Box cell_bbox = cell.bbox ();
// Nothing to draw
if (bbox.empty ()) {
if (bbox.empty () || cell.is_ghost_cell ()) {
return;
}
@ -2095,6 +2130,9 @@ bool
RedrawThreadWorker::drop_cell (const db::Cell &cell, const db::CplxTrans &trans)
{
db::DBox bbox = trans * cell.bbox ();
if (bbox.empty ()) {
return true;
}
double value = 0;
if (m_drop_small_cells_cond == lay::LayoutViewBase::DSC_Min) {
@ -2237,7 +2275,7 @@ RedrawThreadWorker::iterate_variants_rec (const std::vector <db::Box> &redraw_re
db::Coord lim = std::numeric_limits<db::Coord>::max ();
db::DBox world (trans * db::Box (db::Point (-lim, -lim), db::Point (lim, lim)));
db::Box vp = db::Box (trans.inverted () * (world & db::DBox (*rr)));
vp &= mp_layout->cell (ci).bbox (); // this avoids problems when accessing designs through very large viewports
vp &= mp_layout->cell (ci).bbox_with_empty (); // this avoids problems when accessing designs through very large viewports
if (! vp.empty ()) {
actual_regions.push_back (vp);
}

View File

@ -186,7 +186,7 @@ private:
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level);
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const std::vector <db::Box> &redraw_regions, int level, db::properties_id_type prop_id);
void draw_box_properties (bool drawing_context, db::cell_index_type ci, const db::CplxTrans &trans, const db::Box &redraw_box, int level, db::properties_id_type prop_id);
void draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, const std::string &txt);
void draw_cell (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, bool empty_cell, const std::string &txt);
void draw_cell_properties (bool drawing_context, int level, const db::CplxTrans &trans, const db::Box &box, db::properties_id_type prop_id);
void draw_cell_shapes (const db::CplxTrans &trans, const db::Cell &cell, const db::Box &vp, lay::CanvasPlane *fill, lay::CanvasPlane *frame, lay::CanvasPlane *vertex, lay::CanvasPlane *text);
void test_snapshot (const UpdateSnapshotCallback *update_snapshot);
@ -199,6 +199,7 @@ private:
bool any_shapes (db::cell_index_type cell_index, unsigned int levels);
bool any_text_shapes (db::cell_index_type cell_index, unsigned int levels);
bool any_cell_box (db::cell_index_type cell_index, unsigned int levels);
bool need_draw_box (const db::Layout *layout, const db::Cell &cell, int level);
RedrawThread *mp_redraw_thread;
std::vector <db::Box> m_redraw_region;
@ -232,6 +233,7 @@ private:
unsigned int m_cache_hits, m_cache_misses;
std::set <std::pair <db::DCplxTrans, int> > m_box_variants;
std::vector <std::set <lay::LayoutViewBase::cell_index_type> > m_hidden_cells;
std::vector <std::set <lay::LayoutViewBase::cell_index_type> > m_ghost_cells;
std::vector <lay::CellView> m_cellviews;
const db::Layout *mp_layout;
int m_cv_index;

View File

@ -361,3 +361,37 @@ TEST(extraction_meander)
)
}
TEST(extraction_issue2111)
{
db::Point contour[] = {
db::Point (0, 0),
db::Point (0, 740),
db::Point (435, 740),
db::Point (435, 100),
db::Point (365, 100),
db::Point (365, 0)
};
db::Polygon poly;
poly.assign_hull (contour + 0, contour + sizeof (contour) / sizeof (contour[0]));
double dbu = 0.001;
pex::RNetwork rn;
pex::TriangulationRExtractor rex (dbu);
// rex.triangulation_parameters ().max_area = 10000 * dbu * dbu;
// rex.triangulation_parameters ().min_b = 0.3;
std::vector<db::Point> vertex_ports;
vertex_ports.push_back (db::Point (400, 500));
std::vector<db::Polygon> polygon_ports;
polygon_ports.push_back (poly);
rex.extract (poly, vertex_ports, polygon_ports, rn);
EXPECT_EQ (rn.to_string (),
"R P0 V0 0.133103"
)
}

Binary file not shown.

Binary file not shown.

Binary file not shown.