mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into devel
This commit is contained in:
commit
5eb8c760d8
|
|
@ -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'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1661,7 +1661,8 @@ Triangulation::refine (const TriangulationParameters ¶meters)
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ()));
|
||||
|
|
|
|||
|
|
@ -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 ®ion_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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.
Loading…
Reference in New Issue