diff --git a/src/db/db/dbFillTool.cc b/src/db/db/dbFillTool.cc index 5845bde85..809049824 100644 --- a/src/db/db/dbFillTool.cc +++ b/src/db/db/dbFillTool.cc @@ -628,9 +628,9 @@ fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons); } -DB_PUBLIC void -fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, - db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons) +static void +fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, + db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, int iteration) { if (row_step.x () <= 0 || column_step.y () <= 0) { throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row step must have a positive x component while column step must have a positive y component"))); @@ -642,11 +642,27 @@ fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell std::vector rem_pp, rem_poly; + size_t n = 0; for (db::Region::const_iterator p = fr.begin_merged (); !p.at_end (); ++p) { - if (!fill_region (cell, *p, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts ? &rem_pp : 0, fill_margin)) { - if (remaining_polygons) { - rem_poly.push_back (*p); + ++n; + } + + { + std::string progress_title; + if (iteration > 0) { + progress_title = tl::sprintf (tl::to_string (tr ("Fill polygons (iteration #%d)")), iteration); + } else { + progress_title = tl::sprintf (tl::to_string (tr ("Fill polygons"))); + } + tl::RelativeProgress progress (progress_title, n); + + for (db::Region::const_iterator p = fr.begin_merged (); !p.at_end (); ++p) { + if (!fill_region (cell, *p, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts ? &rem_pp : 0, fill_margin)) { + if (remaining_polygons) { + rem_poly.push_back (*p); + } } + ++progress; } } @@ -669,4 +685,35 @@ fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell } } +DB_PUBLIC void +fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, + db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons) +{ + fill_region_impl (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0); +} + +DB_PUBLIC void +fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, + const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, + const db::Vector &fill_margin, db::Region *remaining_polygons) +{ + const db::Region *fill_region = &fr; + + db::Region new_fill_region; + db::Region remaining; + + int iteration = 0; + + while (! fill_region->empty ()) { + + ++iteration; + + fill_region_impl (cell, *fill_region, fill_cell_index, kernel_origin, row_step, column_step, db::Point (), true, &remaining, fill_margin, remaining_polygons, iteration); + + new_fill_region.swap (remaining); + fill_region = &new_fill_region; + + } +} + } diff --git a/src/db/db/dbFillTool.h b/src/db/db/dbFillTool.h index 14e453442..ad2e22b4a 100644 --- a/src/db/db/dbFillTool.h +++ b/src/db/db/dbFillTool.h @@ -104,5 +104,15 @@ DB_PUBLIC void fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill, db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0); -} +/** + * @brief An iterative version for enhanced fill + * + * This version operates like the region-based fill_region version, but repeates the fill step until no further fill cells can be placed. + * The remaining parts will be placed inside "remaining_polygons" unless this pointer is null. + */ +DB_PUBLIC void +fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, + const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, + const db::Vector &fill_margin, db::Region *remaining_polygons = 0); +} diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index 168a20229..2d9eb3847 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1322,6 +1322,13 @@ fill_region2d (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_ce db::fill_region (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons); } +static void +fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &row_step, const db::Vector &column_step, + const db::Vector &fill_margin, db::Region *remaining_polygons) +{ + db::fill_region_repeat (cell, fr, fill_cell_index, kernel_origin, row_step, column_step, fill_margin, remaining_polygons); +} + static db::Instance cell_inst_dtransform_simple (db::Cell *cell, const db::Instance &inst, const db::DTrans &t) { const db::Layout *layout = cell->layout (); @@ -1802,7 +1809,7 @@ Class decl_Cell ("db", "Cell", "This method has been introduced in version 0.23.\n" ) + gsi::method_ext ("fill_region", &fill_region1d, gsi::arg ("region"), gsi::arg ("fill_cell_index"), gsi::arg ("kernel_origin"), gsi::arg ("row_step"), gsi::arg ("column_step"), gsi::arg ("origin"), - "@brief Fills the given region with cells of the given type (diamond-shape fill kernel)\n" + "@brief Fills the given region with cells of the given type (diamond fill kernel)\n" "@param region The region to fill\n" "@param fill_cell_index The fill cell to place\n" "@param kernel_origin The fill cell's footprint\n" @@ -1860,7 +1867,7 @@ Class decl_Cell ("db", "Cell", "This method has been introduced in version 0.23.\n" ) + gsi::method_ext ("fill_region", &fill_region2d, gsi::arg ("region"), gsi::arg ("fill_cell_index"), gsi::arg ("kernel_origin"), gsi::arg ("row_step"), gsi::arg ("column_step"), gsi::arg ("origin"), gsi::arg ("remaining_parts"), gsi::arg ("fill_margin"), gsi::arg ("remaining_polygons"), - "@brief Fills the given region with cells of the given type (diamond-shape fill kernel, extended version)\n" + "@brief Fills the given region with cells of the given type (diamond fill kernel, extended version)\n" "@param region The region to fill\n" "@param fill_cell_index The fill cell to place\n" "@param kernel_origin The fill cell's footprint\n" @@ -1877,6 +1884,14 @@ Class decl_Cell ("db", "Cell", "\n" "This variant has been introduced in version 0.27.\n" ) + + gsi::method_ext ("fill_region_multi", &fill_region_repeat, gsi::arg ("region"), gsi::arg ("fill_cell_index"), gsi::arg ("kernel_origin"), gsi::arg ("row_step"), gsi::arg ("column_step"), gsi::arg ("fill_margin"), gsi::arg ("remaining_polygons"), + "@brief Fills the given region with cells of the given type in enhanced mode with iterations\n" + "This version operates like \\fill_region, but repeates the fill generation until no further fill cells can be placed. " + "As the fill pattern origin changes between the iterations, narrow regions can be filled which cannot with a fixed fill pattern origin. " + "The \\fill_margin parameter is important as it controls the distance between fill cells with a different origin and therefore pitch-incompatible arrays.\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + gsi::method_ext ("begin_shapes_rec", &begin_shapes_rec, gsi::arg ("layer"), "@brief Delivers a recursive shape iterator for the shapes below the cell on the given layer\n" "@param layer The layer from which to get the shapes\n" diff --git a/src/lay/lay/FillDialog.ui b/src/lay/lay/FillDialog.ui index a5ad360b7..8520cc832 100644 --- a/src/lay/lay/FillDialog.ui +++ b/src/lay/lay/FillDialog.ui @@ -13,10 +13,7 @@ Fill Tool - - - 6 - + 9 @@ -29,7 +26,24 @@ 9 - + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Generate Script Code + + + + 0 @@ -969,16 +983,6 @@ - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - diff --git a/src/lay/lay/layFillDialog.cc b/src/lay/lay/layFillDialog.cc index f34ad0f80..2d4abf1ae 100644 --- a/src/lay/lay/layFillDialog.cc +++ b/src/lay/lay/layFillDialog.cc @@ -31,8 +31,8 @@ #include "antService.h" #include "tlException.h" #include "tlString.h" -#include "layMainWindow.h" #include "tlExceptions.h" +#include "layMainWindow.h" #include "layCellSelectionForm.h" #include "edtService.h" @@ -134,66 +134,182 @@ FillDialog::choose_fc_2nd () } } -static void -collect_fill_regions (const db::Layout &layout, - db::cell_index_type cell_index, - unsigned int layer, - const db::CplxTrans &trans, - std::vector ®ions) +void +FillDialog::generate_fill (const FillParameters &fp) { - const db::Cell &cell = layout.cell (cell_index); - if (! cell.bbox (layer).empty ()) { - - // any shapes to consider .. - for (db::ShapeIterator sh = cell.shapes (layer).begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! sh.at_end (); ++sh) { - regions.push_back (db::Polygon ()); - sh->polygon (regions.back ()); - } - - for (db::Cell::const_iterator inst = cell.begin (); ! inst.at_end (); ++inst) { - for (db::CellInstArray::iterator a = inst->cell_inst ().begin (); ! a.at_end (); ++a) { - collect_fill_regions (layout, inst->cell_index (), layer, trans * inst->cell_inst ().complex_trans (*a), regions); - } - } - - } -} - -void -collect_fill_regions (const db::Layout &layout, - db::cell_index_type cell_index, - unsigned int layer, - std::vector ®ions) -{ - collect_fill_regions (layout, cell_index, layer, db::CplxTrans (), regions); -} - -void -FillDialog::ok_pressed () -{ -BEGIN_PROTECTED - if (tl::verbosity () >= 10) { tl::info << "Running fill"; } lay::CellView cv = mp_view->cellview (mp_view->active_cellview_index ()); + db::Layout &ly = cv->layout (); std::vector exclude_layers; - - if (layer_spec_cbx->currentIndex () == 0) { + if (fp.exclude_all_layers) { // all layers - for (db::Layout::layer_iterator l = cv->layout ().begin_layers (); l != cv->layout ().end_layers (); ++l) { + for (db::Layout::layer_iterator l = ly.begin_layers (); l != ly.end_layers (); ++l) { exclude_layers.push_back ((*l).first); } + } else { + // some layers + for (std::vector::const_iterator l = fp.exclude_layers.begin (); l != fp.exclude_layers.end (); ++l) { + exclude_layers.push_back (ly.get_layer (*l)); + } + } + + bool enhanced_fill = enhanced_cb->isChecked (); + + db::Coord exclude_x = db::coord_traits::rounded (fp.exclude_distance.x () / ly.dbu ()); + db::Coord exclude_y = db::coord_traits::rounded (fp.exclude_distance.y () / ly.dbu ()); + + db::Coord distance_x = db::coord_traits::rounded (fp.border_distance.x () / ly.dbu ()); + db::Coord distance_y = db::coord_traits::rounded (fp.border_distance.y () / ly.dbu ()); + + db::Vector fill_margin = db::CplxTrans (ly.dbu ()).inverted () * fp.fill_cell_margin; + db::Vector fill_margin2 = db::CplxTrans (ly.dbu ()).inverted () * fp.fill_cell_margin2; + + std::pair fc = cv->layout ().cell_by_name (fp.fill_cell_name.c_str ()); + if (! fc.first) { + throw tl::Exception (tl::to_string (QObject::tr ("Fill cell not found: ")) + fp.fill_cell_name); + } + + const db::Cell *fill_cell = &ly.cell (fc.second); + + std::pair fc2 = cv->layout ().cell_by_name (fp.fill_cell_name2.c_str ()); + if (! fc.first) { + throw tl::Exception (tl::to_string (QObject::tr ("Secondary fill cell not found: ")) + fp.fill_cell_name2); + } + + const db::Cell *fill_cell2 = &ly.cell (fc2.second); + + db::Vector row_step = db::CplxTrans (ly.dbu ()).inverted () * fp.row_step; + db::Vector column_step = db::CplxTrans (ly.dbu ()).inverted () * fp.column_step; + db::Vector kernel_origin = db::CplxTrans (ly.dbu ()).inverted () * fp.kernel_origin; + + db::Vector row_step2 = db::CplxTrans (ly.dbu ()).inverted () * fp.row_step2; + db::Vector column_step2 = db::CplxTrans (ly.dbu ()).inverted () * fp.column_step2; + db::Vector kernel_origin2 = db::CplxTrans (ly.dbu ()).inverted () * fp.kernel_origin2; + + + if (tl::verbosity () >= 20) { + tl::info << "Collecting fill regions"; + } + + mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Fill"))); + + db::Region fill_region; + if (fp.fill_region_mode == FillParameters::Region) { + fill_region = fp.fill_region; + } else if (fp.fill_region_mode == FillParameters::WholeCell) { + fill_region.insert (cv->layout ().cell (cv.cell_index ()).bbox ()); + } else if (fp.fill_region_mode == FillParameters::Layer) { + unsigned int layer_index = cv->layout ().get_layer (fp.fill_region_layer); + fill_region = db::Region (db::RecursiveShapeIterator (cv->layout (), *cv.cell (), layer_index)); + } + + fill_region.enable_progress (tl::to_string (tr ("Computing fill region"))); + + if (! fill_region.empty ()) { + + db::EdgeProcessor ep; + + if (tl::verbosity () >= 20) { + tl::info << "Preprocessing fill regions"; + } + + // preprocess fill regions + if (distance_x != 0 || distance_y != 0) { + fill_region.size (distance_x, distance_y); + } else { + fill_region.merge (); + } + + db::Box fr_bbox = fill_region.bbox (); + + if (tl::verbosity () >= 20) { + tl::info << "Collecting exclude areas"; + } + + // collect sized shapes from the exclude layers + db::Region es; + es.enable_progress (tl::to_string (tr ("Preparing exclude layers"))); + for (std::vector ::const_iterator l = exclude_layers.begin (); l != exclude_layers.end (); ++l) { + + db::Region exclude (db::RecursiveShapeIterator (cv->layout (), *cv.cell (), *l)); + exclude.enable_progress (tl::to_string (tr ("Preparing exclude layer: ")) + cv->layout ().get_properties (*l).to_string ()); + + if (exclude_x != 0 || exclude_y != 0) { + exclude.size (exclude_x, exclude_y); + } else { + exclude.merge (); + } + + es += exclude; + + } + + if (tl::verbosity () >= 20) { + tl::info << "Computing effective fill region"; + } + + // Perform the NOT operation to create the fill region + fill_region -= es; + + db::Region new_fill_area; + + int step = 0; + + do { + + ++step; + + if (tl::verbosity () >= 20) { + tl::info << "Major iteration (primary/secondary fill cell)"; + } + + if (! enhanced_fill) { + db::fill_region (cv.cell (), fill_region, fill_cell->cell_index (), kernel_origin, row_step, column_step, fr_bbox.p1 (), false, fill_cell2 ? &fill_region : 0, fill_margin, fill_cell2 ? &fill_region : 0); + } else { + db::fill_region_repeat (cv.cell (), fill_region, fill_cell->cell_index (), kernel_origin, row_step, column_step, fill_margin, fill_cell2 ? &fill_region : 0); + } + + fill_cell = fill_cell2; + row_step = row_step2; + column_step = column_step2; + kernel_origin = kernel_origin2; + fill_margin = fill_margin2; + + fill_cell2 = 0; + + } while (fill_cell != 0 && ! fill_region.empty ()); + + } + + if (tl::verbosity () >= 20) { + tl::info << "Fill done"; + } +} + +FillParameters +FillDialog::get_fill_parameters () +{ + FillParameters fp; + + lay::CellView cv = mp_view->cellview (mp_view->active_cellview_index ()); + + fp.exclude_all_layers = false; + + if (layer_spec_cbx->currentIndex () == 0) { + + fp.exclude_all_layers = true; } else if (layer_spec_cbx->currentIndex () == 1) { // visible layers for (lay::LayerPropertiesConstIterator l = mp_view->begin_layers (); ! l.at_end (); ++l) { if (! l->has_children () && l->visible (true)) { - exclude_layers.push_back (l->layer_index ()); + fp.exclude_layers.push_back (cv->layout ().get_properties (l->layer_index ())); } } @@ -203,7 +319,7 @@ BEGIN_PROTECTED std::vector s = mp_view->selected_layers (); for (std::vector::const_iterator l = s.begin (); l != s.end (); ++l) { if (! (*l)->has_children ()) { - exclude_layers.push_back ((*l)->layer_index ()); + fp.exclude_layers.push_back (cv->layout ().get_properties ((*l)->layer_index ())); } } @@ -221,139 +337,14 @@ BEGIN_PROTECTED } } - db::Coord exclude_x = db::coord_traits::rounded (x / cv->layout ().dbu ()); - db::Coord exclude_y = db::coord_traits::rounded (y / cv->layout ().dbu ()); - - // read distance to border - x = 0.0, y = 0.0; - s = tl::to_string (distance_le->text ()); - ex = tl::Extractor (s.c_str ()); - if (ex.try_read (x)) { - if (ex.test (",") && ex.try_read (y)) { - // take x, y - } else { - y = x; - } - } - - db::Coord distance_x = db::coord_traits::rounded (x / cv->layout ().dbu ()); - db::Coord distance_y = db::coord_traits::rounded (y / cv->layout ().dbu ()); - - // read fill cell margin - db::Vector fill_margin; - x = 0.0, y = 0.0; - s = tl::to_string (fill_margin_le->text ()); - ex = tl::Extractor (s.c_str ()); - if (ex.try_read (x)) { - if (ex.test (",") && ex.try_read (y)) { - // take x, y - } else { - y = x; - } - fill_margin = db::Vector (db::coord_traits::rounded (x / cv->layout ().dbu ()), db::coord_traits::rounded (y / cv->layout ().dbu ())); - } - - // read fill cell 2 margin - db::Vector fill2_margin; - x = 0.0, y = 0.0; - s = tl::to_string (fill2_margin_le->text ()); - ex = tl::Extractor (s.c_str ()); - if (ex.try_read (x)) { - if (ex.test (",") && ex.try_read (y)) { - // take x, y - } else { - y = x; - } - fill2_margin = db::Vector (db::coord_traits::rounded (x / cv->layout ().dbu ()), db::coord_traits::rounded (y / cv->layout ().dbu ())); - } - - // get the fill cell - std::pair fc = cv->layout ().cell_by_name (tl::to_string (fill_cell_le->text ()).c_str ()); - if (! fc.first) { - throw tl::Exception (tl::to_string (QObject::tr ("Fill cell not found: ")) + tl::to_string (fill_cell_le->text ())); - } - - const db::Cell *fill_cell = &cv->layout ().cell (fc.second); - - int fc_bbox_layer = fc_boundary_layer->current_layer (); - if (fc_bbox_layer >= 0 && ! cv->layout ().is_valid_layer (fc_bbox_layer)) { - throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get fill cell's bounding box from"))); - } - - db::Box fc_bbox = fc_bbox_layer < 0 ? fill_cell->bbox () : fill_cell->bbox (fc_bbox_layer); - if (fc_bbox.empty ()) { - throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get fill cell's bounding box from - layer is empty for the fill cell"))); - } - - db::Coord row_dx = fc_bbox.width (), row_dy = 0; - db::Coord column_dx = 0.0, column_dy = fc_bbox.height (); - - s = tl::to_string (row_le->text ()); - ex = tl::Extractor (s.c_str ()); - if (ex.try_read (x) && ex.test (",") && ex.try_read (y)) { - row_dx = db::coord_traits::rounded (x / cv->layout ().dbu ()); - row_dy = db::coord_traits::rounded (y / cv->layout ().dbu ()); - } - - s = tl::to_string (column_le->text ()); - ex = tl::Extractor (s.c_str ()); - if (ex.try_read (x) && ex.test (",") && ex.try_read (y)) { - column_dx = db::coord_traits::rounded (x / cv->layout ().dbu ()); - column_dy = db::coord_traits::rounded (y / cv->layout ().dbu ()); - } - - bool enhanced_fill = enhanced_cb->isChecked (); - - double row_dx2 = 0.0, row_dy2 = 0.0; - double column_dx2 = 0.0, column_dy2 = 0.0; - - const db::Cell *fill_cell2 = 0; - db::Box fc_bbox2; - - if (second_order_fill_cb->isChecked ()) { - - std::pair fc = cv->layout ().cell_by_name (tl::to_string (fill_cell_2nd_le->text ()).c_str ()); - if (! fc.first) { - throw tl::Exception (tl::to_string (QObject::tr ("Second order fill cell not found: ")) + tl::to_string (fill_cell_2nd_le->text ())); - } - - fill_cell2 = &cv->layout ().cell (fc.second); - - fc_bbox2 = fc_bbox_layer < 0 ? fill_cell2->bbox () : fill_cell2->bbox (fc_bbox_layer); - if (fc_bbox2.empty ()) { - throw tl::Exception (tl::to_string (QObject::tr ("Second order fill cell is empty for the given boundary layer"))); - } - - row_dx2 = fc_bbox2.width (); - row_dy2 = 0; - column_dx2 = 0.0; - column_dy2 = fc_bbox2.height (); - - s = tl::to_string (row_2nd_le->text ()); - ex = tl::Extractor (s.c_str ()); - if (ex.try_read (x) && ex.test (",") && ex.try_read (y)) { - row_dx2 = db::coord_traits::rounded (x / cv->layout ().dbu ()); - row_dy2 = db::coord_traits::rounded (y / cv->layout ().dbu ()); - } - - s = tl::to_string (column_2nd_le->text ()); - ex = tl::Extractor (s.c_str ()); - if (ex.try_read (x) && ex.test (",") && ex.try_read (y)) { - column_dx2 = db::coord_traits::rounded (x / cv->layout ().dbu ()); - column_dy2 = db::coord_traits::rounded (y / cv->layout ().dbu ()); - } - - } - - if (tl::verbosity () >= 20) { - tl::info << "Collecting fill regions"; - } + fp.exclude_distance = db::DVector (x, y); // get the fill regions - std::vector fill_regions; if (fill_area_cbx->currentIndex () == 3) { + fp.fill_region_mode = FillParameters::Region; + // explicit fill box if (le_x1->text ().isEmpty () || le_x2->text ().isEmpty () || @@ -368,23 +359,27 @@ BEGIN_PROTECTED tl::from_string (tl::to_string (le_y1->text ()), y1); tl::from_string (tl::to_string (le_y2->text ()), y2); - fill_regions.push_back (db::Polygon (db::Box (db::DBox (db::DPoint (x1, y1), db::DPoint (x2, y2)) * (1.0 / cv->layout ().dbu ())))); + fp.fill_region.insert (db::Box (db::DBox (db::DPoint (x1, y1), db::DPoint (x2, y2)) * (1.0 / cv->layout ().dbu ()))); } else if (fill_area_cbx->currentIndex () == 4) { + fp.fill_region_mode = FillParameters::Region; + // ruler ant::Service *ant_service = mp_view->get_plugin (); if (ant_service) { ant::AnnotationIterator ant = ant_service->begin_annotations (); while (! ant.at_end ()) { - fill_regions.push_back (db::Polygon (db::Box (db::DBox (ant->p1 (), ant->p2 ()) * (1.0 / cv->layout ().dbu ())))); + fp.fill_region.insert (db::Box (db::DBox (ant->p1 (), ant->p2 ()) * (1.0 / cv->layout ().dbu ()))); ++ant; } } } else if (fill_area_cbx->currentIndex () == 1) { + fp.fill_region_mode = FillParameters::Layer; + // specified layer int sel_layer = cb_layer->current_layer (); @@ -392,182 +387,169 @@ BEGIN_PROTECTED throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get fill regions from"))); } - collect_fill_regions (cv->layout (), cv.cell_index (), (unsigned int) sel_layer, fill_regions); + fp.fill_region_layer = cv->layout ().get_properties (sel_layer); } else if (fill_area_cbx->currentIndex () == 0) { - // whole cell - fill_regions.push_back (db::Polygon (cv.cell ()->bbox ())); + fp.fill_region_mode = FillParameters::WholeCell; } else if (fill_area_cbx->currentIndex () == 2) { + fp.fill_region_mode = FillParameters::Region; + // selection std::vector edt_services = mp_view->get_plugins (); for (std::vector::const_iterator s = edt_services.begin (); s != edt_services.end (); ++s) { for (edt::Service::objects::const_iterator sel = (*s)->selection ().begin (); sel != (*s)->selection ().end (); ++sel) { if (! sel->is_cell_inst () && (sel->shape ().is_polygon () || sel->shape ().is_path () || sel->shape ().is_box ())) { - fill_regions.push_back (db::Polygon ()); - sel->shape ().polygon (fill_regions.back ()); + db::Polygon poly; + sel->shape ().polygon (poly); + fp.fill_region.insert (poly); } } } } + // read distance to border + x = 0.0, y = 0.0; + s = tl::to_string (distance_le->text ()); + ex = tl::Extractor (s.c_str ()); + if (ex.try_read (x)) { + if (ex.test (",") && ex.try_read (y)) { + // take x, y + } else { + y = x; + } + } + + fp.border_distance = db::DVector (x, y); + + // read fill cell margin + x = 0.0, y = 0.0; + s = tl::to_string (fill_margin_le->text ()); + ex = tl::Extractor (s.c_str ()); + if (ex.try_read (x)) { + if (ex.test (",") && ex.try_read (y)) { + // take x, y + } else { + y = x; + } + } + + fp.fill_cell_margin = db::DVector (x, y); + + // read fill cell 2 margin + x = 0.0, y = 0.0; + s = tl::to_string (fill2_margin_le->text ()); + ex = tl::Extractor (s.c_str ()); + if (ex.try_read (x)) { + if (ex.test (",") && ex.try_read (y)) { + // take x, y + } else { + y = x; + } + } + + fp.fill_cell_margin2 = db::DVector (x, y); + + fp.fill_cell_name = tl::to_string (fill_cell_le->text ()); + + // get the fill cell + std::pair fc = cv->layout ().cell_by_name (fp.fill_cell_name.c_str ()); + if (! fc.first) { + throw tl::Exception (tl::to_string (QObject::tr ("Fill cell not found: ")) + tl::to_string (fill_cell_le->text ())); + } + + const db::Cell *fill_cell = &cv->layout ().cell (fc.second); + + int fc_bbox_layer = fc_boundary_layer->current_layer (); + if (fc_bbox_layer >= 0 && ! cv->layout ().is_valid_layer (fc_bbox_layer)) { + throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get fill cell's bounding box from"))); + } + + fp.enhanced_fill = enhanced_cb->isChecked (); + + db::DBox fc_bbox = db::CplxTrans (cv->layout ().dbu ()) * (fc_bbox_layer < 0 ? fill_cell->bbox () : fill_cell->bbox (fc_bbox_layer)); + if (fc_bbox.empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("No valid layer selected to get fill cell's bounding box from - layer is empty for the fill cell"))); + } + + s = tl::to_string (row_le->text ()); + ex = tl::Extractor (s.c_str ()); + if (ex.try_read (x) && ex.test (",") && ex.try_read (y)) { + fp.row_step = db::DVector (x, y); + } else { + fp.row_step = db::DVector (fc_bbox.width (), 0.0); + } + + s = tl::to_string (column_le->text ()); + ex = tl::Extractor (s.c_str ()); + if (ex.try_read (x) && ex.test (",") && ex.try_read (y)) { + fp.column_step = db::DVector (x, y); + } else { + fp.column_step = db::DVector (0.0, fc_bbox.height ()); + } + + fp.kernel_origin = fc_bbox.p1 () - db::DPoint (); + + const db::Cell *fill_cell2 = 0; + db::DBox fc_bbox2; + + if (second_order_fill_cb->isChecked ()) { + + fp.fill_cell_name2 = tl::to_string (fill_cell_2nd_le->text ()); + + std::pair fc = cv->layout ().cell_by_name (fp.fill_cell_name2.c_str ()); + if (! fc.first) { + throw tl::Exception (tl::to_string (QObject::tr ("Second order fill cell not found: ")) + tl::to_string (fill_cell_2nd_le->text ())); + } + + fill_cell2 = &cv->layout ().cell (fc.second); + + fc_bbox2 = db::CplxTrans (cv->layout ().dbu ()) * (fc_bbox_layer < 0 ? fill_cell2->bbox () : fill_cell2->bbox (fc_bbox_layer)); + if (fc_bbox2.empty ()) { + throw tl::Exception (tl::to_string (QObject::tr ("Second order fill cell is empty for the given boundary layer"))); + } + + s = tl::to_string (row_2nd_le->text ()); + ex = tl::Extractor (s.c_str ()); + if (ex.try_read (x) && ex.test (",") && ex.try_read (y)) { + fp.row_step2 = db::DVector (x, y); + } else { + fp.row_step2 = db::DVector (fc_bbox2.width (), 0.0); + } + + s = tl::to_string (column_2nd_le->text ()); + ex = tl::Extractor (s.c_str ()); + if (ex.try_read (x) && ex.test (",") && ex.try_read (y)) { + fp.column_step2 = db::DVector (x, y); + } else { + fp.column_step2 = db::DVector (0.0, fc_bbox2.height ()); + } + + } + + return fp; +} + +void +FillDialog::ok_pressed () +{ +BEGIN_PROTECTED + + FillParameters fp = get_fill_parameters (); + mp_view->manager ()->transaction (tl::to_string (QObject::tr ("Fill"))); - if (! fill_regions.empty ()) { - - db::EdgeProcessor ep; - - if (tl::verbosity () >= 20) { - tl::info << "Preprocessing fill regions"; - } - - // TODO: progress - - // preprocess fill regions - if (distance_x != 0 || distance_y != 0) { - - std::vector fp; - ep.enable_progress (tl::to_string (QObject::tr ("Preparing fill regions"))); - ep.size (fill_regions, -distance_x, -distance_y, fp, 2 /*mode*/, false /*=don't resolve holes*/); - ep.disable_progress (); - - fill_regions.swap (fp); - - } - - std::sort (fill_regions.begin (), fill_regions.end ()); - fill_regions.erase (std::unique (fill_regions.begin (), fill_regions.end ()), fill_regions.end ()); - - // determine the fill region's bbox for selectively getting the exclude shapes - db::Box fr_bbox; - for (std::vector ::const_iterator fr = fill_regions.begin (); fr != fill_regions.end (); ++fr) { - fr_bbox += fr->box (); - } - - if (tl::verbosity () >= 20) { - tl::info << "Collecting exclude areas"; - } - - // collect sized shapes from the exclude layers - std::vector es; - for (std::vector ::const_iterator l = exclude_layers.begin (); l != exclude_layers.end (); ++l) { - - std::vector shapes; - - size_t n = 0; - for (db::RecursiveShapeIterator si (cv->layout (), *cv.cell (), *l); ! si.at_end (); ++si) { - if (si->is_polygon () || si->is_path () || si->is_box ()) { - ++n; - } - } - - shapes.reserve (n); - - for (db::RecursiveShapeIterator si (cv->layout (), *cv.cell (), *l); ! si.at_end (); ++si) { - if (si->is_polygon () || si->is_path () || si->is_box ()) { - shapes.push_back (db::Polygon ()); - si->polygon (shapes.back ()); - shapes.back ().transform (si.trans ()); - } - } - - ep.enable_progress (tl::to_string (QObject::tr ("Preparing exclude regions"))); - ep.size (shapes, exclude_x, exclude_y, es, 2 /*mode*/, false /*=don't resolve holes*/); - ep.disable_progress (); - - } - - if (tl::verbosity () >= 20) { - tl::info << "Computing effective fill region"; - } - - // Perform the NOT operation to create the fill region - std::vector fill_area; - ep.enable_progress (tl::to_string (QObject::tr ("Computing fill region"))); - ep.boolean (fill_regions, es, fill_area, db::BooleanOp::ANotB, false /*=don't resolve holes*/); - ep.disable_progress (); - - std::vector new_fill_area; - - int step = 0; - - do { - - ++step; - - if (tl::verbosity () >= 20) { - tl::info << "Major iteration (primary/secondary fill cell)"; - } - - std::vector non_filled_area; - - int iteration = 0; - - do { - - ++iteration; - - if (tl::verbosity () >= 20 && enhanced_fill) { - tl::info << "Minor iteration (enhanced fill)"; - } - - tl::RelativeProgress progress (tl::sprintf (tl::to_string (QObject::tr ("Fill iteration %d (%s fill step)")), iteration, step == 1 ? tl::to_string (QObject::tr ("primary")) : tl::to_string (QObject::tr ("secondary"))), fill_area.size (), 10); - - new_fill_area.clear (); - - for (std::vector ::const_iterator fp0 = fill_area.begin (); fp0 != fill_area.end (); ++fp0) { - - if (tl::verbosity () >= 30) { - tl::info << "Compute fill for one region :" << fp0->to_string (); - } - - db::Vector rs (row_dx, row_dy), cs (column_dx, column_dy); - db::Vector ko = fc_bbox.center () - db::Point (row_dx / 2, column_dy / 2); - - bool any_fill = fill_region (cv.cell (), *fp0, fill_cell->cell_index (), ko, rs, cs, fr_bbox.p1 (), enhanced_fill, (enhanced_fill || fill_cell2) ? &new_fill_area : 0, fill_margin); - if (! any_fill) { - non_filled_area.push_back (*fp0); - } - - ++progress; - - } - - fill_area.swap (new_fill_area); - - } while (enhanced_fill && ! fill_area.empty ()); - - if (fill_area.empty ()) { - fill_area.swap (non_filled_area); - } else if (fill_cell2) { - fill_area.insert (fill_area.end (), non_filled_area.begin (), non_filled_area.end ()); - } - - fill_cell = fill_cell2; - fc_bbox = fc_bbox2; - fill_margin = fill2_margin; - - row_dx = row_dx2; - row_dy = row_dy2; - column_dx = column_dx2; - column_dy = column_dy2; - - fill_cell2 = 0; - fc_bbox2 = db::Box (); - - } while (fill_cell != 0 && ! fill_area.empty ()); - + try { + generate_fill (fp); + mp_view->manager ()->commit (); + } catch (...) { + mp_view->manager ()->cancel (); + throw; } - if (tl::verbosity () >= 20) { - tl::info << "Fill done"; - } - - mp_view->manager ()->commit (); - // close this dialog QDialog::accept (); diff --git a/src/lay/lay/layFillDialog.h b/src/lay/lay/layFillDialog.h index 689912dff..e8a894d0c 100644 --- a/src/lay/lay/layFillDialog.h +++ b/src/lay/lay/layFillDialog.h @@ -29,13 +29,44 @@ #include "layLayoutView.h" #include "layPlugin.h" #include "layMarker.h" +#include "layCommon.h" + +#include "dbRegion.h" #include namespace lay { -class FillDialog +struct LAY_PUBLIC FillParameters +{ + FillParameters () + : exclude_all_layers (true), fill_region_mode (WholeCell), enhanced_fill (false) + { } + + enum FillRegionMode { + WholeCell, + Region, + Layer + }; + + bool exclude_all_layers; + std::vector exclude_layers; + FillRegionMode fill_region_mode; + db::Region fill_region; + db::LayerProperties fill_region_layer; + db::DVector exclude_distance; + db::DVector border_distance; + bool enhanced_fill; + std::string fill_cell_name; + db::DVector fill_cell_margin; + db::DVector kernel_origin, row_step, column_step; + std::string fill_cell_name2; + db::DVector fill_cell_margin2; + db::DVector kernel_origin2, row_step2, column_step2; +}; + +class LAY_PUBLIC FillDialog : public QDialog, public lay::Plugin, private Ui::FillDialog @@ -59,6 +90,9 @@ private: // implementation of the lay::Plugin interface void menu_activated (const std::string &symbol); + void generate_fill (const FillParameters &fp); + FillParameters get_fill_parameters (); + lay::LayoutView *mp_view; };