mirror of https://github.com/KLayout/klayout.git
WIP: exclude area for fill functions
This commit is contained in:
parent
6ada4cb6f9
commit
ff6ab4267b
|
|
@ -42,10 +42,18 @@ public:
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
GenericRasterizer (const db::Polygon &fp, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, const db::Vector &dim)
|
||||
GenericRasterizer (const std::vector<db::Polygon> &fr, const db::Box &rasterized_area, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, const db::Vector &dim)
|
||||
: m_row_step (row_step), m_column_step (column_step), m_row_steps (0), m_column_steps (0), m_origin (origin), m_dim (dim)
|
||||
{
|
||||
rasterize (fp);
|
||||
rasterize (rasterized_area, fr);
|
||||
}
|
||||
|
||||
GenericRasterizer (const db::Polygon &fp, const db::Box &rasterized_area, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, const db::Vector &dim)
|
||||
: m_row_step (row_step), m_column_step (column_step), m_row_steps (0), m_column_steps (0), m_origin (origin), m_dim (dim)
|
||||
{
|
||||
std::vector<db::Polygon> fr;
|
||||
fr.push_back (fp);
|
||||
rasterize (rasterized_area, fr);
|
||||
}
|
||||
|
||||
void move (const db::Vector &d)
|
||||
|
|
@ -59,101 +67,6 @@ public:
|
|||
m_area_maps.clear ();
|
||||
}
|
||||
|
||||
void rasterize (const db::Polygon &fp)
|
||||
{
|
||||
db::Coord dx = m_row_step.x ();
|
||||
db::Coord dy = m_column_step.y ();
|
||||
|
||||
if (m_row_step.y () == 0) {
|
||||
m_row_steps = 1;
|
||||
} else {
|
||||
m_row_steps = tl::lcm (dy, std::abs (m_row_step.y ())) / std::abs (m_row_step.y ());
|
||||
}
|
||||
|
||||
if (m_column_step.x () == 0) {
|
||||
m_column_steps = 1;
|
||||
} else {
|
||||
m_column_steps = tl::lcm (dx, std::abs (m_column_step.x ())) / std::abs (m_column_step.x ());
|
||||
}
|
||||
|
||||
// because the rasterizer can't handle overlapping cells we need to multiply the row and columns steps
|
||||
// with an integer until the effective rasterizer pitch gets big enough.
|
||||
m_row_steps *= (m_dim.x () - 1) / (m_row_steps * m_row_step.x ()) + 1;
|
||||
m_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1;
|
||||
|
||||
db::Box fp_bbox = fp.box ();
|
||||
|
||||
// compensate for distortion by sheared kernel
|
||||
db::Coord ex = std::max (std::abs (db::Coord (m_column_step.x () * m_column_steps)), std::abs (db::Coord (m_row_step.x () * m_row_steps)));
|
||||
db::Coord ey = std::max (std::abs (db::Coord (m_column_step.y () * m_column_steps)), std::abs (db::Coord (m_row_step.y () * m_row_steps)));
|
||||
fp_bbox.enlarge (db::Vector (ex, ey));
|
||||
|
||||
int columns_per_rows = (int (m_row_steps) * m_row_step.y ()) / dy;
|
||||
int rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx;
|
||||
|
||||
db::Coord ddx = dx * db::Coord (m_row_steps) - m_column_step.x () * columns_per_rows;
|
||||
db::Coord ddy = dy * db::Coord (m_column_steps) - m_row_step.y () * rows_per_columns;
|
||||
|
||||
// round polygon bbox
|
||||
db::Coord fp_left = db::Coord (tl::round_down (fp_bbox.left () - m_origin.x (), ddx)) + m_origin.x ();
|
||||
db::Coord fp_bottom = db::Coord (tl::round_down (fp_bbox.bottom () - m_origin.y (), ddy)) + m_origin.y ();
|
||||
db::Coord fp_right = db::Coord (tl::round_up (fp_bbox.right () - m_origin.x (), ddx)) + m_origin.x ();
|
||||
db::Coord fp_top = db::Coord (tl::round_up (fp_bbox.top () - m_origin.y (), ddy)) + m_origin.y ();
|
||||
fp_bbox = db::Box (fp_left, fp_bottom, fp_right, fp_top);
|
||||
|
||||
size_t nx = fp_bbox.width () / ddx;
|
||||
size_t ny = fp_bbox.height () / ddy;
|
||||
|
||||
tl_assert (fp.box ().inside (fp_bbox));
|
||||
|
||||
if (nx == 0 || ny == 0) {
|
||||
// nothing to rasterize:
|
||||
return;
|
||||
}
|
||||
|
||||
m_area_maps.reserve (m_row_steps * m_column_steps + std::abs (columns_per_rows) * std::abs (rows_per_columns));
|
||||
|
||||
db::AreaMap am;
|
||||
|
||||
for (unsigned int ic = 0; ic < m_column_steps; ++ic) {
|
||||
|
||||
for (unsigned int ir = 0; ir < m_row_steps; ++ir) {
|
||||
|
||||
db::Vector dr = m_row_step * long (ir);
|
||||
db::Vector dc = m_column_step * long (ic);
|
||||
|
||||
am.reinitialize (db::Point (fp_left, fp_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
|
||||
|
||||
if (db::rasterize (fp, am)) {
|
||||
m_area_maps.push_back (db::AreaMap ());
|
||||
m_area_maps.back ().swap (am);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// adds the "dead corner" piece
|
||||
|
||||
for (unsigned int ic = 0; ic < (unsigned int) std::abs (columns_per_rows); ++ic) {
|
||||
|
||||
for (unsigned int ir = 0; ir < (unsigned int) std::abs (rows_per_columns); ++ir) {
|
||||
|
||||
db::Vector dr = m_row_step * long ((rows_per_columns > 0 ? -int (ir + 1) : ir) + m_row_steps);
|
||||
db::Vector dc = m_column_step * long ((columns_per_rows > 0 ? -int (ic + 1) : ic) + m_column_steps);
|
||||
|
||||
am.reinitialize (db::Point (fp_left, fp_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
|
||||
|
||||
if (db::rasterize (fp, am)) {
|
||||
m_area_maps.push_back (db::AreaMap ());
|
||||
m_area_maps.back ().swap (am);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const db::Point &p0 () const { return m_origin; }
|
||||
|
||||
unsigned int row_steps () const { return m_row_steps; }
|
||||
|
|
@ -180,12 +93,212 @@ private:
|
|||
unsigned int m_row_steps, m_column_steps;
|
||||
db::Point m_origin;
|
||||
db::Vector m_dim;
|
||||
|
||||
void rasterize (const db::Box &rasterized_area, const std::vector<db::Polygon> &fr)
|
||||
{
|
||||
db::Coord dx = m_row_step.x ();
|
||||
db::Coord dy = m_column_step.y ();
|
||||
|
||||
if (m_row_step.y () == 0) {
|
||||
m_row_steps = 1;
|
||||
} else {
|
||||
m_row_steps = tl::lcm (dy, std::abs (m_row_step.y ())) / std::abs (m_row_step.y ());
|
||||
}
|
||||
|
||||
if (m_column_step.x () == 0) {
|
||||
m_column_steps = 1;
|
||||
} else {
|
||||
m_column_steps = tl::lcm (dx, std::abs (m_column_step.x ())) / std::abs (m_column_step.x ());
|
||||
}
|
||||
|
||||
// because the rasterizer can't handle overlapping cells we need to multiply the row and columns steps
|
||||
// with an integer until the effective rasterizer pitch gets big enough.
|
||||
m_row_steps *= (m_dim.x () - 1) / (m_row_steps * m_row_step.x ()) + 1;
|
||||
m_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1;
|
||||
|
||||
db::Box ra_org = rasterized_area;
|
||||
|
||||
// compensate for distortion by sheared kernel
|
||||
db::Coord ex = std::max (std::abs (db::Coord (m_column_step.x () * m_column_steps)), std::abs (db::Coord (m_row_step.x () * m_row_steps)));
|
||||
db::Coord ey = std::max (std::abs (db::Coord (m_column_step.y () * m_column_steps)), std::abs (db::Coord (m_row_step.y () * m_row_steps)));
|
||||
ra_org.enlarge (db::Vector (ex, ey));
|
||||
|
||||
int columns_per_rows = (int (m_row_steps) * m_row_step.y ()) / dy;
|
||||
int rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx;
|
||||
|
||||
db::Coord ddx = dx * db::Coord (m_row_steps) - m_column_step.x () * columns_per_rows;
|
||||
db::Coord ddy = dy * db::Coord (m_column_steps) - m_row_step.y () * rows_per_columns;
|
||||
|
||||
// round polygon bbox
|
||||
db::Coord ra_left = db::Coord (tl::round_down (ra_org.left () - m_origin.x (), ddx)) + m_origin.x ();
|
||||
db::Coord ra_bottom = db::Coord (tl::round_down (ra_org.bottom () - m_origin.y (), ddy)) + m_origin.y ();
|
||||
db::Coord ra_right = db::Coord (tl::round_up (ra_org.right () - m_origin.x (), ddx)) + m_origin.x ();
|
||||
db::Coord ra_top = db::Coord (tl::round_up (ra_org.top () - m_origin.y (), ddy)) + m_origin.y ();
|
||||
db::Box ra = db::Box (ra_left, ra_bottom, ra_right, ra_top);
|
||||
|
||||
size_t nx = ra.width () / ddx;
|
||||
size_t ny = ra.height () / ddy;
|
||||
|
||||
tl_assert (ra_org.inside (ra));
|
||||
|
||||
if (nx == 0 || ny == 0) {
|
||||
// nothing to rasterize:
|
||||
return;
|
||||
}
|
||||
|
||||
m_area_maps.reserve (m_row_steps * m_column_steps + std::abs (columns_per_rows) * std::abs (rows_per_columns));
|
||||
|
||||
db::AreaMap am;
|
||||
|
||||
for (unsigned int ic = 0; ic < m_column_steps; ++ic) {
|
||||
|
||||
for (unsigned int ir = 0; ir < m_row_steps; ++ir) {
|
||||
|
||||
db::Vector dr = m_row_step * long (ir);
|
||||
db::Vector dc = m_column_step * long (ic);
|
||||
|
||||
am.reinitialize (db::Point (ra_left, ra_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
|
||||
|
||||
bool any = false;
|
||||
for (auto i = fr.begin (); i != fr.end (); ++i) {
|
||||
if (db::rasterize (*i, am)) {
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
if (any) {
|
||||
m_area_maps.push_back (db::AreaMap ());
|
||||
m_area_maps.back ().swap (am);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// adds the "dead corner" piece
|
||||
|
||||
for (unsigned int ic = 0; ic < (unsigned int) std::abs (columns_per_rows); ++ic) {
|
||||
|
||||
for (unsigned int ir = 0; ir < (unsigned int) std::abs (rows_per_columns); ++ir) {
|
||||
|
||||
db::Vector dr = m_row_step * long ((rows_per_columns > 0 ? -int (ir + 1) : ir) + m_row_steps);
|
||||
db::Vector dc = m_column_step * long ((columns_per_rows > 0 ? -int (ic + 1) : ic) + m_column_steps);
|
||||
|
||||
am.reinitialize (db::Point (ra_left, ra_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
|
||||
|
||||
bool any = false;
|
||||
for (auto i = fr.begin (); i != fr.end (); ++i) {
|
||||
if (db::rasterize (*i, am)) {
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
if (any) {
|
||||
m_area_maps.push_back (db::AreaMap ());
|
||||
m_area_maps.back ().swap (am);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static size_t
|
||||
create_instances (GenericRasterizer &am, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Vector &kernel_origin, const db::Vector &fill_margin, const GenericRasterizer *exclude_rasterized, std::vector<db::Polygon> *filled_regions)
|
||||
{
|
||||
size_t ninsts = 0;
|
||||
|
||||
for (unsigned int i = 0; i < am.area_maps (); ++i) {
|
||||
|
||||
db::AreaMap &am1 = am.area_map (i);
|
||||
const db::AreaMap *am1_excl = 0;
|
||||
if (exclude_rasterized) {
|
||||
tl_assert (i < exclude_rasterized->area_maps ());
|
||||
am1_excl = &exclude_rasterized->area_map (i);
|
||||
}
|
||||
|
||||
size_t nx = am1.nx ();
|
||||
size_t ny = am1.ny ();
|
||||
|
||||
// Create the fill cell instances
|
||||
for (size_t i = 0; i < nx; ++i) {
|
||||
|
||||
for (size_t j = 0; j < ny; ) {
|
||||
|
||||
size_t jj = j + 1;
|
||||
if (am1.get (i, j) == am1.pixel_area () && (!am1_excl || am1_excl->get (i, j) == 0)) {
|
||||
|
||||
while (jj != ny && am1.get (i, jj) == am1.pixel_area () && (!am1_excl || am1_excl->get (i, jj) == 0)) {
|
||||
++jj;
|
||||
}
|
||||
|
||||
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
|
||||
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
|
||||
|
||||
db::CellInstArray array;
|
||||
|
||||
// try to expand the array in x direction
|
||||
size_t ii = i + 1;
|
||||
for ( ; ii < nx; ++ii) {
|
||||
bool all = true;
|
||||
for (size_t k = j; k < jj && all; ++k) {
|
||||
all = (am1.get (ii, k) == am1.pixel_area () && (!am1_excl || am1_excl->get (ii, k) == 0));
|
||||
}
|
||||
if (all) {
|
||||
for (size_t k = j; k < jj; ++k) {
|
||||
// disable pixel, so we do not see it again in the following columns
|
||||
am1.get (ii, k) = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ninsts += (jj - j) * (ii - i);
|
||||
|
||||
if (jj > j + 1 || ii > i + 1) {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (am1.d ().x (), 0), (unsigned long) (jj - j), (unsigned long) (ii - i));
|
||||
} else {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
|
||||
}
|
||||
|
||||
{
|
||||
// In case we run this from a tiling processor we need to lock against multithread races
|
||||
tl_assert (cell->layout () != 0);
|
||||
tl::MutexLocker locker (&cell->layout ()->lock ());
|
||||
cell->insert (array);
|
||||
}
|
||||
|
||||
if (filled_regions) {
|
||||
if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
|
||||
db::Box fill_box (db::Point (), db::Point (am1.p ().x () * db::Coord (ii - i), am1.p ().y () * db::Coord (jj - j)));
|
||||
filled_regions->push_back (db::Polygon (fill_box.enlarged (fill_margin).moved (kernel_origin + p0)));
|
||||
} else {
|
||||
db::Box fill_box (db::Point (), db::Point () + am1.p ());
|
||||
fill_box.enlarge (fill_margin);
|
||||
for (size_t k = 0; k < jj - j; ++k) {
|
||||
for (size_t l = 0; l < ii - i; ++l) {
|
||||
filled_regions->push_back (db::Polygon (fill_box.moved (kernel_origin + p0 + db::Vector (am1.d ().x () * db::Coord (l), am1.d ().y () * db::Coord (k)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
j = jj;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ninsts;
|
||||
}
|
||||
|
||||
static bool
|
||||
fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box)
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
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")));
|
||||
|
|
@ -197,153 +310,133 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
|
||||
db::Vector kernel_origin (fc_bbox.left (), fc_bbox.bottom ());
|
||||
|
||||
std::vector <db::Polygon> filled_regions;
|
||||
db::EdgeProcessor ep;
|
||||
|
||||
// under- and oversize the polygon to remove slivers that cannot be filled.
|
||||
db::Coord dx = fc_bbox.width () / 2 - 1, dy = fc_bbox.height () / 2 - 1;
|
||||
|
||||
std::vector <db::Polygon> fpa;
|
||||
std::vector <db::Polygon> fpb;
|
||||
fpa.push_back (fp0);
|
||||
db::Region fr (fp0);
|
||||
db::Box rasterized_area = fp0.box ();
|
||||
|
||||
ep.size (fpa, -dx, 0, fpb, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
fpa.swap (fpb);
|
||||
fpb.clear ();
|
||||
std::unique_ptr<GenericRasterizer> exclude_rasterized;
|
||||
|
||||
ep.size (fpa, dx, 0, fpb, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
fpa.swap (fpb);
|
||||
fpb.clear ();
|
||||
if (! exclude_area.empty ()) {
|
||||
|
||||
ep.size (fpa, 0, -dy, fpb, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
fpa.swap (fpb);
|
||||
fpb.clear ();
|
||||
auto iter = exclude_area.iter ();
|
||||
iter.confine_region (fp0.box ());
|
||||
|
||||
ep.size (fpa, 0, dy, fpb, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
fpa.swap (fpb);
|
||||
fpb.clear ();
|
||||
// over- and undersize the polygons to fill gaps that cannot be filled.
|
||||
db::Region excluded (iter);
|
||||
excluded.size (dx, 0);
|
||||
excluded.size (-dx, 0);
|
||||
excluded.size (dy, 0);
|
||||
excluded.size (-dy, 0);
|
||||
excluded.merge ();
|
||||
|
||||
ep.simple_merge (fpa, fpb, false /*=don't resolve holes*/);
|
||||
if (enhanced_fill || remaining_parts != 0) {
|
||||
|
||||
filled_regions.clear ();
|
||||
tl::warn << "@@@ using booleans for exclude";
|
||||
|
||||
// In enhanced fill or if the remaining parts are requested, it is better to implement the
|
||||
// exclude area by a boolean NOT
|
||||
fr -= excluded;
|
||||
|
||||
} else {
|
||||
|
||||
tl::warn << "@@@ using exclude area rasterizer";
|
||||
|
||||
// Otherwise use a second rasterizer for the exclude polygons that must have a zero pixel coverage for the
|
||||
// pixel to be filled.
|
||||
|
||||
std::vector<db::Polygon> excluded_poly;
|
||||
excluded_poly.reserve (excluded.count ());
|
||||
for (auto i = excluded.begin (); ! i.at_end (); ++i) {
|
||||
excluded_poly.push_back (*i);
|
||||
}
|
||||
excluded.clear ();
|
||||
|
||||
exclude_rasterized.reset (new GenericRasterizer (excluded_poly, rasterized_area, row_step, column_step, origin, fc_bbox.p2 () - fc_bbox.p1 ()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector <db::Polygon> filled_poly;
|
||||
|
||||
// under- and oversize the polygon to remove slivers that cannot be filled.
|
||||
fr.size (-dx, 0);
|
||||
fr.size (dx, 0);
|
||||
fr.size (0, -dy);
|
||||
fr.size (0, dy);
|
||||
fr.merge ();
|
||||
|
||||
filled_poly.reserve (fr.count ());
|
||||
for (auto i = fr.begin (); ! i.at_end (); ++i) {
|
||||
filled_poly.push_back (*i);
|
||||
}
|
||||
|
||||
fr.clear ();
|
||||
|
||||
if (filled_poly.empty ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector <db::Polygon> filled_regions;
|
||||
bool any_fill = false;
|
||||
|
||||
for (std::vector <db::Polygon>::const_iterator fp = fpb.begin (); fp != fpb.end (); ++fp) {
|
||||
if (exclude_rasterized.get ()) {
|
||||
|
||||
if (fp->hull ().size () == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box
|
||||
bool ef = enhanced_fill;
|
||||
if (ef && ! glue_box.empty () && ! fp->box ().enlarged (db::Vector (1, 1)).inside (glue_box)) {
|
||||
ef = false;
|
||||
}
|
||||
|
||||
// pick a heuristic "good" starting point in enhanced mode
|
||||
// TODO: this is a pretty weak optimization.
|
||||
db::Point o = origin;
|
||||
if (ef) {
|
||||
o = fp->hull () [0];
|
||||
}
|
||||
|
||||
size_t ninsts = 0;
|
||||
|
||||
GenericRasterizer am (*fp, row_step, column_step, o, fc_bbox.p2 () - fc_bbox.p1 ());
|
||||
|
||||
for (unsigned int i = 0; i < am.area_maps (); ++i) {
|
||||
|
||||
db::AreaMap &am1 = am.area_map (i);
|
||||
|
||||
size_t nx = am1.nx ();
|
||||
size_t ny = am1.ny ();
|
||||
|
||||
// Create the fill cell instances
|
||||
for (size_t i = 0; i < nx; ++i) {
|
||||
|
||||
for (size_t j = 0; j < ny; ) {
|
||||
|
||||
size_t jj = j + 1;
|
||||
if (am1.get (i, j) == am1.pixel_area ()) {
|
||||
|
||||
while (jj != ny && am1.get (i, jj) == am1.pixel_area ()) {
|
||||
++jj;
|
||||
}
|
||||
|
||||
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
|
||||
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
|
||||
|
||||
db::CellInstArray array;
|
||||
|
||||
// try to expand the array in x direction
|
||||
size_t ii = i + 1;
|
||||
for ( ; ii < nx; ++ii) {
|
||||
bool all = true;
|
||||
for (size_t k = j; k < jj && all; ++k) {
|
||||
all = am1.get (ii, k) == am1.pixel_area ();
|
||||
}
|
||||
if (all) {
|
||||
for (size_t k = j; k < jj; ++k) {
|
||||
// disable pixel, so we do not see it again in the following columns
|
||||
am1.get (ii, k) = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ninsts += (jj - j) * (ii - i);
|
||||
|
||||
if (jj > j + 1 || ii > i + 1) {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (am1.d ().x (), 0), (unsigned long) (jj - j), (unsigned long) (ii - i));
|
||||
} else {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
|
||||
}
|
||||
|
||||
{
|
||||
// In case we run this from a tiling processor we need to lock against multithread races
|
||||
tl_assert (cell->layout () != 0);
|
||||
tl::MutexLocker locker (&cell->layout ()->lock ());
|
||||
cell->insert (array);
|
||||
}
|
||||
|
||||
if (remaining_parts) {
|
||||
if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
|
||||
db::Box fill_box (db::Point (), db::Point (am1.p ().x () * db::Coord (ii - i), am1.p ().y () * db::Coord (jj - j)));
|
||||
filled_regions.push_back (db::Polygon (fill_box.enlarged (fill_margin).moved (kernel_origin + p0)));
|
||||
} else {
|
||||
db::Box fill_box (db::Point (), db::Point () + am1.p ());
|
||||
fill_box.enlarge (fill_margin);
|
||||
for (size_t k = 0; k < jj - j; ++k) {
|
||||
for (size_t l = 0; l < ii - i; ++l) {
|
||||
filled_regions.push_back (db::Polygon (fill_box.moved (kernel_origin + p0 + db::Vector (am1.d ().x () * db::Coord (l), am1.d ().y () * db::Coord (k)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
any_fill = true;
|
||||
|
||||
}
|
||||
|
||||
j = jj;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
tl_assert (remaining_parts == 0);
|
||||
GenericRasterizer am (filled_poly, rasterized_area, row_step, column_step, origin, fc_bbox.p2 () - fc_bbox.p1 ());
|
||||
|
||||
size_t ninsts = create_instances (am, cell, fill_cell_index, kernel_origin, fill_margin, exclude_rasterized.get (), 0);
|
||||
if (ninsts > 0) {
|
||||
any_fill = true;
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 30 && ninsts > 0) {
|
||||
tl::info << "Part " << fp->to_string ();
|
||||
tl::info << "Part " << fp0.to_string ();
|
||||
tl::info << "Created " << ninsts << " instances";
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for (auto fp = filled_poly.begin (); fp != filled_poly.end (); ++fp) {
|
||||
|
||||
if (fp->is_empty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box
|
||||
bool ef = enhanced_fill;
|
||||
if (ef && ! glue_box.empty () && ! fp->box ().enlarged (db::Vector (1, 1)).inside (glue_box)) {
|
||||
ef = false;
|
||||
}
|
||||
|
||||
// pick a heuristic "good" starting point in enhanced mode
|
||||
// TODO: this is a pretty weak optimization.
|
||||
db::Point o = origin;
|
||||
if (ef) {
|
||||
o = fp->hull () [0];
|
||||
}
|
||||
|
||||
GenericRasterizer am (*fp, rasterized_area, row_step, column_step, o, fc_bbox.p2 () - fc_bbox.p1 ());
|
||||
|
||||
size_t ninsts = create_instances (am, cell, fill_cell_index, kernel_origin, fill_margin, 0, remaining_parts ? &filled_regions : 0);
|
||||
if (ninsts > 0) {
|
||||
any_fill = true;
|
||||
}
|
||||
|
||||
if (tl::verbosity () >= 30 && ninsts > 0) {
|
||||
tl::info << "Part " << fp->to_string ();
|
||||
tl::info << "Created " << ninsts << " instances";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (any_fill) {
|
||||
|
||||
if (remaining_parts) {
|
||||
db::EdgeProcessor ep;
|
||||
std::vector <db::Polygon> fp1;
|
||||
fp1.push_back (fp0);
|
||||
ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
|
||||
|
|
@ -358,25 +451,25 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
|
||||
DB_PUBLIC bool
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box)
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_box, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, glue_box);
|
||||
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_box, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
DB_PUBLIC bool
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box)
|
||||
std::vector <db::Polygon> *remaining_parts, const db::Vector &fill_margin, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
if (fc_bbox.empty () || fc_bbox.width () == 0 || fc_bbox.height () == 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid fill cell footprint (empty or zero width/height)")));
|
||||
}
|
||||
|
||||
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_bbox, db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()), origin, enhanced_fill, remaining_parts, fill_margin, glue_box);
|
||||
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_bbox, db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()), origin, enhanced_fill, remaining_parts, fill_margin, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, 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, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, int iteration, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
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")));
|
||||
|
|
@ -403,7 +496,7 @@ fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill
|
|||
tl::RelativeProgress progress (progress_title, n);
|
||||
|
||||
for (db::Region::const_iterator p = fr.begin_merged (); !p.at_end (); ++p) {
|
||||
if (! fill_polygon_impl (cell, *p, fill_cell_index, fc_bbox, row_step, column_step, origin, enhanced_fill, remaining_parts ? &rem_pp : 0, fill_margin, glue_box)) {
|
||||
if (! fill_polygon_impl (cell, *p, fill_cell_index, fc_bbox, row_step, column_step, origin, enhanced_fill, remaining_parts ? &rem_pp : 0, fill_margin, glue_box, exclude_area)) {
|
||||
if (remaining_polygons) {
|
||||
rem_poly.push_back (*p);
|
||||
}
|
||||
|
|
@ -433,27 +526,27 @@ fill_region_impl (db::Cell *cell, const db::Region &fr, db::cell_index_type fill
|
|||
|
||||
DB_PUBLIC void
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, 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, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
fill_region_impl (cell, fr, fill_cell_index, fc_bbox, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box);
|
||||
fill_region_impl (cell, fr, fill_cell_index, fc_bbox, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
DB_PUBLIC void
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_bbox, const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
if (fc_bbox.empty () || fc_bbox.width () == 0 || fc_bbox.height () == 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Invalid fill cell footprint (empty or zero width/height)")));
|
||||
}
|
||||
|
||||
fill_region_impl (cell, fr, fill_cell_index, fc_bbox, db::Vector (fc_bbox.width (), 0), db::Vector (0, fc_bbox.height ()),
|
||||
origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box);
|
||||
origin, enhanced_fill, remaining_parts, fill_margin, remaining_polygons, 0, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
DB_PUBLIC void
|
||||
fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index,
|
||||
const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
const db::Region *fill_region = &fr;
|
||||
|
||||
|
|
@ -467,7 +560,7 @@ fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fi
|
|||
++iteration;
|
||||
|
||||
remaining.clear ();
|
||||
fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, db::Point (), true, &remaining, fill_margin, remaining_polygons, iteration, glue_box);
|
||||
fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, db::Point (), true, &remaining, fill_margin, remaining_polygons, iteration, glue_box, exclude_area);
|
||||
|
||||
new_fill_region.swap (remaining);
|
||||
fill_region = &new_fill_region;
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@
|
|||
|
||||
#include "dbTypes.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
class Cell;
|
||||
class Region;
|
||||
|
||||
/**
|
||||
* @brief Creates a tiling pattern for a single polygon using a fill cell which is repeated periodically
|
||||
|
|
@ -41,6 +41,7 @@ class Region;
|
|||
* @param column_step (some_versions) The column advance vector of the fill cell. By default this is (0, fc_bbox.height())
|
||||
* @param origin Specifies the origin of the fill raster if enhanced_fill is false
|
||||
* @param enhanced_fill If set, the tiling offset will be optimized such that as much tiling cells fit into each polygon
|
||||
* @param exclude_area The region which fill cells must not overlap
|
||||
*
|
||||
* Optional parameters:
|
||||
*
|
||||
|
|
@ -79,12 +80,16 @@ class Region;
|
|||
*/
|
||||
|
||||
DB_PUBLIC bool
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), const db::Box &glue_box = db::Box ());
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box,
|
||||
const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (),
|
||||
const db::Box &glue_box = db::Box ());
|
||||
|
||||
DB_PUBLIC bool
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), const db::Box &glue_box = db::Box ());
|
||||
fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box,
|
||||
const db::Vector &row_step, const db::Vector &column_step, const db::Point &origin, bool enhanced_fill,
|
||||
std::vector <db::Polygon> *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (),
|
||||
const db::Box &glue_box = db::Box (), const db::Region &exclude_area = db::Region ());
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -98,12 +103,16 @@ fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cel
|
|||
*/
|
||||
|
||||
DB_PUBLIC void
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ());
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box,
|
||||
const db::Point &origin, bool enhanced_fill,
|
||||
db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0,
|
||||
const db::Box &glue_box = db::Box (), const db::Region &exclude_area = db::Region ());
|
||||
|
||||
DB_PUBLIC void
|
||||
fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box, 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, const db::Box &glue_box = db::Box ());
|
||||
fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell_index, const db::Box &fc_box,
|
||||
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,
|
||||
const db::Box &glue_box = db::Box (), const db::Region &exclude_area = db::Region ());
|
||||
|
||||
/**
|
||||
* @brief An iterative version for enhanced fill
|
||||
|
|
@ -118,6 +127,7 @@ fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell
|
|||
DB_PUBLIC void
|
||||
fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index,
|
||||
const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ());
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons = 0,
|
||||
const db::Box &glue_box = db::Box (), const db::Region &exclude_area = db::Region ());
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1510,23 +1510,23 @@ static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::
|
|||
|
||||
static void
|
||||
fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_skew (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point *origin,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region (cell, fr, fill_cell_index, fc_box, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region (cell, fr, fill_cell_index, fc_box, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_multi (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static db::Instance cell_inst_dtransform_simple (db::Cell *cell, const db::Instance &inst, const db::DTrans &t)
|
||||
|
|
@ -2215,6 +2215,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief Fills the given region with cells of the given type (extended version)\n"
|
||||
"@param region The region to fill\n"
|
||||
"@param fill_cell_index The fill cell to place\n"
|
||||
|
|
@ -2224,6 +2225,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"@param fill_margin See explanation below\n"
|
||||
"@param remaining_polygons See explanation below\n"
|
||||
"@param glue_box Guarantees fill cell compatibility to neighbor regions in enhanced mode\n"
|
||||
"@param exclude_area A region that defines the areas which are not be filled\n"
|
||||
"\n"
|
||||
"This method creates a regular pattern of fill cells to cover the interior of the given region as far as possible. "
|
||||
"This process is also known as tiling. This implementation supports rectangular (not necessarily square) tile cells. "
|
||||
|
|
@ -2236,6 +2238,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"The implementation will basically try to find a repetition pattern of the tile cell's footprint "
|
||||
"and produce instances which fit entirely into the fill region.\n"
|
||||
"If an exclude area is given, the fill cells also must not overlap that region.\n"
|
||||
"\n"
|
||||
"There is also a version available which offers skew step vectors as a generalization of the orthogonal ones.\n"
|
||||
"\n"
|
||||
|
|
@ -2275,7 +2278,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"at the raster implied by origin at the glue box border and beyond. To ensure fill cell compatibility inside the tiling processor, it is sufficient to use the tile "
|
||||
"box as the glue box.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.23 and enhanced in version 0.27.\n"
|
||||
"This method has been introduced in version 0.23 and enhanced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("fill_region", &fill_region_skew, gsi::arg ("region"),
|
||||
gsi::arg ("fill_cell_index"),
|
||||
|
|
@ -2287,16 +2290,18 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief Fills the given region with cells of the given type (skew step version)\n"
|
||||
"@param region The region to fill\n"
|
||||
"@param fill_cell_index The fill cell to place\n"
|
||||
"@param fc_bbox The fill cell's box to place\n"
|
||||
"@param fc_bbox The fill cell's box, defining the box that needs to be inside the fill region\n"
|
||||
"@param row_step The 'rows' step vector\n"
|
||||
"@param column_step The 'columns' step vector\n"
|
||||
"@param origin The global origin of the fill pattern or nil to allow local (per-polygon) optimization\n"
|
||||
"@param remaining_parts See explanation in other version\n"
|
||||
"@param fill_margin See explanation in other version\n"
|
||||
"@param remaining_polygons See explanation in other version\n"
|
||||
"@param exclude_area A region that defines the areas which are not be filled\n"
|
||||
"\n"
|
||||
"This version is similar to the version providing an orthogonal fill, but it offers more generic stepping of the fill cell.\n"
|
||||
"The step pattern is defined by an origin and two vectors (row_step and column_step) which span the axes of the fill cell pattern.\n"
|
||||
|
|
@ -2305,7 +2310,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"be overlapping and there can be space between the fill box instances. Fill boxes are placed where they fit entirely into a polygon of the region. "
|
||||
"The fill boxes lower left corner is the reference for the fill pattern and aligns with the origin if given.\n"
|
||||
"\n"
|
||||
"This variant has been introduced in version 0.27.\n"
|
||||
"This variant has been introduced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\n"
|
||||
) +
|
||||
gsi::method_ext ("fill_region_multi", &fill_region_multi, gsi::arg ("region"),
|
||||
gsi::arg ("fill_cell_index"),
|
||||
|
|
@ -2315,6 +2320,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief Fills the given region with cells of the given type in enhanced mode with iterations\n"
|
||||
"This version operates like \\fill_region, but repeats 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. "
|
||||
|
|
@ -2323,7 +2329,7 @@ Class<db::Cell> decl_Cell ("db", "Cell",
|
|||
"\n"
|
||||
"The origin is ignored unless a glue box is given. See \\fill_region for a description of this concept.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.27.\n"
|
||||
"This method has been introduced in version 0.27. The 'exclude_area' argument has been added in version 0.30.4.\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"
|
||||
|
|
|
|||
|
|
@ -1309,23 +1309,23 @@ tl::Variant complex_op (db::Region *region, db::CompoundRegionOperationNode *nod
|
|||
|
||||
static void
|
||||
fill_region (const db::Region *fr, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region (cell, *fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region (cell, *fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_skew (const db::Region *fr, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, const db::Point *origin,
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
db::Region *remaining_parts, const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region (cell, *fr, fill_cell_index, fc_box, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region (cell, *fr, fill_cell_index, fc_box, row_step, column_step, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_region_multi (const db::Region *fr, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step,
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box)
|
||||
const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box, const db::Region &exclude_area)
|
||||
{
|
||||
db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box);
|
||||
db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box, exclude_area);
|
||||
}
|
||||
|
||||
static db::Region
|
||||
|
|
@ -4340,6 +4340,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief A mapping of \\Cell#fill_region to the Region class\n"
|
||||
"\n"
|
||||
"This method is equivalent to \\Cell#fill_region, but is based on Region (with the cell being the first parameter).\n"
|
||||
|
|
@ -4348,14 +4349,15 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
) +
|
||||
gsi::method_ext ("fill", &fill_region_skew, gsi::arg ("in_cell"),
|
||||
gsi::arg ("fill_cell_index"),
|
||||
gsi::arg ("fc_origin"),
|
||||
gsi::arg ("fc_bbox"),
|
||||
gsi::arg ("row_step"),
|
||||
gsi::arg ("column_step"),
|
||||
gsi::arg ("origin", &default_origin, "(0, 0)"),
|
||||
gsi::arg ("remaining_parts", (db::Region *)0, "nil"),
|
||||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief A mapping of \\Cell#fill_region to the Region class\n"
|
||||
"\n"
|
||||
"This method is equivalent to \\Cell#fill_region, but is based on Region (with the cell being the first parameter).\n"
|
||||
|
|
@ -4364,12 +4366,13 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
|
|||
) +
|
||||
gsi::method_ext ("fill_multi", &fill_region_multi, gsi::arg ("in_cell"),
|
||||
gsi::arg ("fill_cell_index"),
|
||||
gsi::arg ("fc_origin"),
|
||||
gsi::arg ("fc_bbox"),
|
||||
gsi::arg ("row_step"),
|
||||
gsi::arg ("column_step"),
|
||||
gsi::arg ("fill_margin", db::Vector ()),
|
||||
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
|
||||
gsi::arg ("glue_box", db::Box ()),
|
||||
gsi::arg ("exclude_area", db::Region (), "empty"),
|
||||
"@brief A mapping of \\Cell#fill_region to the Region class\n"
|
||||
"\n"
|
||||
"This method is equivalent to \\Cell#fill_region, but is based on Region (with the cell being the first parameter).\n"
|
||||
|
|
|
|||
|
|
@ -644,6 +644,10 @@ module DRC
|
|||
DRCFillStep::new(false, x, y)
|
||||
end
|
||||
|
||||
def fill_exclude(excl)
|
||||
DRCFillExclude::new(excl)
|
||||
end
|
||||
|
||||
def auto_origin
|
||||
DRCFillOrigin::new
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5755,6 +5755,8 @@ CODE
|
|||
# @li @b multi_origin @/b: lets the algorithm choose the origin and repeats the fill with different origins
|
||||
# until no further fill cell can be fitted. @/li
|
||||
# @li @b fill_pattern(..) @/b: specifies the fill pattern. @/li
|
||||
# @li @b fill_exclude(excl) @/b: specifies a fill exclude region ('excl' is a polygon layer). This is conceptually
|
||||
# equivalent to subtracting that layer from the fill region, but usually more efficient. @/li
|
||||
# @/ul
|
||||
#
|
||||
# "fill_pattern" generates a fill pattern object. This object is used for configuring the fill pattern
|
||||
|
|
@ -5895,6 +5897,7 @@ CODE
|
|||
pattern = nil
|
||||
origin = RBA::DPoint::new
|
||||
repeat = false
|
||||
excl = RBA::Region::new
|
||||
|
||||
args.each_with_index do |a,ai|
|
||||
if a.is_a?(DRCSource)
|
||||
|
|
@ -5907,6 +5910,11 @@ CODE
|
|||
raise("Duplicate fill pattern specification for '#{m}' at argument ##{ai+1}")
|
||||
end
|
||||
pattern = a
|
||||
elsif a.is_a?(DRCFillExclude)
|
||||
if excl
|
||||
raise("Duplicate exclude region specification for '#{m}' at argument ##{ai+1}")
|
||||
end
|
||||
excl = a.excl
|
||||
elsif a.is_a?(DRCFillStep)
|
||||
if a.for_row
|
||||
if row_step
|
||||
|
|
@ -5988,6 +5996,7 @@ CODE
|
|||
tp.var("fc_index", fc_index)
|
||||
tp.var("repeat", repeat)
|
||||
tp.var("with_left", with_left)
|
||||
tp.var("excl", excl)
|
||||
|
||||
tp.queue(<<"END")
|
||||
var tc_box = _frame.bbox;
|
||||
|
|
@ -5997,8 +6006,8 @@ CODE
|
|||
tile_box = tile_box & tc_box;
|
||||
var left = with_left ? Region.new : nil;
|
||||
repeat ?
|
||||
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, left, _tile.bbox) :
|
||||
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, fill_margin, left, _tile.bbox);
|
||||
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, left, _tile.bbox, excl) :
|
||||
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, fill_margin, left, _tile.bbox, excl);
|
||||
with_left && _output(#{result_arg}, left)
|
||||
)
|
||||
END
|
||||
|
|
@ -6020,9 +6029,9 @@ END
|
|||
|
||||
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
|
||||
if repeat
|
||||
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, result)
|
||||
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, result, RBA::Box::new, excl)
|
||||
else
|
||||
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, fill_margin, result)
|
||||
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, fill_margin, result, RBA::Box::new, excl)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -475,6 +475,18 @@ module DRC
|
|||
|
||||
end
|
||||
|
||||
# A wrapper for the fill step definition
|
||||
class DRCFillExclude
|
||||
def initialize(excl)
|
||||
excl.is_a?(DRCLayer) || raise("Exclude layer argument needs to be a DRC layer")
|
||||
excl.requires_region("Exclude layer")
|
||||
@excl = excl.data
|
||||
end
|
||||
def excl
|
||||
@excl
|
||||
end
|
||||
end
|
||||
|
||||
# A wrapper for the fill step definition
|
||||
class DRCFillStep
|
||||
def initialize(for_row, x, y = nil)
|
||||
|
|
|
|||
Loading…
Reference in New Issue