Refactoring, preparing script generation.

This commit is contained in:
Matthias Koefferlein 2021-03-06 19:38:19 +01:00
parent 637968cbc4
commit 6e6ce998aa
6 changed files with 446 additions and 354 deletions

View File

@ -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<db::Polygon> 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;
}
}
}

View File

@ -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);
}

View File

@ -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<db::Cell> 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<db::Cell> 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<db::Cell> 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"

View File

@ -13,10 +13,7 @@
<property name="windowTitle">
<string>Fill Tool</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>9</number>
</property>
@ -29,7 +26,24 @@
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<item row="1" column="1">
<widget class="QDialogButtonBox" name="button_box">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="generate_script_pb">
<property name="text">
<string>Generate Script Code</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
@ -969,16 +983,6 @@
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="button_box">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>

View File

@ -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 <db::Polygon> &regions)
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 <db::Polygon> &regions)
{
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 <unsigned int> 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<db::LayerProperties>::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<db::Coord>::rounded (fp.exclude_distance.x () / ly.dbu ());
db::Coord exclude_y = db::coord_traits<db::Coord>::rounded (fp.exclude_distance.y () / ly.dbu ());
db::Coord distance_x = db::coord_traits<db::Coord>::rounded (fp.border_distance.x () / ly.dbu ());
db::Coord distance_y = db::coord_traits<db::Coord>::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<bool, db::cell_index_type> 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<bool, db::cell_index_type> 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 <unsigned int>::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<lay::LayerPropertiesConstIterator> s = mp_view->selected_layers ();
for (std::vector<lay::LayerPropertiesConstIterator>::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<db::Coord>::rounded (x / cv->layout ().dbu ());
db::Coord exclude_y = db::coord_traits<db::Coord>::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<db::Coord>::rounded (x / cv->layout ().dbu ());
db::Coord distance_y = db::coord_traits<db::Coord>::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<db::Coord>::rounded (x / cv->layout ().dbu ()), db::coord_traits<db::Coord>::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<db::Coord>::rounded (x / cv->layout ().dbu ()), db::coord_traits<db::Coord>::rounded (y / cv->layout ().dbu ()));
}
// get the fill cell
std::pair<bool, db::cell_index_type> 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<db::Coord>::rounded (x / cv->layout ().dbu ());
row_dy = db::coord_traits<db::Coord>::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<db::Coord>::rounded (x / cv->layout ().dbu ());
column_dy = db::coord_traits<db::Coord>::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<bool, db::cell_index_type> 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<db::Coord>::rounded (x / cv->layout ().dbu ());
row_dy2 = db::coord_traits<db::Coord>::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<db::Coord>::rounded (x / cv->layout ().dbu ());
column_dy2 = db::coord_traits<db::Coord>::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 <db::Polygon> 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 <ant::Service> ();
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::Service *> edt_services = mp_view->get_plugins <edt::Service> ();
for (std::vector<edt::Service *>::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<bool, db::cell_index_type> 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<bool, db::cell_index_type> 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 <db::Polygon> 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 <db::Polygon>::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 <db::Polygon> es;
for (std::vector <unsigned int>::const_iterator l = exclude_layers.begin (); l != exclude_layers.end (); ++l) {
std::vector <db::Polygon> 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 <db::Polygon> 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 <db::Polygon> new_fill_area;
int step = 0;
do {
++step;
if (tl::verbosity () >= 20) {
tl::info << "Major iteration (primary/secondary fill cell)";
}
std::vector <db::Polygon> 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 <db::Polygon>::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 ();

View File

@ -29,13 +29,44 @@
#include "layLayoutView.h"
#include "layPlugin.h"
#include "layMarker.h"
#include "layCommon.h"
#include "dbRegion.h"
#include <QDialog>
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<db::LayerProperties> 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;
};