mirror of https://github.com/KLayout/klayout.git
1338 lines
41 KiB
C++
1338 lines
41 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2017 Matthias Koefferlein
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
#include "extNetTracer.h"
|
|
|
|
#include "dbRecursiveShapeIterator.h"
|
|
#include "dbPolygonTools.h"
|
|
#include "dbShapeProcessor.h"
|
|
#include "layViewObject.h"
|
|
#include "layPlugin.h"
|
|
#include "layLayoutView.h"
|
|
#include "tlLog.h"
|
|
|
|
// -O3 appears not to work properly for gcc 4.4.7 (RHEL 6)
|
|
// In that case, the net tracer function crashes.
|
|
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR == 4 && defined(__OPTIMIZE__)
|
|
# pragma GCC optimize("O2")
|
|
#endif
|
|
|
|
namespace ext
|
|
{
|
|
|
|
// -----------------------------------------------------------------------------------
|
|
// Two helper functions that help determining interactions
|
|
|
|
static bool
|
|
interacts (const db::Box &box, const NetTracerShape &net_shape)
|
|
{
|
|
if (net_shape.shape ().is_text ()) {
|
|
|
|
return box.touches (net_shape.bbox ());
|
|
|
|
} else if (net_shape.shape ().is_box ()) {
|
|
|
|
if (net_shape.trans ().is_ortho ()) {
|
|
|
|
return box.touches (net_shape.bbox ());
|
|
|
|
} else {
|
|
|
|
db::Polygon box_poly (net_shape.shape ().box ());
|
|
box_poly.transform (db::ICplxTrans (net_shape.trans ()));
|
|
|
|
return (db::interact (box_poly, box));
|
|
|
|
}
|
|
|
|
} else if (net_shape.shape ().is_polygon () || net_shape.shape ().is_path ()) {
|
|
|
|
db::Polygon polygon;
|
|
net_shape.shape ().polygon (polygon);
|
|
polygon.transform (db::ICplxTrans (net_shape.trans ()));
|
|
|
|
return db::interact (polygon, box);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
}
|
|
|
|
static bool
|
|
interacts (const db::Polygon &polygon, const NetTracerShape &net_shape)
|
|
{
|
|
if (net_shape.shape ().is_text ()) {
|
|
|
|
return db::interact (polygon, net_shape.bbox ());
|
|
|
|
} else if (net_shape.shape ().is_box ()) {
|
|
|
|
if (net_shape.trans ().is_ortho ()) {
|
|
|
|
return db::interact (polygon, net_shape.bbox ());
|
|
|
|
} else {
|
|
|
|
db::Polygon box_poly (net_shape.shape ().box ());
|
|
box_poly.transform (db::ICplxTrans (net_shape.trans ()));
|
|
|
|
return db::interact (polygon, box_poly);
|
|
|
|
}
|
|
|
|
} else if (net_shape.shape ().is_polygon () || net_shape.shape ().is_path ()) {
|
|
|
|
db::Polygon p;
|
|
net_shape.shape ().polygon (p);
|
|
p.transform (db::ICplxTrans (net_shape.trans ()));
|
|
|
|
return db::interact (p, polygon);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------
|
|
// NetTracerShapeHeap implementation
|
|
|
|
NetTracerShapeHeap::NetTracerShapeHeap ()
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
db::Shape
|
|
NetTracerShapeHeap::insert (const db::Polygon &p)
|
|
{
|
|
std::map<db::Polygon, db::Shape>::const_iterator c = m_cache.find (p);
|
|
if (c == m_cache.end ()) {
|
|
c = m_cache.insert (std::make_pair (p, m_container.insert (p))).first;
|
|
}
|
|
return c->second;
|
|
}
|
|
|
|
void
|
|
NetTracerShapeHeap::clear ()
|
|
{
|
|
m_container.clear ();
|
|
m_cache.clear ();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------
|
|
// NetTracerData implementation
|
|
|
|
NetTracerData::NetTracerData ()
|
|
: m_next_log_layer (1000000000)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
NetTracerData::~NetTracerData ()
|
|
{
|
|
for (std::map <unsigned int, NetTracerLayerExpression *>::const_iterator l = m_log_layers.begin (); l != m_log_layers.end (); ++l) {
|
|
delete l->second;
|
|
}
|
|
m_log_layers.clear ();
|
|
}
|
|
|
|
void
|
|
NetTracerData::add_connection (const NetTracerConnection &connection)
|
|
{
|
|
if (connection.layer_a () >= 0 && connection.layer_b () >= 0 && (! connection.has_via_layer () || connection.via_layer () >= 0)) {
|
|
m_connections.push_back (connection);
|
|
}
|
|
if (connection.has_via_layer ()) {
|
|
if (connection.layer_a () >= 0) {
|
|
add_layer_pair (connection.layer_a (), connection.via_layer ());
|
|
}
|
|
if (connection.layer_b () >= 0) {
|
|
add_layer_pair (connection.layer_b (), connection.via_layer ());
|
|
}
|
|
} else if (connection.layer_a () >= 0 && connection.layer_b () >= 0) {
|
|
add_layer_pair (connection.layer_a (), connection.layer_b ());
|
|
}
|
|
}
|
|
|
|
void
|
|
NetTracerData::add_layer_pair (unsigned int a, unsigned int b)
|
|
{
|
|
add_layers (a, b);
|
|
add_layers (b, a);
|
|
}
|
|
|
|
void
|
|
NetTracerData::add_layers (unsigned int a, unsigned int b)
|
|
{
|
|
if (m_log_connection_graph.find (a) == m_log_connection_graph.end ()) {
|
|
m_log_connection_graph.insert (std::make_pair (a, std::set <unsigned int> ())).first->second.insert (a);
|
|
}
|
|
m_log_connection_graph.insert (std::make_pair (a, std::set <unsigned int> ())).first->second.insert (b);
|
|
|
|
if (m_connection_graph.find (a) == m_connection_graph.end ()) {
|
|
std::set <unsigned int> aa = expression (a).original_layers ();
|
|
m_connection_graph.insert (std::make_pair (a, std::set <unsigned int> ())).first->second.insert (aa.begin (), aa.end ());
|
|
m_original_layers.insert (std::make_pair (a, aa));
|
|
}
|
|
std::set <unsigned int> bb = expression (b).original_layers ();
|
|
m_connection_graph.insert (std::make_pair (a, std::set <unsigned int> ())).first->second.insert (bb.begin (), bb.end ());
|
|
}
|
|
|
|
const std::set<unsigned int> &
|
|
NetTracerData::connections (unsigned int from_layer) const
|
|
{
|
|
std::map <unsigned int, std::set <unsigned int> >::const_iterator g = m_connection_graph.find (from_layer);
|
|
if (g != m_connection_graph.end ()) {
|
|
return g->second;
|
|
} else {
|
|
static std::set<unsigned int> empty;
|
|
return empty;
|
|
}
|
|
}
|
|
|
|
std::set<unsigned int>
|
|
NetTracerData::log_layers_for (unsigned int original_layer) const
|
|
{
|
|
std::set <unsigned int> log_layers;
|
|
for (std::map <unsigned int, std::set <unsigned int> >::const_iterator g = m_original_layers.begin (); g != m_original_layers.end (); ++g) {
|
|
if (g->second.find (original_layer) != g->second.end ()) {
|
|
log_layers.insert (g->first);
|
|
}
|
|
}
|
|
return log_layers;
|
|
}
|
|
|
|
const std::set<unsigned int> &
|
|
NetTracerData::log_connections (unsigned int from_layer) const
|
|
{
|
|
std::map <unsigned int, std::set <unsigned int> >::const_iterator g = m_log_connection_graph.find (from_layer);
|
|
if (g != m_log_connection_graph.end ()) {
|
|
return g->second;
|
|
} else {
|
|
static std::set<unsigned int> empty;
|
|
return empty;
|
|
}
|
|
}
|
|
|
|
int
|
|
NetTracerData::find_symbol (const std::string &symbol) const
|
|
{
|
|
std::map<std::string, unsigned int>::const_iterator s = m_symbols.find (symbol);
|
|
if (s == m_symbols.end ()) {
|
|
return -1;
|
|
} else {
|
|
return int (s->second);
|
|
}
|
|
}
|
|
|
|
unsigned int
|
|
NetTracerData::register_logical_layer (NetTracerLayerExpression *expr, const char *symbol)
|
|
{
|
|
unsigned int l = ++m_next_log_layer;
|
|
m_log_layers.insert (std::make_pair (l, expr));
|
|
|
|
if (symbol) {
|
|
m_symbols.insert (std::make_pair (std::string (symbol), l));
|
|
}
|
|
|
|
return l;
|
|
}
|
|
|
|
const NetTracerLayerExpression &
|
|
NetTracerData::expression (unsigned int ll) const
|
|
{
|
|
std::map <unsigned int, NetTracerLayerExpression *>::iterator l = m_log_layers.find (ll);
|
|
if (l == m_log_layers.end ()) {
|
|
l = m_log_layers.insert (std::make_pair (ll, new NetTracerLayerExpression (ll))).first;
|
|
}
|
|
return *l->second;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the connected original layers split into the ones requiring booleans and the ones which don't
|
|
* The result pair will contain the ones which do not require booleans in the first element, and the ones which
|
|
* do in the second.
|
|
*/
|
|
const std::pair <std::set <unsigned int>, std::set <unsigned int> > &
|
|
NetTracerData::requires_booleans (unsigned int from_layer) const
|
|
{
|
|
std::map <unsigned int, std::pair <std::set <unsigned int>, std::set <unsigned int> > >::iterator r = m_requires_booleans.find (from_layer);
|
|
if (r == m_requires_booleans.end ()) {
|
|
|
|
std::set <unsigned int> layers_without_booleans = connections (from_layer);
|
|
std::set <unsigned int> layers_with_booleans;
|
|
|
|
std::set <unsigned int> ll = log_connections (from_layer);
|
|
for (std::set <unsigned int>::const_iterator i = ll.begin (); i != ll.end (); ++i) {
|
|
if (! expression (*i).is_alias ()) {
|
|
std::map <unsigned int, std::set <unsigned int> >::const_iterator ol = m_original_layers.find (*i);
|
|
tl_assert (ol != m_original_layers.end ());
|
|
layers_with_booleans.insert (ol->second.begin (), ol->second.end ());
|
|
for (std::set <unsigned int>::const_iterator j = ol->second.begin (); j != ol->second.end (); ++j) {
|
|
layers_without_booleans.erase (*j);
|
|
}
|
|
}
|
|
}
|
|
|
|
r = m_requires_booleans.insert (std::make_pair (from_layer, std::make_pair (layers_without_booleans, layers_with_booleans))).first;
|
|
|
|
}
|
|
|
|
return r->second;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------
|
|
// NetTracerLayerExpression implementation
|
|
|
|
NetTracerLayerExpression::NetTracerLayerExpression ()
|
|
: m_a (0), m_b (0), mp_a (0), mp_b (0), m_op (OPNone)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
NetTracerLayerExpression::NetTracerLayerExpression (int l)
|
|
: m_a (l), m_b (0), mp_a (0), mp_b (0), m_op (OPNone)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
NetTracerLayerExpression::NetTracerLayerExpression (const NetTracerLayerExpression &other)
|
|
: m_a (other.m_a), m_b (other.m_b), mp_a (0), mp_b (0), m_op (other.m_op)
|
|
{
|
|
if (other.mp_a) {
|
|
mp_a = new NetTracerLayerExpression (*other.mp_a);
|
|
}
|
|
if (other.mp_b) {
|
|
mp_b = new NetTracerLayerExpression (*other.mp_b);
|
|
}
|
|
}
|
|
|
|
NetTracerLayerExpression &
|
|
NetTracerLayerExpression::operator= (const NetTracerLayerExpression &other)
|
|
{
|
|
if (this != &other) {
|
|
|
|
m_a = other.m_a;
|
|
m_b = other.m_b;
|
|
m_op = other.m_op;
|
|
|
|
if (mp_a) {
|
|
delete mp_a;
|
|
mp_a = 0;
|
|
}
|
|
if (other.mp_a) {
|
|
mp_a = new NetTracerLayerExpression (*other.mp_a);
|
|
}
|
|
|
|
if (mp_b) {
|
|
delete mp_b;
|
|
mp_b = 0;
|
|
}
|
|
if (other.mp_b) {
|
|
mp_b = new NetTracerLayerExpression (*other.mp_b);
|
|
}
|
|
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
NetTracerLayerExpression::~NetTracerLayerExpression ()
|
|
{
|
|
if (mp_a) {
|
|
delete mp_a;
|
|
mp_a = 0;
|
|
}
|
|
if (mp_b) {
|
|
delete mp_b;
|
|
mp_b = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
NetTracerLayerExpression::merge (Operator op, NetTracerLayerExpression *other)
|
|
{
|
|
if (m_op != OPNone) {
|
|
NetTracerLayerExpression *e = new NetTracerLayerExpression (*this);
|
|
*this = NetTracerLayerExpression ();
|
|
mp_a = e;
|
|
}
|
|
|
|
m_op = op;
|
|
|
|
if (other->m_op == OPNone) {
|
|
if (other->mp_a) {
|
|
mp_b = new NetTracerLayerExpression (*other->mp_a);
|
|
} else {
|
|
m_b = other->m_a;
|
|
}
|
|
delete other;
|
|
} else {
|
|
mp_b = other;
|
|
}
|
|
}
|
|
|
|
void
|
|
NetTracerLayerExpression::collect_original_layers (std::set<unsigned int> &l) const
|
|
{
|
|
if (! mp_a) {
|
|
if (m_a >= 0) {
|
|
l.insert ((unsigned int) m_a);
|
|
}
|
|
} else {
|
|
mp_a->collect_original_layers (l);
|
|
}
|
|
if (m_op != OPNone) {
|
|
if (! mp_b) {
|
|
if (m_b >= 0) {
|
|
l.insert ((unsigned int) m_b);
|
|
}
|
|
} else {
|
|
mp_b->collect_original_layers (l);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class PartialShapeDetection
|
|
: public db::EdgeEvaluatorBase
|
|
{
|
|
public:
|
|
PartialShapeDetection ()
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
virtual void reset ()
|
|
{
|
|
m_wcv.clear ();
|
|
m_inside.clear ();
|
|
}
|
|
|
|
virtual void reserve (size_t n)
|
|
{
|
|
m_wcv.clear ();
|
|
m_inside.clear ();
|
|
m_wcv.resize (n, 0);
|
|
}
|
|
|
|
virtual int edge (bool north, bool enter, db::EdgeEvaluatorBase::property_type p)
|
|
{
|
|
if (! north) {
|
|
return 0;
|
|
} else {
|
|
|
|
tl_assert (p < m_wcv.size ());
|
|
|
|
int *wcv = &m_wcv [p];
|
|
|
|
bool inside_before = (*wcv != 0);
|
|
*wcv += (enter ? 1 : -1);
|
|
bool inside_after = (*wcv != 0);
|
|
|
|
if (inside_after && ! inside_before) {
|
|
m_inside.insert (p);
|
|
} else if (! inside_after && inside_before) {
|
|
m_inside.erase (p);
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
}
|
|
|
|
virtual int compare_ns () const
|
|
{
|
|
if (m_inside.find (0) == m_inside.end ()) {
|
|
m_outside.insert (m_inside.begin (), m_inside.end ());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
virtual bool is_reset () const
|
|
{
|
|
return m_inside.empty ();
|
|
}
|
|
|
|
bool is_outside (size_t n) const
|
|
{
|
|
return m_outside.find (n) != m_outside.end ();
|
|
}
|
|
|
|
private:
|
|
std::vector <int> m_wcv;
|
|
mutable std::set <db::EdgeEvaluatorBase::property_type> m_inside;
|
|
mutable std::set <db::EdgeEvaluatorBase::property_type> m_outside;
|
|
};
|
|
|
|
void
|
|
NetTracerLayerExpression::compute_results (unsigned int layer, db::cell_index_type cell_index, const std::vector<db::Polygon> *mask, const std::set <std::pair<NetTracerShape, const NetTracerShape *> > &input, const HitTestDataBoxTree *seeds_tree, NetTracerShapeHeap &shape_heap, std::set <std::pair<NetTracerShape, const NetTracerShape *> > &output, const NetTracerData &data, db::EdgeProcessor &ep) const
|
|
{
|
|
std::set <std::pair<NetTracerShape, const NetTracerShape *> >::const_iterator i1, i2;
|
|
std::set <std::pair<NetTracerShape, const NetTracerShape *> > shapes, shapes2;
|
|
NetTracerShapeHeap local_shape_heap;
|
|
std::vector<db::Polygon> output_polygons;
|
|
std::vector<const NetTracerShape *> input_shapes;
|
|
|
|
if (mp_a) {
|
|
mp_a->compute_results (layer, cell_index, 0, input, 0, local_shape_heap, shapes, data, ep);
|
|
i1 = shapes.begin ();
|
|
i2 = shapes.end ();
|
|
} else {
|
|
i1 = input.end (), i2 = input.end ();
|
|
if (m_a >= 0) {
|
|
for (i1 = input.begin (); i1 != input.end () && i1->first.layer () != (unsigned int) m_a; ++i1) { }
|
|
for (i2 = i1; i2 != input.end () && i2->first.layer () == (unsigned int) m_a; ++i2) { }
|
|
}
|
|
}
|
|
|
|
std::vector<db::Polygon> input_a;
|
|
for (std::set <std::pair<NetTracerShape, const NetTracerShape *> >::const_iterator i = i1; i != i2; ++i) {
|
|
if (i->first.shape ().is_box () || i->first.shape ().is_polygon () || i->first.shape ().is_path ()) {
|
|
input_a.push_back (db::Polygon ());
|
|
i->first.shape ().polygon (input_a.back ());
|
|
input_a.back ().transform (db::ICplxTrans (i->first.trans ()));
|
|
input_shapes.push_back (&i->first);
|
|
}
|
|
}
|
|
|
|
if (m_op == OPNone) {
|
|
|
|
output_polygons.swap (input_a);
|
|
|
|
} else {
|
|
|
|
if (mp_b) {
|
|
mp_b->compute_results (layer, cell_index, 0, input, 0, local_shape_heap, shapes2, data, ep);
|
|
i1 = shapes2.begin ();
|
|
i2 = shapes2.end ();
|
|
} else {
|
|
i1 = input.end (), i2 = input.end ();
|
|
if (m_b >= 0) {
|
|
for (i1 = input.begin (); i1 != input.end () && i1->first.layer () != (unsigned int) m_b; ++i1) { }
|
|
for (i2 = i1; i2 != input.end () && i2->first.layer () == (unsigned int) m_b; ++i2) { }
|
|
}
|
|
}
|
|
|
|
if (m_op == OPOr) {
|
|
|
|
output_polygons.swap (input_a);
|
|
|
|
for (std::set <std::pair<NetTracerShape, const NetTracerShape *> >::const_iterator i = i1; i != i2; ++i) {
|
|
if (i->first.shape ().is_box () || i->first.shape ().is_polygon () || i->first.shape ().is_path ()) {
|
|
output_polygons.push_back (db::Polygon ());
|
|
i->first.shape ().polygon (output_polygons.back ());
|
|
output_polygons.back ().transform (db::ICplxTrans (i->first.trans ()));
|
|
input_shapes.push_back (&i->first);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
std::vector<db::Polygon> input_b;
|
|
for (std::set <std::pair<NetTracerShape, const NetTracerShape *> >::const_iterator i = i1; i != i2; ++i) {
|
|
if (i->first.shape ().is_box () || i->first.shape ().is_polygon () || i->first.shape ().is_path ()) {
|
|
input_b.push_back (db::Polygon ());
|
|
i->first.shape ().polygon (input_b.back ());
|
|
input_b.back ().transform (db::ICplxTrans (i->first.trans ()));
|
|
}
|
|
}
|
|
|
|
if (m_op == OPAnd) {
|
|
ep.boolean (input_a, input_b, output_polygons, db::BooleanOp::And);
|
|
} else if (m_op == OPNot) {
|
|
ep.boolean (input_a, input_b, output_polygons, db::BooleanOp::ANotB);
|
|
} else if (m_op == OPXor) {
|
|
ep.boolean (input_a, input_b, output_polygons, db::BooleanOp::Xor);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Apply the mask
|
|
if (mask) {
|
|
input_a.clear ();
|
|
input_a.swap (output_polygons);
|
|
ep.boolean (input_a, *mask, output_polygons, db::BooleanOp::And);
|
|
}
|
|
|
|
std::vector <db::Polygon> full_shapes;
|
|
std::vector <db::Polygon> partial_shapes;
|
|
|
|
// Determine what shapes are outside the masked output region
|
|
db::ShapeProcessor sp;
|
|
|
|
for (std::vector<db::Polygon>::const_iterator p = output_polygons.begin (); p != output_polygons.end (); ++p) {
|
|
sp.insert_native (*p, 0);
|
|
}
|
|
|
|
for (std::vector<const NetTracerShape *>::const_iterator i = input_shapes.begin (); i != input_shapes.end (); ++i) {
|
|
sp.insert ((*i)->shape (), (*i)->trans (), std::distance (std::vector<const NetTracerShape *>::const_iterator (input_shapes.begin ()), i) + 1);
|
|
}
|
|
|
|
PartialShapeDetection psd;
|
|
db::EdgeSink es;
|
|
sp.process (es, psd);
|
|
|
|
// Determine all input shapes fully inside the masked delivery. Assign these shapes to seeds by
|
|
// looking them up in the seed tree. Shapes partially inside the masked deliver are treated later.
|
|
for (std::vector<const NetTracerShape *>::const_iterator i = input_shapes.begin (); i != input_shapes.end (); ++i) {
|
|
|
|
db::Polygon ip;
|
|
(*i)->shape ().polygon (ip);
|
|
ip.transform (db::ICplxTrans ((*i)->trans ()));
|
|
|
|
if (! psd.is_outside (std::distance (std::vector<const NetTracerShape *>::const_iterator (input_shapes.begin ()), i) + 1)) {
|
|
|
|
full_shapes.push_back (ip);
|
|
|
|
#if 0
|
|
if (seeds_tree) {
|
|
for (HitTestDataBoxTree::touching_iterator s = seeds_tree->begin_touching (ip.box (), HitTestDataBoxConverter ()); ! s.at_end (); ++s) {
|
|
if (interacts (ip, **s)) {
|
|
output.insert (std::make_pair (**i, *s));
|
|
}
|
|
}
|
|
} else {
|
|
output.insert (std::make_pair (**i, (const NetTracerShape *) 0));
|
|
}
|
|
#else
|
|
db::Shape os = shape_heap.insert (ip);
|
|
|
|
if (seeds_tree) {
|
|
for (HitTestDataBoxTree::touching_iterator s = seeds_tree->begin_touching (ip.box (), HitTestDataBoxConverter ()); ! s.at_end (); ++s) {
|
|
if (interacts (ip, **s)) {
|
|
output.insert (std::make_pair (NetTracerShape (db::ICplxTrans (), os, layer, cell_index), *s));
|
|
}
|
|
}
|
|
} else {
|
|
output.insert (std::make_pair (NetTracerShape (db::ICplxTrans (), os, layer, cell_index), (const NetTracerShape *) 0));
|
|
}
|
|
#endif
|
|
|
|
} else {
|
|
partial_shapes.push_back (ip);
|
|
}
|
|
|
|
}
|
|
|
|
if (! partial_shapes.empty ()) {
|
|
|
|
input_a.clear ();
|
|
input_a.swap (output_polygons);
|
|
ep.boolean (input_a, full_shapes, output_polygons, db::BooleanOp::ANotB);
|
|
|
|
input_a.clear ();
|
|
input_a.swap (output_polygons);
|
|
ep.boolean (input_a, partial_shapes, output_polygons, db::BooleanOp::And);
|
|
|
|
// Assign output to seeds by looking into the seed tree
|
|
for (std::vector<db::Polygon>::const_iterator o = output_polygons.begin (); o != output_polygons.end (); ++o) {
|
|
|
|
db::Shape os = shape_heap.insert (*o);
|
|
|
|
if (seeds_tree) {
|
|
for (HitTestDataBoxTree::touching_iterator s = seeds_tree->begin_touching (o->box (), HitTestDataBoxConverter ()); ! s.at_end (); ++s) {
|
|
if (interacts (*o, **s)) {
|
|
output.insert (std::make_pair (NetTracerShape (db::ICplxTrans (), os, layer, cell_index), *s));
|
|
}
|
|
}
|
|
} else {
|
|
output.insert (std::make_pair (NetTracerShape (db::ICplxTrans (), os, layer, cell_index), (const NetTracerShape *) 0));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
std::string
|
|
NetTracerLayerExpression::to_string () const
|
|
{
|
|
std::string s;
|
|
if (mp_a) {
|
|
s += "(" + mp_a->to_string () + ")";
|
|
} else {
|
|
s += "#" + tl::to_string (m_a);
|
|
}
|
|
if (m_op != OPNone) {
|
|
if (m_op == OPOr) {
|
|
s += "+";
|
|
} else if (m_op == OPAnd) {
|
|
s += "*";
|
|
} else if (m_op == OPXor) {
|
|
s += "^";
|
|
} else if (m_op == OPNot) {
|
|
s += "-";
|
|
}
|
|
if (mp_b) {
|
|
s += "(" + mp_b->to_string () + ")";
|
|
} else {
|
|
s += "#" + tl::to_string (m_b);
|
|
}
|
|
}
|
|
return s;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------
|
|
// NetTracer implementation
|
|
|
|
NetTracer::NetTracer ()
|
|
: mp_layout (0), mp_cell (0), mp_progress (0), m_name_hier_depth (-1), m_incomplete (false)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
void
|
|
NetTracer::clear ()
|
|
{
|
|
m_shapes_graph.clear ();
|
|
m_shapes_found.clear ();
|
|
m_shape_heap.clear ();
|
|
}
|
|
|
|
std::string
|
|
NetTracer::name () const
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
void
|
|
NetTracer::set_name (const std::string &n)
|
|
{
|
|
m_name = n;
|
|
}
|
|
|
|
void
|
|
NetTracer::trace (const db::Layout &layout, const db::Cell &cell, const db::Point &pt_start, unsigned int l_start, const NetTracerData &data)
|
|
{
|
|
db::Shape s_start = m_shape_heap.insert (db::Polygon (db::Box (pt_start - db::Vector (1, 1), pt_start + db::Vector (1, 1))));
|
|
|
|
NetTracerShape start (db::ICplxTrans (), s_start, l_start, cell.cell_index (), true);
|
|
trace (layout, cell, start, data);
|
|
|
|
// remove the artificial point-like seed from the shape list
|
|
for (std::set <NetTracerShape>::iterator s = m_shapes_found.begin (); s != m_shapes_found.end (); ) {
|
|
std::set <NetTracerShape>::iterator s1 = s;
|
|
++s;
|
|
if (s1->shape () == s_start) {
|
|
m_shapes_found.erase (s1);
|
|
}
|
|
}
|
|
|
|
m_shapes_graph.clear ();
|
|
}
|
|
|
|
void
|
|
NetTracer::trace (const db::Layout &layout, const db::Cell &cell, const NetTracerShape &start, const NetTracerData &data)
|
|
{
|
|
trace (layout, cell, start, NetTracerShape (), data);
|
|
}
|
|
|
|
void
|
|
NetTracer::trace (const db::Layout &layout, const db::Cell &cell, const db::Point &pt_start, unsigned int l_start, const db::Point &pt_stop, unsigned int l_stop, const NetTracerData &data)
|
|
{
|
|
db::Shape s_start = m_shape_heap.insert (db::Polygon (db::Box (pt_start - db::Vector (1, 1), pt_start + db::Vector (1, 1))));
|
|
db::Shape s_stop = m_shape_heap.insert (db::Polygon (db::Box (pt_stop - db::Vector (1, 1), pt_stop + db::Vector (1, 1))));
|
|
|
|
NetTracerShape start (db::ICplxTrans (), s_start, l_start, cell.cell_index (), true);
|
|
NetTracerShape stop (db::ICplxTrans (), s_stop, l_stop, cell.cell_index (), true);
|
|
trace (layout, cell, start, stop, data);
|
|
|
|
// remove the artificial point-like seeds from the shape list
|
|
for (std::set <NetTracerShape>::iterator s = m_shapes_found.begin (); s != m_shapes_found.end (); ) {
|
|
std::set <NetTracerShape>::iterator s1 = s;
|
|
++s;
|
|
if (s1->shape () == s_start || s1->shape () == s_stop) {
|
|
m_shapes_found.erase (s1);
|
|
}
|
|
}
|
|
|
|
m_shapes_graph.clear ();
|
|
}
|
|
|
|
void
|
|
NetTracer::compute_results_for_next_iteration (const std::vector <const NetTracerShape *> &new_seeds, unsigned int seed_layer, const std::set<unsigned int> &output_layers, std::set <std::pair<NetTracerShape, const NetTracerShape *> > ¤t, std::set <std::pair<NetTracerShape, const NetTracerShape *> > &output, const NetTracerData &data)
|
|
{
|
|
// Compute the seed hull used to collect all interacting shapes and also to mask them out.
|
|
db::Box secondary_box;
|
|
std::vector <db::Polygon> secondary_seed_polygons;
|
|
secondary_seed_polygons.reserve (current.size ());
|
|
for (std::set <std::pair<NetTracerShape, const NetTracerShape *> >::const_iterator s = current.begin (); s != current.end (); ++s) {
|
|
|
|
if (s->first.shape ().is_polygon () || s->first.shape ().is_path () || s->first.shape ().is_box ()) {
|
|
|
|
secondary_seed_polygons.push_back (db::Polygon ());
|
|
s->first.shape ().polygon (secondary_seed_polygons.back ());
|
|
secondary_seed_polygons.back ().transform(s->first.trans ());
|
|
secondary_box += secondary_seed_polygons.back ().box ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::vector <db::Polygon> secondary_seed_hull;
|
|
m_ep.simple_merge (secondary_seed_polygons, secondary_seed_hull, false);
|
|
|
|
const std::set<unsigned int> &connected_layers = data.connections (seed_layer);
|
|
|
|
// collect all shapes related to that seed hull
|
|
for (std::vector <db::Polygon>::const_iterator s = secondary_seed_hull.begin (); s != secondary_seed_hull.end (); ++s) {
|
|
determine_interactions (*s, 0, connected_layers, current);
|
|
}
|
|
|
|
#if 0
|
|
TODO: optimization idea:
|
|
// build a layer map: holds the starting elements for each layer of the delivery.
|
|
// This exploits the fact that the items in the delivery set are sorted by layer first.
|
|
std::vector<std::set <std::pair<NetTracerShape, const NetTracerShape *> >::const_iterator> layer_chunks;
|
|
for (std::set<std::pair<NetTracerShape, const NetTracerShape *> >::const_iterator c = delivery->begin (); c != delivery->end (); ++c) {
|
|
if (layer_chunks.empty () || layer_chunks.back ()->first.layer != c->first.layer) {
|
|
layer_chunks.push_back (c);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
HitTestDataBoxTree seed_tree;
|
|
for (std::vector<const NetTracerShape *>::const_iterator seed = new_seeds.begin (); seed != new_seeds.end (); ++seed) {
|
|
seed_tree.insert (*seed);
|
|
}
|
|
seed_tree.sort (HitTestDataBoxConverter ());
|
|
|
|
for (std::set<unsigned int>::const_iterator c = output_layers.begin (); c != output_layers.end (); ++c) {
|
|
|
|
// From new_entries compute the results of this operation, use only results interacting with the
|
|
// quad tree entries and store them in the output. Use seed_tree to assign the pieces back to the seeds for
|
|
// building the shape graph.
|
|
data.expression (*c).compute_results (*c, cell ().cell_index (), &secondary_seed_hull, current, &seed_tree, m_shape_heap, output, data, m_ep);
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
NetTracer::trace (const db::Layout &layout, const db::Cell &cell, const NetTracerShape &start, const NetTracerShape &stop, const NetTracerData &data)
|
|
{
|
|
mp_layout = &layout;
|
|
mp_cell = &cell;
|
|
|
|
m_shapes_graph.clear ();
|
|
m_shapes_found.clear ();
|
|
|
|
try {
|
|
|
|
tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Tracing Net")), 1);
|
|
progress.set_format (tl::to_string (QObject::tr ("%.0f shapes")));
|
|
progress.set_unit (100);
|
|
progress.set_format_unit (1);
|
|
|
|
mp_progress = &progress;
|
|
|
|
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Net Tracing")));
|
|
|
|
m_stop_shape = stop;
|
|
m_start_shape = start;
|
|
|
|
m_hit_test_queue.clear ();
|
|
|
|
// Required in order to provide a connection point for the start shape:
|
|
const NetTracerShape *start_shape = deliver_shape (m_start_shape, (const NetTracerShape *) 0);
|
|
|
|
if (! (m_start_shape == m_stop_shape)) {
|
|
|
|
// Use the appropriate logical layer for the start shape
|
|
std::set<unsigned int> ll = data.log_layers_for (start.layer ());
|
|
for (std::set<unsigned int>::const_iterator l = ll.begin (); l != ll.end (); ++l) {
|
|
|
|
std::vector <const NetTracerShape *> new_seeds;
|
|
new_seeds.push_back (start_shape);
|
|
|
|
std::set <std::pair<NetTracerShape, const NetTracerShape *> > new_entries;
|
|
new_entries.insert (std::make_pair (m_start_shape, (const NetTracerShape *) 0));
|
|
|
|
std::set<unsigned int> cl;
|
|
cl.insert (*l);
|
|
compute_results_for_next_iteration (new_seeds, *l, cl, new_entries, m_hit_test_queue, data);
|
|
|
|
}
|
|
|
|
if (m_stop_shape.is_valid ()) {
|
|
|
|
// Required in order to provide a connection point for the stop shape:
|
|
const NetTracerShape *stop_shape = deliver_shape (m_stop_shape, (const NetTracerShape *) 0);
|
|
if (stop_shape) {
|
|
|
|
// Use the appropriate logical layer for the stop shape
|
|
std::set<unsigned int> ll = data.log_layers_for (stop.layer ());
|
|
for (std::set<unsigned int>::const_iterator l = ll.begin (); l != ll.end (); ++l) {
|
|
|
|
std::vector <const NetTracerShape *> new_seeds;
|
|
new_seeds.push_back (stop_shape);
|
|
|
|
std::set <std::pair<NetTracerShape, const NetTracerShape *> > new_entries;
|
|
new_entries.insert (std::make_pair (m_stop_shape, (const NetTracerShape *) 0));
|
|
|
|
std::set<unsigned int> cl;
|
|
cl.insert (*l);
|
|
compute_results_for_next_iteration (new_seeds, *l, cl, new_entries, m_hit_test_queue, data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (! m_hit_test_queue.empty ()) {
|
|
|
|
std::set<std::pair<NetTracerShape, const NetTracerShape *> >::iterator new_seed = m_hit_test_queue.end ();
|
|
--new_seed;
|
|
|
|
db::Box combined_box = new_seed->first.bbox ();
|
|
double asum = new_seed->first.shape ().area ();
|
|
|
|
unsigned int seed_layer = new_seed->first.layer ();
|
|
|
|
std::set<std::pair<NetTracerShape, const NetTracerShape *> >::iterator c;
|
|
size_t n = 1;
|
|
for (c = new_seed; c != m_hit_test_queue.begin (); ) {
|
|
|
|
--c;
|
|
++n;
|
|
|
|
if (c->first.layer () == seed_layer) {
|
|
|
|
db::Box b = c->first.bbox ();
|
|
double a = c->first.shape ().area ();
|
|
|
|
// The ratio theshold of 20 for box/shape area was determined empirically
|
|
if ((combined_box + b).area () > (asum + a) * 20.0) {
|
|
++c;
|
|
--n;
|
|
break;
|
|
}
|
|
|
|
combined_box += b;
|
|
asum += a;
|
|
|
|
} else {
|
|
|
|
// because we sort the set primarily by layer, we can stop now!
|
|
++c;
|
|
--n;
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Take out the new seeds and deliver them
|
|
std::vector <const NetTracerShape *> new_seeds;
|
|
new_seeds.reserve (n);
|
|
|
|
for (std::set <std::pair<NetTracerShape, const NetTracerShape *> >::const_iterator td = c; td != m_hit_test_queue.end (); ++td) {
|
|
const NetTracerShape *shape = deliver_shape (td->first, td->second);
|
|
if (shape) {
|
|
new_seeds.push_back (shape);
|
|
}
|
|
}
|
|
|
|
m_hit_test_queue.erase (c, m_hit_test_queue.end ());
|
|
|
|
const std::pair <std::set <unsigned int>, std::set <unsigned int> > &bb = data.requires_booleans (seed_layer);
|
|
const std::set<unsigned int> &connected_layers_with_booleans = bb.second;
|
|
const std::set<unsigned int> &connected_layers_without_booleans = bb.first;
|
|
|
|
if (! connected_layers_with_booleans.empty ()) {
|
|
|
|
// In the boolean case, we do a collection step first. Then we determine the
|
|
// next generation interactions to get all the involved shapes, compute the
|
|
// results of the boolean operations and do a shape-to-seed assignment later
|
|
std::set <std::pair<NetTracerShape, const NetTracerShape *> > new_entries;
|
|
|
|
// Determine next-generation interactions
|
|
if (new_seeds.size () == 1) {
|
|
|
|
const NetTracerShape *c = new_seeds.back ();
|
|
|
|
if (c->shape ().is_box ()) {
|
|
|
|
if (c->trans ().is_ortho ()) {
|
|
determine_interactions (c->bbox (), c /*do not do seed assignment*/, connected_layers_with_booleans, new_entries);
|
|
} else {
|
|
db::Polygon box_poly (c->shape ().box ());
|
|
box_poly.transform (db::ICplxTrans (c->trans ()));
|
|
determine_interactions (box_poly, c /*do not do seed assignment*/, connected_layers_with_booleans, new_entries);
|
|
}
|
|
|
|
} else if (c->shape ().is_polygon () || c->shape ().is_path ()) {
|
|
db::Polygon p;
|
|
c->shape ().polygon (p);
|
|
p.transform (db::ICplxTrans (c->trans ()));
|
|
determine_interactions (p, c /*do not do seed assignment*/, connected_layers_with_booleans, new_entries);
|
|
}
|
|
|
|
} else if (! new_seeds.empty ()) {
|
|
determine_interactions (new_seeds, combined_box, connected_layers_with_booleans, new_entries, true /*do not do seed assignment*/);
|
|
}
|
|
|
|
std::set <unsigned int> computed_layers;
|
|
std::set <unsigned int> all_connected = data.log_connections (seed_layer);
|
|
std::set <unsigned int> involved = data.log_connections (seed_layer);
|
|
for (std::set <unsigned int>::const_iterator i = connected_layers_with_booleans.begin (); i != connected_layers_with_booleans.end (); ++i) {
|
|
std::set <unsigned int> ll = data.log_layers_for (*i);
|
|
std::set_intersection (all_connected.begin (), all_connected.end (), ll.begin (), ll.end (), std::inserter (computed_layers, computed_layers.begin ()));
|
|
}
|
|
|
|
compute_results_for_next_iteration (new_seeds, seed_layer, computed_layers, new_entries, m_hit_test_queue, data);
|
|
|
|
}
|
|
|
|
if (! connected_layers_without_booleans.empty ()) {
|
|
|
|
// If no boolean step is required afterwards, we simply collect the interacting shapes for the new seeds
|
|
// results. Later we will run the booleans on these results.
|
|
if (new_seeds.size () == 1) {
|
|
|
|
const NetTracerShape *c = new_seeds.back ();
|
|
|
|
if (c->shape ().is_box ()) {
|
|
|
|
if (c->trans ().is_ortho ()) {
|
|
determine_interactions (c->bbox (), c, connected_layers_without_booleans, m_hit_test_queue);
|
|
} else {
|
|
db::Polygon box_poly (c->shape ().box ());
|
|
box_poly.transform (db::ICplxTrans (c->trans ()));
|
|
determine_interactions (box_poly, c, connected_layers_without_booleans, m_hit_test_queue);
|
|
}
|
|
|
|
} else if (c->shape ().is_polygon () || c->shape ().is_path ()) {
|
|
db::Polygon p;
|
|
c->shape ().polygon (p);
|
|
p.transform (db::ICplxTrans (c->trans ()));
|
|
determine_interactions (p, c, connected_layers_without_booleans, m_hit_test_queue);
|
|
}
|
|
|
|
} else if (! new_seeds.empty ()) {
|
|
determine_interactions (new_seeds, combined_box, connected_layers_without_booleans, m_hit_test_queue, true);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_hit_test_queue.clear ();
|
|
m_incomplete = false;
|
|
mp_progress = 0;
|
|
|
|
} catch (...) {
|
|
|
|
m_shapes_graph.clear ();
|
|
|
|
m_hit_test_queue.clear ();
|
|
m_incomplete = true;
|
|
mp_progress = 0;
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (m_stop_shape.is_valid ()) {
|
|
|
|
tl::AbsoluteProgress search_progress (tl::to_string (QObject::tr ("Finding Path")), 100);
|
|
search_progress.set_format (tl::to_string (QObject::tr ("Iteration %.0f00")));
|
|
search_progress.set_unit (100);
|
|
|
|
const NetTracerShape *stop = &m_shapes_graph.find (m_stop_shape)->first;
|
|
const NetTracerShape *start = &m_shapes_graph.find (m_start_shape)->first;
|
|
|
|
// find the shortest path with Dijkstras algorithm
|
|
|
|
std::map<const NetTracerShape *, const NetTracerShape *> previous;
|
|
std::map<const NetTracerShape *, size_t> cost;
|
|
cost.insert (std::make_pair (stop, 0));
|
|
std::set<const NetTracerShape *> visited;
|
|
|
|
bool found = false;
|
|
|
|
while (! cost.empty ()) {
|
|
|
|
++search_progress;
|
|
|
|
size_t min_cost = std::numeric_limits <size_t>::max ();
|
|
for (std::map<const NetTracerShape *, size_t>::const_iterator ac = cost.begin (); ac != cost.end (); ++ac) {
|
|
if (ac->second < min_cost) {
|
|
min_cost = ac->second;
|
|
}
|
|
}
|
|
|
|
const NetTracerShape *current = 0;
|
|
for (std::map<const NetTracerShape *, size_t>::iterator ac = cost.begin (); ac != cost.end (); ++ac) {
|
|
if (ac->second == min_cost) {
|
|
current = ac->first;
|
|
visited.insert (current);
|
|
cost.erase (ac);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (! current) {
|
|
break;
|
|
}
|
|
|
|
const std::vector <const NetTracerShape *> &adj = m_shapes_graph[*current];
|
|
for (std::vector <const NetTracerShape *>::const_iterator a = adj.begin (); a != adj.end (); ++a) {
|
|
if (visited.find (*a) == visited.end ()) {
|
|
std::map<const NetTracerShape *, size_t>::iterator ac = cost.find (*a);
|
|
if (ac == cost.end ()) {
|
|
cost.insert (std::make_pair (*a, min_cost + 1));
|
|
previous.insert (std::make_pair (*a, current));
|
|
} else if (min_cost + 1 < ac->second) {
|
|
ac->second = min_cost + 1;
|
|
previous.insert (std::make_pair (*a, current));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (previous.find (start) != previous.end ()) {
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
m_shapes_found.clear ();
|
|
|
|
if (! found) {
|
|
throw tl::Exception (tl::to_string (QObject::tr ("Nets are not connected")));
|
|
}
|
|
|
|
const NetTracerShape *s = start;
|
|
while (s) {
|
|
m_shapes_found.insert (*s);
|
|
std::map<const NetTracerShape *, const NetTracerShape *>::const_iterator p = previous.find (s);
|
|
if (p == previous.end ()) {
|
|
s = 0;
|
|
} else {
|
|
s = p->second;
|
|
}
|
|
}
|
|
|
|
m_shapes_graph.clear ();
|
|
|
|
}
|
|
|
|
} catch (...) {
|
|
m_shapes_found.clear ();
|
|
m_shapes_graph.clear ();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
void
|
|
NetTracer::evaluate_text (const db::RecursiveShapeIterator &iter)
|
|
{
|
|
if (iter.shape ().is_text ()) {
|
|
if (m_name.empty () || m_name_hier_depth < 0 || m_name_hier_depth > int (iter.depth ())) {
|
|
m_name = iter.shape ().text_string ();
|
|
m_name_hier_depth = int (iter.depth ());
|
|
}
|
|
}
|
|
}
|
|
|
|
const NetTracerShape *
|
|
NetTracer::deliver_shape (const NetTracerShape &net_shape, const NetTracerShape *adjacent)
|
|
{
|
|
const NetTracerShape *ret = 0;
|
|
|
|
if (! m_stop_shape.is_valid ()) {
|
|
|
|
std::pair<std::set <NetTracerShape>::iterator, bool> f = m_shapes_found.insert (net_shape);
|
|
if (f.second) {
|
|
if (mp_progress) {
|
|
++(*mp_progress);
|
|
}
|
|
ret = &*f.first;
|
|
} else if (f.first->is_pseudo ()) {
|
|
ret = &*f.first;
|
|
}
|
|
|
|
} else {
|
|
|
|
std::map <NetTracerShape, std::vector<const NetTracerShape *> >::iterator n = m_shapes_graph.find (net_shape);
|
|
if (n == m_shapes_graph.end ()) {
|
|
|
|
n = m_shapes_graph.insert (std::make_pair (net_shape, std::vector<const NetTracerShape *> ())).first;
|
|
|
|
if (mp_progress) {
|
|
++(*mp_progress);
|
|
}
|
|
|
|
ret = &n->first;
|
|
|
|
} else if (n->first.is_pseudo ()) {
|
|
ret = &n->first;
|
|
}
|
|
|
|
if (adjacent) {
|
|
|
|
n->second.push_back (adjacent);
|
|
|
|
// Record the reverse interaction
|
|
std::map <NetTracerShape, std::vector<const NetTracerShape *> >::iterator m = m_shapes_graph.find (*adjacent);
|
|
m->second.push_back (&n->first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
NetTracer::determine_interactions (const std::vector<const NetTracerShape *> &seeds, const db::Box &combined_box, const std::set<unsigned int> &layers, std::set <std::pair<NetTracerShape, const NetTracerShape *> > &delivery, bool do_seed_assignment)
|
|
{
|
|
bool extract_full_graph = m_stop_shape.is_valid ();
|
|
|
|
HitTestDataBoxTree seed_tree;
|
|
for (std::vector<const NetTracerShape *>::const_iterator seed = seeds.begin (); seed != seeds.end (); ++seed) {
|
|
seed_tree.insert (*seed);
|
|
}
|
|
seed_tree.sort (HitTestDataBoxConverter ());
|
|
|
|
db::RecursiveShapeIterator net_shapes (layout (), cell (), layers, combined_box);
|
|
while (! net_shapes.at_end ()) {
|
|
|
|
NetTracerShape net_shape (net_shapes.trans (), net_shapes.shape (), net_shapes.layer (), net_shapes.cell_index ());
|
|
|
|
for (HitTestDataBoxTree::touching_iterator s = seed_tree.begin_touching (net_shape.bbox (), HitTestDataBoxConverter ()); ! s.at_end (); ++s) {
|
|
|
|
const NetTracerShape *seed = *s;
|
|
|
|
evaluate_text (net_shapes);
|
|
|
|
bool interact = false;
|
|
|
|
if (seed->shape ().is_box ()) {
|
|
|
|
if (seed->trans ().is_ortho ()) {
|
|
interact = interacts (seed->bbox (), net_shape);
|
|
} else {
|
|
db::Polygon box_poly (seed->shape ().box ());
|
|
box_poly.transform (db::ICplxTrans (seed->trans ()));
|
|
interact = interacts (box_poly, net_shape);
|
|
}
|
|
|
|
} else if (seed->shape ().is_polygon () || seed->shape ().is_path ()) {
|
|
db::Polygon p;
|
|
seed->shape ().polygon (p);
|
|
p.transform (db::ICplxTrans (seed->trans ()));
|
|
interact = interacts (p, net_shape);
|
|
}
|
|
|
|
if (interact) {
|
|
delivery.insert (std::make_pair (net_shape, do_seed_assignment ? seed : (const NetTracerShape *) 0));
|
|
if (! extract_full_graph) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
++net_shapes;
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
NetTracer::determine_interactions (const db::Box &seed, const NetTracerShape *shape, const std::set<unsigned int> &layers, std::set <std::pair<NetTracerShape, const NetTracerShape *> > &delivery)
|
|
{
|
|
db::RecursiveShapeIterator net_shapes (layout (), cell (), layers, seed);
|
|
while (! net_shapes.at_end ()) {
|
|
|
|
NetTracerShape net_shape (net_shapes.trans (), net_shapes.shape (), net_shapes.layer (), net_shapes.cell_index ());
|
|
|
|
evaluate_text (net_shapes);
|
|
|
|
if (interacts (seed, net_shape)) {
|
|
delivery.insert (std::make_pair (net_shape, shape));
|
|
}
|
|
|
|
++net_shapes;
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
NetTracer::determine_interactions (const db::Polygon &seed, const NetTracerShape *shape, const std::set<unsigned int> &layers, std::set <std::pair<NetTracerShape, const NetTracerShape *> > &delivery)
|
|
{
|
|
int area_ratio = 2;
|
|
|
|
db::Polygon::area_type poly_area = seed.area ();
|
|
db::Polygon::area_type box_area = seed.box ().area ();
|
|
|
|
if (poly_area == box_area && seed.vertices () == 4) {
|
|
|
|
// The polygon is a box
|
|
determine_interactions (seed.box (), shape, layers, delivery);
|
|
|
|
} else if (poly_area + 1 >= box_area / area_ratio) {
|
|
|
|
// The polygon is sufficiently "dense", so it can be used as it is.
|
|
db::RecursiveShapeIterator net_shapes (layout (), cell (), layers, seed.box ());
|
|
while (! net_shapes.at_end ()) {
|
|
|
|
NetTracerShape net_shape (net_shapes.trans (), net_shapes.shape (), net_shapes.layer (), net_shapes.cell_index ());
|
|
|
|
evaluate_text (net_shapes);
|
|
|
|
if (interacts (seed, net_shape)) {
|
|
delivery.insert (std::make_pair (net_shape, shape));
|
|
}
|
|
|
|
++net_shapes;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// otherwise split polygon and recursively treat these parts ...
|
|
std::vector <db::Polygon> polygons;
|
|
db::split_polygon (seed, polygons);
|
|
|
|
for (std::vector<db::Polygon>::const_iterator p = polygons.begin (); p != polygons.end (); ++p) {
|
|
determine_interactions (*p, shape, layers, delivery);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|