mirror of https://github.com/KLayout/klayout.git
Merge branch 'master' into lvs-enhancements
This commit is contained in:
commit
94556c1448
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, const box_tree_type *complex_region);
|
||||
|
||||
/**
|
||||
* @brief Sets the target layer - shapes will be put there
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ®ion)
|
||||
{
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 >)
|
||||
{
|
||||
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. "
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ include($$PWD/../../lib_ut.pri)
|
|||
|
||||
SOURCES = \
|
||||
dbCompoundOperationTests.cc \
|
||||
dbFillToolTests.cc \
|
||||
dbRecursiveInstanceIteratorTests.cc \
|
||||
dbRegionUtilsTests.cc \
|
||||
dbUtilsTests.cc \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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%
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -683,6 +683,17 @@ The following example computes every part of the input which is closer than
|
|||
out = in.drc(primary & 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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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> ®ions)
|
||||
void
|
||||
FillDialog::generate_fill (const FillParameters &fp)
|
||||
{
|
||||
const db::Cell &cell = layout.cell (cell_index);
|
||||
if (! cell.bbox (layer).empty ()) {
|
||||
|
||||
// any shapes to consider ..
|
||||
for (db::ShapeIterator sh = cell.shapes (layer).begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! sh.at_end (); ++sh) {
|
||||
regions.push_back (db::Polygon ());
|
||||
sh->polygon (regions.back ());
|
||||
}
|
||||
|
||||
for (db::Cell::const_iterator inst = cell.begin (); ! inst.at_end (); ++inst) {
|
||||
for (db::CellInstArray::iterator a = inst->cell_inst ().begin (); ! a.at_end (); ++a) {
|
||||
collect_fill_regions (layout, inst->cell_index (), layer, trans * inst->cell_inst ().complex_trans (*a), regions);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
collect_fill_regions (const db::Layout &layout,
|
||||
db::cell_index_type cell_index,
|
||||
unsigned int layer,
|
||||
std::vector <db::Polygon> ®ions)
|
||||
{
|
||||
collect_fill_regions (layout, cell_index, layer, db::CplxTrans (), regions);
|
||||
}
|
||||
|
||||
void
|
||||
FillDialog::ok_pressed ()
|
||||
{
|
||||
BEGIN_PROTECTED
|
||||
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::info << "Running fill";
|
||||
}
|
||||
|
||||
lay::CellView cv = mp_view->cellview (mp_view->active_cellview_index ());
|
||||
db::Layout &ly = cv->layout ();
|
||||
|
||||
std::vector <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 ();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
|
|
@ -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)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)")
|
||||
|
|
|
|||
Loading…
Reference in New Issue