diff --git a/src/db/db/dbEdgeProcessor.cc b/src/db/db/dbEdgeProcessor.cc index 7119e5f8ac..08daaa8ab0 100644 --- a/src/db/db/dbEdgeProcessor.cc +++ b/src/db/db/dbEdgeProcessor.cc @@ -1595,6 +1595,14 @@ EdgeProcessor::process (db::EdgeSink &es, EdgeEvaluatorBase &op) process (procs); } +void +EdgeProcessor::redo (db::EdgeSink &es, EdgeEvaluatorBase &op) +{ + std::vector > procs; + procs.push_back (std::make_pair (&es, &op)); + redo (procs); +} + namespace { @@ -2137,8 +2145,20 @@ class EdgeProcessorStates } +void +EdgeProcessor::redo (const std::vector > &gen) +{ + redo_or_process (gen, true); +} + void EdgeProcessor::process (const std::vector > &gen) +{ + redo_or_process (gen, false); +} + +void +EdgeProcessor::redo_or_process (const std::vector > &gen, bool redo) { tl::SelfTimer timer (tl::verbosity () >= m_base_verbosity, "EdgeProcessor: process"); @@ -2160,6 +2180,8 @@ EdgeProcessor::process (const std::vectorclear (); + // count the properties + property_type n_props = 0; for (std::vector ::iterator e = mp_work_edges->begin (); e != mp_work_edges->end (); ++e) { if (e->prop > n_props) { @@ -2168,6 +2190,8 @@ EdgeProcessor::process (const std::vector progress; @@ -2186,119 +2210,149 @@ EdgeProcessor::process (const std::vectorbegin (), mp_work_edges->end (), edge_ymin_compare ()); + if (redo) { - y = edge_ymin ((*mp_work_edges) [0]); - future = mp_work_edges->begin (); + // redo mode: skip the intersection detection step and clear the data - for (std::vector ::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); + for (std::vector ::iterator c = mp_work_edges->begin (); c != mp_work_edges->end (); ++c) { + c->data = 0; } - size_t n = std::distance (current, future); - db::Coord yy = y; + todo = todo_next; + todo_next += (todo_max - todo) / 5; - // Use as many scanlines as to fetch approx. 50% new edges into the scanline (this - // is an empirically determined factor) - do { + } else { - while (future != mp_work_edges->end () && edge_ymin (*future) <= yy) { - ++future; - } + // step 2: find intersections + std::sort (mp_work_edges->begin (), mp_work_edges->end (), edge_ymin_compare ()); - if (future != mp_work_edges->end ()) { - yy = edge_ymin (*future); - } else { - yy = std::numeric_limits ::max (); + y = edge_ymin ((*mp_work_edges) [0]); + future = mp_work_edges->begin (); + + for (std::vector ::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); } - } while (future != mp_work_edges->end () && std::distance (current, future) < long (n + n / 2)); + size_t n = std::distance (current, future); + db::Coord yy = y; - bool is90 = true; + // Use as many scanlines as to fetch approx. 50% new edges into the scanline (this + // is an empirically determined factor) + do { - if (current != future) { + while (future != mp_work_edges->end () && edge_ymin (*future) <= yy) { + ++future; + } - for (std::vector ::iterator c = current; c != future && is90; ++c) { - if (c->dx () != 0 && c->dy () != 0) { - is90 = false; + if (future != mp_work_edges->end ()) { + yy = edge_ymin (*future); + } else { + yy = std::numeric_limits ::max (); } - } - 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)); - } + bool is90 = true; + + if (current != future) { + + for (std::vector ::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); + } + + } - y = yy; - for (std::vector ::iterator c = current; c != future; ++c) { - // 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); + y = yy; + for (std::vector ::iterator c = current; c != future; ++c) { + // 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; } - ++current; } + } - - } - // step 3: create new edges from the ones with cutpoints - // - // 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; + // step 3: create new edges from the ones with cutpoints + // + // 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. - size_t n_work = mp_work_edges->size (); - size_t nw = 0; - for (size_t n = 0; n < n_work; ++n) { + todo = todo_next; + todo_next += (todo_max - todo) / 5; - if (m_report_progress) { - double p = double (n) / double (n_work); - progress->set (size_t (double (todo_next - todo) * p) + todo); - } + size_t n_work = mp_work_edges->size (); + size_t nw = 0; + for (size_t n = 0; n < n_work; ++n) { - WorkEdge &ew = (*mp_work_edges) [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]; - CutPoints *cut_points = ew.data ? & ((*mp_cpvector) [ew.data - 1]) : 0; - ew.data = 0; + CutPoints *cut_points = ew.data ? & ((*mp_cpvector) [ew.data - 1]) : 0; + ew.data = 0; - if (ew.dy () == 0 && ! selects_edges) { + if (ew.dy () == 0 && ! selects_edges) { - // don't care about horizontal edges + // don't care about horizontal edges - } else if (cut_points) { + } else if (cut_points) { - if (cut_points->has_cutpoints && ! cut_points->cut_points.empty ()) { + 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::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 (); + db::Point pll = e.p1 (); + db::Point pl = e.p1 (); - for (std::vector ::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); + for (std::vector ::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 ()) { + 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 (cut_points->cut_points.back () != e.p2 ()) { + WorkEdge ne = WorkEdge (db::Edge (pl, e.p2 ()), 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; @@ -2307,22 +2361,14 @@ EdgeProcessor::process (const std::vectorcut_points.back () != e.p2 ()) { - WorkEdge ne = WorkEdge (db::Edge (pl, e.p2 ()), 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); - } - if (selects_edges || ne.dy () != 0) { - if (nw <= n) { - (*mp_work_edges) [nw++] = ne; - } else { - mp_work_edges->push_back (ne); - } + } else { + + if (nw < n) { + (*mp_work_edges) [nw] = (*mp_work_edges) [n]; } + ++nw; + } } else { @@ -2334,28 +2380,21 @@ EdgeProcessor::process (const std::vectorerase (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 - printf ("Output edges:\n"); - for (std::vector ::iterator c1 = mp_work_edges->begin (); c1 != mp_work_edges->end (); ++c1) { - printf ("%s\n", c1->to_string().c_str ()); - } + printf ("Output edges:\n"); + for (std::vector ::iterator c1 = mp_work_edges->begin (); c1 != mp_work_edges->end (); ++c1) { + printf ("%s\n", c1->to_string().c_str ()); + } #endif + } + tl::SelfTimer timer2 (tl::verbosity () >= m_base_verbosity + 10, "EdgeProcessor: production"); @@ -2558,7 +2597,7 @@ EdgeProcessor::process (const std::vector::iterator c = current; c != future; ++c) { + for (std::vector ::iterator c = current; c != future; ++c) { printf ("%ld-", long (c->data)); } printf ("\n"); @@ -2579,7 +2618,7 @@ EdgeProcessor::process (const std::vector= y) { --current; if (current != c) { - *current = *c; + std::swap (*current, *c); } } if (ymax <= y) { @@ -2603,7 +2642,7 @@ EdgeProcessor::process (const std::vector::iterator c = current; c != future; ++c) { + for (std::vector ::iterator c = current; c != future; ++c) { printf ("%ld-", long (c->data)); } printf ("\n"); diff --git a/src/db/db/dbEdgeProcessor.h b/src/db/db/dbEdgeProcessor.h index c6c02bafde..b0e336019f 100644 --- a/src/db/db/dbEdgeProcessor.h +++ b/src/db/db/dbEdgeProcessor.h @@ -672,9 +672,9 @@ class DB_PUBLIC EdgeProcessor } /** - * @brief Clear all edges stored currently in this processor + * @brief Clears all edges stored currently in this processor */ - void clear (); + void clear (); /** * @brief Performs the actual processing @@ -693,6 +693,24 @@ class DB_PUBLIC EdgeProcessor */ void process (const std::vector > &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 > &gen); + /** * @brief Merge the given polygons in a simple "non-zero wrapcount" fashion * @@ -996,6 +1014,8 @@ class DB_PUBLIC EdgeProcessor } return n; } + + void redo_or_process (const std::vector > &gen, bool redo); }; } diff --git a/src/db/unit_tests/dbEdgeProcessorTests.cc b/src/db/unit_tests/dbEdgeProcessorTests.cc index e4c823dce1..830ed72190 100644 --- a/src/db/unit_tests/dbEdgeProcessorTests.cc +++ b/src/db/unit_tests/dbEdgeProcessorTests.cc @@ -2629,6 +2629,24 @@ TEST(103) // 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 + + // 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 diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index 8a98ab2c4e..5f0be90ab2 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -51,13 +51,7 @@ class D25Plugin void menu_activated (const std::string &symbol) { if (symbol == "lay::d25_view") { - - if (mp_dialog->exec_dialog (mp_view)) { - - // ... implementation is in layD25ToolDialog.cc ... - - } - + mp_dialog->exec_dialog (mp_view); } } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 7e9ce7b096..c3e4f1cc9f 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -30,6 +30,7 @@ #include "dbEdgeProcessor.h" #include "dbPolygonGenerators.h" #include "dbPolygonTools.h" +#include "dbClip.h" #include "tlException.h" @@ -538,7 +539,6 @@ D25ViewWidget::prepare_view () m_layers.clear (); m_vertex_chunks.clear (); - m_bbox = db::DBox (); bool zset = false; m_zmin = m_zmax = 0.0; @@ -547,6 +547,8 @@ D25ViewWidget::prepare_view () return false; } + m_bbox = mp_view->viewport ().box (); + ZDataCache zdata; bool any = false; @@ -577,9 +579,7 @@ D25ViewWidget::prepare_view () m_layers.push_back (info); 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); - - m_bbox += db::DBox (cv.cell ()->bbox ((unsigned int) lp->layer_index ())) * cv->layout ().dbu (); + 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); if (! zset) { m_zmin = z0; @@ -600,7 +600,22 @@ D25ViewWidget::prepare_view () void 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 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::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 poly_heap; @@ -654,13 +669,13 @@ D25ViewWidget::render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge & } 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 poly_heap; // 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); for ( ; ! s.at_end (); ++s) { @@ -668,46 +683,15 @@ D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layo s->polygon (polygon); polygon.transform (s.trans ()); - if (polygon.holes () == 0 && polygon.hull ().size () <= 4) { - - render_polygon (chunks, polygon, layout.dbu (), zstart, zstop); - - for (db::Polygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) { - 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); - } + poly_heap.clear (); + db::clip_poly (polygon, clip_box, poly_heap, false /*keep holes*/); - for (std::vector::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) { - render_polygon (chunks, *p, layout.dbu (), zstart, zstop); - } - - poly_heap.clear (); - ep.clear (); + for (std::vector::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) { - 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); - } + render_polygon (chunks, *p, layout.dbu (), zstart, zstop); - for (std::vector::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); - } + for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { + render_wall (chunks, *e, layout.dbu (), zstart, zstop); } } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index 6c5e219959..cee0c67e58 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -149,7 +149,7 @@ public slots: void do_initialize_gl (); 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_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop); };