mirror of https://github.com/KLayout/klayout.git
Merge branch 'clipped-25d-view'
This commit is contained in:
commit
2bbf6b6998
|
|
@ -1595,6 +1595,14 @@ EdgeProcessor::process (db::EdgeSink &es, EdgeEvaluatorBase &op)
|
||||||
process (procs);
|
process (procs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EdgeProcessor::redo (db::EdgeSink &es, EdgeEvaluatorBase &op)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > procs;
|
||||||
|
procs.push_back (std::make_pair (&es, &op));
|
||||||
|
redo (procs);
|
||||||
|
}
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -2137,8 +2145,20 @@ private:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EdgeProcessor::redo (const std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > &gen)
|
||||||
|
{
|
||||||
|
redo_or_process (gen, true);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
EdgeProcessor::process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > &gen)
|
EdgeProcessor::process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > &gen)
|
||||||
|
{
|
||||||
|
redo_or_process (gen, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
EdgeProcessor::redo_or_process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > &gen, bool redo)
|
||||||
{
|
{
|
||||||
tl::SelfTimer timer (tl::verbosity () >= m_base_verbosity, "EdgeProcessor: process");
|
tl::SelfTimer timer (tl::verbosity () >= m_base_verbosity, "EdgeProcessor: process");
|
||||||
|
|
||||||
|
|
@ -2160,6 +2180,8 @@ EdgeProcessor::process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEval
|
||||||
|
|
||||||
mp_cpvector->clear ();
|
mp_cpvector->clear ();
|
||||||
|
|
||||||
|
// count the properties
|
||||||
|
|
||||||
property_type n_props = 0;
|
property_type n_props = 0;
|
||||||
for (std::vector <WorkEdge>::iterator e = mp_work_edges->begin (); e != mp_work_edges->end (); ++e) {
|
for (std::vector <WorkEdge>::iterator e = mp_work_edges->begin (); e != mp_work_edges->end (); ++e) {
|
||||||
if (e->prop > n_props) {
|
if (e->prop > n_props) {
|
||||||
|
|
@ -2168,6 +2190,8 @@ EdgeProcessor::process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEval
|
||||||
}
|
}
|
||||||
++n_props;
|
++n_props;
|
||||||
|
|
||||||
|
// prepare progress
|
||||||
|
|
||||||
size_t todo_max = 1000000;
|
size_t todo_max = 1000000;
|
||||||
|
|
||||||
std::unique_ptr<tl::AbsoluteProgress> progress;
|
std::unique_ptr<tl::AbsoluteProgress> progress;
|
||||||
|
|
@ -2186,119 +2210,149 @@ EdgeProcessor::process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEval
|
||||||
todo_next += (todo_max - todo) / 5;
|
todo_next += (todo_max - todo) / 5;
|
||||||
|
|
||||||
|
|
||||||
// step 2: find intersections
|
if (redo) {
|
||||||
std::sort (mp_work_edges->begin (), mp_work_edges->end (), edge_ymin_compare<db::Coord> ());
|
|
||||||
|
|
||||||
y = edge_ymin ((*mp_work_edges) [0]);
|
// redo mode: skip the intersection detection step and clear the data
|
||||||
future = mp_work_edges->begin ();
|
|
||||||
|
|
||||||
for (std::vector <WorkEdge>::iterator current = mp_work_edges->begin (); current != mp_work_edges->end (); ) {
|
for (std::vector <WorkEdge>::iterator c = mp_work_edges->begin (); c != mp_work_edges->end (); ++c) {
|
||||||
|
c->data = 0;
|
||||||
if (m_report_progress) {
|
|
||||||
double p = double (std::distance (mp_work_edges->begin (), current)) / double (mp_work_edges->size ());
|
|
||||||
progress->set (size_t (double (todo_next - todo) * p) + todo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t n = std::distance (current, future);
|
todo = todo_next;
|
||||||
db::Coord yy = y;
|
todo_next += (todo_max - todo) / 5;
|
||||||
|
|
||||||
// Use as many scanlines as to fetch approx. 50% new edges into the scanline (this
|
} else {
|
||||||
// is an empirically determined factor)
|
|
||||||
do {
|
|
||||||
|
|
||||||
while (future != mp_work_edges->end () && edge_ymin (*future) <= yy) {
|
// step 2: find intersections
|
||||||
++future;
|
std::sort (mp_work_edges->begin (), mp_work_edges->end (), edge_ymin_compare<db::Coord> ());
|
||||||
|
|
||||||
|
y = edge_ymin ((*mp_work_edges) [0]);
|
||||||
|
future = mp_work_edges->begin ();
|
||||||
|
|
||||||
|
for (std::vector <WorkEdge>::iterator current = mp_work_edges->begin (); current != mp_work_edges->end (); ) {
|
||||||
|
|
||||||
|
if (m_report_progress) {
|
||||||
|
double p = double (std::distance (mp_work_edges->begin (), current)) / double (mp_work_edges->size ());
|
||||||
|
progress->set (size_t (double (todo_next - todo) * p) + todo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (future != mp_work_edges->end ()) {
|
size_t n = std::distance (current, future);
|
||||||
yy = edge_ymin (*future);
|
db::Coord yy = y;
|
||||||
} else {
|
|
||||||
yy = std::numeric_limits <db::Coord>::max ();
|
// Use as many scanlines as to fetch approx. 50% new edges into the scanline (this
|
||||||
|
// is an empirically determined factor)
|
||||||
|
do {
|
||||||
|
|
||||||
|
while (future != mp_work_edges->end () && edge_ymin (*future) <= yy) {
|
||||||
|
++future;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (future != mp_work_edges->end ()) {
|
||||||
|
yy = edge_ymin (*future);
|
||||||
|
} else {
|
||||||
|
yy = std::numeric_limits <db::Coord>::max ();
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (future != mp_work_edges->end () && std::distance (current, future) < long (n + n / 2));
|
||||||
|
|
||||||
|
bool is90 = true;
|
||||||
|
|
||||||
|
if (current != future) {
|
||||||
|
|
||||||
|
for (std::vector <WorkEdge>::iterator c = current; c != future && is90; ++c) {
|
||||||
|
if (c->dx () != 0 && c->dy () != 0) {
|
||||||
|
is90 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is90) {
|
||||||
|
get_intersections_per_band_90 (*mp_cpvector, current, future, y, yy, selects_edges);
|
||||||
|
} else {
|
||||||
|
get_intersections_per_band_any (*mp_cpvector, current, future, y, yy, selects_edges);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (future != mp_work_edges->end () && std::distance (current, future) < long (n + n / 2));
|
y = yy;
|
||||||
|
for (std::vector <WorkEdge>::iterator c = current; c != future; ++c) {
|
||||||
bool is90 = true;
|
// Hint: we have to keep the edges ending a y (the new lower band limit) in the all angle case because these edges
|
||||||
|
// may receive cutpoints because the enter the -0.5DBU region below the band
|
||||||
if (current != future) {
|
if ((!is90 && edge_ymax (*c) < y) || (is90 && edge_ymax (*c) <= y)) {
|
||||||
|
if (current != c) {
|
||||||
for (std::vector <WorkEdge>::iterator c = current; c != future && is90; ++c) {
|
std::swap (*current, *c);
|
||||||
if (c->dx () != 0 && c->dy () != 0) {
|
}
|
||||||
is90 = false;
|
++current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is90) {
|
}
|
||||||
get_intersections_per_band_90 (*mp_cpvector, current, future, y, yy, selects_edges);
|
|
||||||
} else {
|
// step 3: create new edges from the ones with cutpoints
|
||||||
get_intersections_per_band_any (*mp_cpvector, current, future, y, yy, selects_edges);
|
//
|
||||||
|
// Hint: when we create the edges from the cutpoints we use the projection to sort the cutpoints along the
|
||||||
|
// edge. However, we have some freedom to connect the points which we use to avoid "z" configurations which could
|
||||||
|
// create new intersections in a 1x1 pixel box.
|
||||||
|
|
||||||
|
todo = todo_next;
|
||||||
|
todo_next += (todo_max - todo) / 5;
|
||||||
|
|
||||||
|
size_t n_work = mp_work_edges->size ();
|
||||||
|
size_t nw = 0;
|
||||||
|
for (size_t n = 0; n < n_work; ++n) {
|
||||||
|
|
||||||
|
if (m_report_progress) {
|
||||||
|
double p = double (n) / double (n_work);
|
||||||
|
progress->set (size_t (double (todo_next - todo) * p) + todo);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
WorkEdge &ew = (*mp_work_edges) [n];
|
||||||
|
|
||||||
y = yy;
|
CutPoints *cut_points = ew.data ? & ((*mp_cpvector) [ew.data - 1]) : 0;
|
||||||
for (std::vector <WorkEdge>::iterator c = current; c != future; ++c) {
|
ew.data = 0;
|
||||||
// Hint: we have to keep the edges ending a y (the new lower band limit) in the all angle case because these edges
|
|
||||||
// may receive cutpoints because the enter the -0.5DBU region below the band
|
|
||||||
if ((!is90 && edge_ymax (*c) < y) || (is90 && edge_ymax (*c) <= y)) {
|
|
||||||
if (current != c) {
|
|
||||||
std::swap (*current, *c);
|
|
||||||
}
|
|
||||||
++current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
if (ew.dy () == 0 && ! selects_edges) {
|
||||||
|
|
||||||
// step 3: create new edges from the ones with cutpoints
|
// don't care about horizontal edges
|
||||||
//
|
|
||||||
// Hint: when we create the edges from the cutpoints we use the projection to sort the cutpoints along the
|
|
||||||
// edge. However, we have some freedom to connect the points which we use to avoid "z" configurations which could
|
|
||||||
// create new intersections in a 1x1 pixel box.
|
|
||||||
|
|
||||||
todo = todo_next;
|
} else if (cut_points) {
|
||||||
todo_next += (todo_max - todo) / 5;
|
|
||||||
|
|
||||||
size_t n_work = mp_work_edges->size ();
|
if (cut_points->has_cutpoints && ! cut_points->cut_points.empty ()) {
|
||||||
size_t nw = 0;
|
|
||||||
for (size_t n = 0; n < n_work; ++n) {
|
|
||||||
|
|
||||||
if (m_report_progress) {
|
db::Edge e = ew;
|
||||||
double p = double (n) / double (n_work);
|
property_type p = ew.prop;
|
||||||
progress->set (size_t (double (todo_next - todo) * p) + todo);
|
std::sort (cut_points->cut_points.begin (), cut_points->cut_points.end (), ProjectionCompare (e));
|
||||||
}
|
|
||||||
|
|
||||||
WorkEdge &ew = (*mp_work_edges) [n];
|
db::Point pll = e.p1 ();
|
||||||
|
db::Point pl = e.p1 ();
|
||||||
|
|
||||||
CutPoints *cut_points = ew.data ? & ((*mp_cpvector) [ew.data - 1]) : 0;
|
for (std::vector <db::Point>::iterator cp = cut_points->cut_points.begin (); cp != cut_points->cut_points.end (); ++cp) {
|
||||||
ew.data = 0;
|
if (*cp != pl) {
|
||||||
|
WorkEdge ne = WorkEdge (db::Edge (pl, *cp), p);
|
||||||
|
if (pl.y () == pll.y () && ne.p2 ().x () != pl.x () && ne.p2 ().x () == pll.x ()) {
|
||||||
|
ne = db::Edge (pll, ne.p2 ());
|
||||||
|
} else if (pl.x () == pll.x () && ne.p2 ().y () != pl.y () && ne.p2 ().y () == pll.y ()) {
|
||||||
|
ne = db::Edge (ne.p1 (), pll);
|
||||||
|
} else {
|
||||||
|
pll = pl;
|
||||||
|
}
|
||||||
|
pl = *cp;
|
||||||
|
if (selects_edges || ne.dy () != 0) {
|
||||||
|
if (nw <= n) {
|
||||||
|
(*mp_work_edges) [nw++] = ne;
|
||||||
|
} else {
|
||||||
|
mp_work_edges->push_back (ne);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ew.dy () == 0 && ! selects_edges) {
|
if (cut_points->cut_points.back () != e.p2 ()) {
|
||||||
|
WorkEdge ne = WorkEdge (db::Edge (pl, e.p2 ()), p);
|
||||||
// don't care about horizontal edges
|
|
||||||
|
|
||||||
} else if (cut_points) {
|
|
||||||
|
|
||||||
if (cut_points->has_cutpoints && ! cut_points->cut_points.empty ()) {
|
|
||||||
|
|
||||||
db::Edge e = ew;
|
|
||||||
property_type p = ew.prop;
|
|
||||||
std::sort (cut_points->cut_points.begin (), cut_points->cut_points.end (), ProjectionCompare (e));
|
|
||||||
|
|
||||||
db::Point pll = e.p1 ();
|
|
||||||
db::Point pl = e.p1 ();
|
|
||||||
|
|
||||||
for (std::vector <db::Point>::iterator cp = cut_points->cut_points.begin (); cp != cut_points->cut_points.end (); ++cp) {
|
|
||||||
if (*cp != pl) {
|
|
||||||
WorkEdge ne = WorkEdge (db::Edge (pl, *cp), p);
|
|
||||||
if (pl.y () == pll.y () && ne.p2 ().x () != pl.x () && ne.p2 ().x () == pll.x ()) {
|
if (pl.y () == pll.y () && ne.p2 ().x () != pl.x () && ne.p2 ().x () == pll.x ()) {
|
||||||
ne = db::Edge (pll, ne.p2 ());
|
ne = db::Edge (pll, ne.p2 ());
|
||||||
} else if (pl.x () == pll.x () && ne.p2 ().y () != pl.y () && ne.p2 ().y () == pll.y ()) {
|
} else if (pl.x () == pll.x () && ne.p2 ().y () != pl.y () && ne.p2 ().y () == pll.y ()) {
|
||||||
ne = db::Edge (ne.p1 (), pll);
|
ne = db::Edge (ne.p1 (), pll);
|
||||||
} else {
|
|
||||||
pll = pl;
|
|
||||||
}
|
}
|
||||||
pl = *cp;
|
|
||||||
if (selects_edges || ne.dy () != 0) {
|
if (selects_edges || ne.dy () != 0) {
|
||||||
if (nw <= n) {
|
if (nw <= n) {
|
||||||
(*mp_work_edges) [nw++] = ne;
|
(*mp_work_edges) [nw++] = ne;
|
||||||
|
|
@ -2307,22 +2361,14 @@ EdgeProcessor::process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (cut_points->cut_points.back () != e.p2 ()) {
|
} else {
|
||||||
WorkEdge ne = WorkEdge (db::Edge (pl, e.p2 ()), p);
|
|
||||||
if (pl.y () == pll.y () && ne.p2 ().x () != pl.x () && ne.p2 ().x () == pll.x ()) {
|
if (nw < n) {
|
||||||
ne = db::Edge (pll, ne.p2 ());
|
(*mp_work_edges) [nw] = (*mp_work_edges) [n];
|
||||||
} else if (pl.x () == pll.x () && ne.p2 ().y () != pl.y () && ne.p2 ().y () == pll.y ()) {
|
|
||||||
ne = db::Edge (ne.p1 (), pll);
|
|
||||||
}
|
|
||||||
if (selects_edges || ne.dy () != 0) {
|
|
||||||
if (nw <= n) {
|
|
||||||
(*mp_work_edges) [nw++] = ne;
|
|
||||||
} else {
|
|
||||||
mp_work_edges->push_back (ne);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
++nw;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2334,28 +2380,21 @@ EdgeProcessor::process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEval
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (nw < n) {
|
|
||||||
(*mp_work_edges) [nw] = (*mp_work_edges) [n];
|
|
||||||
}
|
|
||||||
++nw;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (nw != n_work) {
|
||||||
|
mp_work_edges->erase (mp_work_edges->begin () + nw, mp_work_edges->begin () + n_work);
|
||||||
if (nw != n_work) {
|
}
|
||||||
mp_work_edges->erase (mp_work_edges->begin () + nw, mp_work_edges->begin () + n_work);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
#ifdef DEBUG_EDGE_PROCESSOR
|
||||||
printf ("Output edges:\n");
|
printf ("Output edges:\n");
|
||||||
for (std::vector <WorkEdge>::iterator c1 = mp_work_edges->begin (); c1 != mp_work_edges->end (); ++c1) {
|
for (std::vector <WorkEdge>::iterator c1 = mp_work_edges->begin (); c1 != mp_work_edges->end (); ++c1) {
|
||||||
printf ("%s\n", c1->to_string().c_str ());
|
printf ("%s\n", c1->to_string().c_str ());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
tl::SelfTimer timer2 (tl::verbosity () >= m_base_verbosity + 10, "EdgeProcessor: production");
|
tl::SelfTimer timer2 (tl::verbosity () >= m_base_verbosity + 10, "EdgeProcessor: production");
|
||||||
|
|
||||||
|
|
@ -2579,7 +2618,7 @@ EdgeProcessor::process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEval
|
||||||
if (ymax >= y) {
|
if (ymax >= y) {
|
||||||
--current;
|
--current;
|
||||||
if (current != c) {
|
if (current != c) {
|
||||||
*current = *c;
|
std::swap (*current, *c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ymax <= y) {
|
if (ymax <= y) {
|
||||||
|
|
|
||||||
|
|
@ -672,7 +672,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clear all edges stored currently in this processor
|
* @brief Clears all edges stored currently in this processor
|
||||||
*/
|
*/
|
||||||
void clear ();
|
void clear ();
|
||||||
|
|
||||||
|
|
@ -693,6 +693,24 @@ public:
|
||||||
*/
|
*/
|
||||||
void process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > &gen);
|
void process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > &gen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs the actual processing again
|
||||||
|
*
|
||||||
|
* This method can be called after "process" was used and will re-run the
|
||||||
|
* scanline algorithm. This is somewhat more efficient as the initial
|
||||||
|
* sorting and edge clipping can be skipped.
|
||||||
|
*/
|
||||||
|
void redo (db::EdgeSink &es, EdgeEvaluatorBase &op);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs the actual processing again
|
||||||
|
*
|
||||||
|
* This method can be called after "process" was used and will re-run the
|
||||||
|
* scanline algorithm. This is somewhat more efficient as the initial
|
||||||
|
* sorting and edge clipping can be skipped.
|
||||||
|
*/
|
||||||
|
void redo (const std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > &gen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Merge the given polygons in a simple "non-zero wrapcount" fashion
|
* @brief Merge the given polygons in a simple "non-zero wrapcount" fashion
|
||||||
*
|
*
|
||||||
|
|
@ -996,6 +1014,8 @@ private:
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void redo_or_process (const std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > &gen, bool redo);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2629,6 +2629,26 @@ TEST(103)
|
||||||
// elaborate hole treatment
|
// elaborate hole treatment
|
||||||
EXPECT_EQ (out[0].to_string (), "(0,0;0,400;100,400;100,100;400,100;400,400;0,400;0,500;1500,500;1500,0;1000,0;1000,400;1100,400;1100,100;1400,100;1400,400;500,400;500,0)");
|
EXPECT_EQ (out[0].to_string (), "(0,0;0,400;100,400;100,100;400,100;400,400;0,400;0,500;1500,500;1500,0;1000,0;1000,400;1100,400;1100,100;1400,100;1400,400;500,400;500,0)");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// test "redo" on this occasion
|
||||||
|
|
||||||
|
// @@@
|
||||||
|
db::PolygonContainer pc2 (out);
|
||||||
|
db::PolygonGenerator pg2 (pc2, true, true);
|
||||||
|
db::BooleanOp op2 (db::BooleanOp::ANotB);
|
||||||
|
|
||||||
|
out.clear ();
|
||||||
|
ep.redo (pg2, op2);
|
||||||
|
// @@@
|
||||||
|
|
||||||
|
EXPECT_EQ (out.size (), size_t (1));
|
||||||
|
#if 1
|
||||||
|
// fast hole treatment
|
||||||
|
EXPECT_EQ (out[0].to_string (), "(0,0;0,400;100,400;100,100;400,100;400,400;1100,400;1100,100;1400,100;1400,400;0,400;0,500;1500,500;1500,0;1000,0;1000,400;500,400;500,0)");
|
||||||
|
#else
|
||||||
|
// elaborate hole treatment
|
||||||
|
EXPECT_EQ (out[0].to_string (), "(0,0;0,400;100,400;100,100;400,100;400,400;0,400;0,500;1500,500;1500,0;1000,0;1000,400;1100,400;1100,100;1400,100;1400,400;500,400;500,0)");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bug 134
|
// Bug 134
|
||||||
|
|
|
||||||
|
|
@ -51,13 +51,7 @@ public:
|
||||||
void menu_activated (const std::string &symbol)
|
void menu_activated (const std::string &symbol)
|
||||||
{
|
{
|
||||||
if (symbol == "lay::d25_view") {
|
if (symbol == "lay::d25_view") {
|
||||||
|
mp_dialog->exec_dialog (mp_view);
|
||||||
if (mp_dialog->exec_dialog (mp_view)) {
|
|
||||||
|
|
||||||
// ... implementation is in layD25ToolDialog.cc ...
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include "dbEdgeProcessor.h"
|
#include "dbEdgeProcessor.h"
|
||||||
#include "dbPolygonGenerators.h"
|
#include "dbPolygonGenerators.h"
|
||||||
#include "dbPolygonTools.h"
|
#include "dbPolygonTools.h"
|
||||||
|
#include "dbClip.h"
|
||||||
|
|
||||||
#include "tlException.h"
|
#include "tlException.h"
|
||||||
|
|
||||||
|
|
@ -538,7 +539,6 @@ D25ViewWidget::prepare_view ()
|
||||||
m_layers.clear ();
|
m_layers.clear ();
|
||||||
m_vertex_chunks.clear ();
|
m_vertex_chunks.clear ();
|
||||||
|
|
||||||
m_bbox = db::DBox ();
|
|
||||||
bool zset = false;
|
bool zset = false;
|
||||||
m_zmin = m_zmax = 0.0;
|
m_zmin = m_zmax = 0.0;
|
||||||
|
|
||||||
|
|
@ -547,6 +547,8 @@ D25ViewWidget::prepare_view ()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_bbox = mp_view->viewport ().box ();
|
||||||
|
|
||||||
ZDataCache zdata;
|
ZDataCache zdata;
|
||||||
bool any = false;
|
bool any = false;
|
||||||
|
|
||||||
|
|
@ -577,9 +579,7 @@ D25ViewWidget::prepare_view ()
|
||||||
m_layers.push_back (info);
|
m_layers.push_back (info);
|
||||||
|
|
||||||
const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ());
|
const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ());
|
||||||
render_layout (m_vertex_chunks.back (), cv->layout (), *cv.cell (), (unsigned int) lp->layer_index (), z0, z1);
|
render_layout (m_vertex_chunks.back (), cv->layout (), *cv.cell (), db::CplxTrans (cv->layout ().dbu ()).inverted () * m_bbox, (unsigned int) lp->layer_index (), z0, z1);
|
||||||
|
|
||||||
m_bbox += db::DBox (cv.cell ()->bbox ((unsigned int) lp->layer_index ())) * cv->layout ().dbu ();
|
|
||||||
|
|
||||||
if (! zset) {
|
if (! zset) {
|
||||||
m_zmin = z0;
|
m_zmin = z0;
|
||||||
|
|
@ -600,7 +600,22 @@ D25ViewWidget::prepare_view ()
|
||||||
void
|
void
|
||||||
D25ViewWidget::render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop)
|
D25ViewWidget::render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop)
|
||||||
{
|
{
|
||||||
if (poly.hull ().size () > 4) {
|
if (poly.holes () > 0) {
|
||||||
|
|
||||||
|
std::vector<db::Polygon> poly_heap;
|
||||||
|
|
||||||
|
db::EdgeProcessor ep;
|
||||||
|
ep.insert_sequence (poly.begin_edge ());
|
||||||
|
db::PolygonContainer pc (poly_heap);
|
||||||
|
db::PolygonGenerator out (pc, true /*resolve holes*/, true /*min coherence*/);
|
||||||
|
db::SimpleMerge op;
|
||||||
|
ep.process (out, op);
|
||||||
|
|
||||||
|
for (std::vector<db::Polygon>::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) {
|
||||||
|
render_polygon (chunks, *p, dbu, zstart, zstop);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (poly.hull ().size () > 4) {
|
||||||
|
|
||||||
std::vector<db::Polygon> poly_heap;
|
std::vector<db::Polygon> poly_heap;
|
||||||
|
|
||||||
|
|
@ -654,13 +669,13 @@ D25ViewWidget::render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop)
|
D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, const db::Box &clip_box, unsigned int layer, double zstart, double zstop)
|
||||||
{
|
{
|
||||||
db::EdgeProcessor ep;
|
|
||||||
std::vector<db::Polygon> poly_heap;
|
std::vector<db::Polygon> poly_heap;
|
||||||
|
|
||||||
// TODO: hidden cells, hierarchy depth ...
|
// TODO: hidden cells, hierarchy depth ...
|
||||||
db::RecursiveShapeIterator s (layout, cell, layer);
|
|
||||||
|
db::RecursiveShapeIterator s (layout, cell, layer, clip_box);
|
||||||
s.shape_flags (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes);
|
s.shape_flags (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes);
|
||||||
for ( ; ! s.at_end (); ++s) {
|
for ( ; ! s.at_end (); ++s) {
|
||||||
|
|
||||||
|
|
@ -668,48 +683,17 @@ D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layo
|
||||||
s->polygon (polygon);
|
s->polygon (polygon);
|
||||||
polygon.transform (s.trans ());
|
polygon.transform (s.trans ());
|
||||||
|
|
||||||
if (polygon.holes () == 0 && polygon.hull ().size () <= 4) {
|
poly_heap.clear ();
|
||||||
|
db::clip_poly (polygon, clip_box, poly_heap, false /*keep holes*/);
|
||||||
|
|
||||||
render_polygon (chunks, polygon, layout.dbu (), zstart, zstop);
|
for (std::vector<db::Polygon>::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) {
|
||||||
|
|
||||||
for (db::Polygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) {
|
render_polygon (chunks, *p, layout.dbu (), zstart, zstop);
|
||||||
|
|
||||||
|
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
|
||||||
render_wall (chunks, *e, layout.dbu (), zstart, zstop);
|
render_wall (chunks, *e, layout.dbu (), zstart, zstop);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
poly_heap.clear ();
|
|
||||||
ep.clear ();
|
|
||||||
|
|
||||||
ep.insert_sequence (polygon.begin_edge ());
|
|
||||||
{
|
|
||||||
db::PolygonContainer pc (poly_heap);
|
|
||||||
db::PolygonGenerator out (pc, true /*resolve holes*/, false /*min coherence for splitting*/);
|
|
||||||
db::SimpleMerge op;
|
|
||||||
ep.process (out, op);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::vector<db::Polygon>::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) {
|
|
||||||
render_polygon (chunks, *p, layout.dbu (), zstart, zstop);
|
|
||||||
}
|
|
||||||
|
|
||||||
poly_heap.clear ();
|
|
||||||
ep.clear ();
|
|
||||||
|
|
||||||
ep.insert_sequence (polygon.begin_edge ());
|
|
||||||
{
|
|
||||||
db::PolygonContainer pc (poly_heap);
|
|
||||||
db::PolygonGenerator out (pc, false /*don't resolve holes*/, false /*min coherence for splitting*/);
|
|
||||||
db::SimpleMerge op;
|
|
||||||
ep.process (out, op);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::vector<db::Polygon>::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) {
|
|
||||||
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
|
|
||||||
render_wall (chunks, *e, layout.dbu (), zstart, zstop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ private:
|
||||||
|
|
||||||
void do_initialize_gl ();
|
void do_initialize_gl ();
|
||||||
bool prepare_view();
|
bool prepare_view();
|
||||||
void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop);
|
void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, const db::Box &clip_box, unsigned int layer, double zstart, double zstop);
|
||||||
void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop);
|
void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop);
|
||||||
void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop);
|
void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue