Merge branch 'master' into lvs-enhancements

This commit is contained in:
Matthias Koefferlein 2021-03-30 18:56:27 +02:00
commit 94556c1448
97 changed files with 5349 additions and 2090 deletions

View File

@ -955,7 +955,7 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
// collects the cell mappings we skip because they are variants (variant building or box variants)
std::map<db::cell_index_type, db::HierarchyBuilder::CellMapKey> cm_skipped_variants;
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) {
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell () && original_builder.source ().global_trans ().is_unity ()) {
// This is the case of mapping back to the original. In this case we can use the information
// provided inside the original hierarchy builders. They list the source cells and the target cells

View File

@ -139,6 +139,8 @@ EdgePairs &EdgePairs::transform (const T &trans)
template DB_PUBLIC EdgePairs &EdgePairs::transform (const db::ICplxTrans &);
template DB_PUBLIC EdgePairs &EdgePairs::transform (const db::Trans &);
template DB_PUBLIC EdgePairs &EdgePairs::transform (const db::Disp &);
template DB_PUBLIC EdgePairs &EdgePairs::transform (const db::IMatrix2d &);
template DB_PUBLIC EdgePairs &EdgePairs::transform (const db::IMatrix3d &);
const db::RecursiveShapeIterator &
EdgePairs::iter () const

View File

@ -184,6 +184,8 @@ Edges &Edges::transform (const T &trans)
template DB_PUBLIC Edges &Edges::transform (const db::ICplxTrans &);
template DB_PUBLIC Edges &Edges::transform (const db::Trans &);
template DB_PUBLIC Edges &Edges::transform (const db::Disp &);
template DB_PUBLIC Edges &Edges::transform (const db::IMatrix2d &);
template DB_PUBLIC Edges &Edges::transform (const db::IMatrix3d &);
template <class Sh>
void Edges::insert (const Sh &shape)

View File

@ -26,366 +26,199 @@
#include "dbEdgeProcessor.h"
#include "dbRegion.h"
#include "dbCell.h"
#include "dbTilingProcessor.h"
#include "tlIntervalMap.h"
#include "tlMath.h"
namespace db
{
namespace
class GenericRasterizer
{
struct AddJoinOperator
public:
GenericRasterizer ()
: m_row_step (), m_column_step (), m_row_steps (0), m_column_steps (0), m_origin (), m_dim ()
{
void operator() (unsigned int &a, unsigned int b)
{
a += b;
}
};
}
static db::Vector
optimize_offset (const db::Polygon &fp, const db::AreaMap &am)
{
db::Coord xshift = 0, yshift = 0;
// .. 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)
: m_row_step (row_step), m_column_step (column_step), m_row_steps (0), m_column_steps (0), m_origin (origin), m_dim (dim)
{
tl::interval_map <db::Coord, unsigned int> voting;
AddJoinOperator op;
db::AreaMap::area_type amax = db::AreaMap::area_type (am.d ().x ()) * db::AreaMap::area_type (am.d ().y ());
db::Coord dx = am.d ().x ();
db::Coord dy = am.d ().y ();
size_t nx = am.nx ();
size_t ny = am.ny ();
// Derive a optimal new x offset from the mapping
for (size_t j = 0; j < size_t (ny); ++j) {
bool x1set = false;
bool x2set = false;
db::Coord x1 = 0;
db::Coord x2 = 0;
for (size_t i = 0; i < size_t (nx); ++i) {
if (am.get (i, j) >= amax) {
if (! x1set) {
x1 = 0;
x1set = true;
} else if (x2set) {
x1 = x2;
x1set = true;
x2set = false;
}
} else if (am.get (i, j) > 0) {
if (! x1set || x2set) {
x1 = db::Coord (am.get (i, j) / dy);
x1set = true;
x2set = false;
} else if (! x2set) {
x2 = db::Coord (am.get (i, j) / dy);
x2set = true;
}
} else if (am.get (i, j) == 0) {
if (x1set) {
if (! x2set) {
x2 = 0;
}
if (x1 + x2 < dx) {
voting.add (-x1, x2 + 1, (unsigned int) 1, op);
} else {
voting.add (-x1, x2 - dx + 1, (unsigned int) 1, op);
voting.add (dx - x1, x2 + 1, (unsigned int) 1, op);
}
x1set = false;
x2set = false;
}
}
}
if (x1set) {
if (! x2set) {
x2 = 0;
}
if (x1 + x2 < dx) {
voting.add (-x1, x2 + 1, (unsigned int) 1, op);
} else {
voting.add (-x1, x2 - dx + 1, (unsigned int) 1, op);
voting.add (dx - x1, x2 + 1, (unsigned int) 1, op);
}
}
}
std::set <db::Coord> xshifts;
for (db::Polygon::polygon_edge_iterator e = fp.begin_edge (); ! e.at_end (); ++e) {
xshifts.insert (((*e).p1 ().x () - am.p0 ().x ()) % dx);
}
unsigned int max_votes = 0;
for (std::set <db::Coord>::const_iterator xs = xshifts.begin (); xs != xshifts.end (); ++xs) {
const unsigned int *z = voting.mapped (*xs);
if (z && *z > max_votes) {
xshift = *xs;
max_votes = *z;
}
}
rasterize (fp);
}
void move (const db::Vector &d)
{
m_origin += d;
clear ();
}
tl::interval_map <db::Coord, unsigned int> voting;
AddJoinOperator op;
void clear ()
{
m_area_maps.clear ();
}
db::AreaMap::area_type amax = db::AreaMap::area_type (am.d ().x ()) * db::AreaMap::area_type (am.d ().y ());
void rasterize (const db::Polygon &fp)
{
db::Coord dx = m_row_step.x ();
db::Coord dy = m_column_step.y ();
db::Coord dx = am.d ().x ();
db::Coord dy = am.d ().y ();
size_t nx = am.nx ();
size_t ny = am.ny ();
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 ());
}
// Derive a optimal new y offset from the mapping
for (size_t i = 0; i < size_t (nx); ++i) {
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 ());
}
bool y1set = false;
bool y2set = false;
db::Coord y1 = 0;
db::Coord y2 = 0;
// 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 get 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;
for (size_t j = 0; j < size_t (ny); ++j) {
db::Box fp_bbox = fp.box ();
if (am.get (i, j) >= amax) {
// compensate for distortion by sheared kernel
fp_bbox.enlarge (db::Vector (db::coord_traits<db::Coord>::rounded (double (fp_bbox.height ()) * std::abs (m_column_step.x ()) / dy), db::coord_traits<db::Coord>::rounded (double (fp_bbox.width ()) * std::abs (m_row_step.y ()) / dx)));
if (! y1set) {
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;
y1 = 0;
y1set = true;
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;
} else if (y2set) {
// 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);
y1 = y2;
y1set = true;
y2set = false;
size_t nx = fp_bbox.width () / ddx;
size_t ny = fp_bbox.height () / ddy;
}
tl_assert (fp.box ().inside (fp_bbox));
} else if (am.get (i, j) > 0) {
if (nx == 0 || ny == 0) {
// nothing to rasterize:
return;
}
if (! y1set || y2set) {
m_area_maps.reserve (m_row_steps * m_column_steps + std::abs (columns_per_rows) * std::abs (rows_per_columns));
y1 = db::Coord (am.get (i, j) / dx);
y1set = true;
y2set = false;
db::AreaMap am;
} else if (! y2set) {
for (unsigned int ic = 0; ic < m_column_steps; ++ic) {
y2 = db::Coord (am.get (i, j) / dx);
y2set = true;
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);
} else if (am.get (i, j) == 0) {
am.reinitialize (db::Point (fp_left, fp_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
if (y1set) {
if (! y2set) {
y2 = 0;
}
if (y1 + y2 < dy) {
voting.add (-y1, y2 + 1, (unsigned int) 1, op);
} else {
voting.add (-y1, y2 - dy + 1, (unsigned int) 1, op);
voting.add (dy - y1, y2 + 1, (unsigned int) 1, op);
}
y1set = false;
y2set = false;
}
}
}
if (y1set) {
if (! y2set) {
y2 = 0;
}
if (y1 + y2 < dy) {
voting.add (-y1, y2 + 1, (unsigned int) 1, op);
} else {
voting.add (-y1, y2 - dy + 1, (unsigned int) 1, op);
voting.add (dy - y1, y2 + 1, (unsigned int) 1, op);
if (db::rasterize (fp, am)) {
m_area_maps.push_back (db::AreaMap ());
m_area_maps.back ().swap (am);
}
}
}
std::set <db::Coord> yshifts;
for (db::Polygon::polygon_edge_iterator e = fp.begin_edge (); ! e.at_end (); ++e) {
yshifts.insert (((*e).p1 ().y () - am.p0 ().y ()) % dy);
}
// adds the "dead corner" piece
unsigned int max_votes = 0;
for (std::set <db::Coord>::const_iterator ys = yshifts.begin (); ys != yshifts.end (); ++ys) {
const unsigned int *z = voting.mapped (*ys);
if (z && *z > max_votes) {
yshift = *ys;
max_votes = *z;
}
}
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) {
return db::Vector (xshift, yshift);
}
db::Vector dr = m_row_step * long ((rows_per_columns > 0 ? -(ir + 1) : ir) + m_row_steps);
db::Vector dc = m_column_step * long ((columns_per_rows > 0 ? -(ic + 1) : ic) + m_column_steps);
static bool
rasterize_simple (const db::Polygon &fp, const db::Box &fc_bbox, const db::Point &p0, db::AreaMap &am)
{
db::Coord dx = fc_bbox.width ();
db::Coord dy = fc_bbox.height ();
am.reinitialize (db::Point (fp_left, fp_bottom) + dr + dc, db::Vector (ddx, ddy), m_dim, nx, ny);
if (tl::verbosity () >= 50) {
tl::info << "Simple rasterize polygon: " << fp.to_string () << " with box " << fc_bbox.to_string ();
}
db::Box fp_bbox = fp.box ();
// round polygon bbox
db::Coord fp_left = dx * ((fp_bbox.left () - p0.x ()) / dx) + p0.x ();
db::Coord fp_bottom = dy * ((fp_bbox.bottom () - p0.y ()) / dy) + p0.y ();
db::Coord fp_right = dx * ((fp_bbox.right () + dx - 1 - p0.x ()) / dx) + p0.x ();
db::Coord fp_top = dy * ((fp_bbox.top () + dy - 1 - p0.y ()) / dy) + p0.y ();
fp_bbox = db::Box (fp_left, fp_bottom, fp_right, fp_top);
db::Coord nx = fp_bbox.width () / dx;
db::Coord ny = fp_bbox.height () / dy;
if (nx <= 0 || ny <= 0) {
// nothing to rasterize:
return false;
}
am.reinitialize (fp_bbox.p1 (), db::Vector (dx, dy), size_t (nx), size_t (ny));
// Rasterize to determine fill regions
db::rasterize (fp, am);
return true;
}
static bool
rasterize_extended (const db::Polygon &fp, const db::Box &fc_bbox, db::AreaMap &am)
{
db::Coord dx = fc_bbox.width ();
db::Coord dy = fc_bbox.height ();
if (tl::verbosity () >= 50) {
tl::info << "Optimized rasterize polygon: " << fp.to_string () << " with box " << fc_bbox.to_string ();
}
db::Box fp_bbox = fp.box ();
db::Coord nx = (fp_bbox.width () + dx - 1) / dx;
db::Coord ny = (fp_bbox.height () + dy - 1) / dy;
if (nx <= 0 || ny <= 0) {
// nothing to rasterize:
return false;
}
am.reinitialize (fp_bbox.p1 (), db::Vector (dx, dy), size_t (nx), size_t (ny));
// Rasterize to determine fill regions
db::rasterize (fp, am);
if (tl::verbosity () >= 50) {
db::Coord nx = db::Coord (am.nx ());
db::Coord ny = db::Coord (am.ny ());
db::AreaMap::area_type amax = am.pixel_area ();
double n = 0;
for (size_t i = 0; i < size_t (nx); ++i) {
for (size_t j = 0; j < size_t (ny); ++j) {
if (am.get (i, j) >= amax) {
n += 1;
if (db::rasterize (fp, am)) {
m_area_maps.push_back (db::AreaMap ());
m_area_maps.back ().swap (am);
}
}
}
tl::info << "Number of fill regions before optimization: " << n;
}
db::Vector d = optimize_offset (fp, am);
size_t filled_pixels () const
{
size_t n = 0;
if (tl::verbosity () >= 50) {
tl::info << "Shift vector: " << d.to_string ();
}
for (std::vector<db::AreaMap>::const_iterator a = m_area_maps.begin (); a != m_area_maps.end (); ++a) {
if (d.x () != 0 || d.y () != 0) {
db::Coord nx = db::Coord (a->nx ());
db::Coord ny = db::Coord (a->ny ());
db::AreaMap::area_type amax = a->pixel_area ();
am.move (d);
am.clear ();
db::rasterize (fp, am);
if (tl::verbosity () >= 50) {
db::Coord nx = db::Coord (am.nx ());
db::Coord ny = db::Coord (am.ny ());
db::AreaMap::area_type amax = am.pixel_area ();
double n = 0;
for (size_t i = 0; i < size_t (nx); ++i) {
for (size_t j = 0; j < size_t (ny); ++j) {
if (am.get (i, j) >= amax) {
if (a->get (i, j) >= amax) {
n += 1;
}
}
}
tl::info << "Number of fill regions after optimization: " << n;
}
return n;
}
return true;
}
const db::Point &p0 () const { return m_origin; }
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)
unsigned int row_steps () const { return m_row_steps; }
unsigned int column_steps () const { return m_column_steps; }
unsigned int area_maps () const
{
return m_area_maps.size ();
}
const db::AreaMap &area_map (unsigned int i) const
{
return m_area_maps [i];
}
private:
std::vector<db::AreaMap> m_area_maps;
db::Vector m_row_step, m_column_step;
unsigned int m_row_steps, m_column_steps;
db::Point m_origin;
db::Vector m_dim;
};
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)
{
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")));
}
if (db::vprod_sign (row_step, column_step) <= 0) {
throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row_step x column_step vector vector product must be > 0")));
}
// disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box
if (enhanced_fill && ! glue_box.empty () && ! fp0.box ().enlarged (db::Vector (1, 1)).inside (glue_box)) {
enhanced_fill = false;
}
db::Vector kernel_origin (fc_bbox.left (), fc_bbox.bottom ());
std::vector <db::Polygon> filled_regions;
db::EdgeProcessor ep;
@ -419,17 +252,25 @@ fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_ce
for (std::vector <db::Polygon>::const_iterator fp = fpb.begin (); fp != fpb.end (); ++fp) {
if (fp->hull ().size () == 0) {
continue;
}
size_t ninsts = 0;
db::AreaMap am;
db::Point o = origin;
if (enhanced_fill) {
o = fp->hull () [0];
}
// Rasterize to determine fill regions
if ((enhanced_fill && rasterize_extended (*fp, fc_bbox, am)) || (!enhanced_fill && rasterize_simple (*fp, fc_bbox, origin, am))) {
GenericRasterizer am (*fp, row_step, column_step, o, fc_bbox.p2 () - fc_bbox.p1 ());
size_t nx = am.nx ();
size_t ny = am.ny ();
for (unsigned int i = 0; i < am.area_maps (); ++i) {
db::AreaMap::area_type amax = am.pixel_area ();
const 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) {
@ -437,31 +278,41 @@ fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_ce
for (size_t j = 0; j < ny; ) {
size_t jj = j + 1;
if (am.get (i, j) >= amax) {
if (am1.get (i, j) == am1.pixel_area ()) {
while (jj != ny && am.get (i, jj) >= amax) {
while (jj != ny && am1.get (i, jj) == am1.pixel_area ()) {
++jj;
}
ninsts += (jj - j);
db::Vector p0 (am.p0 () - fc_bbox.p1 ());
p0 += db::Vector (db::Coord (i) * fc_bbox.width (), db::Coord (j) * fc_bbox.height ());
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
db::CellInstArray array;
if (jj > j + 1) {
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, fc_bbox.height ()), db::Vector (fc_bbox.width (), 0), (unsigned long) (jj - j), 1);
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (), (unsigned long) (jj - j), 1);
} else {
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
}
cell->insert (array);
{
// In case we run this from a tiling processor we need to lock against multithread races
tl::MutexLocker locker (&db::TilingProcessor::output_lock ());
cell->insert (array);
}
if (remaining_parts) {
db::Box filled_box = array.raw_bbox () * fc_bbox;
filled_regions.push_back (db::Polygon (filled_box.enlarged (fill_margin)));
if (am1.d ().y () == am1.p ().y ()) {
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point (am1.p ().x (), am1.p ().y () * (jj - j))).moved (kernel_origin + p0)));
} else {
for (size_t k = 0; k < jj - j; ++k) {
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point () + am1.p ()).moved (kernel_origin + p0 + db::Vector (0, am1.d ().y () * db::Coord (k)))));
}
}
}
any_fill = true;
}
@ -484,9 +335,19 @@ fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_ce
if (any_fill) {
if (remaining_parts) {
std::vector <db::Polygon> fp1;
if (fill_margin != db::Vector ()) {
ep.size (filled_regions, fill_margin.x (), fill_margin.y (), fp1, 3 /*mode*/, false /*=don't resolve holes*/);
filled_regions.swap (fp1);
fp1.clear ();
}
fp1.push_back (fp0);
ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
}
return true;
@ -496,17 +357,59 @@ fill_region (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type fill_ce
}
}
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, const db::Vector &fill_margin, db::Region *remaining_polygons)
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)
{
return fill_polygon_impl (cell, fp0, fill_cell_index, fc_box, row_step, column_step, origin, enhanced_fill, remaining_parts, fill_margin, glue_box);
}
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)
{
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);
}
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)
{
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")));
}
if (db::vprod_sign (row_step, column_step) <= 0) {
throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row_step x column_step vector vector product must be > 0")));
}
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, fc_box, 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_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 (remaining_polygons) {
rem_poly.push_back (*p);
}
}
++progress;
}
}
@ -529,4 +432,48 @@ 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::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)
{
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);
}
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)
{
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);
}
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::Point &origin, const db::Box &glue_box)
{
const db::Region *fill_region = &fr;
db::Region new_fill_region;
db::Region remaining;
int iteration = 0;
while (! fill_region->empty ()) {
++iteration;
remaining.clear ();
fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, origin, true, &remaining, fill_margin, remaining_polygons, iteration, glue_box);
new_fill_region.swap (remaining);
fill_region = &new_fill_region;
}
}
}

View File

@ -37,6 +37,8 @@ class Region;
* @param fp0 The polygon to fill. Ideally, this polygon is merged and does not overlap with any other polygons.
* @param fill_cell_index The index of the cell to use for tiling
* @param fc_bbox The fill cell's footprint box. The footprint gives the area covered by one instance of the tiling cell.
* @param row_step (some_versions) The row advance vector of the fill cell. By default this is (fc_bbox.width(), 0)
* @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
*
@ -44,13 +46,45 @@ class Region;
*
* @param remaining_parts If non-null, this vector receives the parts of the polygons not covered by the tiling cells (plus the fill_margin)
* @param fill_margin Only used if remaining_parts is not 0 (see there)
* @param glue_box Guarantees boundary compatibility
*
* Return value: true, if the polygon could be filled, false if no fill tile at all could be applied (remaining_parts will not be fed in that case)
*
* Explanation for the fill fc_box, row step and column step vectors:
*
* The "fc_box" is a rectangular area which is repeated along the primary fill axes given by row_step
* and column_step vectors. The fill box is placed with the lower-left corner.
*
* Formally, the fill box will be placed a positions
*
* p(i,j) = p0 + i * row_step + j * column_step
*
* p0 is a position chosen by the fill alogorithm or the "origin", if enhanced_fill is false.
*
* This pattern is overlaid with the polygon to fill and all instances where the fill box moved by p(i,j) is entirely inside
* the polygon generate a fill cell instance with a displacement of p.
*
* Afterwards, the residual parts are computed by subtracting all moved fill boxes from the polygon to fill.
* This implies that ideally the fc_boxes should overlap while they are repeated with row_step and column_step.
*
* As a practical consequence, if all fill cell geometries are within the fill boxes boundary, they will also
* be within the polygon to fill.
*
* If the glue box is non-empty, fill cells are guaranteed to use the global origin even in enhanced mode if
* unless they are entirely inside and not touching the boundary of the glue box.
* The glue box is useful to put the fill algorithm inside a tiling processor. In this case, the glue box
* is the tile box while the actual fill region can be larger to allow overlapping tiles.
*
* In enhanced fill mode, the origin is ignored unless a glue box is given.
*/
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 ());
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 ());
/**
@ -59,11 +93,31 @@ fill_region (db::Cell *cell, const db::Polygon &fp, db::cell_index_type fill_cel
* remaining_parts (if non-null) will receive the non-filled parts of partially filled polygons.
* fill_margin will specify the margin around the filled area when computing (through subtraction of the tiled area) the remaining_parts.
* remaining_polygons (if non-null) will receive the polygons which could not be filled at all.
*
* In enhanced fill mode, the origin is ignored unless a glue box is given.
*/
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);
db::Region *remaining_parts = 0, const db::Vector &fill_margin = db::Vector (), db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ());
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 ());
/**
* @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.
*
* This version implies enhanced_mode (see "fill_region").
*
* The origin is ignored unless a glue box is given.
*/
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::Point &origin = db::Point (), const db::Box &glue_box = db::Box ());
}

View File

@ -40,10 +40,10 @@ int
compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2)
{
if ((iter1.layout () == 0) != (iter2.layout () == 0)) {
return (iter1.layout () == 0) < (iter2.layout () == 0);
return (iter1.layout () == 0) < (iter2.layout () == 0) ? -1 : 1;
}
if ((iter1.top_cell () == 0) != (iter2.top_cell () == 0)) {
return (iter1.top_cell () == 0) < (iter2.top_cell () == 0);
return (iter1.top_cell () == 0) < (iter2.top_cell () == 0) ? -1 : 1;
}
// basic source (layout, top_cell) needs to be the same of course
@ -70,6 +70,11 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
return iter1.enables () < iter2.enables () ? -1 : 1;
}
// compare global transformations
if (! iter1.global_trans ().equal (iter2.global_trans ())) {
return iter1.global_trans ().less (iter2.global_trans ()) ? -1 : 1;
}
// if a region is set, the hierarchical appearance is the same only if the layers and
// complex region are identical
if ((iter1.region () == db::Box::world ()) != (iter2.region () == db::Box::world ())) {
@ -338,7 +343,7 @@ HierarchyBuilder::make_cell_variant (const HierarchyBuilder::CellMapKey &key, co
}
HierarchyBuilder::new_inst_mode
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
if (all) {
@ -349,6 +354,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (inst, &mp_target->array_repository ());
new_inst.object () = db::CellInst (new_cell);
new_inst.transform (always_apply);
new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst);
@ -367,7 +373,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
}
bool
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
{
if (all) {
@ -386,7 +392,7 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
// for a new cell, create this instance
if (m_cell_stack.back ().first) {
db::CellInstArray new_inst (db::CellInst (new_cell), trans);
db::CellInstArray new_inst (db::CellInst (new_cell), always_apply * trans);
new_inst.transform_into (m_trans);
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
(*c)->insert (new_inst);
@ -399,11 +405,11 @@ HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db:
}
void
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box &region, const box_tree_type *complex_region)
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &apply_always, const db::ICplxTrans & /*trans*/, const db::Box &region, const box_tree_type *complex_region)
{
for (std::vector<db::Cell *>::const_iterator c = m_cell_stack.back ().second.begin (); c != m_cell_stack.back ().second.end (); ++c) {
db::Shapes &shapes = (*c)->shapes (m_target_layer);
mp_pipe->push (shape, m_trans, region, complex_region, &shapes);
mp_pipe->push (shape, m_trans * apply_always, region, complex_region, &shapes);
}
}
@ -528,9 +534,12 @@ ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Box &box, const
if (complex_region) {
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (bb, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
mp_pipe->push (*cr & bb, trans, world, 0, target);
db::Box bc = *cr & bb;
if (! bc.empty ()) {
mp_pipe->push (bc, trans, world, 0, target);
}
}
} else {
} else if (! bb.empty ()) {
mp_pipe->push (bb, trans, world, 0, target);
}
}

View File

@ -273,9 +273,9 @@ public:
virtual void end (const RecursiveShapeIterator *iter);
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box &region, const box_tree_type *complex_region);
virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell);
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region);
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region);
/**
* @brief Sets the target layer - shapes will be put there

View File

@ -37,14 +37,16 @@ inline double mnorm (double x)
return fabs (x) < 1e-14 ? 0.0 : x;
}
template <class C>
std::string
Matrix2d::to_string () const
matrix_2d<C>::to_string () const
{
return tl::sprintf ("(%.12g,%.12g) (%.12g,%.12g)", mnorm (m_m11), mnorm (m_m12), mnorm (m_m21), mnorm (m_m22));
}
std::pair<double, double>
Matrix2d::mag () const
template <class C>
std::pair<double, double>
matrix_2d<C>::mag () const
{
double s1 = sqrt (m_m11 * m_m11 + m_m21 * m_m21);
double s2 = sqrt (m_m12 * m_m12 + m_m22 * m_m22);
@ -52,14 +54,16 @@ Matrix2d::mag () const
return std::make_pair (n * s1, n * s2);
}
template <class C>
bool
Matrix2d::has_rotation () const
matrix_2d<C>::has_rotation () const
{
return fabs (m_m11 - 1.0) > 1e-10 || fabs (m_m12) > 1e-10 || fabs (m_m21) > 1e-10 || fabs (m_m22 - 1.0) > 1e-10;
}
double
Matrix2d::angle () const
template <class C>
double
matrix_2d<C>::angle () const
{
std::pair <double, double> m = mag ();
double u1 = m.first;
@ -82,15 +86,17 @@ Matrix2d::angle () const
return 180.0 * atan2 (sin_a, cos_a) / M_PI;
}
Matrix2d
Matrix2d::rotation (double a)
template <class C>
matrix_2d<C>
matrix_2d<C>::rotation (double a)
{
a *= M_PI / 180.0;
return Matrix2d (cos (a), -sin (a), sin (a), cos (a));
}
bool
Matrix2d::has_shear () const
template <class C>
bool
matrix_2d<C>::has_shear () const
{
std::pair <double, double> m = mag ();
double u1 = m.first;
@ -104,8 +110,9 @@ Matrix2d::has_shear () const
return fabs (fsin_a) > 1e-10;
}
double
Matrix2d::shear_angle () const
template <class C>
double
matrix_2d<C>::shear_angle () const
{
std::pair <double, double> m = mag ();
double u1 = m.first;
@ -124,8 +131,9 @@ Matrix2d::shear_angle () const
return 180.0 * atan2 (fsin_a, fcos_a) / M_PI;
}
Matrix2d
Matrix2d::shear (double a)
template <class C>
matrix_2d<C>
matrix_2d<C>::shear (double a)
{
a *= M_PI / 180.0;
double cos_a = cos (a);
@ -134,21 +142,32 @@ Matrix2d::shear (double a)
return Matrix2d (f * cos_a, f * sin_a, f * sin_a, f * cos_a);
}
bool
Matrix2d::is_ortho () const
template <class C>
bool
matrix_2d<C>::is_ortho () const
{
return fabs (m_m11 * m_m12 + m_m21 * m_m22) < 1e-10 && fabs (m_m11 * m_m12) < 1e-10 && fabs (m_m21 * m_m22) < 1e-10;
}
bool
Matrix2d::equal (const Matrix2d &d) const
template <class C>
bool
matrix_2d<C>::is_unity () const
{
static matrix_2d<C> u;
return equal (u);
}
template <class C>
bool
matrix_2d<C>::equal (const matrix_2d<C> &d) const
{
return fabs (m_m11 - d.m_m11) < 1e-10 && fabs (m_m12 - d.m_m12) < 1e-10 &&
fabs (m_m21 - d.m_m21) < 1e-10 && fabs (m_m22 - d.m_m22) < 1e-10;
}
bool
Matrix2d::less (const Matrix2d &d) const
template <class C>
bool
matrix_2d<C>::less (const matrix_2d<C> &d) const
{
if (fabs (m_m11 - d.m_m11) > 1e-10) {
return m_m11 < d.m_m11;
@ -165,10 +184,14 @@ Matrix2d::less (const Matrix2d &d) const
return false;
}
template class matrix_2d<db::Coord>;
template class matrix_2d<db::DCoord>;
// --------------------------------------------------------------------------------------------
double
Matrix3d::det () const
template <class C>
double
matrix_3d<C>::det () const
{
double d = 0.0;
for (int i0 = 0; i0 < 3; ++i0) {
@ -182,8 +205,9 @@ Matrix3d::det () const
return d;
}
db::DVector
Matrix3d::trans (const db::DPoint &p, const db::DVector &v) const
template <class C>
db::vector<C>
matrix_3d<C>::trans (const db::point<C> &p, const db::vector<C> &v) const
{
double t[2][2];
for (int i = 0; i < 2; ++i) {
@ -191,11 +215,12 @@ Matrix3d::trans (const db::DPoint &p, const db::DVector &v) const
t[i][j] = (m_m[i][j] * m_m[2][1 - j] - m_m[i][1 - j] * m_m[2][j]) * (j == 0 ? p.y() : p.x()) + (m_m[2][2] * m_m[i][j] - m_m[i][2] * m_m[2][j]);
}
}
return db::DVector(v.x() * t[0][0] + v.y() * t[0][1], v.x() * t[1][0] + v.y() * t[1][1]);
return db::vector<C>(v.x() * t[0][0] + v.y() * t[0][1], v.x() * t[1][0] + v.y() * t[1][1]);
}
template <class C>
bool
Matrix3d::can_transform (const db::DPoint &p) const
matrix_3d<C>::can_transform (const db::point<C> &p) const
{
double r[3] = { 0, 0, 0 };
for (int i = 0; i < 3; ++i) {
@ -205,8 +230,9 @@ Matrix3d::can_transform (const db::DPoint &p) const
return (r[2] > (std::abs (r[0]) + std::abs (r[1])) * 1e-10);
}
db::DPoint
Matrix3d::trans (const db::DPoint &p) const
template <class C>
db::point<C>
matrix_3d<C>::trans (const db::point<C> &p) const
{
double r[3] = { 0, 0, 0 };
for (int i = 0; i < 3; ++i) {
@ -215,14 +241,15 @@ Matrix3d::trans (const db::DPoint &p) const
// safe approximation to the forbidden area where z <= 0
double z = std::max (r [2], (std::abs (r[0]) + std::abs (r[1])) * 1e-10);
return db::DPoint (r[0] / z, r[1] / z);
return db::point<C> (r[0] / z, r[1] / z);
}
Matrix3d
Matrix3d::inverted () const
template <class C>
matrix_3d<C>
matrix_3d<C>::inverted () const
{
double m[3][3];
Matrix3d r (1.0);
matrix_3d<C> r (1.0);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
@ -268,71 +295,88 @@ Matrix3d::inverted () const
return r;
}
db::DVector
Matrix3d::disp () const
template <class C>
db::vector<C>
matrix_3d<C>::disp () const
{
return db::DVector (m_m[0][2] / m_m[2][2], m_m[1][2] / m_m[2][2]);
return db::vector<C> (m_m[0][2] / m_m[2][2], m_m[1][2] / m_m[2][2]);
}
double
Matrix3d::perspective_tilt_x (double z) const
template <class C>
double
matrix_3d<C>::perspective_tilt_x (double z) const
{
db::DVector d = disp ();
db::Matrix3d m = db::Matrix3d::disp (-d) * *this;
db::vector<C> d = disp ();
db::matrix_3d<C> m = db::matrix_3d<C>::disp (-d) * *this;
return 180 * atan (z * (m.m ()[2][0] * m.m ()[1][1] - m.m ()[2][1] * m.m ()[1][0]) / (m.m ()[0][0] * m.m ()[1][1] - m.m ()[0][1] * m.m ()[1][0])) / M_PI;
}
double
Matrix3d::perspective_tilt_y (double z) const
template <class C>
double
matrix_3d<C>::perspective_tilt_y (double z) const
{
db::DVector d = disp ();
db::Matrix3d m = db::Matrix3d::disp (-d) * *this;
db::vector<C> d = disp ();
db::matrix_3d<C> m = db::matrix_3d<C>::disp (-d) * *this;
return 180 * atan (z * (m.m ()[2][1] * m.m ()[0][0] - m.m ()[2][0] * m.m ()[0][1]) / (m.m ()[0][0] * m.m ()[1][1] - m.m ()[0][1] * m.m ()[1][0])) / M_PI;
}
bool
Matrix3d::has_perspective () const
template <class C>
bool
matrix_3d<C>::has_perspective () const
{
return fabs (m_m[2][0]) + fabs (m_m[2][1]) > 1e-10;
}
Matrix3d
Matrix3d::perspective (double tx, double ty, double z)
template <class C>
matrix_3d<C>
matrix_3d<C>::perspective (double tx, double ty, double z)
{
tx *= M_PI / 180.0;
ty *= M_PI / 180.0;
return Matrix3d (1.0, 0.0, 0.0, 1.0, 0.0, 0.0, tan (tx) / z, tan (ty) / z);
return matrix_3d<C> (1.0, 0.0, 0.0, 1.0, 0.0, 0.0, tan (tx) / z, tan (ty) / z);
}
Matrix2d
Matrix3d::m2d () const
template <class C>
matrix_2d<C>
matrix_3d<C>::m2d () const
{
db::DVector d = disp ();
db::Matrix3d m = db::Matrix3d::disp (-d) * *this;
db::vector<C> d = disp ();
db::matrix_3d<C> m = db::matrix_3d<C>::disp (-d) * *this;
if (has_perspective ()) {
m = Matrix3d::perspective (-perspective_tilt_x (1.0), -perspective_tilt_y (1.0), 1.0) * m;
m = matrix_3d<C>::perspective (-perspective_tilt_x (1.0), -perspective_tilt_y (1.0), 1.0) * m;
}
return Matrix2d (m.m_m[0][0] / m.m_m[2][2], m.m_m[0][1] / m.m_m[2][2], m.m_m[1][0] / m.m_m[2][2], m.m_m[1][1] / m.m_m[2][2]);
return matrix_2d<C> (m.m_m[0][0] / m.m_m[2][2], m.m_m[0][1] / m.m_m[2][2], m.m_m[1][0] / m.m_m[2][2], m.m_m[1][1] / m.m_m[2][2]);
}
std::string
Matrix3d::to_string () const
template <class C>
std::string
matrix_3d<C>::to_string () const
{
return tl::sprintf ("(%.12g,%.12g,%.12g)", mnorm (m_m[0][0]), mnorm (m_m[0][1]), mnorm (m_m[0][2])) + " "
+ tl::sprintf ("(%.12g,%.12g,%.12g)", mnorm (m_m[1][0]), mnorm (m_m[1][1]), mnorm (m_m[1][2])) + " "
+ tl::sprintf ("(%.12g,%.12g,%.12g)", mnorm (m_m[2][0]), mnorm (m_m[2][1]), mnorm (m_m[2][2]));
}
bool
Matrix3d::is_ortho () const
template <class C>
bool
matrix_3d<C>::is_ortho () const
{
return ! has_perspective () && m2d ().is_ortho ();
}
bool
Matrix3d::equal (const Matrix3d &d) const
template <class C>
bool
matrix_3d<C>::is_unity () const
{
static matrix_3d<C> u;
return equal (u);
}
template <class C>
bool
matrix_3d<C>::equal (const matrix_3d<C> &d) const
{
for (unsigned int i = 0; i < 3; ++i) {
for (unsigned int j = 0; j < 3; ++j) {
@ -344,8 +388,9 @@ Matrix3d::equal (const Matrix3d &d) const
return true;
}
bool
Matrix3d::less (const Matrix3d &d) const
template <class C>
bool
matrix_3d<C>::less (const matrix_3d<C> &d) const
{
for (unsigned int i = 0; i < 3; ++i) {
for (unsigned int j = 0; j < 3; ++j) {
@ -357,6 +402,9 @@ Matrix3d::less (const Matrix3d &d) const
return false;
}
template class matrix_3d<db::Coord>;
template class matrix_3d<db::DCoord>;
// --------------------------------------------------------------------------------------------
/**
@ -775,7 +823,7 @@ adjust_matrix (Matrix3d &matrix, const std::vector <db::DPoint> &landmarks_befor
namespace tl
{
template<> bool test_extractor_impl (tl::Extractor &ex, db::Matrix2d &m)
template<class C> bool test_extractor_impl_matrix2d (tl::Extractor &ex, db::matrix_2d<C> &m)
{
double m11 = 0.0, m12 = 0.0, m21 = 0.0, m22 = 0.0;
@ -811,18 +859,18 @@ namespace tl
return false;
}
m = db::Matrix2d (m11, m12, m21, m22);
m = db::matrix_2d<C> (m11, m12, m21, m22);
return true;
}
template<> void extractor_impl (tl::Extractor &ex, db::Matrix2d &m)
template<class C> void extractor_impl_matrix2d (tl::Extractor &ex, db::matrix_2d<C> &m)
{
if (! test_extractor_impl (ex, m)) {
ex.error (tl::to_string (tr ("Expected a 2d matrix specification")));
}
}
template<> bool test_extractor_impl (tl::Extractor &ex, db::Matrix3d &m)
template<class C> bool test_extractor_impl_matrix3d (tl::Extractor &ex, db::matrix_3d<C> &m)
{
double m11 = 0.0, m12 = 0.0, m13 = 0.0, m21 = 0.0, m22 = 0.0, m23 = 0.0, m31 = 0.0, m32 = 0.0, m33 = 0.0;
@ -892,16 +940,56 @@ namespace tl
return false;
}
m = db::Matrix3d (m11, m12, m13, m21, m22, m23, m31, m32, m33);
m = db::matrix_3d<C> (m11, m12, m13, m21, m22, m23, m31, m32, m33);
return true;
}
template<> void extractor_impl (tl::Extractor &ex, db::Matrix3d &m)
template<class C> void extractor_impl_matrix3d (tl::Extractor &ex, db::matrix_3d<C> &m)
{
if (! test_extractor_impl (ex, m)) {
ex.error (tl::to_string (tr ("Expected a 3d matrix specification")));
}
}
template<> void extractor_impl<db::matrix_2d<db::Coord> > (tl::Extractor &ex, db::matrix_2d<db::Coord> &m)
{
extractor_impl_matrix2d (ex, m);
}
template<> void extractor_impl<db::matrix_2d<db::DCoord> > (tl::Extractor &ex, db::matrix_2d<db::DCoord> &m)
{
extractor_impl_matrix2d (ex, m);
}
template<> void extractor_impl<db::matrix_3d<db::Coord> > (tl::Extractor &ex, db::matrix_3d<db::Coord> &m)
{
extractor_impl_matrix3d (ex, m);
}
template<> void extractor_impl<db::matrix_3d<db::DCoord> > (tl::Extractor &ex, db::matrix_3d<db::DCoord> &m)
{
extractor_impl_matrix3d (ex, m);
}
template<> bool test_extractor_impl<db::matrix_2d<db::Coord> > (tl::Extractor &ex, db::matrix_2d<db::Coord> &m)
{
return test_extractor_impl_matrix2d (ex, m);
}
template<> bool test_extractor_impl<db::matrix_2d<db::DCoord> > (tl::Extractor &ex, db::matrix_2d<db::DCoord> &m)
{
return test_extractor_impl_matrix2d (ex, m);
}
template<> bool test_extractor_impl<db::matrix_3d<db::Coord> > (tl::Extractor &ex, db::matrix_3d<db::Coord> &m)
{
return test_extractor_impl_matrix3d (ex, m);
}
template<> bool test_extractor_impl<db::matrix_3d<db::DCoord> > (tl::Extractor &ex, db::matrix_3d<db::DCoord> &m)
{
return test_extractor_impl_matrix3d (ex, m);
}
}

View File

@ -42,23 +42,24 @@ namespace db
/**
* @brief A class representing a 2d matrix, mainly to represent a rotation or shear transformation of 2d vectors
*/
class DB_PUBLIC Matrix2d
template <class C>
class DB_PUBLIC matrix_2d
{
public:
/**
* @brief typedefs for compatibility with the other transformations
*/
typedef double target_coord_type;
typedef double coord_type;
typedef db::DPoint displacement_type;
typedef Matrix2d inverse_trans;
typedef C target_coord_type;
typedef C coord_type;
typedef db::point<C> displacement_type;
typedef matrix_2d<C> inverse_trans;
/**
* @brief Default ctor
*
* Creates a null matrix
*/
Matrix2d ()
matrix_2d ()
: m_m11 (0.0), m_m12 (0.0), m_m21 (0.0), m_m22 (0.0)
{
// .. nothing yet ..
@ -69,18 +70,30 @@ public:
*
* Creates a matrix (m11, m12) (m21, m22)
*/
Matrix2d (double m11, double m12, double m21, double m22)
matrix_2d (double m11, double m12, double m21, double m22)
: m_m11 (m11), m_m12 (m12), m_m21 (m21), m_m22 (m22)
{
// .. nothing yet ..
}
/**
* @brief Full ctor
*
* Creates a matrix (m11, m12) (m21, m22)
*/
template <class D>
matrix_2d (const matrix_2d<D> &m)
: m_m11 (m.m11 ()), m_m12 (m.m12 ()), m_m21 (m.m21 ()), m_m22 (m.m22 ())
{
// .. nothing yet ..
}
/**
* @brief Scalar ctor
*
* Creates a matrix (d, 0) (0, d)
*/
Matrix2d (double d)
matrix_2d (double d)
: m_m11 (d), m_m12 (0.0), m_m21 (0.0), m_m22 (d)
{
// .. nothing yet ..
@ -91,7 +104,7 @@ public:
*
* Creates a matrix (d1, 0) (0, d2)
*/
Matrix2d (double d1, double d2)
matrix_2d (double d1, double d2)
: m_m11 (d1), m_m12 (0.0), m_m21 (0.0), m_m22 (d2)
{
// .. nothing yet ..
@ -101,7 +114,7 @@ public:
* @brief Make a matrix from a transformation
*/
template <class Tr>
Matrix2d (const Tr &t)
matrix_2d (const Tr &t)
{
*this = t.to_matrix2d ();
}
@ -109,9 +122,10 @@ public:
/**
* @brief Add operator
*/
Matrix2d operator+ (const Matrix2d &other) const
template <class D>
matrix_2d operator+ (const matrix_2d<D> &other) const
{
Matrix2d m (*this);
matrix_2d m (*this);
m += other;
return m;
}
@ -119,7 +133,8 @@ public:
/**
* @brief Add to operator
*/
Matrix2d &operator+= (const Matrix2d &other)
template <class D>
matrix_2d &operator+= (const matrix_2d<D> &other)
{
m_m11 += other.m_m11;
m_m12 += other.m_m12;
@ -131,18 +146,19 @@ public:
/**
* @brief Product of two matrices
*/
Matrix2d operator* (const Matrix2d &other) const
template <class D>
matrix_2d operator* (const matrix_2d<D> &other) const
{
return Matrix2d (m_m11 * other.m_m11 + m_m12 * other.m_m21,
m_m11 * other.m_m12 + m_m12 * other.m_m22,
m_m21 * other.m_m11 + m_m22 * other.m_m21,
m_m21 * other.m_m12 + m_m22 * other.m_m22);
return matrix_2d (m_m11 * other.m_m11 + m_m12 * other.m_m21,
m_m11 * other.m_m12 + m_m12 * other.m_m22,
m_m21 * other.m_m11 + m_m22 * other.m_m21,
m_m21 * other.m_m12 + m_m22 * other.m_m22);
}
/**
* @brief Multiply another to this matrix
*/
Matrix2d &operator*= (const Matrix2d &other)
matrix_2d &operator*= (const matrix_2d &other)
{
*this = (*this * other);
return *this;
@ -151,9 +167,9 @@ public:
/**
* @brief Multiply with a scalar
*/
Matrix2d operator* (double d) const
matrix_2d operator* (double d) const
{
Matrix2d m (*this);
matrix_2d m (*this);
m *= d;
return m;
}
@ -161,7 +177,7 @@ public:
/**
* @brief Multiply a scalar to this matrix
*/
Matrix2d &operator*= (double d)
matrix_2d &operator*= (double d)
{
m_m11 *= d;
m_m12 *= d;
@ -173,15 +189,15 @@ public:
/**
* @brief Transformation of a vector
*/
db::DVector operator* (const db::DVector &v) const
db::vector<C> operator* (const db::vector<C> &v) const
{
return db::DVector (m_m11 * v.x () + m_m12 * v.y (), m_m21 * v.x () + m_m22 * v.y ());
return db::vector<C> (m_m11 * v.x () + m_m12 * v.y (), m_m21 * v.x () + m_m22 * v.y ());
}
/**
* @brief "trans" alias for compatibility with the other transformations
*/
db::DVector trans (const db::DVector &p) const
db::vector<C> trans (const db::vector<C> &p) const
{
return operator* (p);
}
@ -189,7 +205,7 @@ public:
/**
* @brief "operator()" alias for compatibility with the other transformations
*/
db::DVector operator() (const db::DVector &p) const
db::vector<C> operator() (const db::vector<C> &p) const
{
return operator* (p);
}
@ -197,15 +213,15 @@ public:
/**
* @brief Transformation of a point
*/
db::DPoint operator* (const db::DPoint &v) const
db::point<C> operator* (const db::point<C> &v) const
{
return db::DPoint (m_m11 * v.x () + m_m12 * v.y (), m_m21 * v.x () + m_m22 * v.y ());
return db::point<C> (m_m11 * v.x () + m_m12 * v.y (), m_m21 * v.x () + m_m22 * v.y ());
}
/**
* @brief "trans" alias for compatibility with the other transformations
*/
db::DPoint trans (const db::DPoint &p) const
db::point<C> trans (const db::point<C> &p) const
{
return operator* (p);
}
@ -213,7 +229,7 @@ public:
/**
* @brief "operator()" alias for compatibility with the other transformations
*/
db::DPoint operator() (const db::DPoint &p) const
db::point<C> operator() (const db::point<C> &p) const
{
return operator* (p);
}
@ -221,9 +237,9 @@ public:
/**
* @brief Return the transposed matrix
*/
Matrix2d transposed () const
matrix_2d<C> transposed () const
{
return Matrix2d (m_m11, m_m21, m_m12, m_m22);
return matrix_2d<C> (m_m11, m_m21, m_m12, m_m22);
}
/**
@ -245,9 +261,9 @@ public:
/**
* @brief Return the inverted matrix
*/
Matrix2d inverted () const
matrix_2d<C> inverted () const
{
Matrix2d m (*this);
matrix_2d<C> m (*this);
m.invert ();
return m;
}
@ -325,9 +341,9 @@ public:
* @param mx The x magnification
* @param my The y magnification
*/
static Matrix2d mag (double mx, double my)
static matrix_2d<C> mag (double mx, double my)
{
return Matrix2d (mx, 0.0, 0.0, my);
return matrix_2d<C> (mx, 0.0, 0.0, my);
}
/**
@ -335,9 +351,9 @@ public:
*
* @param m The magnification
*/
static Matrix2d mag (double m)
static matrix_2d<C> mag (double m)
{
return Matrix2d (m, 0.0, 0.0, m);
return matrix_2d<C> (m, 0.0, 0.0, m);
}
/**
@ -356,9 +372,9 @@ public:
/**
* @brief Create the mirror matrix
*/
static Matrix2d mirror (bool m)
static matrix_2d<C> mirror (bool m)
{
return Matrix2d (1.0, 0.0, 0.0, m ? -1.0 : 1.0);
return matrix_2d<C> (1.0, 0.0, 0.0, m ? -1.0 : 1.0);
}
/**
@ -380,7 +396,7 @@ public:
/**
* @brief Create the rotation matrix from the given angle
*/
static Matrix2d rotation (double a);
static matrix_2d<C> rotation (double a);
/**
* @brief Determine the shear component of the matrix and return the shear angle in degree
@ -403,7 +419,7 @@ public:
/**
* @brief Create the shear matrix from the given angle
*/
static Matrix2d shear (double a);
static matrix_2d<C> shear (double a);
/**
* @brief Determine whether the matrix represents an orthogonal transformation
@ -412,6 +428,13 @@ public:
*/
bool is_ortho () const;
/**
* @brief Determine whether the matrix represents an unit transformation
*
* This method is provided for compatibility to the other transformations.
*/
bool is_unity () const;
/**
* @brief Convert to a string
*/
@ -420,37 +443,41 @@ public:
/**
* @brief A fuzzy compare operator (equal)
*/
bool equal (const Matrix2d &d) const;
bool equal (const matrix_2d<C> &d) const;
/**
* @brief A fuzzy compare operator (less)
*/
bool less (const Matrix2d &d) const;
bool less (const matrix_2d<C> &d) const;
private:
double m_m11, m_m12, m_m21, m_m22;
};
typedef matrix_2d<db::DCoord> Matrix2d;
typedef matrix_2d<db::Coord> IMatrix2d;
/**
* @brief A class representing a 3d matrix, mainly to represent a rotation, shear or perspective transformation of 2d vectors
*/
class DB_PUBLIC Matrix3d
template <class C>
class DB_PUBLIC matrix_3d
{
public:
/**
* @brief typedefs for compatibility with the other transformations
*/
typedef double target_coord_type;
typedef double coord_type;
typedef db::DPoint displacement_type;
typedef Matrix3d inverse_trans;
typedef C target_coord_type;
typedef C coord_type;
typedef db::point<C> displacement_type;
typedef matrix_3d<C> inverse_trans;
/**
* @brief Default ctor
*
* Creates a null matrix
*/
Matrix3d ()
matrix_3d ()
{
set (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
}
@ -460,7 +487,7 @@ public:
*
* Creates a matrix (m11, m12, 0) (m21, m22, 0) (0, 0, 1)
*/
Matrix3d (double m11, double m12, double m21, double m22)
matrix_3d (double m11, double m12, double m21, double m22)
{
set (m11, m12, 0.0, m21, m22, 0.0, 0.0, 0.0, 1.0);
}
@ -470,17 +497,33 @@ public:
*
* Creates a matrix (m11, m12, m13) (m21, m22, m23) (m31, m32, m33)
*/
Matrix3d (double m11, double m12, double m13, double m21, double m22, double m23, double m31, double m32, double m33)
matrix_3d (double m11, double m12, double m13, double m21, double m22, double m23, double m31, double m32, double m33)
{
set (m11, m12, m13, m21, m22, m23, m31, m32, m33);
}
/**
* @brief Full ctor
*
* Creates a matrix (m11, m12) (m21, m22)
*/
template <class D>
matrix_3d (const matrix_3d<D> &m)
{
const double (&mm) [3][3] = m.m ();
for (unsigned int i = 0; i < 3; ++i) {
for (unsigned int j = 0; j < 3; ++j) {
m_m [i][j] = mm [i][j];
}
}
}
/**
* @brief Matrix2d ctor from eight components
*
* Creates a matrix (m11, m12, d1) (m21, m22, d2) (p1, p2, 1)
*/
Matrix3d (double m11, double m12, double m21, double m22, double d1, double d2, double p1, double p2)
matrix_3d (double m11, double m12, double m21, double m22, double d1, double d2, double p1, double p2)
{
set (m11, m12, d1, m21, m22, d2, p1, p2, 1.0);
}
@ -490,7 +533,8 @@ public:
*
* Creates a matrix representing the given Matrix2d.
*/
explicit Matrix3d (const Matrix2d &m)
template <class D>
explicit matrix_3d (const matrix_2d<D> &m)
{
set (m.m11 (), m.m12 (), 0.0, m.m21 (), m.m22 (), 0.0, 0.0, 0.0, 1.0);
}
@ -499,7 +543,7 @@ public:
* @brief Make a matrix from a transformation
*/
template <class Tr>
explicit Matrix3d (const Tr &t)
explicit matrix_3d (const Tr &t)
{
*this = t.to_matrix3d ();
}
@ -509,7 +553,7 @@ public:
*
* Creates a matrix (d, 0, 0) (0, d, 0) (0, 0, 1)
*/
explicit Matrix3d (double d)
explicit matrix_3d (double d)
{
set (d, 0.0, 0.0, 0.0, d, 0.0, 0.0, 0.0, 1.0);
}
@ -517,9 +561,10 @@ public:
/**
* @brief Add operator
*/
Matrix3d operator+ (const Matrix3d &other) const
template <class D>
matrix_3d operator+ (const matrix_3d<D> &other) const
{
Matrix3d m (*this);
matrix_3d m (*this);
m += other;
return m;
}
@ -527,7 +572,8 @@ public:
/**
* @brief Add to operator
*/
Matrix3d &operator+= (const Matrix3d &other)
template <class D>
matrix_3d &operator+= (const matrix_3d<D> &other)
{
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
@ -540,13 +586,14 @@ public:
/**
* @brief Product of two matrices
*/
Matrix3d operator* (const Matrix3d &other) const
template <class D>
matrix_3d operator* (const matrix_3d<D> &other) const
{
Matrix3d res;
matrix_3d res;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
res.m_m [i][j] += m_m [i][k] * other.m_m [k][j];
res.m_m [i][j] += m_m [i][k] * other.m () [k][j];
}
}
}
@ -556,7 +603,8 @@ public:
/**
* @brief Multiply another to this matrix
*/
Matrix3d &operator*= (const Matrix3d &other)
template <class D>
matrix_3d &operator*= (const matrix_3d<D> &other)
{
*this = (*this * other);
return *this;
@ -565,9 +613,9 @@ public:
/**
* @brief Multiply with a scalar
*/
Matrix3d operator* (double d) const
matrix_3d operator* (double d) const
{
Matrix3d m (*this);
matrix_3d m (*this);
m *= d;
return m;
}
@ -575,7 +623,7 @@ public:
/**
* @brief Multiply a scalar to this matrix
*/
Matrix3d &operator*= (double d)
matrix_3d &operator*= (double d)
{
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
@ -591,17 +639,17 @@ public:
* A point can be transformed if the resulting point is
* located in the positive z plane.
*/
bool can_transform (const db::DPoint &p) const;
bool can_transform (const db::point<C> &p) const;
/**
* @brief Transforms a vector which emerges from a certain point
*/
db::DVector trans (const db::DPoint &p, const db::DVector &v) const;
db::vector<C> trans (const db::point<C> &p, const db::vector<C> &v) const;
/**
* @brief Transforms a point
*/
db::DPoint trans (const db::DPoint &p) const;
db::point<C> trans (const db::point<C> &p) const;
/**
* @brief Transforms a vector
@ -613,34 +661,34 @@ public:
* In this implementation we assume the vector starts at 0, 0. This at least renders this
* feature useful for implementing shear and anisotropic scaling.
*/
db::DVector trans (const db::DVector &p) const
db::vector<C> trans (const db::vector<C> &p) const
{
return this->trans (db::DPoint () + p) - this->trans (db::DPoint ());
return this->trans (db::point<C> () + p) - this->trans (db::point<C> ());
}
/**
* @brief "trans" alias for compatibility with the other transformations
*/
template <class C>
db::DPoint trans (const db::point<C> &p) const
template <class D>
db::point<C> trans (const db::point<D> &p) const
{
return trans (db::DPoint (p));
return trans (db::point<C> (p));
}
/**
* @brief "trans" alias for compatibility with the other transformations
*/
template <class C>
db::DVector trans (const db::vector<C> &p) const
template <class D>
db::vector<C> trans (const db::vector<D> &p) const
{
return trans (db::DVector (p));
return trans (db::vector<C> (p));
}
/**
* @brief "operator()" alias for compatibility with the other transformations
*/
template <class C>
db::DPoint operator() (const db::point<C> &p) const
template <class D>
db::point<C> operator() (const db::point<D> &p) const
{
return trans (p);
}
@ -648,8 +696,8 @@ public:
/**
* @brief "operator()" alias for compatibility with the other transformations
*/
template <class C>
db::DVector operator() (const db::vector<C> &p) const
template <class D>
db::vector<C> operator() (const db::vector<D> &p) const
{
return trans (p);
}
@ -657,9 +705,9 @@ public:
/**
* @brief Return the transposed matrix
*/
Matrix3d transposed () const
matrix_3d transposed () const
{
Matrix3d res;
matrix_3d res;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
res.m_m [i][j] = m_m [j][i];
@ -684,7 +732,7 @@ public:
/**
* @brief Return the inverted matrix
*/
Matrix3d inverted () const;
matrix_3d inverted () const;
/**
* @brief In-place invert
@ -697,7 +745,12 @@ public:
/**
* @brief Accessor to the internal matrix
*/
const double (*m () const) [3] { return m_m; }
const double (&m () const) [3][3] { return m_m; }
/**
* @brief Accessor to the internal matrix
*/
double (&m ()) [3][3] { return m_m; }
/**
* @brief Return the magnification component of the matrix
@ -730,17 +783,17 @@ public:
/**
* @brief Create the magnification matrix with isotropic magnification
*/
static Matrix3d mag (double m)
static matrix_3d mag (double m)
{
return Matrix3d (m, 0.0, 0.0, m);
return matrix_3d (m, 0.0, 0.0, m);
}
/**
* @brief Create the magnification matrix with anisotropic magnification
*/
static Matrix3d mag (double mx, double my)
static matrix_3d mag (double mx, double my)
{
return Matrix3d (mx, 0.0, 0.0, my);
return matrix_3d (mx, 0.0, 0.0, my);
}
/**
@ -759,9 +812,9 @@ public:
/**
* @brief Create the mirror matrix
*/
static Matrix3d mirror (bool m)
static matrix_3d mirror (bool m)
{
return Matrix3d (1.0, 0.0, 0.0, m ? -1.0 : 1.0);
return matrix_3d (1.0, 0.0, 0.0, m ? -1.0 : 1.0);
}
/**
@ -789,9 +842,9 @@ public:
/**
* @brief Create the rotation matrix from the given angle
*/
static Matrix3d rotation (double a)
static matrix_3d rotation (double a)
{
return Matrix3d (Matrix2d::rotation (a));
return matrix_3d (Matrix2d::rotation (a));
}
/**
@ -821,9 +874,9 @@ public:
/**
* @brief Create the shear matrix from the given angle
*/
static Matrix3d shear (double a)
static matrix_3d shear (double a)
{
return Matrix3d (Matrix2d::shear (a));
return matrix_3d (Matrix2d::shear (a));
}
/**
@ -860,19 +913,19 @@ public:
* @param ty The tilt angle in y direction (around the x axis) in degree for the given observer distance.
* @param z The observer distance.
*/
static Matrix3d perspective (double tx, double ty, double z);
static matrix_3d perspective (double tx, double ty, double z);
/**
* @brief Get the displacement vector component
*/
db::DVector disp () const;
db::vector<C> disp () const;
/**
* @brief Create the mirror matrix
*/
static Matrix3d disp (const db::DVector &d)
static matrix_3d disp (const db::vector<C> &d)
{
return Matrix3d (1.0, 0.0, 0.0, 1.0, d.x (), d.y (), 0.0, 0.0);
return matrix_3d (1.0, 0.0, 0.0, 1.0, d.x (), d.y (), 0.0, 0.0);
}
/**
@ -882,10 +935,17 @@ public:
*/
bool is_ortho () const;
/**
* @brief Determine whether the matrix represents an unit transformation
*
* This method is provided for compatibility to the other transformations.
*/
bool is_unity () const;
/**
* @brief Get the 2d matrix component (without perspective transformation or displacement)
*/
Matrix2d m2d () const;
matrix_2d<C> m2d () const;
/**
* @brief Convert to a string
@ -895,12 +955,12 @@ public:
/**
* @brief A fuzzy compare operator (equal)
*/
bool equal (const Matrix3d &d) const;
bool equal (const matrix_3d &d) const;
/**
* @brief A fuzzy compare operator (less)
*/
bool less (const Matrix3d &d) const;
bool less (const matrix_3d &d) const;
private:
double m_m[3][3];
@ -919,6 +979,9 @@ private:
}
};
typedef matrix_3d<db::DCoord> Matrix3d;
typedef matrix_3d<db::Coord> IMatrix3d;
/**
* @brief Some adjustment flags
*
@ -982,10 +1045,15 @@ void DB_PUBLIC adjust_matrix (Matrix3d &matrix, const std::vector <db::DPoint> &
namespace tl
{
template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Matrix2d &t);
template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Matrix3d &t);
template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Matrix2d &t);
template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Matrix3d &t);
template<> DB_PUBLIC void extractor_impl<db::matrix_2d<db::Coord> > (tl::Extractor &ex, db::matrix_2d<db::Coord> &t);
template<> DB_PUBLIC void extractor_impl<db::matrix_2d<db::DCoord> > (tl::Extractor &ex, db::matrix_2d<db::DCoord> &t);
template<> DB_PUBLIC void extractor_impl<db::matrix_3d<db::Coord> > (tl::Extractor &ex, db::matrix_3d<db::Coord> &t);
template<> DB_PUBLIC void extractor_impl<db::matrix_3d<db::DCoord> > (tl::Extractor &ex, db::matrix_3d<db::DCoord> &t);
template<> DB_PUBLIC bool test_extractor_impl<db::matrix_2d<db::Coord> > (tl::Extractor &ex, db::matrix_2d<db::Coord> &t);
template<> DB_PUBLIC bool test_extractor_impl<db::matrix_2d<db::DCoord> > (tl::Extractor &ex, db::matrix_2d<db::DCoord> &t);
template<> DB_PUBLIC bool test_extractor_impl<db::matrix_3d<db::Coord> > (tl::Extractor &ex, db::matrix_3d<db::Coord> &t);
template<> DB_PUBLIC bool test_extractor_impl<db::matrix_3d<db::DCoord> > (tl::Extractor &ex, db::matrix_3d<db::DCoord> &t);
} // namespace tl
#endif

View File

@ -1565,8 +1565,35 @@ AreaMap::AreaMap ()
mp_av = 0;
}
AreaMap::AreaMap (const AreaMap &other)
: m_nx (0), m_ny (0)
{
mp_av = 0;
operator= (other);
}
AreaMap &
AreaMap::operator= (const AreaMap &other)
{
if (this != &other) {
// TODO: this could be copy on write
reinitialize (other.p0 (), other.d (), other.p (), other.nx (), other.ny ());
if (other.mp_av) {
memcpy (mp_av, other.mp_av, m_nx * m_ny * sizeof (*mp_av));
}
}
return *this;
}
AreaMap::AreaMap (const db::Point &p0, const db::Vector &d, size_t nx, size_t ny)
: m_p0 (p0), m_d (d), m_nx (nx), m_ny (ny)
: m_p0 (p0), m_d (d), m_p (d), m_nx (nx), m_ny (ny)
{
mp_av = new area_type [nx * ny];
clear ();
}
AreaMap::AreaMap (const db::Point &p0, const db::Vector &d, const db::Vector &p, size_t nx, size_t ny)
: m_p0 (p0), m_d (d), m_p (std::min (d.x (), p.x ()), std::min (d.y (), p.y ())), m_nx (nx), m_ny (ny)
{
mp_av = new area_type [nx * ny];
clear ();
@ -1582,18 +1609,30 @@ AreaMap::~AreaMap ()
void
AreaMap::reinitialize (const db::Point &p0, const db::Vector &d, size_t nx, size_t ny)
{
reinitialize (p0, d, d, nx, ny);
}
void
AreaMap::reinitialize (const db::Point &p0, const db::Vector &d, const db::Vector &p, size_t nx, size_t ny)
{
m_p0 = p0;
m_d = d;
m_nx = nx;
m_ny = ny;
m_p = db::Vector (std::min (d.x (), p.x ()), std::min (d.y (), p.y ()));
if (nx != m_nx || ny != m_ny) {
m_nx = nx;
m_ny = ny;
if (mp_av) {
delete mp_av;
}
mp_av = new area_type [nx * ny];
if (mp_av) {
delete mp_av;
}
mp_av = new area_type [nx * ny];
clear ();
}
@ -1613,6 +1652,7 @@ AreaMap::swap (AreaMap &other)
{
std::swap (m_p0, other.m_p0);
std::swap (m_d, other.m_d);
std::swap (m_p, other.m_p);
std::swap (m_nx, other.m_nx);
std::swap (m_ny, other.m_ny);
std::swap (mp_av, other.mp_av);
@ -1631,10 +1671,20 @@ AreaMap::total_area () const
return asum;
}
db::Box
AreaMap::bbox () const
{
if (m_nx == 0 || m_ny == 0) {
return db::Box ();
} else {
return db::Box (m_p0, m_p0 + db::Vector (db::Coord (m_nx - 1) * m_d.x () + m_p.x (), db::Coord (m_ny - 1) * m_d.y () + m_p.y ()));
}
}
// -------------------------------------------------------------------------
// Implementation of rasterize
void
bool
rasterize (const db::Polygon &polygon, db::AreaMap &am)
{
typedef db::AreaMap::area_type area_type;
@ -1643,11 +1693,12 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
// check if the polygon overlaps the rasterization area. Otherwise, we simply do nothing.
if (! pbox.overlaps (box)) {
return;
return false;
}
db::Coord ymin = box.bottom (), ymax = box.top ();
db::Coord dy = am.d ().y (), dx = am.d ().x ();
db::Coord py = am.p ().y (), px = am.p ().x ();
db::Coord y0 = am.p0 ().y (), x0 = am.p0 ().x ();
size_t ny = am.ny (), nx = am.nx ();
@ -1659,7 +1710,7 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
// no scanning required (i.e. degenerated polygon) -> do nothing
if (iy0 == iy1 || ix0 == ix1) {
return;
return false;
}
// collect edges
@ -1689,11 +1740,15 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
++c;
}
if (c == edges.end ()) {
return false;
}
std::vector <db::Edge>::iterator f = c;
for (size_t iy = iy0; iy < iy1; ++iy) {
db::Coord yy = y + dy;
db::Coord yy = y + py;
while (f != edges.end () && db::edge_ymin (*f) < yy) {
++f;
}
@ -1706,10 +1761,10 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
std::vector <db::Edge>::iterator cc = c;
while (cc != edges.end () && db::edge_xmax (*cc) <= x) {
while (cc != edges.end () && cc != f && db::edge_xmax (*cc) <= x) {
db::Coord y1 = std::max (y, std::min (yy, cc->p1 ().y ()));
db::Coord y2 = std::max (y, std::min (yy, cc->p2 ().y ()));
a += area_type (dx) * area_type (y2 - y1);
a += area_type (px) * area_type (y2 - y1);
++cc;
}
@ -1717,7 +1772,8 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
for (size_t ix = ix0; ix < ix1; ++ix) {
db::Coord xx = x + dx;
db::Coord xx = x + px;
db::Coord xxx = x + dx;
// TODO: edge_xmin_at_interval(y, yy) and edge_xmax.. would be more efficient in the
// all-angle case. However, it is crucial that the edge clipping produces
@ -1728,6 +1784,14 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
++ff;
}
std::vector <db::Edge>::iterator fff = ff;
if (xx < xxx) {
while (fff != f && db::edge_xmin (*fff) < xxx) {
++fff;
}
}
if (xl < x) {
// consider all edges or parts of those left of the first cell
@ -1737,24 +1801,50 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
std::pair<bool, db::Edge> ec = e->clipped (left);
if (ec.first && db::edge_xmin (ec.second) < x) {
a += area_type (ec.second.dy ()) * area_type (dx);
a += area_type (ec.second.dy ()) * area_type (px);
}
}
}
db::Box cell (x, y, xx, yy);
area_type aa = a;
for (std::vector <db::Edge>::iterator e = cc; e != ff; ++e) {
if (dx == py) {
std::pair<bool, db::Edge> ec = e->clipped (cell);
if (ec.first && db::edge_xmin (ec.second) < xx) {
db::Box cell (x, y, xx, yy);
aa += area_type (ec.second.dy ()) * area_type (2 * xx - (ec.second.p2 ().x () + ec.second.p1 ().x ())) / 2;
a += area_type (ec.second.dy ()) * area_type (dx);
for (std::vector <db::Edge>::iterator e = cc; e != ff; ++e) {
std::pair<bool, db::Edge> ec = e->clipped (cell);
if (ec.first && db::edge_xmin (ec.second) < xx) {
aa += (area_type (ec.second.dy ()) * area_type (2 * xx - (ec.second.p2 ().x () + ec.second.p1 ().x ()))) / 2;
a += area_type (ec.second.dy ()) * area_type (px);
}
}
} else {
db::Box cell (x, y, xx, yy);
for (std::vector <db::Edge>::iterator e = cc; e != ff; ++e) {
std::pair<bool, db::Edge> ec = e->clipped (cell);
if (ec.first && db::edge_xmin (ec.second) < xx) {
aa += (area_type (ec.second.dy ()) * area_type (2 * xx - (ec.second.p2 ().x () + ec.second.p1 ().x ()))) / 2;
}
}
db::Box wide_cell (x, y, x + dx, yy);
for (std::vector <db::Edge>::iterator e = cc; e != fff; ++e) {
std::pair<bool, db::Edge> wide_ec = e->clipped (wide_cell);
if (wide_ec.first && db::edge_xmin (wide_ec.second) < x + dx) {
a += area_type (wide_ec.second.dy ()) * area_type (px);
}
}
@ -1762,8 +1852,10 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
am.get (ix, iy) += aa;
x = xx;
xl = xx;
x += dx;
xl = x;
ff = fff;
for (std::vector <db::Edge>::iterator ccx = cc; ccx != ff; ++ccx) {
if (db::edge_xmax (*ccx) <= x) {
@ -1774,6 +1866,13 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
}
if (yy < y + dy) {
yy = y + dy;
while (f != edges.end () && db::edge_ymin (*f) < yy) {
++f;
}
}
y = yy;
for (std::vector <db::Edge>::iterator cx = c; cx != f; ++cx) {
@ -1785,6 +1884,7 @@ rasterize (const db::Polygon &polygon, db::AreaMap &am)
}
return true;
}
// -------------------------------------------------------------------------

View File

@ -503,21 +503,41 @@ public:
*/
AreaMap ();
/**
* @brief Copy constructor
*/
AreaMap (const AreaMap &);
/**
* @brief Constructor
*/
AreaMap (const db::Point &p0, const db::Vector &d, size_t nx, size_t ny);
/**
* @brief Constructor with pixel size
*/
AreaMap (const db::Point &p0, const db::Vector &d, const db::Vector &p, size_t nx, size_t ny);
/**
* @brief Destructor
*/
~AreaMap ();
/**
* @brief Assignment
*/
AreaMap &operator= (const AreaMap &);
/**
* @brief Reinitialize
*/
void reinitialize (const db::Point &p0, const db::Vector &d, size_t nx, size_t ny);
/**
* @brief Reinitialize with pixel size
*/
void reinitialize (const db::Point &p0, const db::Vector &d, const db::Vector &p, size_t nx, size_t ny);
/**
* @brief Swap of two maps
*/
@ -579,13 +599,18 @@ public:
return m_d;
}
/**
* @brief The pixel size (must be less than d)
*/
const db::Vector &p () const
{
return m_p;
}
/**
* @brief Compute the bounding box of the area map
*/
db::Box bbox () const
{
return db::Box (m_p0, m_p0 + db::Vector (db::Coord (m_nx) * m_d.x (), db::Coord (m_ny) * m_d.y ()));
}
db::Box bbox () const;
/**
* @brief Compute the total area
@ -597,7 +622,7 @@ public:
*/
area_type pixel_area () const
{
return area_type (m_d.x ()) * area_type (m_d.y ());
return area_type (m_p.x ()) * area_type (m_p.y ());
}
/**
@ -609,11 +634,8 @@ private:
area_type *mp_av;
db::Point m_p0;
db::Vector m_d;
db::Vector m_p;
size_t m_nx, m_ny;
// no copying
AreaMap (const AreaMap &);
AreaMap &operator= (const AreaMap &);
};
/**
@ -621,8 +643,10 @@ private:
*
* This will decompose the polygon and produce per-pixel area values for the given
* polygon. The area contributions will be added to the given area map.
*
* Returns a value indicating whether the map will be non-empty.
*/
void DB_PUBLIC rasterize (const db::Polygon &polygon, db::AreaMap &am);
bool DB_PUBLIC rasterize (const db::Polygon &polygon, db::AreaMap &am);
/**
* @brief Minkowsky sum of an edge and a polygon

View File

@ -72,6 +72,7 @@ RecursiveShapeIterator &RecursiveShapeIterator::operator= (const RecursiveShapeI
m_current_layer = d.m_current_layer;
m_shape = d.m_shape;
m_trans = d.m_trans;
m_global_trans = d.m_global_trans;
m_trans_stack = d.m_trans_stack;
m_inst_iterators = d.m_inst_iterators;
m_inst_array_iterators = d.m_inst_array_iterators;
@ -286,6 +287,7 @@ RecursiveShapeIterator::init ()
m_shape_quad_id = 0;
mp_cell = 0;
m_current_layer = 0;
m_global_trans = cplx_trans_type ();
}
void
@ -318,6 +320,26 @@ RecursiveShapeIterator::init_region (const RecursiveShapeIterator::region_type &
}
}
void
RecursiveShapeIterator::set_global_trans (const cplx_trans_type &tr)
{
if (m_global_trans != tr) {
m_global_trans = tr;
m_needs_reinit = true;
}
}
const db::RecursiveShapeIterator::cplx_trans_type &
RecursiveShapeIterator::always_apply () const
{
if (m_trans_stack.empty ()) {
return m_global_trans;
} else {
static cplx_trans_type unity;
return unity;
}
}
void
RecursiveShapeIterator::set_region (const box_type &region)
{
@ -420,13 +442,13 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
m_inst_quad_id_stack.clear ();
m_inst_array_iterators.clear ();
m_cells.clear ();
m_trans = cplx_trans_type ();
m_trans = m_global_trans;
m_current_layer = 0;
m_shape = shape_iterator ();
m_shape_quad_id = 0;
m_local_region_stack.clear ();
m_local_region_stack.push_back (m_region);
m_local_region_stack.push_back (m_global_trans.inverted () * m_region);
m_local_complex_region_stack.clear ();
if (mp_complex_region.get ()) {
@ -571,6 +593,8 @@ RecursiveShapeIterator::bbox () const
}
}
box = box.transformed (m_global_trans);
if (m_region != box_type::world ()) {
box &= m_region;
}
@ -749,8 +773,8 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
box_type new_region = box_type::world ();
// compute the region inside the new cell
if (new_region != m_local_region_stack.front ()) {
new_region = m_trans.inverted () * m_local_region_stack.front ();
if (new_region != m_region) {
new_region = m_trans.inverted () * m_region;
new_region &= cell ()->bbox ();
}
m_local_region_stack.push_back (new_region);
@ -911,7 +935,7 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all;
if (receiver) {
ni = receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
ni = receiver->new_inst (this, m_inst->cell_inst (), always_apply (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
}
if (ni == RecursiveShapeReceiver::NI_skip) {
@ -956,7 +980,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
}
while (! m_inst_array.at_end () && receiver) {
if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
if (receiver->new_inst_member (this, m_inst->cell_inst (), always_apply (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
break;
} else {
++m_inst_array;
@ -999,7 +1023,7 @@ RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
validate (receiver);
while (! at_end ()) {
receiver->shape (this, *m_shape, m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
receiver->shape (this, *m_shape, always_apply (), m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
next (receiver);
}

View File

@ -391,6 +391,30 @@ public:
}
}
/**
* @brief Sets a global transformation
*
* The global transformation will be applied to all shapes delivered by biasing the "trans" attribute
*/
void set_global_trans (const cplx_trans_type &tr);
/**
* @brief Gets the global transformation
*/
cplx_trans_type global_trans () const
{
return m_global_trans;
}
/**
* @brief Gets the transformation which is to be applied always in push mode
*
* The reasoning behind this method is that in push mode and with the presence of a global transformation we need to
* somehow reflect the fact that the top-level is transformed. Instead of transforming every shape and instance we use
* this attribute. It is unity for all cells below top level and equal to the global transformation for the top cell.
*/
const cplx_trans_type &always_apply () const;
/**
* @brief Reset the iterator
*/
@ -727,6 +751,7 @@ private:
bool m_shape_inv_prop_sel;
bool m_overlapping;
std::set<db::cell_index_type> m_start, m_stop;
cplx_trans_type m_global_trans;
const layout_type *mp_layout;
const cell_type *mp_top_cell;
@ -881,7 +906,7 @@ public:
* - NI_single: iterate a single member (the first one)
* - NI_skip: skips the whole array (not a single instance is iterated)
*/
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
/**
* @brief Enters a new array member of the instance
@ -894,14 +919,14 @@ public:
*
* If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered.
*/
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
/**
* @brief Delivers a shape
*
* @param trans The transformation which maps the shape to the top cell.
*/
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
};
} // namespace db

View File

@ -145,6 +145,8 @@ Region &Region::transform (const T &trans)
template DB_PUBLIC Region &Region::transform (const db::ICplxTrans &);
template DB_PUBLIC Region &Region::transform (const db::Trans &);
template DB_PUBLIC Region &Region::transform (const db::Disp &);
template DB_PUBLIC Region &Region::transform (const db::IMatrix2d &);
template DB_PUBLIC Region &Region::transform (const db::IMatrix3d &);
template <class Sh>
void Region::insert (const Sh &shape)

View File

@ -327,11 +327,14 @@ public:
: tl::JobBase (nworkers),
mp_proc (proc),
m_has_tiles (has_tiles),
m_progress (0)
m_progress_count (0),
m_progress (std::string ())
{
// .. nothing yet ..
}
void start (const std::string &job_description);
bool has_tiles () const
{
return m_has_tiles;
@ -340,18 +343,18 @@ public:
void next_progress ()
{
tl::MutexLocker locker (&m_mutex);
++m_progress;
++m_progress_count;
}
void update_progress (tl::RelativeProgress &progress)
void update_progress ()
{
unsigned int p;
{
tl::MutexLocker locker (&m_mutex);
p = m_progress;
p = m_progress_count;
}
progress.set (p, true /*force yield*/);
m_progress.set (p, true /*force yield*/);
}
TilingProcessor *processor () const
@ -361,11 +364,14 @@ public:
virtual tl::Worker *create_worker ();
virtual void after_sync_task (tl::Task *task);
private:
TilingProcessor *mp_proc;
bool m_has_tiles;
unsigned int m_progress;
unsigned int m_progress_count;
tl::Mutex m_mutex;
tl::RelativeProgress m_progress;
};
class TilingProcessorTask
@ -601,9 +607,28 @@ TilingProcessorJob::create_worker ()
return new TilingProcessorWorker (this);
}
void
TilingProcessorJob::after_sync_task (tl::Task * /*task*/)
{
// This needs to be done here as there is no external loop to do this
update_progress ();
}
void
TilingProcessorJob::start (const std::string &job_description)
{
m_progress = tl::RelativeProgress (job_description, tasks (), 1);
// prevents child progress objects from showing
m_progress.set_final (true);
tl::JobBase::start ();
}
// ----------------------------------------------------------------------------------
// The tiling processor implementation
tl::Mutex TilingProcessor::s_output_lock;
TilingProcessor::TilingProcessor ()
: m_tile_width (0.0), m_tile_height (0.0),
m_ntiles_w (0), m_ntiles_h (0),
@ -781,7 +806,7 @@ TilingProcessor::output (const std::string &name, db::Edges &edges)
tl::Variant
TilingProcessor::receiver (const std::vector<tl::Variant> &args)
{
tl::MutexLocker locker (&m_output_mutex);
tl::MutexLocker locker (&s_output_lock);
if (args.size () != 1) {
throw tl::Exception (tl::to_string (tr ("_rec function requires one argument: the handle of the output channel")));
@ -803,7 +828,7 @@ TilingProcessor::receiver (const std::vector<tl::Variant> &args)
void
TilingProcessor::put (size_t ix, size_t iy, const db::Box &tile, const std::vector<tl::Variant> &args)
{
tl::MutexLocker locker (&m_output_mutex);
tl::MutexLocker locker (&s_output_lock);
if (args.size () < 2 || args.size () > 3) {
throw tl::Exception (tl::to_string (tr ("_output function requires two or three arguments: handle and object and a clip flag (optional)")));
@ -930,11 +955,6 @@ TilingProcessor::execute (const std::string &desc)
}
// TODO: there should be a general scheme of how thread-specific progress is merged
// into a global one ..
size_t todo_count = ntiles_w * ntiles_h * m_scripts.size ();
tl::RelativeProgress progress (desc, todo_count, 1);
try {
try {
@ -946,10 +966,10 @@ TilingProcessor::execute (const std::string &desc)
}
}
job.start ();
job.start (desc);
while (job.is_running ()) {
// This may throw an exception, if the cancel button has been pressed.
job.update_progress (progress);
job.update_progress ();
job.wait (100);
}

View File

@ -644,6 +644,14 @@ public:
*/
void execute (const std::string &desc);
/**
* @brief Gets the output mutex for operations not using the output method
*/
static tl::Mutex &output_lock ()
{
return s_output_lock;
}
private:
friend class TilingProcessorWorker;
friend class TilingProcessorOutputFunction;
@ -689,8 +697,8 @@ private:
bool m_dbu_specific_set;
bool m_scale_to_dbu;
std::vector<std::string> m_scripts;
tl::Mutex m_output_mutex;
tl::Eval m_top_eval;
static tl::Mutex s_output_lock;
};
}

View File

@ -101,6 +101,11 @@ struct box_defs
return std::hfunc (*box);
}
static const C &bbox (const C *box)
{
return *box;
}
static gsi::Methods methods ()
{
return
@ -172,6 +177,12 @@ struct box_defs
method ("p2=", &C::set_p2, gsi::arg ("p"),
"@brief Sets the upper right point of the box\n"
) +
method_ext ("bbox", &bbox,
"@brief Returns the bounding box\n"
"This method is provided for consistency of the shape API is returns the box itself.\n"
"\n"
"This method has been introduced in version 0.27."
) +
method_ext ("contains?", &box_defs<C>::contains, gsi::arg ("x"), gsi::arg ("y"),
"@brief Returns true if the box contains the given point\n"
"\n"

View File

@ -1297,22 +1297,24 @@ static void move_tree_shapes3 (db::Cell *cell, db::Cell &source_cell, const db::
}
static void
fill_region1 (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Point *origin)
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)
{
if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) {
throw tl::Exception (tl::to_string (tr ("Invalid fill cell footprint (empty or zero width/height)")));
}
db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, 0, db::Vector (), 0);
db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
}
static void
fill_region2 (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)
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)
{
if (fc_box.empty () || fc_box.width () == 0 || fc_box.height () == 0) {
throw tl::Exception (tl::to_string (tr ("Invalid fill cell footprint (empty or zero width/height)")));
}
db::fill_region (cell, fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons);
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);
}
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::Point &origin, const db::Box &glue_box)
{
db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, origin, glue_box);
}
static db::Instance cell_inst_dtransform_simple (db::Cell *cell, const db::Instance &inst, const db::DTrans &t)
@ -1497,6 +1499,8 @@ static db::Cell *dup_cell (const db::Cell *cell)
return new_cell;
}
static db::Point default_origin;
Class<db::Cell> decl_Cell ("db", "Cell",
gsi::method ("name", &db::Cell::get_basic_name,
"@brief Gets the cell's name\n"
@ -1770,26 +1774,14 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"\n"
"This method has been introduced in version 0.23.\n"
) +
gsi::method_ext ("fill_region", &fill_region1, gsi::arg ("region"), gsi::arg ("fill_cell_index"), gsi::arg ("fc_box"), gsi::arg ("origin"),
"@brief Fills the given region with cells of the given type\n"
"@param region The region to fill\n"
"@param fill_cell_index The fill cell to place\n"
"@param fc_box The fill cell's footprint\n"
"@param origin The global origin of the fill pattern or nil to allow local (per-polygon) optimization\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. The current implementation supports rectangular (not necessarily square) tile cells. "
"The tile cell's footprint is given by the fc_box parameter and the cells will be arranged with their footprints forming "
"a seamless array.\n"
"\n"
"The algorithm supports a global fill raster as well as local (per-polygon) origin optimization. In the latter case "
"the origin of the regular raster is optimized per individual polygon of the fill region.\n"
"\n"
"A more elaborate version of this method is available which also returns information about the non-filled parts.\n"
"\n"
"This method has been introduced in version 0.23.\n"
) +
gsi::method_ext ("fill_region", &fill_region2, gsi::arg ("region"), gsi::arg ("fill_cell_index"), gsi::arg ("fc_box"), gsi::arg ("origin"), gsi::arg ("remaining_parts"), gsi::arg ("fill_margin"), gsi::arg ("remaining_polygons"),
gsi::method_ext ("fill_region", &fill_region, gsi::arg ("region"),
gsi::arg ("fill_cell_index"),
gsi::arg ("fc_box"),
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 ()),
"@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"
@ -1798,10 +1790,21 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"@param remaining_parts See explanation below\n"
"@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"
"\n"
"First of all, this method behaves like the simple form. In addition, it can be configured to return information about the "
"parts which could not be filled. Those can be full polygons from the input (without a chance to fill) or parts of original polygons "
"which are worth being fed into the fill algorithm again.\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. "
"The tile cell's footprint is given by the fc_box parameter and the cells will be arranged with their footprints forming "
"a seamless array.\n"
"\n"
"The algorithm supports a global fill raster as well as local (per-polygon) origin optimization. In the latter case "
"the origin of the regular raster is optimized per individual polygon of the fill region. To enable optimization, pass 'nil' to "
"the 'origin' argument.\n"
"\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"
"\n"
"There is also a version available which offers skew step vectors as a generalization of the orthogonal ones.\n"
"\n"
"If the 'remaining_parts' argument is non-nil, the corresponding region will receive the parts of the polygons which are not "
"covered by tiles. Basically the tiles are subtracted from the original polygons. A margin can be specified which is applied "
@ -1830,7 +1833,65 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"end\n"
"@/code\n"
"\n"
"This method has been introduced in version 0.23.\n"
"The glue box parameter supports fill cell array compatibility with neighboring regions. This is specifically useful when putting the fill_cell "
"method into a tiling processor. Fill cell array compatibility means that the fill cell array continues over tile boundaries. This is easy with an origin: "
"you can chose the origin identically over all tiles which is sufficient to guarantee fill cell array compatibility across the tiles. "
"However there is no freedom of choice of the origin then and fill cell placement may not be optimal. To enable the origin for the tile boundary only, "
"a glue box can given. The origin will then be used only when the polygons to fill not entirely inside and not at the border of the glue box. Hence, "
"while a certain degree of freedom is present for the placement of fill cells inside the glue box, the fill cells are guaranteed to be placed "
"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"
) +
gsi::method_ext ("fill_region", &fill_region_skew, gsi::arg ("region"),
gsi::arg ("fill_cell_index"),
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 ()),
"@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 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"
"\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"
"\n"
"The fill box and the step vectors are decoupled which means the fill box can be larger or smaller than the step pitch - it can "
"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"
) +
gsi::method_ext ("fill_region_multi", &fill_region_multi, gsi::arg ("region"),
gsi::arg ("fill_cell_index"),
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 ("origin", db::Point ()),
gsi::arg ("glue_box", db::Box ()),
"@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. "
"The \\fill_margin parameter is important as it controls the distance between fill cells with a different origin and therefore "
"introduces a safety distance between pitch-incompatible arrays.\n"
"\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"
) +
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"

View File

@ -398,6 +398,30 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"\n"
"@return The transformed edge pairs.\n"
) +
method ("transformed", (db::EdgePairs (db::EdgePairs::*)(const db::IMatrix2d &) const) &db::EdgePairs::transformed, gsi::arg ("t"),
"@brief Transform the edge pair collection\n"
"\n"
"Transforms the edge pairs with the given 2d matrix transformation.\n"
"Does not modify the edge pair collection but returns the transformed edge pairs.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed edge pairs.\n"
"\n"
"This variant has been introduced in version 0.27.\n"
) +
method ("transformed", (db::EdgePairs (db::EdgePairs::*)(const db::IMatrix3d &) const) &db::EdgePairs::transformed, gsi::arg ("t"),
"@brief Transform the edge pair collection\n"
"\n"
"Transforms the edge pairs with the given 3d matrix transformation.\n"
"Does not modify the edge pair collection but returns the transformed edge pairs.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed edge pairs.\n"
"\n"
"This variant has been introduced in version 0.27.\n"
) +
method ("transform", (db::EdgePairs &(db::EdgePairs::*)(const db::Trans &)) &db::EdgePairs::transform, gsi::arg ("t"),
"@brief Transform the edge pair collection (modifies self)\n"
"\n"
@ -418,6 +442,30 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"\n"
"@return The transformed edge pair collection.\n"
) +
method ("transform", (db::EdgePairs &(db::EdgePairs::*)(const db::IMatrix2d &)) &db::EdgePairs::transform, gsi::arg ("t"),
"@brief Transform the edge pair collection (modifies self)\n"
"\n"
"Transforms the edge pair collection with the given 2d matrix transformation.\n"
"This version modifies the edge pair collection and returns a reference to self.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed edge pair collection.\n"
"\n"
"This variant has been introduced in version 0.27.\n"
) +
method ("transform", (db::EdgePairs &(db::EdgePairs::*)(const db::IMatrix3d &)) &db::EdgePairs::transform, gsi::arg ("t"),
"@brief Transform the edge pair collection (modifies self)\n"
"\n"
"Transforms the edge pair collection with the given 3d matrix transformation.\n"
"This version modifies the edge pair collection and returns a reference to self.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed edge pair collection.\n"
"\n"
"This variant has been introduced in version 0.27.\n"
) +
method_ext ("insert", &insert_e, gsi::arg ("edge_pairs"),
"@brief Inserts all edge pairs from the other edge pair collection into this edge pair collection\n"
"This method has been introduced in version 0.25."

View File

@ -1040,6 +1040,30 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"\n"
"@return The transformed edge collection.\n"
) +
method ("transformed", (db::Edges (db::Edges::*)(const db::IMatrix2d &) const) &db::Edges::transformed, gsi::arg ("t"),
"@brief Transform the edge collection\n"
"\n"
"Transforms the edge collection with the given 2d matrix transformation.\n"
"Does not modify the edge collection but returns the transformed edge collection.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed edge collection.\n"
"\n"
"This variant has been introduced in version 0.27."
) +
method ("transformed", (db::Edges (db::Edges::*)(const db::IMatrix3d &) const) &db::Edges::transformed, gsi::arg ("t"),
"@brief Transform the edge collection\n"
"\n"
"Transforms the edge collection with the given 3d matrix transformation.\n"
"Does not modify the edge collection but returns the transformed edge collection.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed edge collection.\n"
"\n"
"This variant has been introduced in version 0.27."
) +
method ("transform", (db::Edges &(db::Edges::*)(const db::Trans &)) &db::Edges::transform, gsi::arg ("t"),
"@brief Transform the edge collection (modifies self)\n"
"\n"
@ -1060,6 +1084,30 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"\n"
"@return The transformed edge collection.\n"
) +
method ("transform", (db::Edges &(db::Edges::*)(const db::IMatrix2d &)) &db::Edges::transform, gsi::arg ("t"),
"@brief Transform the edge collection (modifies self)\n"
"\n"
"Transforms the edge collection with the given 2d matrix transformation.\n"
"This version modifies the edge collection and returns a reference to self.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed edge collection.\n"
"\n"
"This variant has been introduced in version 0.27."
) +
method ("transform", (db::Edges &(db::Edges::*)(const db::IMatrix3d &)) &db::Edges::transform, gsi::arg ("t"),
"@brief Transform the edge collection (modifies self)\n"
"\n"
"Transforms the edge collection with the given 3d matrix transformation.\n"
"This version modifies the edge collection and returns a reference to self.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed edge collection.\n"
"\n"
"This variant has been introduced in version 0.27."
) +
method_ext ("width_check", &width2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"),
"@brief Performs a width check with options\n"
"@param d The minimum width for which the edges are checked\n"

View File

@ -24,6 +24,9 @@
#include "gsiDecl.h"
#include "dbMatrix.h"
#include "dbTrans.h"
#include "dbBox.h"
#include "dbPolygon.h"
#include "dbEdge.h"
namespace gsi
{
@ -31,62 +34,104 @@ namespace gsi
// ---------------------------------------------------------------
// Matrix2d binding
static db::Matrix2d *new_matrix2d ()
template <class C>
static db::matrix_2d<C> *new_matrix2d ()
{
return new db::Matrix2d (1.0);
return new db::matrix_2d<C> (1.0);
}
static db::Matrix2d *new_matrix2d_m (double mag)
template <class C>
static db::matrix_2d<C> *new_matrix2d_m (double mag)
{
return new db::Matrix2d (mag);
return new db::matrix_2d<C> (mag);
}
static db::Matrix2d *new_matrix2d_m2 (double mx, double my)
template <class C>
static db::matrix_2d<C> *new_matrix2d_m2 (double mx, double my)
{
return new db::Matrix2d (mx, my);
return new db::matrix_2d<C> (mx, my);
}
static db::Matrix2d *new_matrix2d_t (const db::DCplxTrans &t)
template <class C>
static db::matrix_2d<C> *new_matrix2d_t (const db::DCplxTrans &t)
{
return new db::Matrix2d (t);
return new db::matrix_2d<C> (t);
}
static db::Matrix2d *new_matrix2d_mrm (double mag, double rot, bool m)
template <class C>
static db::matrix_2d<C> *new_matrix2d_mrm (double mag, double rot, bool m)
{
return new db::Matrix2d (db::Matrix2d::rotation (rot) * db::Matrix2d::mag (mag) * db::Matrix2d::mirror (m));
return new db::matrix_2d<C> (db::matrix_2d<C>::rotation (rot) * db::matrix_2d<C>::mag (mag) * db::matrix_2d<C>::mirror (m));
}
static db::Matrix2d *new_matrix2d_smrm (double shear, double mx, double my, double rot, bool m)
template <class C>
static db::matrix_2d<C> *new_matrix2d_smrm (double shear, double mx, double my, double rot, bool m)
{
return new db::Matrix2d (db::Matrix2d::rotation (rot) * db::Matrix2d::shear (shear) * db::Matrix2d::mag (mx, my) * db::Matrix2d::mirror (m));
return new db::matrix_2d<C> (db::matrix_2d<C>::rotation (rot) * db::matrix_2d<C>::shear (shear) * db::matrix_2d<C>::mag (mx, my) * db::matrix_2d<C>::mirror (m));
}
static db::Matrix2d *new_matrix2d_m4 (double m11, double m12, double m21, double m22)
template <class C>
static db::matrix_2d<C> *new_matrix2d_m4 (double m11, double m12, double m21, double m22)
{
return new db::Matrix2d (m11, m12, m21, m22);
return new db::matrix_2d<C> (m11, m12, m21, m22);
}
static db::DCplxTrans to_cplx_trans (const db::Matrix2d *m)
template <class C>
static db::complex_trans<C, C> to_cplx_trans (const db::matrix_2d<C> *m)
{
return db::DCplxTrans (db::Matrix3d (*m));
return db::complex_trans<C, C> (db::matrix_3d<C> (*m));
}
static db::Matrix2d sum_m (const db::Matrix2d *m, const db::Matrix2d &d)
template <class C>
static db::matrix_2d<C> sum_m (const db::matrix_2d<C> *m, const db::matrix_2d<C> &d)
{
return *m + d;
}
static db::Matrix2d prod_m (const db::Matrix2d *m, const db::Matrix2d &d)
template <class C>
static db::matrix_2d<C> prod_m (const db::matrix_2d<C> *m, const db::matrix_2d<C> &d)
{
return *m * d;
}
static db::DPoint trans_p (const db::Matrix2d *m, const db::DPoint &p)
template <class C>
static db::point<C> trans_p (const db::matrix_2d<C> *m, const db::point<C> &p)
{
return *m * p;
}
static double coeff_m (const db::Matrix2d *m, int i, int j)
template <class C>
static db::vector<C> trans_v (const db::matrix_2d<C> *m, const db::vector<C> &p)
{
return *m * p;
}
template <class C>
static db::polygon<C> trans_polygon (const db::matrix_2d<C> *m, const db::polygon<C> &p)
{
return p.transformed (*m);
}
template <class C>
static db::simple_polygon<C> trans_simple_polygon (const db::matrix_2d<C> *m, const db::simple_polygon<C> &p)
{
return p.transformed (*m);
}
template <class C>
static db::box<C> trans_box (const db::matrix_2d<C> *m, const db::box<C> &p)
{
return p.transformed (*m);
}
template <class C>
static db::edge<C> trans_edge (const db::matrix_2d<C> *m, const db::edge<C> &e)
{
return e.transformed (*m);
}
template <class C>
static double coeff_m (const db::matrix_2d<C> *m, int i, int j)
{
if (i == 0 && j == 0) {
return m->m11 ();
@ -101,211 +146,307 @@ static double coeff_m (const db::Matrix2d *m, int i, int j)
}
}
template <class C>
gsi::Methods
matrix2d_methods ()
{
return
gsi::constructor ("new", &new_matrix2d<C>,
"@brief Create a new Matrix2d representing a unit transformation"
) +
gsi::constructor ("new", &new_matrix2d_m<C>, gsi::arg ("m"),
"@brief Create a new Matrix2d representing an isotropic magnification\n"
"@param m The magnification\n"
) +
gsi::constructor ("new", &new_matrix2d_m2<C>, gsi::arg ("mx"), gsi::arg ("my"),
"@brief Create a new Matrix2d representing an anisotropic magnification\n"
"@param mx The magnification in x direction\n"
"@param my The magnification in y direction\n"
) +
gsi::constructor ("new", &new_matrix2d_t<C>, gsi::arg ("t"),
"@brief Create a new Matrix2d from the given complex transformation"
"@param t The transformation from which to create the matrix (not taking into account the displacement)\n"
) +
gsi::constructor ("newc", &new_matrix2d_mrm<C>, gsi::arg ("mag"), gsi::arg ("rotation"), gsi::arg ("mirror"),
"@brief Create a new Matrix2d representing an isotropic magnification, rotation and mirroring\n"
"@param mag The magnification in x direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirror The mirror flag (at x axis)\n"
"\n"
"This constructor is provided to construct a matrix similar to the complex transformation.\n"
"This constructor is called 'newc' to distinguish it from the constructors taking matrix coefficients ('c' is for composite).\n"
"The order of execution of the operations is mirror, magnification, rotation (as for complex transformations).\n"
) +
gsi::constructor ("newc", &new_matrix2d_smrm<C>, gsi::arg ("shear"), gsi::arg ("mx"), gsi::arg ("my"), gsi::arg ("rotation"), gsi::arg ("mirror"),
"@brief Create a new Matrix2d representing a shear, anisotropic magnification, rotation and mirroring\n"
"@param shear The shear angle\n"
"@param mx The magnification in x direction\n"
"@param my The magnification in y direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirror The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification, shear and rotation.\n"
"This constructor is called 'newc' to distinguish it from the constructor taking the four matrix coefficients ('c' is for composite).\n"
) +
gsi::constructor ("new", &new_matrix2d_m4<C>, gsi::arg ("m11"), gsi::arg ("m12"), gsi::arg ("m21"), gsi::arg ("m22"),
"@brief Create a new Matrix2d from the four coefficients\n"
) +
gsi::method ("m11", &db::matrix_2d<C>::m11,
"@brief Gets the m11 coefficient.\n"
"@return The value of the m11 coefficient\n"
) +
gsi::method ("m12", &db::matrix_2d<C>::m12,
"@brief Gets the m12 coefficient.\n"
"@return The value of the m12 coefficient\n"
) +
gsi::method ("m21", &db::matrix_2d<C>::m21,
"@brief Gets the m21 coefficient.\n"
"@return The value of the m21 coefficient\n"
) +
gsi::method ("m22", &db::matrix_2d<C>::m22,
"@brief Gets the m22 coefficient.\n"
"@return The value of the m22 coefficient\n"
) +
gsi::method_ext ("m", &coeff_m<C>, gsi::arg ("i"), gsi::arg ("j"),
"@brief Gets the m coefficient with the given index.\n"
"@return The coefficient [i,j]\n"
) +
gsi::method ("to_s", &db::matrix_2d<C>::to_string,
"@brief Convert the matrix to a string.\n"
"@return The string representing this matrix\n"
) +
gsi::method ("inverted", &db::matrix_2d<C>::inverted,
"@brief The inverse of this matrix.\n"
"@return The inverse of this matrix\n"
) +
gsi::method_ext ("trans|*", &trans_p<C>, gsi::arg ("p"),
"@brief Transforms a point with this matrix.\n"
"@param p The point to transform.\n"
"@return The transformed point\n"
) +
gsi::method_ext ("*", &trans_v<C>, gsi::arg ("v"),
"@brief Transforms a vector with this matrix.\n"
"@param v The vector to transform.\n"
"@return The transformed vector\n"
) +
gsi::method_ext ("*", &trans_edge<C>, gsi::arg ("e"),
"@brief Transforms an edge with this matrix.\n"
"@param e The edge to transform.\n"
"@return The transformed edge\n"
) +
gsi::method_ext ("*", &trans_box<C>, gsi::arg ("box"),
"@brief Transforms a box with this matrix.\n"
"@param box The box to transform.\n"
"@return The transformed box\n"
"\n"
"Please note that the box remains a box, even though the matrix supports shear and rotation. The returned box "
"will be the bounding box of the sheared and rotated rectangle."
) +
gsi::method_ext ("*", &trans_simple_polygon<C>, gsi::arg ("p"),
"@brief Transforms a simple polygon with this matrix.\n"
"@param p The simple polygon to transform.\n"
"@return The transformed simple polygon\n"
) +
gsi::method_ext ("*", &trans_polygon<C>, gsi::arg ("p"),
"@brief Transforms a polygon with this matrix.\n"
"@param p The polygon to transform.\n"
"@return The transformed polygon\n"
) +
gsi::method_ext ("*", &prod_m<C>, gsi::arg ("m"),
"@brief Product of two matrices.\n"
"@param m The other matrix.\n"
"@return The matrix product self*m\n"
) +
gsi::method_ext ("+", &sum_m<C>, gsi::arg ("m"),
"@brief Sum of two matrices.\n"
"@param m The other matrix.\n"
"@return The (element-wise) sum of self+m\n"
) +
gsi::method_ext ("cplx_trans", &to_cplx_trans<C>,
"@brief Converts this matrix to a complex transformation (if possible).\n"
"@return The complex transformation.\n"
"This method is successful only if the matrix does not contain shear components and the magnification must be isotropic.\n"
) +
gsi::method ("angle", &db::matrix_2d<C>::angle,
"@brief Returns the rotation angle of the rotation component of this matrix.\n"
"@return The angle in degree.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, rotation, magnification and shear."
) +
gsi::method ("mag_x", (double (db::matrix_2d<C>::*) () const) &db::matrix_2d<C>::mag_x,
"@brief Returns the x magnification of the magnification component of this matrix.\n"
"@return The magnification factor.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, magnification, shear and rotation."
) +
gsi::method ("mag_y", (double (db::matrix_2d<C>::*) () const) &db::matrix_2d<C>::mag_y,
"@brief Returns the y magnification of the magnification component of this matrix.\n"
"@return The magnification factor.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, magnification, shear and rotation."
) +
gsi::method ("shear_angle", &db::matrix_2d<C>::shear_angle,
"@brief Returns the magnitude of the shear component of this matrix.\n"
"@return The shear angle in degree.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, rotation, magnification and shear.\n"
"The shear basic transformation will tilt the x axis towards the y axis and vice versa. The shear angle "
"gives the tilt angle of the axes towards the other one. The possible range for this angle is -45 to 45 degree."
) +
gsi::method ("is_mirror?", &db::matrix_2d<C>::is_mirror,
"@brief Returns the mirror flag of this matrix.\n"
"@return True if this matrix has a mirror component.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, rotation, magnification and shear."
);
}
gsi::Class<db::Matrix2d> decl_Matrix2d ("db", "Matrix2d",
gsi::constructor ("new", &new_matrix2d,
"@brief Create a new Matrix2d representing a unit transformation"
) +
gsi::constructor ("new", &new_matrix2d_m, gsi::arg ("m"),
"@brief Create a new Matrix2d representing an isotropic magnification\n"
"@param m The magnification\n"
) +
gsi::constructor ("new", &new_matrix2d_m2, gsi::arg ("mx"), gsi::arg ("my"),
"@brief Create a new Matrix2d representing an anisotropic magnification\n"
"@param mx The magnification in x direction\n"
"@param my The magnification in y direction\n"
) +
gsi::constructor ("new", &new_matrix2d_t, gsi::arg ("t"),
"@brief Create a new Matrix2d from the given complex transformation"
"@param t The transformation from which to create the matrix (not taking into account the displacement)\n"
) +
gsi::constructor ("newc", &new_matrix2d_mrm, gsi::arg ("mag"), gsi::arg ("rotation"), gsi::arg ("mirror"),
"@brief Create a new Matrix2d representing an isotropic magnification, rotation and mirroring\n"
"@param mag The magnification in x direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirror The mirror flag (at x axis)\n"
"\n"
"This constructor is provided to construct a matrix similar to the complex transformation.\n"
"This constructor is called 'newc' to distinguish it from the constructors taking matrix coefficients ('c' is for composite).\n"
"The order of execution of the operations is mirror, magnification, rotation (as for complex transformations).\n"
) +
gsi::constructor ("newc", &new_matrix2d_smrm, gsi::arg ("shear"), gsi::arg ("mx"), gsi::arg ("my"), gsi::arg ("rotation"), gsi::arg ("mirror"),
"@brief Create a new Matrix2d representing a shear, anisotropic magnification, rotation and mirroring\n"
"@param shear The shear angle\n"
"@param mx The magnification in x direction\n"
"@param my The magnification in y direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirror The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification, shear and rotation.\n"
"This constructor is called 'newc' to distinguish it from the constructor taking the four matrix coefficients ('c' is for composite).\n"
) +
gsi::constructor ("new", &new_matrix2d_m4, gsi::arg ("m11"), gsi::arg ("m12"), gsi::arg ("m21"), gsi::arg ("m22"),
"@brief Create a new Matrix2d from the four coefficients\n"
) +
gsi::method ("m11", &db::Matrix2d::m11,
"@brief Gets the m11 coefficient.\n"
"@return The value of the m11 coefficient\n"
) +
gsi::method ("m12", &db::Matrix2d::m12,
"@brief Gets the m12 coefficient.\n"
"@return The value of the m12 coefficient\n"
) +
gsi::method ("m21", &db::Matrix2d::m21,
"@brief Gets the m21 coefficient.\n"
"@return The value of the m21 coefficient\n"
) +
gsi::method ("m22", &db::Matrix2d::m22,
"@brief Gets the m22 coefficient.\n"
"@return The value of the m22 coefficient\n"
) +
gsi::method_ext ("m", &coeff_m, gsi::arg ("i"), gsi::arg ("j"),
"@brief Gets the m coefficient with the given index.\n"
"@return The coefficient [i,j]\n"
) +
gsi::method ("to_s", &db::Matrix2d::to_string,
"@brief Convert the matrix to a string.\n"
"@return The string representing this matrix\n"
) +
gsi::method ("inverted", &db::Matrix2d::inverted,
"@brief The inverse of this matrix.\n"
"@return The inverse of this matrix\n"
) +
gsi::method_ext ("trans", &trans_p, gsi::arg ("p"),
"@brief Transforms a point with this matrix.\n"
"@param p The point to transform.\n"
"@return The product if self and the point p\n"
) +
gsi::method_ext ("*", &prod_m, gsi::arg ("m"),
"@brief Product of two matrices.\n"
"@param m The other matrix.\n"
"@return The matrix product self*m\n"
) +
gsi::method_ext ("+", &sum_m, gsi::arg ("m"),
"@brief Sum of two matrices.\n"
"@param m The other matrix.\n"
"@return The (element-wise) sum of self+m\n"
) +
gsi::method_ext ("cplx_trans", &to_cplx_trans,
"@brief Converts this matrix to a complex transformation (if possible).\n"
"@return The complex transformation.\n"
"This method is successful only if the matrix does not contain shear components and the magnification must be isotropic.\n"
) +
gsi::method ("angle", &db::Matrix2d::angle,
"@brief Returns the rotation angle of the rotation component of this matrix.\n"
"@return The angle in degree.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, rotation, magnification and shear."
) +
gsi::method ("mag_x", (double (db::Matrix2d::*) () const) &db::Matrix2d::mag_x,
"@brief Returns the x magnification of the magnification component of this matrix.\n"
"@return The magnification factor.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, magnification, shear and rotation."
) +
gsi::method ("mag_y", (double (db::Matrix2d::*) () const) &db::Matrix2d::mag_y,
"@brief Returns the y magnification of the magnification component of this matrix.\n"
"@return The magnification factor.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, magnification, shear and rotation."
) +
gsi::method ("shear_angle", &db::Matrix2d::shear_angle,
"@brief Returns the magnitude of the shear component of this matrix.\n"
"@return The shear angle in degree.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, rotation, magnification and shear.\n"
"The shear basic transformation will tilt the x axis towards the y axis and vice versa. The shear angle "
"gives the tilt angle of the axes towards the other one. The possible range for this angle is -45 to 45 degree."
) +
gsi::method ("is_mirror?", &db::Matrix2d::is_mirror,
"@brief Returns the mirror flag of this matrix.\n"
"@return True if this matrix has a mirror component.\n"
"The matrix is decomposed into basic transformations assuming an execution order of "
"mirroring at the x axis, rotation, magnification and shear."
),
matrix2d_methods<db::DCoord> (),
"@brief A 2d matrix object used mainly for representing rotation and shear transformations.\n"
"\n"
"This object represents a 2x2 matrix. This matrix is used to represent affine transformations "
"This object represents a 2x2 matrix. This matrix is used to implement affine transformations "
"in the 2d space mainly. It can be decomposed into basic transformations: mirroring, rotation and shear. "
"In that case, the assumed execution order of the basic transformations is "
"mirroring at the x axis, rotation, magnification and shear."
"mirroring at the x axis, rotation, magnification and shear.\n"
"\n"
"The matrix is a generalisation of the transformations and is of limited use in a layout database context. "
"It is useful however to implement shear transformations on polygons, edges and polygon or edge collections."
"\n\n"
"This class was introduced in version 0.22.\n"
);
gsi::Class<db::IMatrix2d> decl_IMatrix2d ("db", "IMatrix2d",
matrix2d_methods<db::Coord> (),
"@brief A 2d matrix object used mainly for representing rotation and shear transformations (integer coordinate version).\n"
"\n"
"This object represents a 2x2 matrix. This matrix is used to implement affine transformations "
"in the 2d space mainly. It can be decomposed into basic transformations: mirroring, rotation and shear. "
"In that case, the assumed execution order of the basic transformations is "
"mirroring at the x axis, rotation, magnification and shear."
"\n\n"
"The integer variant was introduced in version 0.27.\n"
);
// ---------------------------------------------------------------
// Matrix2d binding
// Matrix3d binding
static db::Matrix3d *new_matrix3d ()
template <class C>
static db::matrix_3d<C> *new_matrix3d ()
{
return new db::Matrix3d (1.0);
return new db::matrix_3d<C> (1.0);
}
static db::Matrix3d *new_matrix3d_t (const db::DCplxTrans &t)
template <class C>
static db::matrix_3d<C> *new_matrix3d_t (const db::complex_trans<C, C> &t)
{
return new db::Matrix3d (t);
return new db::matrix_3d<C> (t);
}
static db::Matrix3d *new_matrix3d_m (double mag)
template <class C>
static db::matrix_3d<C> *new_matrix3d_m (double mag)
{
return new db::Matrix3d (mag);
return new db::matrix_3d<C> (mag);
}
static db::Matrix3d *new_matrix3d_mrm (double mag, double rot, bool m)
template <class C>
static db::matrix_3d<C> *new_matrix3d_mrm (double mag, double rot, bool m)
{
return new db::Matrix3d (db::Matrix3d::rotation (rot) * db::Matrix3d::mag (mag) * db::Matrix3d::mirror (m));
return new db::matrix_3d<C> (db::matrix_3d<C>::rotation (rot) * db::matrix_3d<C>::mag (mag) * db::matrix_3d<C>::mirror (m));
}
static db::Matrix3d *new_matrix3d_smrm (double shear, double mx, double my, double rot, bool m)
template <class C>
static db::matrix_3d<C> *new_matrix3d_smrm (double shear, double mx, double my, double rot, bool m)
{
return new db::Matrix3d (db::Matrix3d::rotation (rot) * db::Matrix3d::shear (shear) * db::Matrix3d::mag (mx, my) * db::Matrix3d::mirror (m));
return new db::matrix_3d<C> (db::matrix_3d<C>::rotation (rot) * db::matrix_3d<C>::shear (shear) * db::matrix_3d<C>::mag (mx, my) * db::matrix_3d<C>::mirror (m));
}
static db::Matrix3d *new_matrix3d_dsmrm (const db::DVector &d, double shear, double mx, double my, double rot, bool m)
template <class C>
static db::matrix_3d<C> *new_matrix3d_dsmrm (const db::vector<C> &d, double shear, double mx, double my, double rot, bool m)
{
return new db::Matrix3d (db::Matrix3d::disp (d) * db::Matrix3d::rotation (rot) * db::Matrix3d::shear (shear) * db::Matrix3d::mag (mx, my) * db::Matrix3d::mirror (m));
return new db::matrix_3d<C> (db::matrix_3d<C>::disp (d) * db::matrix_3d<C>::rotation (rot) * db::matrix_3d<C>::shear (shear) * db::matrix_3d<C>::mag (mx, my) * db::matrix_3d<C>::mirror (m));
}
static db::Matrix3d *new_matrix3d_pdsmrm (double tx, double ty, double z, const db::DVector &d, double shear, double mx, double my, double rot, bool m)
template <class C>
static db::matrix_3d<C> *new_matrix3d_pdsmrm (double tx, double ty, double z, const db::vector<C> &d, double shear, double mx, double my, double rot, bool m)
{
return new db::Matrix3d (db::Matrix3d::disp (d) * db::Matrix3d::perspective (tx, ty, z) * db::Matrix3d::rotation (rot) * db::Matrix3d::shear (shear) * db::Matrix3d::mag (mx, my) * db::Matrix3d::mirror (m));
return new db::matrix_3d<C> (db::matrix_3d<C>::disp (d) * db::matrix_3d<C>::perspective (tx, ty, z) * db::matrix_3d<C>::rotation (rot) * db::matrix_3d<C>::shear (shear) * db::matrix_3d<C>::mag (mx, my) * db::matrix_3d<C>::mirror (m));
}
static db::Matrix3d *new_matrix3d_m4 (double m11, double m12, double m21, double m22)
template <class C>
static db::matrix_3d<C> *new_matrix3d_m4 (double m11, double m12, double m21, double m22)
{
return new db::Matrix3d (m11, m12, m21, m22);
return new db::matrix_3d<C> (m11, m12, m21, m22);
}
static db::Matrix3d *new_matrix3d_m6 (double m11, double m12, double m21, double m22, double dx, double dy)
template <class C>
static db::matrix_3d<C> *new_matrix3d_m6 (double m11, double m12, double m21, double m22, double dx, double dy)
{
return new db::Matrix3d (m11, m12, m21, m22, dx, dy, 0.0, 0.0);
return new db::matrix_3d<C> (m11, m12, m21, m22, dx, dy, 0.0, 0.0);
}
static db::Matrix3d *new_matrix3d_m9 (double m11, double m12, double m13, double m21, double m22, double m23, double m31, double m32, double m33)
template <class C>
static db::matrix_3d<C> *new_matrix3d_m9 (double m11, double m12, double m13, double m21, double m22, double m23, double m31, double m32, double m33)
{
return new db::Matrix3d (m11, m12, m13, m21, m22, m23, m31, m32, m33);
return new db::matrix_3d<C> (m11, m12, m13, m21, m22, m23, m31, m32, m33);
}
static db::DCplxTrans to_cplx_trans3 (const db::Matrix3d *m)
template <class C>
static db::DCplxTrans to_cplx_trans3 (const db::matrix_3d<C> *m)
{
return db::DCplxTrans (*m);
}
static db::Matrix3d sum_m3 (const db::Matrix3d *m, const db::Matrix3d &d)
template <class C>
static db::matrix_3d<C> sum_m3 (const db::matrix_3d<C> *m, const db::matrix_3d<C> &d)
{
return *m + d;
}
static db::Matrix3d prod_m3 (const db::Matrix3d *m, const db::Matrix3d &d)
template <class C>
static db::matrix_3d<C> prod_m3 (const db::matrix_3d<C> *m, const db::matrix_3d<C> &d)
{
return *m * d;
}
static db::DPoint trans_p3 (const db::Matrix3d *m, const db::DPoint &p)
template <class C>
static db::point<C> trans_p3 (const db::matrix_3d<C> *m, const db::point<C> &p)
{
return *m * p;
}
static double coeff_m3 (const db::Matrix3d *m, int i, int j)
template <class C>
static db::vector<C> trans_v3 (const db::matrix_3d<C> *m, const db::vector<C> &p)
{
return *m * p;
}
template <class C>
static db::polygon<C> trans_polygon3 (const db::matrix_3d<C> *m, const db::polygon<C> &p)
{
return p.transformed (*m);
}
template <class C>
static db::simple_polygon<C> trans_simple_polygon3 (const db::matrix_3d<C> *m, const db::simple_polygon<C> &p)
{
return p.transformed (*m);
}
template <class C>
static db::box<C> trans_box3 (const db::matrix_3d<C> *m, const db::box<C> &p)
{
return p.transformed (*m);
}
template <class C>
static db::edge<C> trans_edge3 (const db::matrix_3d<C> *m, const db::edge<C> &e)
{
return e.transformed (*m);
}
template <class C>
static double coeff_m3 (const db::matrix_3d<C> *m, int i, int j)
{
if (i < 0 || i >= 3 || j < 0 || j >= 3) {
return 0.0;
@ -359,166 +500,198 @@ static int adjust_all ()
return db::MatrixAdjustFlags::All;
}
template <class C>
gsi::Methods
matrix3d_methods ()
{
return
gsi::constructor ("new", &new_matrix3d<C>,
"@brief Create a new Matrix3d representing a unit transformation"
) +
gsi::constructor ("new", &new_matrix3d_m<C>, gsi::arg ("m"),
"@brief Create a new Matrix3d representing a magnification\n"
"@param m The magnification\n"
) +
gsi::constructor ("new", &new_matrix3d_t<C>, gsi::arg ("t"),
"@brief Create a new Matrix3d from the given complex transformation"
"@param t The transformation from which to create the matrix\n"
) +
gsi::constructor ("newc", &new_matrix3d_mrm<C>, gsi::arg ("mag"), gsi::arg ("rotation"), gsi::arg ("mirrx"),
"@brief Create a new Matrix3d representing a isotropic magnification, rotation and mirroring\n"
"@param mag The magnification\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirrx The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification and rotation.\n"
"This constructor is called 'newc' to distinguish it from the constructors taking coefficients ('c' is for composite).\n"
) +
gsi::constructor ("newc", &new_matrix3d_smrm<C>, gsi::arg ("shear"), gsi::arg ("mx"), gsi::arg ("my"), gsi::arg ("rotation"), gsi::arg ("mirrx"),
"@brief Create a new Matrix3d representing a shear, anisotropic magnification, rotation and mirroring\n"
"@param shear The shear angle\n"
"@param mx The magnification in x direction\n"
"@param mx The magnification in y direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirrx The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification, rotation and shear.\n"
"This constructor is called 'newc' to distinguish it from the constructor taking the four matrix coefficients ('c' is for composite).\n"
) +
gsi::constructor ("newc", &new_matrix3d_dsmrm<C>, gsi::arg ("u"), gsi::arg ("shear"), gsi::arg ("mx"), gsi::arg ("my"), gsi::arg ("rotation"), gsi::arg ("mirrx"),
"@brief Create a new Matrix3d representing a displacement, shear, anisotropic magnification, rotation and mirroring\n"
"@param u The displacement\n"
"@param shear The shear angle\n"
"@param mx The magnification in x direction\n"
"@param mx The magnification in y direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirrx The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification, rotation, shear and displacement.\n"
"This constructor is called 'newc' to distinguish it from the constructor taking the four matrix coefficients ('c' is for composite).\n"
"\n"
"Starting with version 0.25 the displacement is of vector type."
) +
gsi::constructor ("newc", &new_matrix3d_pdsmrm<C>, gsi::arg ("tx"), gsi::arg ("ty"), gsi::arg ("z"), gsi::arg ("u"), gsi::arg ("shear"), gsi::arg ("mx"), gsi::arg ("my"), gsi::arg ("rotation"), gsi::arg ("mirrx"),
"@brief Create a new Matrix3d representing a perspective distortion, displacement, shear, anisotropic magnification, rotation and mirroring\n"
"@param tx The perspective tilt angle x (around the y axis)\n"
"@param ty The perspective tilt angle y (around the x axis)\n"
"@param z The observer distance at which the tilt angles are given\n"
"@param u The displacement\n"
"@param shear The shear angle\n"
"@param mx The magnification in x direction\n"
"@param mx The magnification in y direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirrx The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification, rotation, shear, perspective distortion and displacement.\n"
"This constructor is called 'newc' to distinguish it from the constructor taking the four matrix coefficients ('c' is for composite).\n"
"\n"
"The tx and ty parameters represent the perspective distortion. They denote a tilt of the xy plane around the y axis (tx) or the x axis (ty) in degree. "
"The same effect is achieved for different tilt angles for different observer distances. Hence, the observer distance must be given at which the tilt angles are given. "
"If the magnitude of the tilt angle is not important, z can be set to 1.\n"
"\n"
"Starting with version 0.25 the displacement is of vector type."
) +
gsi::constructor ("new", &new_matrix3d_m4<C>, gsi::arg ("m11"), gsi::arg ("m12"), gsi::arg ("m21"), gsi::arg ("m22"),
"@brief Create a new Matrix3d from the four coefficients of a Matrix2d\n"
) +
gsi::constructor ("new", &new_matrix3d_m6<C>, gsi::arg ("m11"), gsi::arg ("m12"), gsi::arg ("m21"), gsi::arg ("m22"), gsi::arg ("dx"), gsi::arg ("dy"),
"@brief Create a new Matrix3d from the four coefficients of a Matrix2d plus a displacement\n"
) +
gsi::constructor ("new", &new_matrix3d_m9<C>, gsi::arg ("m11"), gsi::arg ("m12"), gsi::arg ("m13"), gsi::arg ("m21"), gsi::arg ("m22"), gsi::arg ("m23"), gsi::arg ("m31"), gsi::arg ("m32"), gsi::arg ("m33"),
"@brief Create a new Matrix3d from the nine matrix coefficients\n"
) +
gsi::method_ext ("m", &coeff_m3<C>, gsi::arg ("i"), gsi::arg ("j"),
"@brief Gets the m coefficient with the given index.\n"
"@return The coefficient [i,j]\n"
) +
gsi::method ("to_s", &db::matrix_3d<C>::to_string,
"@brief Convert the matrix to a string.\n"
"@return The string representing this matrix\n"
) +
gsi::method ("inverted", &db::matrix_3d<C>::inverted,
"@brief The inverse of this matrix.\n"
"@return The inverse of this matrix\n"
) +
gsi::method_ext ("*", &prod_m3<C>, gsi::arg ("m"),
"@brief Product of two matrices.\n"
"@param m The other matrix.\n"
"@return The matrix product self*m\n"
) +
gsi::method_ext ("+", &sum_m3<C>, gsi::arg ("m"),
"@brief Sum of two matrices.\n"
"@param m The other matrix.\n"
"@return The (element-wise) sum of self+m\n"
) +
gsi::method_ext ("trans|*", &trans_p3<C>, gsi::arg ("p"),
"@brief Transforms a point with this matrix.\n"
"@param p The point to transform.\n"
"@return The transformed point\n"
) +
gsi::method_ext ("*", &trans_v3<C>, gsi::arg ("v"),
"@brief Transforms a vector with this matrix.\n"
"@param v The vector to transform.\n"
"@return The transformed vector\n"
) +
gsi::method_ext ("*", &trans_edge3<C>, gsi::arg ("e"),
"@brief Transforms an edge with this matrix.\n"
"@param e The edge to transform.\n"
"@return The transformed edge\n"
) +
gsi::method_ext ("*", &trans_box3<C>, gsi::arg ("box"),
"@brief Transforms a box with this matrix.\n"
"@param box The box to transform.\n"
"@return The transformed box\n"
"\n"
"Please note that the box remains a box, even though the matrix supports shear and rotation. The returned box "
"will be the bounding box of the sheared and rotated rectangle."
) +
gsi::method_ext ("*", &trans_simple_polygon3<C>, gsi::arg ("p"),
"@brief Transforms a simple polygon with this matrix.\n"
"@param p The simple polygon to transform.\n"
"@return The transformed simple polygon\n"
) +
gsi::method_ext ("*", &trans_polygon3<C>, gsi::arg ("p"),
"@brief Transforms a polygon with this matrix.\n"
"@param p The polygon to transform.\n"
"@return The transformed polygon\n"
) +
gsi::method_ext ("cplx_trans", &to_cplx_trans3<C>,
"@brief Converts this matrix to a complex transformation (if possible).\n"
"@return The complex transformation.\n"
"This method is successful only if the matrix does not contain shear or perspective distortion components and the magnification must be isotropic.\n"
) +
gsi::method ("mag_x", (double (db::matrix_3d<C>::*) () const) &db::matrix_3d<C>::mag_x,
"@brief Returns the x magnification of the magnification component of this matrix.\n"
"@return The magnification factor.\n"
) +
gsi::method ("mag_y", (double (db::matrix_3d<C>::*) () const) &db::matrix_3d<C>::mag_y,
"@brief Returns the y magnification of the magnification component of this matrix.\n"
"@return The magnification factor.\n"
) +
gsi::method ("angle", &db::matrix_3d<C>::angle,
"@brief Returns the rotation angle of the rotation component of this matrix.\n"
"@return The angle in degree.\n"
"See the description of this class for details about the basic transformations."
) +
gsi::method ("shear_angle", &db::matrix_3d<C>::shear_angle,
"@brief Returns the magnitude of the shear component of this matrix.\n"
"@return The shear angle in degree.\n"
"The shear basic transformation will tilt the x axis towards the y axis and vice versa. The shear angle "
"gives the tilt angle of the axes towards the other one. The possible range for this angle is -45 to 45 degree."
"See the description of this class for details about the basic transformations."
) +
gsi::method ("disp", (db::vector<C> (db::matrix_3d<C>::*) () const) &db::matrix_3d<C>::disp,
"@brief Returns the displacement vector of this transformation.\n"
"\n"
"Starting with version 0.25 this method returns a vector type instead of a point.\n"
"@return The displacement vector.\n"
) +
gsi::method ("tx", &db::matrix_3d<C>::perspective_tilt_x, gsi::arg ("z"),
"@brief Returns the perspective tilt angle tx.\n"
"@param z The observer distance at which the tilt angle is computed.\n"
"@return The tilt angle tx.\n"
"The tx and ty parameters represent the perspective distortion. They denote a tilt of the xy plane around the y axis (tx) or the x axis (ty) in degree. "
"The same effect is achieved for different tilt angles at different observer distances. Hence, the observer distance must be specified at which the tilt angle is computed. "
"If the magnitude of the tilt angle is not important, z can be set to 1.\n"
) +
gsi::method ("ty", &db::matrix_3d<C>::perspective_tilt_y, gsi::arg ("z"),
"@brief Returns the perspective tilt angle ty.\n"
"@param z The observer distance at which the tilt angle is computed.\n"
"@return The tilt angle ty.\n"
"The tx and ty parameters represent the perspective distortion. They denote a tilt of the xy plane around the y axis (tx) or the x axis (ty) in degree. "
"The same effect is achieved for different tilt angles at different observer distances. Hence, the observer distance must be specified at which the tilt angle is computed. "
"If the magnitude of the tilt angle is not important, z can be set to 1.\n"
) +
gsi::method ("is_mirror?", &db::matrix_3d<C>::is_mirror,
"@brief Returns the mirror flag of this matrix.\n"
"@return True if this matrix has a mirror component.\n"
"See the description of this class for details about the basic transformations."
);
}
gsi::Class<db::Matrix3d> decl_Matrix3d ("db", "Matrix3d",
gsi::constructor ("new", &new_matrix3d,
"@brief Create a new Matrix3d representing a unit transformation"
) +
gsi::constructor ("new", &new_matrix3d_m, gsi::arg ("m"),
"@brief Create a new Matrix3d representing a magnification\n"
"@param m The magnification\n"
) +
gsi::constructor ("new", &new_matrix3d_t, gsi::arg ("t"),
"@brief Create a new Matrix3d from the given complex transformation"
"@param t The transformation from which to create the matrix\n"
) +
gsi::constructor ("newc", &new_matrix3d_mrm, gsi::arg ("mag"), gsi::arg ("rotation"), gsi::arg ("mirrx"),
"@brief Create a new Matrix3d representing a isotropic magnification, rotation and mirroring\n"
"@param mag The magnification\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirrx The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification and rotation.\n"
"This constructor is called 'newc' to distinguish it from the constructors taking coefficients ('c' is for composite).\n"
) +
gsi::constructor ("newc", &new_matrix3d_smrm, gsi::arg ("shear"), gsi::arg ("mx"), gsi::arg ("my"), gsi::arg ("rotation"), gsi::arg ("mirrx"),
"@brief Create a new Matrix3d representing a shear, anisotropic magnification, rotation and mirroring\n"
"@param shear The shear angle\n"
"@param mx The magnification in x direction\n"
"@param mx The magnification in y direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirrx The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification, rotation and shear.\n"
"This constructor is called 'newc' to distinguish it from the constructor taking the four matrix coefficients ('c' is for composite).\n"
) +
gsi::constructor ("newc", &new_matrix3d_dsmrm, gsi::arg ("u"), gsi::arg ("shear"), gsi::arg ("mx"), gsi::arg ("my"), gsi::arg ("rotation"), gsi::arg ("mirrx"),
"@brief Create a new Matrix3d representing a displacement, shear, anisotropic magnification, rotation and mirroring\n"
"@param u The displacement\n"
"@param shear The shear angle\n"
"@param mx The magnification in x direction\n"
"@param mx The magnification in y direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirrx The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification, rotation, shear and displacement.\n"
"This constructor is called 'newc' to distinguish it from the constructor taking the four matrix coefficients ('c' is for composite).\n"
"\n"
"Starting with version 0.25 the displacement is of vector type."
) +
gsi::constructor ("newc", &new_matrix3d_pdsmrm, gsi::arg ("tx"), gsi::arg ("ty"), gsi::arg ("z"), gsi::arg ("u"), gsi::arg ("shear"), gsi::arg ("mx"), gsi::arg ("my"), gsi::arg ("rotation"), gsi::arg ("mirrx"),
"@brief Create a new Matrix3d representing a perspective distortion, displacement, shear, anisotropic magnification, rotation and mirroring\n"
"@param tx The perspective tilt angle x (around the y axis)\n"
"@param ty The perspective tilt angle y (around the x axis)\n"
"@param z The observer distance at which the tilt angles are given\n"
"@param u The displacement\n"
"@param shear The shear angle\n"
"@param mx The magnification in x direction\n"
"@param mx The magnification in y direction\n"
"@param rotation The rotation angle (in degree)\n"
"@param mirrx The mirror flag (at x axis)\n"
"\n"
"The order of execution of the operations is mirror, magnification, rotation, shear, perspective distortion and displacement.\n"
"This constructor is called 'newc' to distinguish it from the constructor taking the four matrix coefficients ('c' is for composite).\n"
"\n"
"The tx and ty parameters represent the perspective distortion. They denote a tilt of the xy plane around the y axis (tx) or the x axis (ty) in degree. "
"The same effect is achieved for different tilt angles for different observer distances. Hence, the observer distance must be given at which the tilt angles are given. "
"If the magnitude of the tilt angle is not important, z can be set to 1.\n"
"\n"
"Starting with version 0.25 the displacement is of vector type."
) +
gsi::constructor ("new", &new_matrix3d_m4, gsi::arg ("m11"), gsi::arg ("m12"), gsi::arg ("m21"), gsi::arg ("m22"),
"@brief Create a new Matrix3d from the four coefficients of a Matrix2d\n"
) +
gsi::constructor ("new", &new_matrix3d_m6, gsi::arg ("m11"), gsi::arg ("m12"), gsi::arg ("m21"), gsi::arg ("m22"), gsi::arg ("dx"), gsi::arg ("dy"),
"@brief Create a new Matrix3d from the four coefficients of a Matrix2d plus a displacement\n"
) +
gsi::constructor ("new", &new_matrix3d_m9, gsi::arg ("m11"), gsi::arg ("m12"), gsi::arg ("m13"), gsi::arg ("m21"), gsi::arg ("m22"), gsi::arg ("m23"), gsi::arg ("m31"), gsi::arg ("m32"), gsi::arg ("m33"),
"@brief Create a new Matrix3d from the nine matrix coefficients\n"
) +
gsi::method_ext ("m", &coeff_m3, gsi::arg ("i"), gsi::arg ("j"),
"@brief Gets the m coefficient with the given index.\n"
"@return The coefficient [i,j]\n"
) +
gsi::method ("to_s", &db::Matrix3d::to_string,
"@brief Convert the matrix to a string.\n"
"@return The string representing this matrix\n"
) +
gsi::method ("inverted", &db::Matrix3d::inverted,
"@brief The inverse of this matrix.\n"
"@return The inverse of this matrix\n"
) +
gsi::method_ext ("trans", &trans_p3, gsi::arg ("p"),
"@brief Transforms a point with this matrix.\n"
"@param p The point to transform.\n"
"@return The product if self and the point p\n"
) +
gsi::method_ext ("*", &prod_m3, gsi::arg ("m"),
"@brief Product of two matrices.\n"
"@param m The other matrix.\n"
"@return The matrix product self*m\n"
) +
gsi::method_ext ("*", &trans_p3, gsi::arg ("p"),
"@brief Transform a point.\n"
"@param p The point to transform.\n"
"@return The transformed point\n"
) +
gsi::method_ext ("+", &sum_m3, gsi::arg ("m"),
"@brief Sum of two matrices.\n"
"@param m The other matrix.\n"
"@return The (element-wise) sum of self+m\n"
) +
gsi::method_ext ("cplx_trans", &to_cplx_trans3,
"@brief Converts this matrix to a complex transformation (if possible).\n"
"@return The complex transformation.\n"
"This method is successful only if the matrix does not contain shear or perspective distortion components and the magnification must be isotropic.\n"
) +
gsi::method ("mag_x", (double (db::Matrix3d::*) () const) &db::Matrix3d::mag_x,
"@brief Returns the x magnification of the magnification component of this matrix.\n"
"@return The magnification factor.\n"
) +
gsi::method ("mag_y", (double (db::Matrix3d::*) () const) &db::Matrix3d::mag_y,
"@brief Returns the y magnification of the magnification component of this matrix.\n"
"@return The magnification factor.\n"
) +
gsi::method ("angle", &db::Matrix3d::angle,
"@brief Returns the rotation angle of the rotation component of this matrix.\n"
"@return The angle in degree.\n"
"See the description of this class for details about the basic transformations."
) +
gsi::method ("shear_angle", &db::Matrix3d::shear_angle,
"@brief Returns the magnitude of the shear component of this matrix.\n"
"@return The shear angle in degree.\n"
"The shear basic transformation will tilt the x axis towards the y axis and vice versa. The shear angle "
"gives the tilt angle of the axes towards the other one. The possible range for this angle is -45 to 45 degree."
"See the description of this class for details about the basic transformations."
) +
gsi::method ("disp", (db::DVector (db::Matrix3d::*) () const) &db::Matrix3d::disp,
"@brief Returns the displacement vector of this transformation.\n"
"\n"
"Starting with version 0.25 this method returns a vector type instead of a point.\n"
"@return The displacement vector.\n"
) +
gsi::method ("tx", &db::Matrix3d::perspective_tilt_x, gsi::arg ("z"),
"@brief Returns the perspective tilt angle tx.\n"
"@param z The observer distance at which the tilt angle is computed.\n"
"@return The tilt angle tx.\n"
"The tx and ty parameters represent the perspective distortion. They denote a tilt of the xy plane around the y axis (tx) or the x axis (ty) in degree. "
"The same effect is achieved for different tilt angles at different observer distances. Hence, the observer distance must be specified at which the tilt angle is computed. "
"If the magnitude of the tilt angle is not important, z can be set to 1.\n"
) +
gsi::method ("ty", &db::Matrix3d::perspective_tilt_y, gsi::arg ("z"),
"@brief Returns the perspective tilt angle ty.\n"
"@param z The observer distance at which the tilt angle is computed.\n"
"@return The tilt angle ty.\n"
"The tx and ty parameters represent the perspective distortion. They denote a tilt of the xy plane around the y axis (tx) or the x axis (ty) in degree. "
"The same effect is achieved for different tilt angles at different observer distances. Hence, the observer distance must be specified at which the tilt angle is computed. "
"If the magnitude of the tilt angle is not important, z can be set to 1.\n"
) +
gsi::method ("is_mirror?", &db::Matrix3d::is_mirror,
"@brief Returns the mirror flag of this matrix.\n"
"@return True if this matrix has a mirror component.\n"
"See the description of this class for details about the basic transformations."
) +
matrix3d_methods<db::DCoord> () +
gsi::method_ext ("adjust", &adjust, gsi::arg ("landmarks_before"), gsi::arg ("landmarks_after"), gsi::arg ("flags"), gsi::arg ("fixed_point"),
"@brief Adjust a 3d matrix to match the given set of landmarks\n"
"\n"
@ -558,7 +731,7 @@ gsi::Class<db::Matrix3d> decl_Matrix3d ("db", "Matrix3d",
),
"@brief A 3d matrix object used mainly for representing rotation, shear, displacement and perspective transformations.\n"
"\n"
"This object represents a 3x3 matrix. This matrix is used to represent geometrical transformations "
"This object represents a 3x3 matrix. This matrix is used to implement generic geometrical transformations "
"in the 2d space mainly. It can be decomposed into basic transformations: mirroring, rotation, shear, displacement and perspective distortion. "
"In that case, the assumed execution order of the basic transformations is "
"mirroring at the x axis, rotation, magnification, shear, displacement and perspective distortion."
@ -566,4 +739,16 @@ gsi::Class<db::Matrix3d> decl_Matrix3d ("db", "Matrix3d",
"This class was introduced in version 0.22.\n"
);
gsi::Class<db::IMatrix3d> decl_IMatrix3d ("db", "IMatrix3d",
matrix3d_methods<db::Coord> (),
"@brief A 3d matrix object used mainly for representing rotation, shear, displacement and perspective transformations (integer coordinate version).\n"
"\n"
"This object represents a 3x3 matrix. This matrix is used to implement generic geometrical transformations "
"in the 2d space mainly. It can be decomposed into basic transformations: mirroring, rotation, shear, displacement and perspective distortion. "
"In that case, the assumed execution order of the basic transformations is "
"mirroring at the x axis, rotation, magnification, shear, displacement and perspective distortion."
"\n\n"
"The integer variant was introduced in version 0.27.\n"
);
}

View File

@ -1855,7 +1855,7 @@ Class<db::Polygon> decl_Polygon ("db", "Polygon",
"\n"
"This method was introduced in version 0.24.\n"
) +
method_ext ("transformed", &transformed_icplx_dp, gsi::arg ("t"),
method_ext ("#transformed", &transformed_icplx_dp, gsi::arg ("t"),
"@brief Transforms the polygon with a complex transformation\n"
"\n"
"Transforms the polygon with the given complex transformation.\n"

View File

@ -70,6 +70,27 @@ static db::DCplxTrans si_dtrans (const db::RecursiveShapeIterator *r)
return db::CplxTrans (ly->dbu ()) * r->trans () * db::VCplxTrans (1.0 / ly->dbu ());
}
static db::DCplxTrans si_global_dtrans (const db::RecursiveShapeIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return db::CplxTrans (ly->dbu ()) * r->global_trans () * db::VCplxTrans (1.0 / ly->dbu ());
}
static db::DCplxTrans si_always_apply_dtrans (const db::RecursiveShapeIterator *r)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
return db::CplxTrans (ly->dbu ()) * r->always_apply () * db::VCplxTrans (1.0 / ly->dbu ());
}
static void si_set_global_dtrans (db::RecursiveShapeIterator *r, const db::DCplxTrans &gt)
{
const db::Layout *ly = r->layout ();
tl_assert (ly != 0);
r->set_global_trans (db::VCplxTrans (1.0 / ly->dbu ()) * gt * db::CplxTrans (ly->dbu ()));
}
static void select_cells1 (db::RecursiveShapeIterator *r, const std::vector<db::cell_index_type> &cells)
{
std::set<db::cell_index_type> cc;
@ -270,7 +291,47 @@ Class<db::RecursiveShapeIterator> decl_RecursiveShapeIterator ("db", "RecursiveS
"\n"
"This method has been introduced in version 0.23.\n"
) +
gsi::method ("region", &db::RecursiveShapeIterator::region,
gsi::method ("global_trans=", &db::RecursiveShapeIterator::set_global_trans, gsi::arg ("t"),
"@brief Sets the global transformation to apply to all shapes delivered\n"
"The global transformation will be applied to all shapes delivered by biasing the \"trans\" attribute.\n"
"The search regions apply to the coordinate space after global transformation.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("global_trans", &db::RecursiveShapeIterator::global_trans,
"@brief Gets the global transformation to apply to all shapes delivered\n"
"See also \\global_trans=.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("global_dtrans=", &si_set_global_dtrans,
"@brief Sets the global transformation to apply to all shapes delivered (transformation in micrometer units)\n"
"The global transformation will be applied to all shapes delivered by biasing the \"trans\" attribute.\n"
"The search regions apply to the coordinate space after global transformation.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("global_dtrans", &si_global_dtrans,
"@brief Gets the global transformation to apply to all shapes delivered (in micrometer units)\n"
"See also \\global_dtrans=.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("always_apply_trans", &db::RecursiveShapeIterator::always_apply,
"@brief Gets the global transformation if at top level, unity otherwise\n"
"As the global transformation is only applicable on top level, use this method to transform shapes and instances into their local (cell-level) version "
"while considering the global transformation properly.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("always_apply_dtrans", &si_always_apply_dtrans,
"@brief Gets the global transformation if at top level, unity otherwise (micrometer-unit version)\n"
"As the global transformation is only applicable on top level, use this method to transform shapes and instances into their local (cell-level) version "
"while considering the global transformation properly.\n"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method ("region", &db::RecursiveShapeIterator::region,
"@brief Gets the basic region that is iterator is using\n"
"The basic region is the overall box the region iterator iterates over. "
"There may be an additional complex region that confines the region iterator. "

View File

@ -32,6 +32,7 @@
#include "dbShapes.h"
#include "dbDeepShapeStore.h"
#include "dbRegion.h"
#include "dbFillTool.h"
#include "dbRegionProcessors.h"
#include "dbCompoundOperation.h"
#include "tlGlobPattern.h"
@ -713,6 +714,29 @@ 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::fill_region (cell, *fr, fill_cell_index, fc_box, origin ? *origin : db::Point (), origin == 0, remaining_parts, fill_margin, remaining_polygons, glue_box);
}
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::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);
}
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::Point &origin, const db::Box &glue_box)
{
db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, origin, glue_box);
}
static db::Point default_origin;
// provided by gsiDeclDbPolygon.cc:
int td_simple ();
int po_any ();
@ -2320,8 +2344,32 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The transformed region.\n"
) +
method ("transform", (db::Region &(db::Region::*)(const db::IMatrix2d &)) &db::Region::transform, gsi::arg ("t"),
"@brief Transform the region (modifies self)\n"
"\n"
"Transforms the region with the given 2d matrix transformation.\n"
"This version modifies the region and returns a reference to self.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed region.\n"
"\n"
"This variant was introduced in version 0.27.\n"
) +
method ("transform", (db::Region &(db::Region::*)(const db::IMatrix3d &)) &db::Region::transform, gsi::arg ("t"),
"@brief Transform the region (modifies self)\n"
"\n"
"Transforms the region with the given 3d matrix transformation.\n"
"This version modifies the region and returns a reference to self.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed region.\n"
"\n"
"This variant was introduced in version 0.27.\n"
) +
method ("transformed", (db::Region (db::Region::*)(const db::Trans &) const) &db::Region::transformed, gsi::arg ("t"),
"@brief Transform the region\n"
"@brief Transforms the region\n"
"\n"
"Transforms the region with the given transformation.\n"
"Does not modify the region but returns the transformed region.\n"
@ -2331,7 +2379,7 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@return The transformed region.\n"
) +
method ("transformed|#transformed_icplx", (db::Region (db::Region::*)(const db::ICplxTrans &) const) &db::Region::transformed, gsi::arg ("t"),
"@brief Transform the region with a complex transformation\n"
"@brief Transforms the region with a complex transformation\n"
"\n"
"Transforms the region with the given complex transformation.\n"
"Does not modify the region but returns the transformed region.\n"
@ -2340,6 +2388,30 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"\n"
"@return The transformed region.\n"
) +
method ("transformed", (db::Region (db::Region::*)(const db::IMatrix2d &) const) &db::Region::transformed, gsi::arg ("t"),
"@brief Transforms the region\n"
"\n"
"Transforms the region with the given 2d matrix transformation.\n"
"Does not modify the region but returns the transformed region.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed region.\n"
"\n"
"This variant was introduced in version 0.27.\n"
) +
method ("transformed", (db::Region (db::Region::*)(const db::IMatrix3d &) const) &db::Region::transformed, gsi::arg ("t"),
"@brief Transforms the region\n"
"\n"
"Transforms the region with the given 3d matrix transformation.\n"
"Does not modify the region but returns the transformed region.\n"
"\n"
"@param t The transformation to apply.\n"
"\n"
"@return The transformed region.\n"
"\n"
"This variant was introduced in version 0.27.\n"
) +
method_ext ("width_check", &width2, gsi::arg ("d"), gsi::arg ("whole_edges", false), gsi::arg ("metrics", db::metrics_type::Euclidian, "Euclidian"), gsi::arg ("ignore_angle", tl::Variant (), "default"), gsi::arg ("min_projection", tl::Variant (), "0"), gsi::arg ("max_projection", tl::Variant (), "max"), gsi::arg ("shielded", true), gsi::arg ("negative", false),
"@brief Performs a width check with options\n"
"@param d The minimum width for which the polygons are checked\n"
@ -2811,6 +2883,51 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"See \\base_verbosity= for details.\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
gsi::method_ext ("fill", &fill_region, gsi::arg ("in_cell"),
gsi::arg ("fill_cell_index"),
gsi::arg ("fc_box"),
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 ()),
"@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"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("fill", &fill_region_skew, gsi::arg ("in_cell"),
gsi::arg ("fill_cell_index"),
gsi::arg ("fc_origin"),
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 ()),
"@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"
"\n"
"This method has been introduced in version 0.27.\n"
) +
gsi::method_ext ("fill_multi", &fill_region_multi, gsi::arg ("in_cell"),
gsi::arg ("fill_cell_index"),
gsi::arg ("fc_origin"),
gsi::arg ("row_step"),
gsi::arg ("column_step"),
gsi::arg ("fill_margin", db::Vector ()),
gsi::arg ("remaining_polygons", (db::Region *)0, "nil"),
gsi::arg ("origin", db::Point ()),
gsi::arg ("glue_box", db::Box ()),
"@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"
"\n"
"This method has been introduced in version 0.27.\n"
),
"@brief A region (a potentially complex area consisting of multiple polygons)\n"
"\n\n"

View File

@ -0,0 +1,315 @@
/*
KLayout Layout Viewer
Copyright (C) 2006-2021 Matthias Koefferlein
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dbFillTool.h"
#include "dbReader.h"
#include "dbRegion.h"
#include "dbTestSupport.h"
#include "dbRegion.h"
#include "tlUnitTest.h"
#include "tlStream.h"
TEST(1)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, ly.cell (fill_cell).bbox (), db::Point (), false);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au1.gds");
}
TEST(2)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::Region remaining_parts, remaining_polygons;
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, ly.cell (fill_cell).bbox (), db::Point (), true, &remaining_parts, db::Vector (50, 100), &remaining_polygons);
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
unsigned int l101 = ly.insert_layer (db::LayerProperties (101, 0));
remaining_parts.insert_into (&ly, top_cell, l100);
remaining_polygons.insert_into (&ly, top_cell, l101);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au2.gds");
}
TEST(3)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool3.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::Region remaining_parts, remaining_polygons;
db::Vector ko (-100, -130);
db::Vector rs (230, 40);
db::Vector cs (40, 230);
db::Box fc_box (db::Point () + ko, db::Point (rs.x (), cs.y ()) + ko);
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), true, &remaining_parts, db::Vector (50, 100), &remaining_polygons);
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
unsigned int l101 = ly.insert_layer (db::LayerProperties (101, 0));
remaining_parts.insert_into (&ly, top_cell, l100);
remaining_polygons.insert_into (&ly, top_cell, l101);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au3.gds");
}
TEST(3a)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool3.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::Region remaining_parts, remaining_polygons;
db::Vector ko (-100, -130);
db::Vector rs (230, 40);
db::Vector cs (-40, 230);
db::Box fc_box (db::Point () + ko, db::Point (rs.x (), cs.y ()) + ko);
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), true, &remaining_parts, db::Vector (50, 100), &remaining_polygons);
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
unsigned int l101 = ly.insert_layer (db::LayerProperties (101, 0));
remaining_parts.insert_into (&ly, top_cell, l100);
remaining_polygons.insert_into (&ly, top_cell, l101);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au3a.gds");
}
TEST(3b)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool3.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::Region remaining_parts, remaining_polygons;
db::Vector ko (-100, -130);
db::Vector rs (230, -40);
db::Vector cs (40, 230);
db::Box fc_box (db::Point () + ko, db::Point (rs.x (), cs.y ()) + ko);
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), true, &remaining_parts, db::Vector (50, 100), &remaining_polygons);
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
unsigned int l101 = ly.insert_layer (db::LayerProperties (101, 0));
remaining_parts.insert_into (&ly, top_cell, l100);
remaining_polygons.insert_into (&ly, top_cell, l101);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au3b.gds");
}
TEST(3c)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool3.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::Region remaining_parts, remaining_polygons;
db::Vector ko (-100, -130);
db::Vector rs (230, -40);
db::Vector cs (-40, 230);
db::Box fc_box (db::Point () + ko, db::Point (rs.x (), cs.y ()) + ko);
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), true, &remaining_parts, db::Vector (50, 100), &remaining_polygons);
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
unsigned int l101 = ly.insert_layer (db::LayerProperties (101, 0));
remaining_parts.insert_into (&ly, top_cell, l100);
remaining_polygons.insert_into (&ly, top_cell, l101);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au3c.gds");
}
TEST(4)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool4.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::Region remaining_polygons;
db::Vector ko (-100, -130);
db::Vector rs (230, 0);
db::Vector cs (0, 230);
db::Box fc_box (db::Point () + ko, db::Point (rs.x (), cs.y ()) + ko);
db::fill_region_repeat (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Vector (50, 100), &remaining_polygons);
unsigned int l101 = ly.insert_layer (db::LayerProperties (101, 0));
remaining_polygons.insert_into (&ly, top_cell, l101);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au4.gds");
}
TEST(4b)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool4.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::Region remaining_polygons;
db::Vector ko (-100, -130);
db::Vector rs (230, 0);
db::Vector cs (0, 230);
db::Box fc_box (db::Point () + ko, db::Point ());
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), true, &remaining_polygons);
unsigned int l101 = ly.insert_layer (db::LayerProperties (101, 0));
remaining_polygons.insert_into (&ly, top_cell, l101);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au4b.gds");
}
TEST(4c)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/fill_tool4.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
db::Region remaining_polygons;
db::Vector ko (-100, -130);
db::Vector rs (230, 0);
db::Vector cs (0, 230);
db::Box fc_box (db::Point () + ko, db::Point (rs.x (), cs.y ()) + ko);
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box.enlarged (db::Vector (100, 100)), rs, cs, db::Point (), true, &remaining_polygons);
unsigned int l101 = ly.insert_layer (db::LayerProperties (101, 0));
remaining_polygons.insert_into (&ly, top_cell, l101);
CHECKPOINT();
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/fill_tool_au4c.gds");
}

View File

@ -630,3 +630,12 @@ TEST(10)
EXPECT_EQ ((m * p[2]).to_string (), "2,3");
}
TEST(11)
{
// double and integer versions basic functionality
EXPECT_EQ ((db::Matrix2d (1.0, 0.5, -0.5, 2.0) * db::DPoint (1, 2)).to_string (), "2,3.5");
EXPECT_EQ ((db::IMatrix2d (1.0, 0.5, -0.5, 2.0) * db::Point (10, 20)).to_string (), "20,35");
EXPECT_EQ ((db::Matrix3d (1.0, 0.5, 0.0, -0.5, 2.0, 1.0, 0.0, 0.0, 1.0) * db::DPoint (1, 2)).to_string (), "2,4.5");
EXPECT_EQ ((db::IMatrix3d (1.0, 0.5, 0.0, -0.5, 2.0, 1.0, 0.0, 0.0, 1.0) * db::DPoint (10, 20)).to_string (), "20,36");
}

View File

@ -918,6 +918,37 @@ TEST(25)
EXPECT_EQ (am_to_string (am), "(1650,5000,8350,3000,0),(3350,9175,10000,8660,330),(0,825,6650,10000,5000),(0,0,0,3350,8845),(0,0,0,0,825)");
EXPECT_EQ (am.total_area (), 85010);
am.reinitialize (db::Point (0, 0), db::Vector (100, 100), db::Vector (50, 50), 5, 5);
db::rasterize (in, am);
EXPECT_EQ (am_to_string (am), "(0,0,1250,750,0),(825,2500,2500,2500,0),(0,0,2287,2500,1750),(0,0,0,825,2500),(0,0,0,0,0)");
EXPECT_EQ (am.total_area (), 20187);
am.reinitialize (db::Point (200, 0), db::Vector (100, 100), db::Vector (50, 50), 1, 1);
db::rasterize (in, am);
EXPECT_EQ (am_to_string (am), "(1250)");
am.reinitialize (db::Point (300, 0), db::Vector (100, 100), db::Vector (50, 50), 1, 1);
db::rasterize (in, am);
EXPECT_EQ (am_to_string (am), "(750)");
am.reinitialize (db::Point (400, 0), db::Vector (100, 100), db::Vector (50, 50), 1, 1);
db::rasterize (in, am);
EXPECT_EQ (am_to_string (am), "(0)");
am.reinitialize (db::Point (400, 100), db::Vector (100, 100), db::Vector (50, 50), 1, 1);
db::rasterize (in, am);
EXPECT_EQ (am_to_string (am), "(0)");
am.reinitialize (db::Point (400, 200), db::Vector (100, 100), db::Vector (50, 50), 1, 1);
db::rasterize (in, am);
EXPECT_EQ (am_to_string (am), "(1750)");
}
TEST(26)
@ -1047,7 +1078,7 @@ TEST(30)
EXPECT_EQ (am_to_string (am), "(5418,1071,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(6642,6267,1967,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(6642,6642,6582,3119,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(6642,6642,6642,6642,4317,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(1701,1701,1701,4995,6642,5303,735,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,4428,6642,6642,5952,1127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,4428,6642,6642,6642,6178,1484,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,2430,3645,3645,4644,6642,6355,1859,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,2214,6642,6642,6489,2275,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,2214,6642,6642,6642,6582,2698,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,1863,5589,5589,5589,6642,6632,2994,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,6642,6642,6624,2698,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,6642,6642,6642,6587,2379,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,6642,6642,6642,6642,6537,2111,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,891,891,891,4725,6642,6471,1859,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,4428,6642,6642,6378,1570,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,4428,6642,6642,6642,6166,960,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,1890,2835,2835,4104,6642,5617,432,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2214,6642,6642,4860,104,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2214,6642,6642,6642,3854,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1593,4779,4779,4779,6642,2788,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6642,6538,1777,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6642,6642,6110,704),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6642,6642,6642,4539),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,81,81,55)");
}
TEST(31)
TEST(41)
{
db::Point pattern [] = {
db::Point (0, -100),
@ -1131,7 +1162,7 @@ TEST(31)
EXPECT_EQ (pout.to_string (), "(10,-90;10,-65;-90,-65;-90,235;10,410;510,410;535,385;610,385;610,-40;510,-90)");
}
TEST(32)
TEST(42)
{
db::Point pattern [] = {
db::Point (0, -100),

View File

@ -107,12 +107,35 @@ TEST(1)
std::string x;
db::RecursiveShapeIterator i0s (g, c0, 0);
x = collect(i0s, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)/[$4](1200,0;2200,1100)/[$4](-1200,0;-100,1000)");
EXPECT_EQ (i0s.bbox ().to_string (), "(-1200,0;2200,1200)");
i0s.set_global_trans (db::ICplxTrans (2.0));
x = collect(i0s, g);
EXPECT_EQ (x, "[$1](0,200;2000,2400)/[$2](0,200;2000,2400)/[$3](200,0;2200,2200)/[$4](2400,0;4400,2200)/[$4](-2400,0;-200,2000)");
EXPECT_EQ (i0s.bbox ().to_string (), "(-2400,0;4400,2400)");
db::RecursiveShapeIterator i1 (g, c0, 0, db::Box (0, 0, 100, 100));
x = collect(i1, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](0,100;1000,1200)/[$2](0,100;1000,1200)/[$3](100,0;1100,1100)");
i1.set_global_trans (db::ICplxTrans (db::Trans (db::Vector (10, 20))));
i1.set_region (db::Box (10, 20, 110, 120));
x = collect(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
i1.reset ();
x = collect(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
x = collect_with_copy(i1, g);
EXPECT_EQ (x, "[$1](10,120;1010,1220)/[$2](10,120;1010,1220)/[$3](110,20;1110,1120)");
db::RecursiveShapeIterator i1_1inf (g, c0, 0, db::Box (0, 0, 100, 100));
i1_1inf.min_depth(1);
x = collect(i1_1inf, g);
@ -731,7 +754,7 @@ namespace {
public:
FlatPusher (std::set<db::Box> *boxes) : mp_boxes (boxes) { }
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
mp_boxes->insert (trans * shape.bbox ());
}
@ -766,6 +789,8 @@ TEST(4)
}
// ...
db::Box search_box (2500, 2500, 7500, 7500);
std::set<db::Box> selected_boxes;
@ -794,6 +819,45 @@ TEST(4)
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// with global trans
selected_boxes.clear ();
selected_boxes2.clear ();
db::ICplxTrans ctr (db::Trans (db::Vector (10, 20)));
{
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
for ( ; !iter.at_end (); ++iter) {
selected_boxes.insert (iter->bbox ().transformed (iter.trans ()));
}
}
{
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (b->transformed (ctr))) {
selected_boxes2.insert (b->transformed (ctr));
}
}
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
iter.push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// ...
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
@ -882,6 +946,40 @@ TEST(5)
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
selected_boxes.clear ();
selected_boxes2.clear ();
db::ICplxTrans ctr (db::Trans (db::Vector (10, 20)));
{
db::RecursiveShapeIterator iter = db::RecursiveShapeIterator (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
for ( ; !iter.at_end (); ++iter) {
selected_boxes.insert (iter.trans () * iter->bbox ());
}
}
for (std::set<db::Box>::const_iterator b = boxes.begin (); b != boxes.end (); ++b) {
if (search_box.overlaps (b->transformed (ctr))) {
selected_boxes2.insert (b->transformed (ctr));
}
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
// push mode
{
selected_boxes.clear ();
FlatPusher pusher (&selected_boxes);
db::RecursiveShapeIterator iter (g, c0, 0, search_box, true);
iter.set_global_trans (ctr);
iter.push (&pusher);
}
EXPECT_EQ (selected_boxes.size () > 100, true);
EXPECT_EQ (db::compare_layouts (boxes2layout (selected_boxes), boxes2layout (selected_boxes2), db::layout_diff::f_verbose, 0, 100 /*max diff lines*/), true);
db::Box search_box2 (500, 500, 1000, 1000);
selected_boxes.clear ();
@ -936,7 +1034,7 @@ public:
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
}
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
if (all) {
@ -946,9 +1044,9 @@ public:
return NI_all;
}
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans);
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (always_apply * trans);
if (all) {
m_text += ",all";
}
@ -956,7 +1054,7 @@ public:
return true;
}
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
m_text += "shape(" + shape.to_string () + "," + tl::to_string (trans) + ")\n";
}
@ -971,9 +1069,9 @@ class ReceiverRejectingACellInstanceArray
public:
ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst (iter, inst, region, complex_region, all);
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip;
}
@ -987,9 +1085,9 @@ class ReceiverRejectingACellInstanceArrayExceptOne
public:
ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst (iter, inst, region, complex_region, all);
LoggingReceiver::new_inst (iter, inst, always_apply, region, complex_region, all);
return inst.object ().cell_index () != m_rejected ? NI_all : NI_single;
}
@ -1003,9 +1101,9 @@ class ReceiverRejectingACellInstance
public:
ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { }
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &always_apply, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region, all);
LoggingReceiver::new_inst_member (iter, inst, always_apply, trans, region, complex_region, all);
return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected;
}
@ -1127,6 +1225,100 @@ TEST(10)
"end\n"
);
LoggingReceiver lr1_gt;
db::RecursiveShapeIterator i1_gt (g, c0, 0);
i1_gt.set_global_trans (db::ICplxTrans (db::Trans (db::Vector (10, 20))));
i1_gt.push (&lr1_gt);
EXPECT_EQ (lr1_gt.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 10,20,all)\n"
// It's a bit weird to have shape events after new_inst_member, but remember, new_inst_member is a query callback, not an event.
"shape(box (0,0;1000,1000),r0 *1 10,20)\n"
"shape(box (-1000,0;0,1000),r0 *1 10,20)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,20)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,2020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,1020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,3020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 10,6020,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,6020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 10,8020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,7020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3010,9020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6010,20,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,20)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,2020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,1020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,3020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6010,6020,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,6020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6010,8020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,7020)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9010,9020)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"end\n"
);
ReceiverRejectingACellInstanceArray rr1 (c2.cell_index ());
db::RecursiveShapeIterator ir1 (g, c0, 0);
ir1.push (&rr1);

View File

@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
SOURCES = \
dbCompoundOperationTests.cc \
dbFillToolTests.cc \
dbRecursiveInstanceIteratorTests.cc \
dbRegionUtilsTests.cc \
dbUtilsTests.cc \

View File

@ -63,6 +63,36 @@ module DRC
@in_context = nil
end
def shift(x, y)
self._context("shift") do
RBA::DCplxTrans::new(RBA::DVector::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu))
end
end
def magnify(m)
self._context("magnify") do
RBA::DCplxTrans::new(_make_numeric_value(m))
end
end
def rotate(a)
self._context("rotate") do
RBA::DCplxTrans::new(1.0, _make_numeric_value(a), false, RBA::DVector::new)
end
end
def mirror_x
self._context("mirror_x") do
RBA::DCplxTrans::new(1.0, 0.0, true, RBA::DVector::new)
end
end
def mirror_y
self._context("mirror_y") do
RBA::DCplxTrans::new(1.0, 180.0, true, RBA::DVector::new)
end
end
def joined
DRCJoinFlag::new(true)
@ -212,6 +242,26 @@ module DRC
DRCAreaAndPerimeter::new(r, 1.0, f)
end
end
def fill_pattern(name)
DRCFillCell::new(name)
end
def hstep(x, y = nil)
DRCFillStep::new(true, x, y)
end
def vstep(x, y = nil)
DRCFillStep::new(false, x, y)
end
def auto_origin
DRCFillOrigin::new
end
def origin(x, y)
DRCFillOrigin::new(x, y)
end
def tile_size(x, y = nil)
DRCTileSize::new(_make_value(x) * self.dbu, _make_value(y || x) * self.dbu)
@ -1494,6 +1544,22 @@ CODE
nil
end
# %DRC%
# @name global_transform
# @brief Gets or sets a global transformation
# @synopsis global_transform
# @synopsis global_transform([ transformations ])
#
# Applies a global transformation to the default source layout.
# See \Source#global_transform for a description of this feature.
def global_transform(*args)
self._context("global_transform") do
@def_source = layout.global_transform(*args)
end
nil
end
# %DRC%
# @name cheat
# @brief Hierarchy cheats
@ -1679,8 +1745,6 @@ CODE
pull_overlapping
rectangles
rectilinear
rotate
rotated
rounded_corners
scale
scaled
@ -2107,6 +2171,47 @@ CODE
obj.send(method, *args)
end
end
def _bx
@bx
end
def _by
@by
end
def _tx
@tx
end
def _ty
@ty
end
def _output_layout
if @output_layout
output = @output_layout
else
output = @def_layout
output || raise("No output layout specified")
end
output
end
def _output_cell
if @output_layout
if @output_cell
output_cell = @output_cell
elsif @def_cell
output_cell = @output_layout.cell(@def_cell.name) || @output_layout.create_cell(@def_cell.name)
end
output_cell || raise("No output cell specified (see 'target' instruction)")
else
output_cell = @output_cell || @def_cell
output_cell || raise("No output cell specified")
end
output_cell
end
def _start(job_description)
@ -2439,6 +2544,13 @@ CODE
v
end
def _use_output_layer(li)
if !@used_output_layers[li]
@output_layers.push(li)
@used_output_layers[li] = true
end
end
private
def _make_string(v)
@ -2449,7 +2561,7 @@ CODE
end
end
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, cls)
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, global_trans, cls)
if layers.empty? && ! @deep
@ -2463,6 +2575,7 @@ CODE
iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers)
end
iter.shape_flags = shape_flags
iter.global_dtrans = global_trans
sel.each do |s|
if s == "-"
@ -2500,8 +2613,12 @@ CODE
end
# clip if a box is specified
if box && clip && (cls == RBA::Region || cls == RBA::Edge)
r &= RBA::Region::new(box)
# TODO: the whole clip thing could be a part of the Region constructor
if cls == RBA::Region && clip && box
# HACK: deep regions will always clip in the constructor, so skip this
if ! @deep
r &= RBA::Region::new(box)
end
end
end
@ -2529,20 +2646,8 @@ CODE
else
if @output_layout
output = @output_layout
if @output_cell
output_cell = @output_cell
elsif @def_cell
output_cell = @output_layout.cell(@def_cell.name) || @output_layout.create_cell(@def_cell.name)
end
output_cell || raise("No output cell specified (see 'target' instruction)")
else
output = @def_layout
output || raise("No output layout specified")
output_cell = @output_cell || @def_cell
output_cell || raise("No output cell specified")
end
output = self._output_layout
output_cell = self._output_cell
info = nil
if args.size == 1
@ -2606,7 +2711,7 @@ CODE
data
end
def make_source(layout, cell = nil, path = nil)
name = "layout" + @lnum.to_s
@lnum += 1

View File

@ -4231,6 +4231,262 @@ CODE
@engine._vcmd(@engine, :_output, self.data, *args)
end
end
# %DRC%
# @name fill
# @brief Fills the region with regular pattern of shapes
# @synopsis layer.fill([ options ])
#
# This method will attempt to fill the polygons of the layer with a regular pattern
# of shapes.
#
# The fill function currently is not available in deep mode.
#
# Options are:
# @ul
# @li @b hstep(x) @/b or @b hstep(x, y) @/b: specifies the horizontal step pitch of the pattern. x must be
# a positive value. A vertical displacement component can be specified too, which results in a skewed pattern. @/li
# @li @b vstep(y) @/b or @b vstep(x, y) @/b: specifies the vertical step pitch of the pattern. y must be
# a positive value. A horizontal displacement component can be specified too, which results in a skewed pattern. @/li
# @li @b origin(x, y) @/b: specifies a fixed point to align the pattern with. This point specifies the location
# of the reference point for one pattern cell. @/li
# @li @b auto_origin @/b: lets the algorithm choose the origin. This may result is a slightly better fill coverage
# as the algorithm is able to determine a pattern origin per fill island. @/li
# @li @b fill_pattern(..) @/b: specifies the fill pattern. @/li
# @/ul
#
# "fill_pattern" generates a fill pattern object. This object is used for configuring the fill pattern
# content. Fill pattern need to be named. The name will be used for generating the fill cell.
#
# To provide a fill pattern, create a fill pattern object and add shapes to it. The following example creates
# a fill pattern named "FILL_CELL" and adds a 1x1 micron box on layer 1/0:
#
# @code
# p = fill_pattern("FILL_CELL")
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
# @/code
#
# See \global#box for details about the box specification. You can also add paths or polygons with \global#path or \global#polygon.
#
# A more compact way of writing this is:
#
# @code
# p = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
# @/code
#
# The fill pattern can be given a reference point which is used for placing the pattern. The reference point
# is the one which is aligned with the pattern origin. The following code will assign (-0.5, -0.5) as the reference
# point for the 1x1 micron rectangle. Hence the reference point is a little below and left of the rectangle which
# in turn shifts the rectangle fill pattern to the right and up:
#
# @code
# p = fill_pattern("FILL_CELL")
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
# p.origin(-0.5, -0.5)
# @/code
#
# Without a reference point given, the lower left corner of the fill pattern's bounding box will be used
# as the reference point. The reference point will also defined the footprint of the fill cell - more precisely
# the lower left corner. When step vectors are given, the fill cell's footprint is taken to be a rectangle
# having the horizontal and vertical step pitch for width and height respectively. This way the fill cells
# will be arrange seamlessly. However, the cell's dimensions can be changed, so that the fill cells
# can overlap or there is a space between the cells. To change the dimensions use the "dim" method.
#
# The following example specifies a fill cell with an active area of -0.5 .. 1.5 in both directions
# (2 micron width and height). With these dimensions the fill cell's footprint is independent of the
# step pitch:
#
# @code
# p = fill_pattern("FILL_CELL")
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
# p.origin(-0.5, -0.5)
# p.dim(2.0, 2.0)
# @/code
#
# With these ingredients will can use the fill function. The first example fills the polygons
# of "to_fill" with an orthogonal pattern of 1x1 micron rectangles with a pitch of 2 microns:
#
# @code
# pattern = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0)).origin(-0.5, -0.5)
# to_fill.fill(pattern, hstep(2.0), vstep(2.0))
# @/code
#
# This second example will create a skewed fill pattern in auto-origin mode:
#
# @code
# pattern = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0)).origin(-0.5, -0.5)
# to_fill.fill(pattern, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
# @/code
#
# The fill function can only work with a target layout for output.
# It will not work for report output.
#
# The layers generated by the fill cells is only available for input later in the
# script if the output layout is identical to the input layouts.
# If you need the area missed by the fill function, try \fill_with_left.
def fill(*args)
self._fill(false, *args)
end
# %DRC%
# @name fill_with_left
# @brief Fills the region with regular pattern of shapes
# @synopsis layer.fill_with_left([ options ])
#
# This method has the same call syntax and functionality than \fill. Other than this method
# it will return the area not covered by fill cells as a DRC layer.
def fill_with_left(*args)
self._fill(true, *args)
end
def _fill(with_left, *args)
m = with_left ? "fill_with_left" : "fill"
# generation of new cells not tested in deep mode
@deep && raise("#{m} command not supported in deep mode currently")
(@engine._output_layout && @engine._output_cell) || raise("#{m} command needs an output layout and output cell")
source = @engine.source
row_step = nil
column_step = nil
pattern = nil
origin = RBA::DPoint::new
args.each_with_index do |a,ai|
if a.is_a?(DRCSource)
if source
raise("Duplicate source specification for '#{m}' at argument ##{ai+1}")
end
source = a
elsif a.is_a?(DRCFillCell)
if pattern
raise("Duplicate fill pattern specification for '#{m}' at argument ##{ai+1}")
end
pattern = a
elsif a.is_a?(DRCFillStep)
if a.for_row
if row_step
raise("Duplicate hstep specification for '#{m}' at argument ##{ai+1}")
end
row_step = a.step
else
if column_step
raise("Duplicate vstep specification for '#{m}' at argument ##{ai+1}")
end
column_step = a.step
end
elsif a.is_a?(DRCFillOrigin)
origin = a.origin
else
raise("Argument ##{ai+1} not understood for '#{m}'")
end
end
if !pattern
raise("No fill pattern given for '#{m}' (use 'fill_pattern')")
end
if !row_step
row_step = RBA::DVector::new(pattern.default_xpitch, 0)
end
if !column_step
column_step = RBA::DVector::new(0, pattern.default_ypitch)
end
dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu)
result = nil
fill_cell = pattern.create_cell(@engine._output_layout, @engine)
top_cell = @engine._output_cell
fc_box = dbu_trans * pattern.cell_box(row_step.x, column_step.y)
rs = dbu_trans * row_step
cs = dbu_trans * column_step
origin = origin ? dbu_trans * origin : nil
fc_index = fill_cell.cell_index
if @engine._tx && @engine._ty
tp = RBA::TilingProcessor::new
tp.dbu = @engine.dbu
tp.frame = RBA::CplxTrans::new(@engine.dbu) * self.data.bbox
tp.scale_to_dbu = false
tp.tile_size(@engine._tx, @engine._ty)
bx = [ @engine._bx || 0.0, row_step.x ].max
by = [ @engine._by || 0.0, column_step.y ].max
tp.tile_border(bx, by)
tp.threads = (@engine.threads || 1)
result_arg = "nil"
if with_left
result = RBA::Region::new
result_arg = "result"
tp.output(result_arg, result)
end
tp.input("region", self.data)
tp.var("top_cell", top_cell)
tp.var("fc_box", fc_box)
tp.var("rs", rs)
tp.var("cs", cs)
tp.var("origin", origin)
tp.var("fc_index", fc_index)
if with_left
tp.queue(<<"END")
var tc_box = _frame.bbox;
var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box;
!tile_box.empty && (
tile_box = tile_box.enlarged(Vector.new(max(rs.x, fc_box.width), max(cs.y, fc_box.height)));
tile_box = tile_box & tc_box;
var left = Region.new;
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, Vector.new, left, _tile.bbox);
_output(#{result_arg}, left)
)
END
else
tp.queue(<<"END")
var tc_box = _frame.bbox;
var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box;
!tile_box.empty && (
tile_box.right = tile_box.right + rs.x - 1;
tile_box.top = tile_box.top + cs.y - 1;
tile_box = tile_box & tc_box;
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, nil, Vector.new, nil, _tile.bbox)
)
END
end
begin
@engine._output_layout.start_changes
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
tp.execute("Tiled \"#{m}\" in: #{@engine.src_line}")
end
ensure
@engine._output_layout.end_changes
end
else
if with_left
result = RBA::Region::new
end
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, RBA::Vector::new, result)
end
end
self.data.disable_progress
return result ? DRCLayer::new(@engine, result) : nil
end
# %DRC%
# @name data

View File

@ -27,6 +27,7 @@ module DRC
@clip = false
@overlapping = false
@tmp_layers = []
@global_trans = RBA::DCplxTrans::new
end
# Conceptual deep copy (not including the temp layers)
@ -70,6 +71,24 @@ module DRC
def cell_obj
@cell
end
def inplace_global_transform(*args)
gt = RBA::DCplxTrans::new
args.each do |a|
if a.is_a?(RBA::DVector) || a.is_a?(RBA::DTrans)
gt = RBA::DCplxTrans::new(a) * gt
elsif a.is_a?(RBA::DCplxTrans)
gt = a * gt
else
raise("Expected a transformation spec instead of #{a.inspect}")
end
end
@global_trans = gt
end
def global_transformation
@global_trans
end
def finish
@tmp_layers.each do |li|
@ -245,8 +264,40 @@ module DRC
# \touching is a similar method which delivers shapes touching
# the search region with their bounding box (without the requirement to overlap)
# %DRC%
# @name global_transform
# @brief Gets or sets a global transformation
# @synopsis global_transform
# @synopsis global_transform([ transformations ])
#
# This method returns a new source representing the transformed layout. It is provided in the spritit of
# \Source#clip and similar methods.
#
# The transformation
# is either given as a RBA::DTrans, RBA::DVector or RBA::DCplxTrans object or as one of the
# following specifications:
#
# @ul
# @li "shift(x, y)": shifts the input layout horizontally by x and vertically by y micrometers @/li
# @li "rotate(a)": rotates the input layout by a degree counter-clockwise @/li
# @li "magnify(m)": magnifies the input layout by the factor m (NOTE: using fractional scale factors may result in small gaps due to grid snapping) @/li
# @li "mirror_x": mirrors the input layout at the x axis @/li
# @li "mirror_y": mirrors the input layout at the y axis @/li
# @/ul
#
# Multiple transformation specs can be given. In that case the transformations are applied right to left.
# Using "global_transform" will reset any global transformation present already.
# Without an argument, the global transformation is reset.
#
# The following example rotates the layout by 90 degree at the origin (0, 0) and then shifts it up by
# 100 micrometers:
#
# @code
# source.global_transform(shift(0, 100.um), rotate(90.0))
# @/code
# export inplace_* as * out-of-place
%w(select cell clip touching overlapping).each do |f|
%w(select cell clip touching overlapping global_transform).each do |f|
eval <<"CODE"
def #{f}(*args)
@engine._context("#{f}") do
@ -274,7 +325,7 @@ CODE
if @box
layer.insert(RBA::DBox::from_ibox(@box) * @layout.dbu)
else
layer.insert(RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu)
layer.insert((RBA::DBox::from_ibox(@cell.bbox) * @layout.dbu).transformed(@global_trans))
end
layer
end
@ -326,7 +377,7 @@ CODE
def input(*args)
@engine._context("input") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
end
end
@ -350,7 +401,7 @@ CODE
def labels(*args)
@engine._context("labels") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, RBA::Texts))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, @global_trans, RBA::Texts))
end
end
@ -373,7 +424,7 @@ CODE
def polygons(*args)
@engine._context("polygons") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, RBA::Region))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs, @global_trans, RBA::Region))
end
end
@ -399,7 +450,7 @@ CODE
def edges(*args)
@engine._context("edges") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, RBA::Edges))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, @global_trans, RBA::Edges))
end
end
@ -425,7 +476,7 @@ CODE
def edge_pairs(*args)
@engine._context("edge_pairs") do
layers = parse_input_layers(*args)
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, RBA::EdgePairs))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SEdgePairs, @global_trans, RBA::EdgePairs))
end
end
@ -437,7 +488,7 @@ CODE
def make_layer
layers = []
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region))
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, @global_trans, RBA::Region))
end
# %DRC%

View File

@ -181,6 +181,177 @@ module DRC
end
end
# A wrapper for the fill cell definition
class DRCFillCell
def initialize(name)
@cell_name = name
@shapes = []
@origin = nil
@dim = nil
end
def create_cell(layout, engine)
cell = layout.create_cell(@cell_name)
@shapes.each do |s|
li = layout.layer(s[0])
engine._use_output_layer(li)
s[1].each { |t| cell.shapes(li).insert(t) }
end
cell
end
def cell_box(def_w, def_h)
o = @origin || self._computed_origin
d = @dim || RBA::DVector::new(def_w, def_h)
RBA::DBox::new(o, o + d)
end
def default_xpitch
@dim ? @dim.x : self.bbox.width
end
def default_ypitch
@dim ? @dim.y : self.bbox.height
end
def _computed_origin
b = self.bbox
return b.empty? ? RBA::DPoint::new : b.p1
end
def bbox
box = RBA::DBox::new
@shapes.each do |s|
s[1].each { |t| box += t.bbox }
end
box
end
def shape(*args)
layer = nil
datatype = nil
name = nil
shapes = []
args.each_with_index do |a,ai|
if a.is_a?(1.class)
if !layer
layer = a
elsif !datatype
datatype = a
else
raise("Argument ##{ai+1} not understood for FillCell#shape")
end
elsif a.is_a?(String)
if !name
name = a
else
raise("Argument ##{ai+1} not understood for FillCell#shape")
end
elsif a.is_a?(RBA::DBox) || a.is_a?(RBA::DPath) || a.is_a?(RBA::DPolygon) || a.is_a?(RBA::DText)
shapes << a
else
raise("Argument ##{ai+1} not understood for FillCell#shape (needs to one of: number, string or box, path, polygon or text)")
end
end
if !shapes.empty?
li = RBA::LayerInfo::new
if layer
li.layer = layer
li.datatype = datatype || 0
end
if name
li.name = name
end
@shapes << [ li, shapes ]
end
self
end
def origin(x, y)
if !x.is_a?(1.class) && !x.is_a?(1.0.class)
raise("x argument not numeric FillCell#origin")
end
if !y.is_a?(1.class) && !y.is_a?(1.0.class)
raise("y argument not numeric FillCell#origin")
end
@origin = RBA::DVector::new(x, y)
self
end
def dim(w, h)
if !w.is_a?(1.class) && !w.is_a?(1.0.class)
raise("w argument not numeric FillCell#dim")
end
if !h.is_a?(1.class) && !h.is_a?(1.0.class)
raise("h argument not numeric FillCell#dim")
end
@dim = RBA::DVector::new(w, h)
self
end
end
# A wrapper for the fill step definition
class DRCFillStep
def initialize(for_row, x, y = nil)
@for_row = for_row
if !x.is_a?(1.class) && !x.is_a?(1.0.class)
raise("x argument not numeric in fill step")
end
if y && !y.is_a?(1.class) && !y.is_a?(1.0.class)
raise("y argument not numeric in fill step")
end
if y
@step = RBA::DVector::new(x, y)
elsif for_row
@step = RBA::DVector::new(x, 0)
else
@step = RBA::DVector::new(0, x)
end
end
def for_row
@for_row
end
def step
@step
end
end
# A wrapper for the fill origin definition
class DRCFillOrigin
def initialize(x = nil, y = nil)
if !x && !y
@origin = nil
else
if !x.is_a?(1.class) && !x.is_a?(1.0.class)
raise("x argument not numeric in fill origin")
end
if !y.is_a?(1.class) && !y.is_a?(1.0.class)
raise("y argument not numeric in fill origin")
end
@origin = RBA::DVector::new(x, y)
end
end
def origin
@origin
end
end
# A wrapper for the tile_size option
class DRCTileSize
def initialize(*args)
@ -230,6 +401,6 @@ module DRC
@b
end
end
end

View File

@ -1168,3 +1168,57 @@ TEST(30_density)
run_test (_this, "30", false);
}
TEST(31_globaTransformation)
{
run_test (_this, "31", false);
}
TEST(31d_globalTransformation)
{
run_test (_this, "31", true);
}
TEST(32_globalTransformationWithClip)
{
run_test (_this, "32", false);
}
TEST(32d_globalTransformationWithClip)
{
run_test (_this, "32", true);
}
TEST(33_globalTransformationWithTiles)
{
run_test (_this, "33", true);
}
TEST(40_fill)
{
run_test (_this, "40", false);
}
TEST(41_fillTiled)
{
run_test (_this, "41", false);
}
TEST(42_fillWithLeft)
{
run_test (_this, "42", false);
}
TEST(43_fillWithLeftTiled)
{
run_test (_this, "43", false);
}
TEST(44_fillWithOverlappingBoxes)
{
run_test (_this, "44", false);
}
TEST(45_fillWithOverlappingBoxesTiled)
{
run_test (_this, "45", false);
}

View File

@ -1504,9 +1504,14 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
tl::Heap heap;
size_t narg = 0;
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && narg < args.size (); ++a, ++narg) {
// Note: this const_cast is ugly, but it will basically enable "out" parameters
// TODO: clean this up.
gsi::do_on_type<writer> () (a->type (), &arglist, const_cast<tl::Variant *> (&args [narg]), *a, &heap);
try {
// Note: this const_cast is ugly, but it will basically enable "out" parameters
// TODO: clean this up.
gsi::do_on_type<writer> () (a->type (), &arglist, const_cast<tl::Variant *> (&args [narg]), *a, &heap);
} catch (tl::Exception &ex) {
std::string msg = ex.msg () + tl::sprintf (tl::to_string (tr (" (argument '%s')")), a->spec ()->name ());
throw tl::Exception (msg);
}
}
SerialArgs retlist (meth->retsize ());
@ -1518,7 +1523,12 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Iterators not supported yet (method %s, class %s)")), method.c_str (), mp_cls->name ()));
} else {
out = tl::Variant ();
gsi::do_on_type<reader> () (meth->ret_type ().type (), &out, &retlist, meth->ret_type (), &heap);
try {
gsi::do_on_type<reader> () (meth->ret_type ().type (), &out, &retlist, meth->ret_type (), &heap);
} catch (tl::Exception &ex) {
std::string msg = ex.msg () + tl::to_string (tr (" (return value)"));
throw tl::Exception (msg);
}
}
}

View File

@ -939,7 +939,7 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
#define _FUNCARGLIST A1
#define _ADDARGS this->template add_arg<A1> (m_s1);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init ();
#define _ARGVARLIST a1
#define _ARGSPECARGS s1
#define _ARGSPEC const ArgSpec<A1> &s1
@ -973,8 +973,8 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
#define _ADDARGS this->template add_arg<A1> (m_s1); \
this->template add_arg<A2> (m_s2);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init ();
#define _ARGVARLIST a1, a2
#define _ARGSPECARGS s1, s2
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2
@ -1010,9 +1010,9 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A2> (m_s2); \
this->template add_arg<A3> (m_s3);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init ();
#define _ARGVARLIST a1, a2, a3
#define _ARGSPECARGS s1, s2, s3
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3
@ -1050,10 +1050,10 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A3> (m_s3); \
this->template add_arg<A4> (m_s4);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init ();
#define _ARGVARLIST a1, a2, a3, a4
#define _ARGSPECARGS s1, s2, s3, s4
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4
@ -1093,11 +1093,11 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A4> (m_s4); \
this->template add_arg<A5> (m_s5);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5
#define _ARGSPECARGS s1, s2, s3, s4, s5
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5
@ -1139,12 +1139,12 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A5> (m_s5); \
this->template add_arg<A6> (m_s6);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6
@ -1188,13 +1188,13 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A6> (m_s6); \
this->template add_arg<A7> (m_s7);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7
@ -1240,14 +1240,14 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A7> (m_s7); \
this->template add_arg<A8> (m_s8);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8
@ -1295,15 +1295,15 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A8> (m_s8); \
this->template add_arg<A9> (m_s9);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap) : m_s9.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap, &m_s9) : m_s9.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8, a9
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8, s9
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8, const ArgSpec<A9> &s9
@ -1353,16 +1353,16 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A9> (m_s9); \
this->template add_arg<A10> (m_s10);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap) : m_s10.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap, &m_s9) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap, &m_s10) : m_s10.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8, a9, a10
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8, const ArgSpec<A9> &s9, const ArgSpec<A10> &s10
@ -1414,17 +1414,17 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A10> (m_s10); \
this->template add_arg<A11> (m_s11);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap) : m_s11.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap, &m_s9) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap, &m_s10) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap, &m_s11) : m_s11.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8, const ArgSpec<A9> &s9, const ArgSpec<A10> &s10, const ArgSpec<A11> &s11
@ -1478,18 +1478,18 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A11> (m_s11); \
this->template add_arg<A12> (m_s12);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap) : m_s12.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap, &m_s9) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap, &m_s10) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap, &m_s11) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap, &m_s12) : m_s12.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8, const ArgSpec<A9> &s9, const ArgSpec<A10> &s10, const ArgSpec<A11> &s11, const ArgSpec<A12> &s12
@ -1545,19 +1545,19 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A12> (m_s12); \
this->template add_arg<A13> (m_s13);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap) : m_s12.init (); \
A13 a13 = args ? args.template read<A13> (heap) : m_s13.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap, &m_s9) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap, &m_s10) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap, &m_s11) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap, &m_s12) : m_s12.init (); \
A13 a13 = args ? args.template read<A13> (heap, &m_s13) : m_s13.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8, const ArgSpec<A9> &s9, const ArgSpec<A10> &s10, const ArgSpec<A11> &s11, const ArgSpec<A12> &s12, const ArgSpec<A13> &s13
@ -1615,20 +1615,20 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A13> (m_s13); \
this->template add_arg<A14> (m_s14);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap) : m_s12.init (); \
A13 a13 = args ? args.template read<A13> (heap) : m_s13.init (); \
A14 a14 = args ? args.template read<A14> (heap) : m_s14.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap, &m_s9) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap, &m_s10) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap, &m_s11) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap, &m_s12) : m_s12.init (); \
A13 a13 = args ? args.template read<A13> (heap, &m_s13) : m_s13.init (); \
A14 a14 = args ? args.template read<A14> (heap, &m_s14) : m_s14.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8, const ArgSpec<A9> &s9, const ArgSpec<A10> &s10, const ArgSpec<A11> &s11, const ArgSpec<A12> &s12, const ArgSpec<A13> &s13, const ArgSpec<A14> &s14
@ -1688,21 +1688,21 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A14> (m_s14); \
this->template add_arg<A15> (m_s15);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap) : m_s12.init (); \
A13 a13 = args ? args.template read<A13> (heap) : m_s13.init (); \
A14 a14 = args ? args.template read<A14> (heap) : m_s14.init (); \
A15 a15 = args ? args.template read<A15> (heap) : m_s15.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap, &m_s9) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap, &m_s10) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap, &m_s11) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap, &m_s12) : m_s12.init (); \
A13 a13 = args ? args.template read<A13> (heap, &m_s13) : m_s13.init (); \
A14 a14 = args ? args.template read<A14> (heap, &m_s14) : m_s14.init (); \
A15 a15 = args ? args.template read<A15> (heap, &m_s15) : m_s15.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8, const ArgSpec<A9> &s9, const ArgSpec<A10> &s10, const ArgSpec<A11> &s11, const ArgSpec<A12> &s12, const ArgSpec<A13> &s13, const ArgSpec<A14> &s14, const ArgSpec<A15> &s15
@ -1764,22 +1764,22 @@ constant (const std::string &name, const R &v, const std::string &doc = std::str
this->template add_arg<A15> (m_s15); \
this->template add_arg<A16> (m_s16);
#define _GETARGVARS tl::Heap heap;\
A1 a1 = args ? args.template read<A1> (heap) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap) : m_s12.init (); \
A13 a13 = args ? args.template read<A13> (heap) : m_s13.init (); \
A14 a14 = args ? args.template read<A14> (heap) : m_s14.init (); \
A15 a15 = args ? args.template read<A15> (heap) : m_s15.init (); \
A16 a16 = args ? args.template read<A16> (heap) : m_s16.init ();
A1 a1 = args ? args.template read<A1> (heap, &m_s1) : m_s1.init (); \
A2 a2 = args ? args.template read<A2> (heap, &m_s2) : m_s2.init (); \
A3 a3 = args ? args.template read<A3> (heap, &m_s3) : m_s3.init (); \
A4 a4 = args ? args.template read<A4> (heap, &m_s4) : m_s4.init (); \
A5 a5 = args ? args.template read<A5> (heap, &m_s5) : m_s5.init (); \
A6 a6 = args ? args.template read<A6> (heap, &m_s6) : m_s6.init (); \
A7 a7 = args ? args.template read<A7> (heap, &m_s7) : m_s7.init (); \
A8 a8 = args ? args.template read<A8> (heap, &m_s8) : m_s8.init (); \
A9 a9 = args ? args.template read<A9> (heap, &m_s9) : m_s9.init (); \
A10 a10 = args ? args.template read<A10> (heap, &m_s10) : m_s10.init (); \
A11 a11 = args ? args.template read<A11> (heap, &m_s11) : m_s11.init (); \
A12 a12 = args ? args.template read<A12> (heap, &m_s12) : m_s12.init (); \
A13 a13 = args ? args.template read<A13> (heap, &m_s13) : m_s13.init (); \
A14 a14 = args ? args.template read<A14> (heap, &m_s14) : m_s14.init (); \
A15 a15 = args ? args.template read<A15> (heap, &m_s15) : m_s15.init (); \
A16 a16 = args ? args.template read<A16> (heap, &m_s16) : m_s16.init ();
#define _ARGVARLIST a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16
#define _ARGSPECARGS s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16
#define _ARGSPEC const ArgSpec<A1> &s1, const ArgSpec<A2> &s2, const ArgSpec<A3> &s3, const ArgSpec<A4> &s4, const ArgSpec<A5> &s5, const ArgSpec<A6> &s6, const ArgSpec<A7> &s7, const ArgSpec<A8> &s8, const ArgSpec<A9> &s9, const ArgSpec<A10> &s10, const ArgSpec<A11> &s11, const ArgSpec<A12> &s12, const ArgSpec<A13> &s13, const ArgSpec<A14> &s14, const ArgSpec<A15> &s15, const ArgSpec<A16> &s16

View File

@ -83,6 +83,17 @@ struct GSI_PUBLIC ArglistUnderflowException
{ }
};
/**
* @brief An exception thrown if there are not enough arguments on the serialization buffer
*/
struct GSI_PUBLIC ArglistUnderflowExceptionWithType
: public tl::Exception
{
ArglistUnderflowExceptionWithType (const ArgSpecBase &as)
: tl::Exception (tl::to_string (tr ("Too few arguments - missing '%s'")), as.name ())
{ }
};
/**
* @brief An exception thrown if a reference is null (nil)
*/
@ -94,6 +105,17 @@ struct GSI_PUBLIC NilPointerToReference
{ }
};
/**
* @brief An exception thrown if a reference is null (nil)
*/
struct GSI_PUBLIC NilPointerToReferenceWithType
: public tl::Exception
{
NilPointerToReferenceWithType (const ArgSpecBase &as)
: tl::Exception (tl::to_string (tr ("nil object passed to a reference for '%s'")), as.name ())
{ }
};
/**
* @brief This class provides the basic argument serialization mechanism for the C++/scripting interface
*/
@ -208,7 +230,16 @@ public:
template <class X>
inline X read (tl::Heap &heap)
{
return this->read_impl<X> (typename type_traits<X>::tag (), heap);
return this->read_impl<X> (typename type_traits<X>::tag (), heap, 0);
}
/**
* @brief Reads a value from the buffer
*/
template <class X>
inline X read (tl::Heap &heap, const ArgSpecBase *as)
{
return this->read_impl<X> (typename type_traits<X>::tag (), heap, as);
}
/**
@ -231,6 +262,26 @@ private:
}
}
inline void check_data (const ArgSpecBase *as) const
{
if (! *this) {
if (as) {
throw ArglistUnderflowExceptionWithType (*as);
} else {
throw ArglistUnderflowException ();
}
}
}
inline void throw_nil_for_reference (const ArgSpecBase *as) const
{
if (as) {
throw NilPointerToReferenceWithType (*as);
} else {
throw NilPointerToReference ();
}
}
// -----------------------------------------------------------
// reader implementations
@ -369,18 +420,18 @@ private:
// reader implementations
template <class X>
X read_impl (const pod_direct_tag &, tl::Heap &)
X read_impl (const pod_direct_tag &, tl::Heap &, const ArgSpecBase *as)
{
check_data ();
check_data (as);
X r = *((X *)mp_read);
mp_read += item_size<X> ();
return r;
}
template <class X>
X read_impl (const x_tag &, tl::Heap &)
X read_impl (const x_tag &, tl::Heap &, const ArgSpecBase *as)
{
check_data ();
check_data (as);
X *xp = *(X **)mp_read;
X x = *xp;
delete xp;
@ -389,7 +440,7 @@ private:
}
template <class X>
X read_impl (const vptr_tag &, tl::Heap &)
X read_impl (const vptr_tag &, tl::Heap &, const ArgSpecBase *)
{
void *r = *((void **)mp_read);
mp_read += item_size<void *> ();
@ -398,73 +449,73 @@ private:
}
template <class X>
X read_impl (const ref_tag &, tl::Heap &)
X read_impl (const ref_tag &, tl::Heap &, const ArgSpecBase *as)
{
typedef typename type_traits<X>::value_type value_type;
check_data ();
check_data (as);
value_type *r = *((value_type **)mp_read);
mp_read += item_size<value_type *> ();
if (! r) {
throw NilPointerToReference ();
throw_nil_for_reference (as);
}
return *r;
}
template <class X>
X read_impl (const pod_cref_tag &, tl::Heap &)
X read_impl (const pod_cref_tag &, tl::Heap &, const ArgSpecBase *as)
{
// X is actually an (const X &)
typedef typename type_traits<X>::value_type value_type;
check_data ();
check_data (as);
const value_type *r = ((const value_type *)mp_read);
mp_read += item_size<value_type> ();
return *r;
}
template <class X>
X read_impl (const npod_cref_tag &, tl::Heap &)
X read_impl (const npod_cref_tag &, tl::Heap &, const ArgSpecBase *as)
{
// X is actually an (const X &)
typedef typename type_traits<X>::value_type value_type;
check_data ();
check_data (as);
const value_type *r = *((const value_type **)mp_read);
mp_read += item_size<const value_type *> ();
if (! r) {
throw NilPointerToReference ();
throw_nil_for_reference (as);
}
return *r;
}
template <class X>
X read_impl (const x_cref_tag &, tl::Heap &)
X read_impl (const x_cref_tag &, tl::Heap &, const ArgSpecBase *as)
{
// X is actually an (const X &)
typedef typename type_traits<X>::value_type value_type;
check_data ();
check_data (as);
const value_type *r = *((const value_type **)mp_read);
mp_read += item_size<const value_type *> ();
if (! r) {
throw NilPointerToReference ();
throw_nil_for_reference (as);
}
return *r;
}
template <class X>
X read_impl (const ptr_tag &, tl::Heap &)
X read_impl (const ptr_tag &, tl::Heap &, const ArgSpecBase *as)
{
// X is actually an (X *)
typedef typename type_traits<X>::value_type value_type;
check_data ();
check_data (as);
value_type * const &r = *((value_type **)mp_read);
mp_read += item_size<value_type *> ();
return r;
}
template <class X>
X read_impl (const pod_cptr_tag &, tl::Heap &)
X read_impl (const pod_cptr_tag &, tl::Heap &, const ArgSpecBase *as)
{
// X is actually an (const X *)
check_data ();
check_data (as);
bool h = *(bool *)mp_read;
mp_read += item_size<bool> ();
X r = h ? (X)mp_read : (X)0;
@ -474,29 +525,29 @@ private:
// see notes on the serialization for this type:
template <class X>
X read_impl (const npod_cptr_tag &, tl::Heap &)
X read_impl (const npod_cptr_tag &, tl::Heap &, const ArgSpecBase *as)
{
// X is actually an (const X *)
check_data ();
check_data (as);
X r = *((X *)mp_read);
mp_read += item_size<X> ();
return r;
}
template <class X>
X read_impl (const x_cptr_tag &, tl::Heap &)
X read_impl (const x_cptr_tag &, tl::Heap &, const ArgSpecBase *as)
{
// X is actually an (const X *)
check_data ();
check_data (as);
X r = *((X *)mp_read);
mp_read += item_size<X> ();
return r;
}
template <class X>
X read_impl (const adaptor_direct_tag &, tl::Heap &heap)
X read_impl (const adaptor_direct_tag &, tl::Heap &heap, const ArgSpecBase *as)
{
check_data ();
check_data (as);
std::unique_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
mp_read += item_size<AdaptorBase *> ();
@ -508,11 +559,11 @@ private:
}
template <class X>
X read_impl (const adaptor_cref_tag &, tl::Heap &heap)
X read_impl (const adaptor_cref_tag &, tl::Heap &heap, const ArgSpecBase *as)
{
typedef typename tl::get_inner_type<X>::result x_type;
check_data ();
check_data (as);
std::unique_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
mp_read += item_size<AdaptorBase *> ();
@ -526,11 +577,11 @@ private:
}
template <class X>
X read_impl (const adaptor_ref_tag &, tl::Heap &heap)
X read_impl (const adaptor_ref_tag &, tl::Heap &heap, const ArgSpecBase *as)
{
typedef typename tl::get_inner_type<X>::result x_type;
check_data ();
check_data (as);
AdaptorBase *p = *(AdaptorBase **)mp_read;
mp_read += item_size<AdaptorBase *> ();
@ -544,11 +595,11 @@ private:
}
template <class X>
X read_impl (const adaptor_cptr_tag &, tl::Heap &heap)
X read_impl (const adaptor_cptr_tag &, tl::Heap &heap, const ArgSpecBase *as)
{
typedef typename tl::get_inner_type<X>::result x_type;
check_data ();
check_data (as);
std::unique_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
mp_read += item_size<AdaptorBase *> ();
@ -564,11 +615,11 @@ private:
}
template <class X>
X read_impl (const adaptor_ptr_tag &, tl::Heap &heap)
X read_impl (const adaptor_ptr_tag &, tl::Heap &heap, const ArgSpecBase *as)
{
typedef typename tl::get_inner_type<X>::result x_type;
check_data ();
check_data (as);
AdaptorBase *p = *(AdaptorBase **)mp_read;
mp_read += item_size<AdaptorBase *> ();

File diff suppressed because it is too large Load Diff

View File

@ -683,6 +683,17 @@ The following example computes every part of the input which is closer than
out = in.drc(primary &amp; foreign.sized(0.5.um))
</pre>
</p>
<a name="global_transform"/><h2>"global_transform" - Gets or sets a global transformation</h2>
<keyword name="global_transform"/>
<p>Usage:</p>
<ul>
<li><tt>global_transform</tt></li>
<li><tt>global_transform([ transformations ])</tt></li>
</ul>
<p>
Applies a global transformation to the default source layout.
See <a href="/about/drc_ref_source.xml#global_transform">Source#global_transform</a> for a description of this feature.
</p>
<a name="holes"/><h2>"holes" - Selects all holes from the input polygons</h2>
<keyword name="holes"/>
<p>Usage:</p>

View File

@ -1023,6 +1023,111 @@ The following images show the effect of the extents method:
</tr>
</table>
</p>
<a name="fill"/><h2>"fill" - Fills the region with regular pattern of shapes</h2>
<keyword name="fill"/>
<p>Usage:</p>
<ul>
<li><tt>layer.fill([ options ])</tt></li>
</ul>
<p>
This method will attempt to fill the polygons of the layer with a regular pattern
of shapes.
</p><p>
The fill function currently is not available in deep mode.
</p><p>
Options are:
<ul>
<li><b>hstep(x) </b>or <b>hstep(x, y) </b>: specifies the horizontal step pitch of the pattern. x must be
a positive value. A vertical displacement component can be specified too, which results in a skewed pattern. </li>
<li><b>vstep(y) </b>or <b>vstep(x, y) </b>: specifies the vertical step pitch of the pattern. y must be
a positive value. A horizontal displacement component can be specified too, which results in a skewed pattern. </li>
<li><b>origin(x, y) </b>: specifies a fixed point to align the pattern with. This point specifies the location
of the reference point for one pattern cell. </li>
<li><b>auto_origin </b>: lets the algorithm choose the origin. This may result is a slightly better fill coverage
as the algorithm is able to determine a pattern origin per fill island. </li>
<li><b>fill_pattern(..) </b>: specifies the fill pattern. </li>
</ul>
</p><p>
"fill_pattern" generates a fill pattern object. This object is used for configuring the fill pattern
content. Fill pattern need to be named. The name will be used for generating the fill cell.
</p><p>
To provide a fill pattern, create a fill pattern object and add shapes to it. The following example creates
a fill pattern named "FILL_CELL" and adds a 1x1 micron box on layer 1/0:
</p><p>
<pre>
p = fill_pattern("FILL_CELL")
p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
</pre>
</p><p>
See <a href="/about/drc_ref_global.xml#box">box</a> for details about the box specification. You can also add paths or polygons with <a href="/about/drc_ref_global.xml#path">path</a> or <a href="/about/drc_ref_global.xml#polygon">polygon</a>.
</p><p>
A more compact way of writing this is:
</p><p>
<pre>
p = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
</pre>
</p><p>
The fill pattern can be given a reference point which is used for placing the pattern. The reference point
is the one which is aligned with the pattern origin. The following code will assign (-0.5, -0.5) as the reference
point for the 1x1 micron rectangle. Hence the reference point is a little below and left of the rectangle which
in turn shifts the rectangle fill pattern to the right and up:
</p><p>
<pre>
p = fill_pattern("FILL_CELL")
p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
p.origin(-0.5, -0.5)
</pre>
</p><p>
Without a reference point given, the lower left corner of the fill pattern's bounding box will be used
as the reference point. The reference point will also defined the footprint of the fill cell - more precisely
the lower left corner. When step vectors are given, the fill cell's footprint is taken to be a rectangle
having the horizontal and vertical step pitch for width and height respectively. This way the fill cells
will be arrange seamlessly. However, the cell's dimensions can be changed, so that the fill cells
can overlap or there is a space between the cells. To change the dimensions use the "dim" method.
</p><p>
The following example specifies a fill cell with an active area of -0.5 .. 1.5 in both directions
(2 micron width and height). With these dimensions the fill cell's footprint is independent of the
step pitch:
</p><p>
<pre>
p = fill_pattern("FILL_CELL")
p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
p.origin(-0.5, -0.5)
p.dim(2.0, 2.0)
</pre>
</p><p>
With these ingredients will can use the fill function. The first example fills the polygons
of "to_fill" with an orthogonal pattern of 1x1 micron rectangles with a pitch of 2 microns:
</p><p>
<pre>
pattern = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0)).origin(-0.5, -0.5)
to_fill.fill(pattern, hstep(2.0), vstep(2.0))
</pre>
</p><p>
This second example will create a skewed fill pattern in auto-origin mode:
</p><p>
<pre>
pattern = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0)).origin(-0.5, -0.5)
to_fill.fill(pattern, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
</pre>
</p><p>
The fill function can only work with a target layout for output.
It will not work for report output.
</p><p>
The layers generated by the fill cells is only available for input later in the
script if the output layout is identical to the input layouts.
If you need the area missed by the fill function, try <a href="#fill_with_left">fill_with_left</a>.
</p>
<a name="fill_with_left"/><h2>"fill_with_left" - Fills the region with regular pattern of shapes</h2>
<keyword name="fill_with_left"/>
<p>Usage:</p>
<ul>
<li><tt>layer.fill_with_left([ options ])</tt></li>
</ul>
<p>
This method has the same call syntax and functionality than <a href="#fill">fill</a>. Other than this method
it will return the area not covered by fill cells as a DRC layer.
</p>
<a name="first_edges"/><h2>"first_edges" - Returns the first edges of an edge pair collection</h2>
<keyword name="first_edges"/>
<p>Usage:</p>

View File

@ -109,6 +109,40 @@ The extent function is useful to invert a layer:
inverse_1 = extent.sized(100.0) - input(1, 0)
</pre>
</p>
<a name="global_transform"/><h2>"global_transform" - Gets or sets a global transformation</h2>
<keyword name="global_transform"/>
<p>Usage:</p>
<ul>
<li><tt>global_transform</tt></li>
<li><tt>global_transform([ transformations ])</tt></li>
</ul>
<p>
This method returns a new source representing the transformed layout. It is provided in the spritit of
<a href="/about/drc_ref_source.xml#clip">Source#clip</a> and similar methods.
</p><p>
The transformation
is either given as a <class_doc href="DTrans">DTrans</class_doc>, <class_doc href="DVector">DVector</class_doc> or <class_doc href="DCplxTrans">DCplxTrans</class_doc> object or as one of the
following specifications:
</p><p>
<ul>
<li>"shift(x, y)": shifts the input layout horizontally by x and vertically by y micrometers </li>
<li>"rotate(a)": rotates the input layout by a degree counter-clockwise </li>
<li>"magnify(m)": magnifies the input layout by the factor m (NOTE: using fractional scale factors may result in small gaps due to grid snapping) </li>
<li>"mirror_x": mirrors the input layout at the x axis </li>
<li>"mirror_y": mirrors the input layout at the y axis </li>
</ul>
</p><p>
Multiple transformation specs can be given. In that case the transformations are applied right to left.
Using "global_transform" will reset any global transformation present already.
Without an argument, the global transformation is reset.
</p><p>
The following example rotates the layout by 90 degree at the origin (0, 0) and then shifts it up by
100 micrometers:
</p><p>
<pre>
source.global_transform(shift(0, 100.um), rotate(90.0))
</pre>
</p>
<a name="input"/><h2>"input" - Specifies input from a source</h2>
<keyword name="input"/>
<p>Usage:</p>

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"
@ -83,6 +83,8 @@ FillDialog::FillDialog (lay::Dispatcher *main, lay::LayoutView *view)
Ui::FillDialog::setupUi (this);
fc_boundary_layer->set_no_layer_available (true);
fill_area_stack->setCurrentIndex (0);
connect (fill_area_cbx, SIGNAL (currentIndexChanged (int)), this, SLOT (fill_area_changed (int)));
connect (button_box, SIGNAL (accepted ()), this, SLOT (ok_pressed ()));
@ -132,66 +134,184 @@ 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);
const db::Cell *fill_cell2 = 0;
if (! fp.fill_cell_name2.empty ()) {
std::pair<bool, db::cell_index_type> fc2 = cv->layout ().cell_by_name (fp.fill_cell_name2.c_str ());
if (! fc2.first) {
throw tl::Exception (tl::to_string (QObject::tr ("Secondary fill cell not found: ")) + fp.fill_cell_name2);
}
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::Box fc_bbox = db::CplxTrans (ly.dbu ()).inverted () * fp.fc_bbox;
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::Box fc_bbox2 = db::CplxTrans (ly.dbu ()).inverted () * fp.fc_bbox2;
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 (), fc_bbox, 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 (), fc_bbox, row_step, column_step, fill_margin, fill_cell2 ? &fill_region : 0);
}
fill_cell = fill_cell2;
row_step = row_step2;
column_step = column_step2;
fc_bbox = fc_bbox2;
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 ()));
}
}
@ -201,7 +321,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 ()));
}
}
@ -219,100 +339,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 (exclude_x, exclude_y);
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 (exclude_x, exclude_y);
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 = 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")));
}
bool enhanced_fill = enhanced_cb->isChecked ();
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 = 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")));
}
}
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 () ||
@ -327,23 +361,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 ();
@ -351,174 +389,174 @@ 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 ()) {
if (fc_bbox_layer >= 0) {
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")));
} else {
throw tl::Exception (tl::to_string (QObject::tr ("Fill cell is empty")));
}
}
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.fc_bbox = fc_bbox;
if (second_order_fill_cb->isChecked ()) {
db::DBox fc_bbox2;
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 ()));
}
const db::Cell *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 ());
}
fp.fc_bbox2 = fc_bbox2;
}
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 ();
}
bool any_fill = fill_region (cv.cell (), *fp0, fill_cell->cell_index (), fc_bbox, 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;
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,46 @@
#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 row_step, column_step;
db::DBox fc_bbox;
std::string fill_cell_name2;
db::DVector fill_cell_margin2;
db::DVector row_step2, column_step2;
db::DBox fc_bbox2;
};
class LAY_PUBLIC FillDialog
: public QDialog,
public lay::Plugin,
private Ui::FillDialog
@ -59,6 +92,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;
};

View File

@ -338,7 +338,11 @@ ProgressWidget::set_progress (tl::Progress *progress)
double v = progress->value ();
pb->set_value (v, value);
progress = progress->next ();
if (progress->final ()) {
progress = 0;
} else {
progress = progress->next ();
}
} else {
pb->hide ();

View File

@ -43,7 +43,8 @@
namespace db
{
class Matrix3d;
template <class C> class matrix_3d;
typedef matrix_3d<db::DCoord> Matrix3d;
/**
* @brief Generic base class of DXF reader exceptions

View File

@ -513,6 +513,7 @@ RS274XReader::do_read ()
if (m_polygon_mode) {
// D02 strokes close the polygon (and restart a new one)
if (m_polygon_points.size () >= 3) {
db::DPolygon poly;
poly.assign_hull (m_polygon_points.begin (), m_polygon_points.end ());
@ -520,6 +521,7 @@ RS274XReader::do_read ()
}
m_polygon_points.clear ();
m_polygon_points.push_back (db::DPoint (x, y));
}

View File

@ -297,6 +297,11 @@ TEST(26)
run_test (_this, "pos-neg");
}
TEST(27)
{
run_test (_this, "polygon-mode");
}
TEST(X2_1)
{
run_test (_this, "x2-1");

View File

@ -146,7 +146,7 @@ public:
m_cell_stack.pop_back ();
}
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
{
db::cell_index_type ci = inst.object ().cell_index ();
if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) {
@ -156,7 +156,7 @@ public:
}
}
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
tl_assert (! m_cell_stack.empty ());
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape);
@ -209,9 +209,9 @@ public:
}
}
virtual void shape (const db::RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * iter->trans (), shape);
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * trans, shape);
}
public:

View File

@ -104,7 +104,7 @@ ExpressionParserContext::where () const
int line = 1;
size_t col = 0;
for (size_t p = 0; p < len; ++p, ++col) {
for (size_t p = 0; p < pos; ++p) {
if (text [p] == '\n') {
++line;
col = 1;
@ -2044,7 +2044,7 @@ public:
throw EvalError (tl::sprintf (tl::to_string (tr ("Not a valid object for a method call (not an object) - value is %s")), v->to_parsable_string ()), m_context);
}
} else {
throw EvalError (tl::sprintf (tl::to_string (tr ("Not a valid object for a method call (wrong type) - value is %1")), v->to_parsable_string ()), m_context);
throw EvalError (tl::sprintf (tl::to_string (tr ("Not a valid object for a method call (wrong type) - value is %s")), v->to_parsable_string ()), m_context);
}
tl::Variant o;

View File

@ -138,7 +138,7 @@ const double yield_timeout = 0.3;
const size_t default_yield_interval = 1000;
Progress::Progress (const std::string &desc, size_t yield_interval, bool can_cancel)
: m_desc (desc), m_title (desc),
: m_desc (desc), m_title (desc), m_final (false),
m_interval_count (0),
m_yield_interval (yield_interval == 0 ? default_yield_interval : yield_interval),
m_last_value (-1.0),

View File

@ -250,6 +250,25 @@ public:
return m_desc;
}
/**
* @brief Sets a value indicating whether the progress is a "final" one
*
* A final progress will prevent child progress objects from showing. It basically summarizes child operations.
* By default, a progress object is not final.
*/
void set_final (bool f)
{
m_final = f;
}
/**
* @brief Gets a value indicating whether the progress is a "final" one
*/
bool final () const
{
return m_final;
}
/**
* @brief Render the title string
*/
@ -296,6 +315,7 @@ private:
std::string m_desc, m_last_desc;
std::string m_title;
bool m_final;
size_t m_interval_count;
size_t m_yield_interval;
double m_last_value;

View File

@ -159,6 +159,16 @@ TaskList::put_front (Task *task)
}
}
size_t
TaskList::size () const
{
size_t n = 0;
for (Task *t = mp_first; t; t = t->mp_next) {
++n;
}
return n;
}
// -----------------------------------------------------------------------------
// tl::JobBase implementation
@ -264,6 +274,11 @@ JobBase::start ()
mp_workers.back ()->start (this, int (mp_workers.size ()) - 1);
}
while (m_nworkers < int (mp_workers.size ())) {
delete mp_workers.back ();
mp_workers.pop_back ();
}
for (int i = 0; i < int (mp_workers.size ()); ++i) {
setup_worker (mp_workers [i]);
mp_workers [i]->reset_stop_request ();
@ -278,39 +293,59 @@ JobBase::start ()
std::unique_ptr <Worker> sync_worker (create_worker ());
setup_worker (sync_worker.get ());
while (! m_task_list.is_empty ()) {
std::unique_ptr<Task> task (m_task_list.fetch ());
try {
sync_worker->perform_task (task.get ());
} catch (TaskTerminatedException) {
// Stop the thread.
break;
} catch (WorkerTerminatedException) {
// Stop the thread.
break;
} catch (tl::Exception &ex) {
log_error (ex.msg ());
} catch (std::exception &ex) {
log_error (ex.what ());
} catch (...) {
log_error (tl::to_string (tr ("Unspecific error")));
}
}
// clean up any remaining tasks
while (! m_task_list.is_empty ()) {
Task *task = m_task_list.fetch ();
if (task) {
delete task;
try {
while (! m_task_list.is_empty ()) {
std::unique_ptr<Task> task (m_task_list.fetch ());
before_sync_task (task.get ());
try {
sync_worker->perform_task (task.get ());
} catch (TaskTerminatedException) {
// Stop the thread.
break;
} catch (WorkerTerminatedException) {
// Stop the thread.
break;
} catch (tl::Exception &ex) {
log_error (ex.msg ());
} catch (std::exception &ex) {
log_error (ex.what ());
} catch (...) {
log_error (tl::to_string (tr ("Unspecific error")));
}
after_sync_task (task.get ());
}
} catch (...) {
// handle exceptions raised by before_sync_task or after_sync_task
cleanup ();
m_running = false;
throw;
}
cleanup ();
finished ();
m_running = false;
}
}
void
JobBase::cleanup ()
{
// clean up any remaining tasks
while (! m_task_list.is_empty ()) {
Task *task = m_task_list.fetch ();
if (task) {
delete task;
}
}
}
bool
JobBase::is_running ()
{

View File

@ -109,6 +109,11 @@ public:
return mp_first;
}
/**
* @brief Gets the number of tasks
*/
size_t size () const;
private:
Task *mp_first, *mp_last;
@ -163,6 +168,14 @@ public:
*/
void schedule (Task *task);
/**
* @brief Gets the number of tasks in the queue
*/
size_t tasks () const
{
return m_task_list.size ();
}
/**
* @brief Start the execution of the job
*/
@ -227,6 +240,16 @@ protected:
*/
virtual void setup_worker (Worker * /*worker*/) { }
/**
* @brief This method is called before the given task is started in sync mode (workers == 0)
*/
virtual void before_sync_task (Task * /*task*/) { }
/**
* @brief This method is called after the given task has finished in sync mode (workers == 0)
*/
virtual void after_sync_task (Task * /*task*/) { }
/**
* @brief Indicates that the job has finished
*
@ -276,6 +299,7 @@ private:
Task *get_task (int for_worker);
void log_error (const std::string &s);
void cleanup ();
};
/**

BIN
testdata/algo/fill_tool1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool3.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool4.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au3.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au3a.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au3b.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au3c.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au4.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au4b.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/fill_tool_au4c.gds vendored Normal file

Binary file not shown.

57
testdata/drc/drcSimpleTests_31.drc vendored Normal file
View File

@ -0,0 +1,57 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
def self_test(id, a, b)
a == b || raise(id + ": self-test failed (" + a.inspect + " != " + b.inspect + ")")
end
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *1 0,0")
global_transform(magnify(2.0))
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *2 0,0")
global_transform(magnify(2.0), rotate(90.0))
self_test("magnify(2.0)", source.global_transformation.to_s, "r90 *2 0,0")
global_transform(mirror_x, mirror_y)
self_test("magnify(2.0)", source.global_transformation.to_s, "r180 *1 0,0")
global_transform(magnify(2.0), shift(10.um, 20.um))
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *2 10,20")
# The actual DRC test
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(1, 0)
l2.output(2, 0)
l1.merged.output(10, 0)
l1.sized(100.nm).output(11, 0)
l2.sized(100.nm).output(12, 0)
# reset
global_transform
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(101, 0)
l2.output(102, 0)
l1.merged.output(110, 0)
l1.sized(100.nm).output(111, 0)
l2.sized(100.nm).output(112, 0)

BIN
testdata/drc/drcSimpleTests_31.gds vendored Normal file

Binary file not shown.

59
testdata/drc/drcSimpleTests_32.drc vendored Normal file
View File

@ -0,0 +1,59 @@
source $drc_test_source
target $drc_test_target
clip(0.um, 0.um, 26.um, 45.um)
if $drc_test_deep
deep
end
def self_test(id, a, b)
a == b || raise(id + ": self-test failed (" + a.inspect + " != " + b.inspect + ")")
end
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *1 0,0")
global_transform(magnify(2.0))
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *2 0,0")
global_transform(magnify(2.0), rotate(90.0))
self_test("magnify(2.0)", source.global_transformation.to_s, "r90 *2 0,0")
global_transform(mirror_x, mirror_y)
self_test("magnify(2.0)", source.global_transformation.to_s, "r180 *1 0,0")
global_transform(magnify(2.0), shift(10.um, 20.um))
self_test("magnify(2.0)", source.global_transformation.to_s, "r0 *2 10,20")
# The actual DRC test
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(1, 0)
l2.output(2, 0)
l1.merged.output(10, 0)
l1.sized(100.nm).output(11, 0)
l2.sized(100.nm).output(12, 0)
# reset
global_transform
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(101, 0)
l2.output(102, 0)
l1.merged.output(110, 0)
l1.sized(100.nm).output(111, 0)
l2.sized(100.nm).output(112, 0)

BIN
testdata/drc/drcSimpleTests_32.gds vendored Normal file

Binary file not shown.

34
testdata/drc/drcSimpleTests_33.drc vendored Normal file
View File

@ -0,0 +1,34 @@
source $drc_test_source
target $drc_test_target
tiles(10.um)
global_transform(magnify(2.0), shift(10.um, 20.um))
# The actual DRC test
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(1, 0)
l2.output(2, 0)
l1.merged.output(10, 0)
l1.sized(100.nm).output(11, 0)
l2.sized(100.nm).output(12, 0)
# reset
global_transform
l1 = input(1, 0)
l2 = input(2, 0)
l1.output(101, 0)
l2.output(102, 0)
l1.merged.output(110, 0)
l1.sized(100.nm).output(111, 0)
l2.sized(100.nm).output(112, 0)

BIN
testdata/drc/drcSimpleTests_33.gds vendored Normal file

Binary file not shown.

33
testdata/drc/drcSimpleTests_40.drc vendored Normal file
View File

@ -0,0 +1,33 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
f1 = l1
f2 = extent - l1.sized(1.0)
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
p2 = fill_pattern("PAT2").shape(100, 1, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
p3 = fill_pattern("PAT3").shape(100, 2, box(0, 0, 1.um, 1.um)).shape(1000, 0, box(-0.5.um, -0.5.um, 1.5.um, 1.5.um))
p11 = fill_pattern("PAT11").shape(101, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
p12 = fill_pattern("PAT12").shape(101, 1, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
p13 = fill_pattern("PAT13").shape(101, 2, box(0, 0, 1.um, 1.um)).shape(1000, 0, box(-0.5.um, -0.5.um, 1.5.um, 1.5.um))
f1.fill(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0))
f1.fill(p2, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
f1.fill(p3)
f2.fill(p11, hstep(2.0, 1.0), vstep(-1.0, 2.0))
f2.fill(p12, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
f2.fill(p13)
l1.output(1, 0)
f1.output(10, 0)
f2.output(11, 0)

BIN
testdata/drc/drcSimpleTests_40.gds vendored Normal file

Binary file not shown.

35
testdata/drc/drcSimpleTests_41.drc vendored Normal file
View File

@ -0,0 +1,35 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
tiles(100, 100)
l1 = input(1, 0)
f1 = l1
f2 = extent - l1.sized(1.0)
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
p2 = fill_pattern("PAT2").shape(100, 1, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
p3 = fill_pattern("PAT3").shape(100, 2, box(0, 0, 1.um, 1.um)).shape(1000, 0, box(-0.5.um, -0.5.um, 1.5.um, 1.5.um))
p11 = fill_pattern("PAT11").shape(101, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
p12 = fill_pattern("PAT12").shape(101, 1, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
p13 = fill_pattern("PAT13").shape(101, 2, box(0, 0, 1.um, 1.um)).shape(1000, 0, box(-0.5.um, -0.5.um, 1.5.um, 1.5.um))
f1.fill(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0))
f1.fill(p2, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
f1.fill(p3)
f2.fill(p11, hstep(2.0, 1.0), vstep(-1.0, 2.0))
f2.fill(p12, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
f2.fill(p13)
l1.output(1, 0)
f1.output(10, 0)
f2.output(11, 0)

BIN
testdata/drc/drcSimpleTests_41.gds vendored Normal file

Binary file not shown.

19
testdata/drc/drcSimpleTests_42.drc vendored Normal file
View File

@ -0,0 +1,19 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
f1 = l1
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(100, 0)
l1.output(1, 0)
f1.output(10, 0)

BIN
testdata/drc/drcSimpleTests_42.gds vendored Normal file

Binary file not shown.

21
testdata/drc/drcSimpleTests_43.drc vendored Normal file
View File

@ -0,0 +1,21 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
tiles(5, 5)
l1 = input(1, 0)
f1 = l1
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(100, 0)
l1.output(1, 0)
f1.output(10, 0)

BIN
testdata/drc/drcSimpleTests_43.gds vendored Normal file

Binary file not shown.

19
testdata/drc/drcSimpleTests_44.drc vendored Normal file
View File

@ -0,0 +1,19 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
f1 = l1
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-1.um, -1.um).dim(3.um, 3.um)
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(100, 0)
l1.output(1, 0)
f1.output(10, 0)

BIN
testdata/drc/drcSimpleTests_44.gds vendored Normal file

Binary file not shown.

21
testdata/drc/drcSimpleTests_45.drc vendored Normal file
View File

@ -0,0 +1,21 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
tiles(5, 5)
l1 = input(1, 0)
f1 = l1
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-1.um, -1.um).dim(3.um, 3.um)
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(100, 0)
l1.output(1, 0)
f1.output(10, 0)

BIN
testdata/drc/drcSimpleTests_45.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au31.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au31d.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au32.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au32d.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au33d.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au40.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au41.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au42.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au43.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au44.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au45.gds vendored Normal file

Binary file not shown.

View File

@ -67,6 +67,48 @@ class DBMatrix_TestClass < TestBase
end
def test_1i
m = RBA::IMatrix2d.new
assert_equal("(1,0) (0,1)", m.to_s)
m = RBA::IMatrix2d.new(2.0)
assert_equal("(2,0) (0,2)", m.to_s)
m = RBA::IMatrix2d.newc(2, 90, true)
assert_equal("(0,2) (2,0)", m.to_s)
m = RBA::IMatrix2d.new(RBA::ICplxTrans.new(2, 90, true, RBA::Point.new(0, 0)))
assert_equal("(0,2) (2,0)", m.to_s)
m = RBA::IMatrix2d.newc(0.0, 2, 2, 90, true)
assert_equal("(0,2) (2,0)", m.to_s)
m = RBA::IMatrix2d.newc(17.0, 2, 3, 90, true)
assert_equal("17.000000", "%.6f" % m.shear_angle)
assert_equal("90.0", m.angle.to_s)
assert_equal("2.000000", "%.6f" % m.mag_x)
assert_equal("3.000000", "%.6f" % m.mag_y)
assert_equal(true, m.is_mirror?)
m = RBA::IMatrix2d.new(1, 2, 3, 4)
assert_equal("(1,2) (3,4)", m.to_s)
assert_equal("1.0", m.m11.to_s)
assert_equal("2.0", m.m12.to_s)
assert_equal("3.0", m.m21.to_s)
assert_equal("4.0", m.m22.to_s)
assert_equal("4.0", m.m(1,1).to_s)
assert_equal("2.0", m.m(0,1).to_s)
m = RBA::IMatrix2d.newc(2, 90, true)
assert_equal(true, m.is_mirror?)
t = m.cplx_trans
assert_equal("m45 *2 0,0", t.to_s)
m = RBA::IMatrix2d.newc(2, 90, false)
assert_equal("90.0", m.angle.to_s)
assert_equal(false, m.is_mirror?)
t = m.inverted.cplx_trans
assert_equal("r270 *0.5 0,0", t.to_s)
p = m.trans(RBA::Point.new(1, 2))
assert_equal("-4,2", p.to_s)
assert_equal("(1,0) (0,1)", (m.inverted*m).to_s)
assert_equal("(0,-1.5) (1.5,0)", (m+m.inverted).to_s)
end
def test_2
m = RBA::Matrix3d.new
@ -127,6 +169,66 @@ class DBMatrix_TestClass < TestBase
end
def test_2i
m = RBA::IMatrix3d.new
assert_equal("(1,0,0) (0,1,0) (0,0,1)", m.to_s)
m = RBA::IMatrix3d.new(2.0)
assert_equal("(2,0,0) (0,2,0) (0,0,1)", m.to_s)
m = RBA::IMatrix3d.newc(2, 90, true)
assert_equal("(0,2,0) (2,0,0) (0,0,1)", m.to_s)
m = RBA::IMatrix3d.new(RBA::ICplxTrans.new(2, 90, true, RBA::Point.new(1, 2)))
assert_equal("(0,2,1) (2,0,2) (0,0,1)", m.to_s)
m = RBA::IMatrix3d.newc(0.0, 2, 3, 90, true)
assert_equal("(0,3,0) (2,0,0) (0,0,1)", m.to_s)
m = RBA::IMatrix3d.newc(17.0, 2, 3, 90, true)
assert_equal("17.000000", "%.6f" % m.shear_angle)
assert_equal("90.0", m.angle.to_s)
assert_equal("2.000000", "%.6f" % m.mag_x)
assert_equal("3.000000", "%.6f" % m.mag_y)
assert_equal(true, m.is_mirror?)
m = RBA::IMatrix3d.newc(RBA::Point.new(1, 2), 17.0, 2, 3, 90, true)
assert_equal("17.000000", "%.6f" % m.shear_angle)
assert_equal("90.0", m.angle.to_s)
assert_equal("2.000000", "%.6f" % m.mag_x)
assert_equal("3.000000", "%.6f" % m.mag_y)
assert_equal("1,2", m.disp.to_s)
assert_equal(true, m.is_mirror?)
m = RBA::IMatrix3d.new(1, 2, 3, 4)
assert_equal("(1,2,0) (3,4,0) (0,0,1)", m.to_s)
assert_equal("4.0", m.m(1,1).to_s)
assert_equal("2.0", m.m(0,1).to_s)
assert_equal("0.0", m.m(0,2).to_s)
assert_equal("1.0", m.m(2,2).to_s)
m = RBA::IMatrix3d.newc(2, 90, true)
assert_equal(true, m.is_mirror?)
t = m.cplx_trans
assert_equal("m45 *2 0,0", t.to_s)
m = RBA::IMatrix3d.newc(2, 90, false)
assert_equal("90.0", m.angle.to_s)
assert_equal(false, m.is_mirror?)
t = m.inverted.cplx_trans
assert_equal("r270 *0.5 0,0", t.to_s)
p = m.trans(RBA::Point.new(1, 2))
assert_equal("-4,2", p.to_s)
assert_equal("(1,0,0) (0,1,0) (0,0,1)", (m.inverted*m).to_s)
assert_equal("(0,-1.5,0) (1.5,0,0) (0,0,2)", (m+m.inverted).to_s)
m = RBA::IMatrix3d.new(0, 1, -1, 0, 1, 2)
t = m.cplx_trans
assert_equal("r270 *1 1,2", t.to_s)
m = RBA::IMatrix3d.new(0, 1, 1, -1, 0, 2, 0, 0, 1)
t = m.cplx_trans
assert_equal("r270 *1 1,2", t.to_s)
assert_equal("1", m.disp.x.to_s)
assert_equal("2", m.disp.y.to_s)
m = RBA::IMatrix3d.newc(0.1, -0.2, 1.0, RBA::Point.new(1, 2), 17.0, 2, 2, 270, true)
assert_equal("0.100000", "%.6f" % m.tx(1.0))
assert_equal("-0.200000", "%.6f" % m.ty(1.0))
assert_equal("17.000000", "%.6f" % m.shear_angle)
assert_equal("1,2", m.disp.to_s)
end
def test_3
p = [ RBA::DPoint.new(1, 1), RBA::DPoint.new(2, 1), RBA::DPoint.new(2, 2) ]
@ -142,6 +244,66 @@ class DBMatrix_TestClass < TestBase
end
def test_4
m = RBA::IMatrix2d::new(1.0, 0.5, -0.5, 2.0)
assert_equal((m * RBA::Point::new(10, 20)).to_s, "20,35")
assert_equal((m * RBA::Vector::new(10, 20)).to_s, "20,35")
assert_equal((m * RBA::Box::new(-5, -10, 10, 20)).to_s, "(-10,-25;20,43)")
assert_equal((m * RBA::Polygon::new(RBA::Box::new(-5, -10, 10, 20))).to_s, "(5,-25;-10,-18;5,43;20,35)")
assert_equal((m * RBA::SimplePolygon::new(RBA::Box::new(-5, -10, 10, 20))).to_s, "(5,-25;-10,-18;5,43;20,35)")
assert_equal((m * RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20))).to_s, "(-10,-18;20,35)")
assert_equal(RBA::Region::new(RBA::Box::new(-5, -10, 10, 20)).transformed(m).to_s, "(5,-25;-10,-18;5,43;20,35)")
r = RBA::Region::new(RBA::Box::new(-5, -10, 10, 20))
r.transform(m)
assert_equal(r.to_s, "(5,-25;-10,-18;5,43;20,35)")
assert_equal(RBA::Edges::new(RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20))).transformed(m).to_s, "(-10,-18;20,35)")
r = RBA::Edges::new(RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20)))
r.transform(m)
assert_equal(r.to_s, "(-10,-18;20,35)")
assert_equal(RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20)), RBA::Edge::new(RBA::Point::new(-6, -10), RBA::Point::new(11, 20)))).transformed(m).to_s, "(-10,-18;20,35)/(-11,-17;21,35)")
r = RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20)), RBA::Edge::new(RBA::Point::new(-6, -10), RBA::Point::new(11, 20))))
r.transform(m)
assert_equal(r.to_s, "(-10,-18;20,35)/(-11,-17;21,35)")
m = RBA::Matrix2d::new(1.0, 0.5, -0.5, 2.0)
assert_equal((m * RBA::DPoint::new(10, 20)).to_s, "20,35")
assert_equal((m * RBA::DVector::new(10, 20)).to_s, "20,35")
assert_equal((m * RBA::DBox::new(-5, -10, 10, 20)).to_s, "(-10,-25;20,42.5)")
assert_equal((m * RBA::DPolygon::new(RBA::DBox::new(-5, -10, 10, 20))).to_s, "(5,-25;-10,-17.5;5,42.5;20,35)")
assert_equal((m * RBA::DSimplePolygon::new(RBA::DBox::new(-5, -10, 10, 20))).to_s, "(5,-25;-10,-17.5;5,42.5;20,35)")
assert_equal((m * RBA::DEdge::new(RBA::DPoint::new(-5, -10), RBA::DPoint::new(10, 20))).to_s, "(-10,-17.5;20,35)")
m = RBA::IMatrix3d::new(1.0, 0.5, 1.0, -0.5, 2.0, 0.0, 0.0, 0.0, 1.0)
assert_equal((m * RBA::Point::new(10, 20)).to_s, "21,35")
assert_equal((m * RBA::Vector::new(10, 20)).to_s, "20,35")
assert_equal((m * RBA::Box::new(-5, -10, 10, 20)).to_s, "(-9,-25;21,43)")
assert_equal((m * RBA::Polygon::new(RBA::Box::new(-5, -10, 10, 20))).to_s, "(6,-25;-9,-18;6,43;21,35)")
assert_equal((m * RBA::SimplePolygon::new(RBA::Box::new(-5, -10, 10, 20))).to_s, "(6,-25;-9,-18;6,43;21,35)")
assert_equal((m * RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20))).to_s, "(-9,-18;21,35)")
assert_equal(RBA::Region::new(RBA::Box::new(-5, -10, 10, 20)).transformed(m).to_s, "(6,-25;-9,-18;6,43;21,35)")
r = RBA::Region::new(RBA::Box::new(-5, -10, 10, 20))
r.transform(m)
assert_equal(r.to_s, "(6,-25;-9,-18;6,43;21,35)")
assert_equal(RBA::Edges::new(RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20))).transformed(m).to_s, "(-9,-18;21,35)")
r = RBA::Edges::new(RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20)))
r.transform(m)
assert_equal(r.to_s, "(-9,-18;21,35)")
assert_equal(RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20)), RBA::Edge::new(RBA::Point::new(-6, -10), RBA::Point::new(11, 20)))).transformed(m).to_s, "(-9,-18;21,35)/(-10,-17;22,35)")
r = RBA::EdgePairs::new(RBA::EdgePair::new(RBA::Edge::new(RBA::Point::new(-5, -10), RBA::Point::new(10, 20)), RBA::Edge::new(RBA::Point::new(-6, -10), RBA::Point::new(11, 20))))
r.transform(m)
assert_equal(r.to_s, "(-9,-18;21,35)/(-10,-17;22,35)")
m = RBA::Matrix3d::new(1.0, 0.5, 1.0, -0.5, 2.0, 0.0, 0.0, 0.0, 1.0)
assert_equal((m * RBA::DPoint::new(10, 20)).to_s, "21,35")
assert_equal((m * RBA::DVector::new(10, 20)).to_s, "20,35")
assert_equal((m * RBA::DBox::new(-5, -10, 10, 20)).to_s, "(-9,-25;21,42.5)")
assert_equal((m * RBA::DPolygon::new(RBA::DBox::new(-5, -10, 10, 20))).to_s, "(6,-25;-9,-17.5;6,42.5;21,35)")
assert_equal((m * RBA::DSimplePolygon::new(RBA::DBox::new(-5, -10, 10, 20))).to_s, "(6,-25;-9,-17.5;6,42.5;21,35)")
assert_equal((m * RBA::DEdge::new(RBA::DPoint::new(-5, -10), RBA::DPoint::new(10, 20))).to_s, "(-9,-17.5;21,35)")
end
end
load("test_epilogue.rb")

View File

@ -63,6 +63,25 @@ class DBRecursiveShapeIterator_TestClass < TestBase
end
def acollect(s, l)
res = []
while !s.at_end?
r = "[#{l.cell_name(s.cell_index)}]"
if s.shape.is_box?
box = s.shape.box
r += box.transformed(s.always_apply_trans).to_s
else
r += "X";
end
s.next
res.push(r)
end
return res.join("/")
end
def test_1
# Recursive shape iterator tests
@ -197,6 +216,19 @@ class DBRecursiveShapeIterator_TestClass < TestBase
ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), false)
assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)/[c3](1101,101;2101,1201)")
ii.reset
assert_equal(acollect(ii, l), "[c2](0,100;1000,1200)/[c3](0,100;1000,1200)/[c3](1,101;1001,1201)")
ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 20, 2000, 121), true)
ii.global_trans = RBA::ICplxTrans::new(RBA::Vector::new(10, 20))
assert_equal(ii.global_trans.to_s, "r0 *1 10,20")
assert_equal(collect(ii, l), "[c2](10,120;1010,1220)/[c3](1110,120;2110,1220)")
ii.global_dtrans = RBA::DCplxTrans::new(RBA::DVector::new(0.01, 0.02))
ii.reset
assert_equal(ii.global_dtrans.to_s, "r0 *1 0.01,0.02")
assert_equal(collect(ii, l), "[c2](10,120;1010,1220)/[c3](1110,120;2110,1220)")
ii.reset
assert_equal(acollect(ii, l), "[c2](10,120;1010,1220)/[c3](0,100;1000,1200)")
ii = RBA::RecursiveShapeIterator::new(l, c2, [0, 1], RBA::Box.new(-100, 0, 2000, 101), true)
assert_equal(collect(ii, l), "[c2](0,100;1000,1200)/[c3](1100,100;2100,1200)")