mirror of https://github.com/KLayout/klayout.git
commit
f2bfa1522b
16
Changelog
16
Changelog
|
|
@ -31,7 +31,21 @@
|
|||
* Enhancement: %GITHUB%/issues/393
|
||||
DRC syntax errors are now shown in their original code line
|
||||
of the DRC script.
|
||||
* Enhancement: New Region#pull_* methods and DRC features
|
||||
* Bugfix: %GITHUB%/issues/400
|
||||
Snap feature wasn't working for deep regions in certain use
|
||||
cases.
|
||||
* Enhancement: new "scale_and_snap" methods
|
||||
These methods allow scaling and snapping of layouts. Scaling
|
||||
is supported by a rational factor. After scaling, snapping can
|
||||
be applied to an integer grid. There are two incarnations.
|
||||
Region#scale_and_snap (or Region#scaled_and_snapped): this is
|
||||
a flat implementation which allows anisotropic scaling/snapping
|
||||
as well.
|
||||
And there is Layout#scale_and_snap which is a fully
|
||||
hierarchical scale-and-snap feature. The latter does not support
|
||||
anisotropic scaling/snapping, but works hierarchically without
|
||||
opening gaps. It operates on a top cell and on all layers.
|
||||
* Enhancement: new Region#pull_* methods and DRC features
|
||||
"pull_*" is a class of methods that allows rehierarchisation
|
||||
of shapes. These methods act similar to "interacting", but
|
||||
the other way around: instead of delivering interacting
|
||||
|
|
|
|||
|
|
@ -632,56 +632,11 @@ AsIfFlatRegion::angle_check (double min, double max, bool inverse) const
|
|||
return res.release ();
|
||||
}
|
||||
|
||||
static inline db::Coord snap_to_grid (db::Coord c, db::Coord g)
|
||||
{
|
||||
// This form of snapping always snaps g/2 to right/top.
|
||||
if (c < 0) {
|
||||
c = -g * ((-c + (g - 1) / 2) / g);
|
||||
} else {
|
||||
c = g * ((c + g / 2) / g);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
db::Polygon
|
||||
AsIfFlatRegion::snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vector<db::Point> &heap)
|
||||
{
|
||||
db::Polygon pnew;
|
||||
|
||||
for (size_t i = 0; i < poly.holes () + 1; ++i) {
|
||||
|
||||
heap.clear ();
|
||||
|
||||
db::Polygon::polygon_contour_iterator b, e;
|
||||
|
||||
if (i == 0) {
|
||||
b = poly.begin_hull ();
|
||||
e = poly.end_hull ();
|
||||
} else {
|
||||
b = poly.begin_hole ((unsigned int) (i - 1));
|
||||
e = poly.end_hole ((unsigned int) (i - 1));
|
||||
}
|
||||
|
||||
for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) {
|
||||
heap.push_back (db::Point (snap_to_grid ((*pt).x (), gx), snap_to_grid ((*pt).y (), gy)));
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
pnew.assign_hull (heap.begin (), heap.end ());
|
||||
} else {
|
||||
pnew.insert_hole (heap.begin (), heap.end ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pnew;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy)
|
||||
{
|
||||
if (gx < 0 || gy < 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value")));
|
||||
throw tl::Exception (tl::to_string (tr ("Grid snap requires a positive grid value")));
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatRegion> new_region (new FlatRegion (merged_semantics ()));
|
||||
|
|
@ -698,6 +653,31 @@ AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy)
|
|||
return new_region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy)
|
||||
{
|
||||
if (gx < 0 || gy < 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Grid snap requires a positive grid value")));
|
||||
}
|
||||
|
||||
if (mx <= 0 || dx <= 0 || my <= 0 || dy <= 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Scale and snap requires positive and non-null magnification or divisor values")));
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatRegion> new_region (new FlatRegion (merged_semantics ()));
|
||||
|
||||
gx = std::max (db::Coord (1), gx);
|
||||
gy = std::max (db::Coord (1), gy);
|
||||
|
||||
std::vector<db::Point> heap;
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
|
||||
new_region->raw_polygons ().insert (scaled_and_snapped_polygon (*p, gx, mx, dx, 0, gy, my, dy, 0, heap));
|
||||
}
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
EdgePairsDelegate *
|
||||
AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -105,6 +105,13 @@ public:
|
|||
|
||||
virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy);
|
||||
|
||||
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy)
|
||||
{
|
||||
return scaled_and_snapped (gx, mx, dx, gy, my, dy);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy);
|
||||
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
|
||||
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter)
|
||||
|
|
@ -247,7 +254,6 @@ protected:
|
|||
static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes);
|
||||
template <class Trans>
|
||||
static void produce_markers_for_angle_check (const db::Polygon &poly, const Trans &tr, double min, double max, bool inverse, db::Shapes &shapes);
|
||||
static db::Polygon snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vector<db::Point> &heap);
|
||||
|
||||
private:
|
||||
AsIfFlatRegion &operator= (const AsIfFlatRegion &other);
|
||||
|
|
|
|||
|
|
@ -295,9 +295,26 @@ CellMapping::create_from_names (const db::Layout &layout_a, db::cell_index_type
|
|||
}
|
||||
|
||||
std::vector<db::cell_index_type>
|
||||
CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
|
||||
CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
|
||||
{
|
||||
std::vector<db::cell_index_type> new_cells;
|
||||
do_create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b, exclude_cells, include_cells, &new_cells, 0);
|
||||
return new_cells;
|
||||
}
|
||||
|
||||
std::vector<std::pair<db::cell_index_type, db::cell_index_type> >
|
||||
CellMapping::create_missing_mapping2 (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells)
|
||||
{
|
||||
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > cell_pairs;
|
||||
do_create_missing_mapping (layout_a, cell_index_a, layout_b, cell_index_b, exclude_cells, include_cells, 0, &cell_pairs);
|
||||
return cell_pairs;
|
||||
}
|
||||
|
||||
void
|
||||
CellMapping::do_create_missing_mapping (db::Layout &layout_a, db::cell_index_type /*cell_index_a*/, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells_ptr, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs)
|
||||
{
|
||||
std::vector<db::cell_index_type> new_cells_int;
|
||||
std::vector<db::cell_index_type> &new_cells = *(new_cells_ptr ? new_cells_ptr : &new_cells_int);
|
||||
std::vector<db::cell_index_type> new_cells_b;
|
||||
|
||||
std::set<db::cell_index_type> called_b;
|
||||
|
|
@ -308,10 +325,17 @@ CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /
|
|||
if (m_b2a_mapping.find (*b) == m_b2a_mapping.end ()
|
||||
&& (! exclude_cells || exclude_cells->find (*b) == exclude_cells->end ())
|
||||
&& (! include_cells || include_cells->find (*b) != include_cells->end ())) {
|
||||
|
||||
db::cell_index_type new_cell = layout_a.add_cell (layout_b.cell_name (*b));
|
||||
new_cells.push_back (new_cell);
|
||||
new_cells_b.push_back (*b);
|
||||
|
||||
if (mapped_pairs) {
|
||||
mapped_pairs->push_back (std::make_pair (*b, new_cell));
|
||||
}
|
||||
|
||||
map (*b, new_cell);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -355,8 +379,6 @@ CellMapping::create_missing_mapping (db::Layout &layout_a, db::cell_index_type /
|
|||
layout_a.end_changes ();
|
||||
|
||||
}
|
||||
|
||||
return new_cells;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -197,6 +197,14 @@ public:
|
|||
*/
|
||||
std::vector<db::cell_index_type> create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0);
|
||||
|
||||
/**
|
||||
* @brief Like create_missing_mapping, but returns the newly mapped pairs
|
||||
*
|
||||
* The first cell index of the pair is the old cell in layout_a, the second cell index
|
||||
* is the new cell in layout_b.
|
||||
*/
|
||||
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > create_missing_mapping2 (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells = 0, const std::set<db::cell_index_type> *include_cells = 0);
|
||||
|
||||
private:
|
||||
void extract_unique (std::map <db::cell_index_type, std::vector<db::cell_index_type> >::const_iterator cand,
|
||||
std::map<db::cell_index_type, db::cell_index_type> &unique_mapping,
|
||||
|
|
@ -205,6 +213,8 @@ private:
|
|||
void dump_mapping (const std::map <db::cell_index_type, std::vector<db::cell_index_type> > &candidates,
|
||||
const db::Layout &layout_a, const db::Layout &layout_b);
|
||||
|
||||
void do_create_missing_mapping (db::Layout &layout_a, db::cell_index_type cell_index_a, const db::Layout &layout_b, db::cell_index_type cell_index_b, const std::set<db::cell_index_type> *exclude_cells, const std::set<db::cell_index_type> *include_cells, std::vector<db::cell_index_type> *new_cells, std::vector<std::pair<db::cell_index_type, db::cell_index_type> > *mapped_pairs);
|
||||
|
||||
std::map <db::cell_index_type, db::cell_index_type> m_b2a_mapping;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,124 @@
|
|||
|
||||
|
||||
#include "dbCellVariants.h"
|
||||
#include "dbRegionUtils.h"
|
||||
#include "tlUtils.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
db::ICplxTrans OrientationReducer::reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
db::ICplxTrans res (trans);
|
||||
res.disp (db::Vector ());
|
||||
res.mag (1.0);
|
||||
return res;
|
||||
}
|
||||
|
||||
db::Trans OrientationReducer::reduce (const db::Trans &trans) const
|
||||
{
|
||||
return db::Trans (trans.fp_trans ());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
db::ICplxTrans MagnificationReducer::reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
return db::ICplxTrans (trans.mag ());
|
||||
}
|
||||
|
||||
db::Trans MagnificationReducer::reduce (const db::Trans &) const
|
||||
{
|
||||
return db::Trans ();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
db::ICplxTrans MagnificationAndOrientationReducer::reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
db::ICplxTrans res (trans);
|
||||
res.disp (db::Vector ());
|
||||
return res;
|
||||
}
|
||||
|
||||
db::Trans MagnificationAndOrientationReducer::reduce (const db::Trans &trans) const
|
||||
{
|
||||
return db::Trans (trans.fp_trans ());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
GridReducer::GridReducer (db::Coord grid)
|
||||
: m_grid (grid)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
db::ICplxTrans GridReducer::reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
// NOTE: we need to keep magnification, angle and mirror so when combining the
|
||||
// reduced transformations, the result will be equivalent to reducing the combined
|
||||
// transformation.
|
||||
db::ICplxTrans res (trans);
|
||||
res.disp (db::Vector (trans.disp ().x () - snap_to_grid (trans.disp ().x (), m_grid), trans.disp ().y () - snap_to_grid (trans.disp ().y (), m_grid)));
|
||||
return res;
|
||||
}
|
||||
|
||||
db::Trans GridReducer::reduce (const db::Trans &trans) const
|
||||
{
|
||||
db::Trans res (trans);
|
||||
res.disp (db::Vector (trans.disp ().x () - snap_to_grid (trans.disp ().x (), m_grid), trans.disp ().y () - snap_to_grid (trans.disp ().y (), m_grid)));
|
||||
return res;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
ScaleAndGridReducer::ScaleAndGridReducer (db::Coord grid, db::Coord mult, db::Coord div)
|
||||
: m_mult (mult), m_grid (int64_t (grid) * int64_t (div))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
db::ICplxTrans ScaleAndGridReducer::reduce_trans (const db::ICplxTrans &trans) const
|
||||
{
|
||||
db::ICplxTrans res (trans);
|
||||
int64_t dx = int64_t (trans.disp ().x ()) * m_mult;
|
||||
int64_t dy = int64_t (trans.disp ().y ()) * m_mult;
|
||||
res.disp (db::Vector (db::Coord (dx - snap_to_grid (dx, m_grid)), db::Coord (dy - snap_to_grid (dy, m_grid))));
|
||||
return res;
|
||||
}
|
||||
|
||||
db::Trans ScaleAndGridReducer::reduce_trans (const db::Trans &trans) const
|
||||
{
|
||||
db::Trans res (trans);
|
||||
int64_t dx = int64_t (trans.disp ().x ()) * m_mult;
|
||||
int64_t dy = int64_t (trans.disp ().y ()) * m_mult;
|
||||
res.disp (db::Vector (db::Coord (dx - snap_to_grid (dx, m_grid)), db::Coord (dy - snap_to_grid (dy, m_grid))));
|
||||
return res;
|
||||
}
|
||||
|
||||
db::ICplxTrans ScaleAndGridReducer::reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
db::ICplxTrans res (trans);
|
||||
int64_t dx = int64_t (trans.disp ().x ());
|
||||
int64_t dy = int64_t (trans.disp ().y ());
|
||||
res.disp (db::Vector (db::Coord (dx - snap_to_grid (dx, m_grid)), db::Coord (dy - snap_to_grid (dy, m_grid))));
|
||||
return res;
|
||||
}
|
||||
|
||||
db::Trans ScaleAndGridReducer::reduce (const db::Trans &trans) const
|
||||
{
|
||||
db::Trans res (trans);
|
||||
int64_t dx = int64_t (trans.disp ().x ());
|
||||
int64_t dy = int64_t (trans.disp ().y ());
|
||||
res.disp (db::Vector (db::Coord (dx - snap_to_grid (dx, m_grid)), db::Coord (dy - snap_to_grid (dy, m_grid))));
|
||||
return res;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
|
||||
VariantsCollectorBase::VariantsCollectorBase ()
|
||||
: mp_red ()
|
||||
{
|
||||
|
|
@ -219,7 +332,7 @@ VariantsCollectorBase::commit_shapes (db::Layout &layout, db::Cell &top_cell, un
|
|||
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
|
||||
|
||||
db::ICplxTrans t = i->complex_trans (*ia);
|
||||
db::ICplxTrans rt = mp_red->reduce (vc->first * t);
|
||||
db::ICplxTrans rt = mp_red->reduce (vc->first * mp_red->reduce_trans (t));
|
||||
std::map<db::ICplxTrans, db::Shapes>::const_iterator v = vt.find (rt);
|
||||
if (v != vt.end ()) {
|
||||
|
||||
|
|
@ -263,7 +376,7 @@ VariantsCollectorBase::commit_shapes (db::Layout &layout, db::Cell &top_cell, un
|
|||
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
|
||||
|
||||
db::ICplxTrans t = i->complex_trans (*ia);
|
||||
db::ICplxTrans rt = mp_red->reduce (vvc.begin ()->first * t);
|
||||
db::ICplxTrans rt = mp_red->reduce (vvc.begin ()->first * mp_red->reduce_trans (t));
|
||||
std::map<db::ICplxTrans, db::Shapes>::const_iterator v = vt.find (rt);
|
||||
|
||||
if (v != vt.end ()) {
|
||||
|
|
@ -325,11 +438,11 @@ VariantsCollectorBase::add_variant_non_tl_invariant (std::map<db::ICplxTrans, si
|
|||
{
|
||||
if (inst.is_complex ()) {
|
||||
for (db::CellInstArray::iterator i = inst.begin (); ! i.at_end (); ++i) {
|
||||
variants [mp_red->reduce (inst.complex_trans (*i))] += 1;
|
||||
variants [mp_red->reduce_trans (inst.complex_trans (*i))] += 1;
|
||||
}
|
||||
} else {
|
||||
for (db::CellInstArray::iterator i = inst.begin (); ! i.at_end (); ++i) {
|
||||
variants [db::ICplxTrans (mp_red->reduce (*i))] += 1;
|
||||
variants [db::ICplxTrans (mp_red->reduce_trans (*i))] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -338,9 +451,9 @@ void
|
|||
VariantsCollectorBase::add_variant_tl_invariant (std::map<db::ICplxTrans, size_t> &variants, const db::CellInstArray &inst) const
|
||||
{
|
||||
if (inst.is_complex ()) {
|
||||
variants [mp_red->reduce (inst.complex_trans ())] += inst.size ();
|
||||
variants [mp_red->reduce_trans (inst.complex_trans ())] += inst.size ();
|
||||
} else {
|
||||
variants [db::ICplxTrans (mp_red->reduce (inst.front ()))] += inst.size ();
|
||||
variants [db::ICplxTrans (mp_red->reduce_trans (inst.front ()))] += inst.size ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +468,7 @@ VariantsCollectorBase::product (const std::map<db::ICplxTrans, size_t> &v1, cons
|
|||
}
|
||||
|
||||
void
|
||||
VariantsCollectorBase::copy_shapes (db::Layout &layout, db::cell_index_type ci_to, db::cell_index_type ci_from) const
|
||||
VariantsCollectorBase::copy_shapes (db::Layout &layout, db::cell_index_type ci_to, db::cell_index_type ci_from)
|
||||
{
|
||||
db::Cell &to = layout.cell (ci_to);
|
||||
const db::Cell &from = layout.cell (ci_from);
|
||||
|
|
@ -390,7 +503,7 @@ VariantsCollectorBase::create_var_instances_non_tl_invariant (db::Cell &in_cell,
|
|||
|
||||
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
|
||||
|
||||
db::ICplxTrans rt = mp_red->reduce (for_var * i->complex_trans (*ia));
|
||||
db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans (*ia)));
|
||||
std::map<db::ICplxTrans, db::cell_index_type>::const_iterator v = vt.find (rt);
|
||||
tl_assert (v != vt.end ());
|
||||
|
||||
|
|
@ -419,7 +532,7 @@ VariantsCollectorBase::create_var_instances_tl_invariant (db::Cell &in_cell, std
|
|||
|
||||
std::map<db::ICplxTrans, db::cell_index_type>::const_iterator v;
|
||||
|
||||
db::ICplxTrans rt = mp_red->reduce (for_var * i->complex_trans ());
|
||||
db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans ()));
|
||||
v = vt.find (rt);
|
||||
tl_assert (v != vt.end ());
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,8 @@ public:
|
|||
TransformationReducer () { }
|
||||
virtual ~TransformationReducer () { }
|
||||
|
||||
virtual db::Trans reduce_trans (const db::Trans &trans) const { return reduce (trans); }
|
||||
virtual db::ICplxTrans reduce_trans (const db::ICplxTrans &trans) const { return reduce (trans); }
|
||||
virtual db::Trans reduce (const db::Trans &trans) const = 0;
|
||||
virtual db::ICplxTrans reduce (const db::ICplxTrans &trans) const = 0;
|
||||
virtual bool is_translation_invariant () const { return true; }
|
||||
|
|
@ -63,18 +65,8 @@ public:
|
|||
struct DB_PUBLIC OrientationReducer
|
||||
: public TransformationReducer
|
||||
{
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
db::ICplxTrans res (trans);
|
||||
res.disp (db::Vector ());
|
||||
res.mag (1.0);
|
||||
return res;
|
||||
}
|
||||
|
||||
db::Trans reduce (const db::Trans &trans) const
|
||||
{
|
||||
return db::Trans (trans.fp_trans ());
|
||||
}
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const;
|
||||
db::Trans reduce (const db::Trans &trans) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -85,15 +77,8 @@ struct DB_PUBLIC OrientationReducer
|
|||
struct DB_PUBLIC MagnificationReducer
|
||||
: public TransformationReducer
|
||||
{
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
return db::ICplxTrans (trans.mag ());
|
||||
}
|
||||
|
||||
db::Trans reduce (const db::Trans &) const
|
||||
{
|
||||
return db::Trans ();
|
||||
}
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const;
|
||||
db::Trans reduce (const db::Trans &) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -104,17 +89,8 @@ struct DB_PUBLIC MagnificationReducer
|
|||
struct DB_PUBLIC MagnificationAndOrientationReducer
|
||||
: public TransformationReducer
|
||||
{
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
db::ICplxTrans res (trans);
|
||||
res.disp (db::Vector ());
|
||||
return res;
|
||||
}
|
||||
|
||||
db::Trans reduce (const db::Trans &trans) const
|
||||
{
|
||||
return db::Trans (trans.fp_trans ());
|
||||
}
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const;
|
||||
db::Trans reduce (const db::Trans &trans) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -125,47 +101,39 @@ struct DB_PUBLIC MagnificationAndOrientationReducer
|
|||
struct DB_PUBLIC GridReducer
|
||||
: public TransformationReducer
|
||||
{
|
||||
GridReducer (db::Coord grid)
|
||||
: m_grid (grid)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
GridReducer (db::Coord grid);
|
||||
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const
|
||||
{
|
||||
// NOTE: we need to keep magnification, angle and mirror so when combining the
|
||||
// reduced transformations, the result will be equivalent to reducing the combined
|
||||
// transformation.
|
||||
db::ICplxTrans res (trans);
|
||||
res.disp (db::Vector (mod (trans.disp ().x ()), mod (trans.disp ().y ())));
|
||||
return res;
|
||||
}
|
||||
|
||||
db::Trans reduce (const db::Trans &trans) const
|
||||
{
|
||||
db::Trans res (trans);
|
||||
res.disp (db::Vector (mod (trans.disp ().x ()), mod (trans.disp ().y ())));
|
||||
return res;
|
||||
}
|
||||
db::ICplxTrans reduce (const db::ICplxTrans &trans) const;
|
||||
db::Trans reduce (const db::Trans &trans) const;
|
||||
|
||||
bool is_translation_invariant () const { return false; }
|
||||
|
||||
private:
|
||||
db::Coord m_grid;
|
||||
};
|
||||
|
||||
inline db::Coord mod (db::Coord c) const
|
||||
{
|
||||
if (c < 0) {
|
||||
c = m_grid - (-c) % m_grid;
|
||||
if (c == m_grid) {
|
||||
return 0;
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
} else {
|
||||
return c % m_grid;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief A scale+grid reducer
|
||||
*
|
||||
* This reducer incarnation reduces the transformation to it's displacement modulo a grid
|
||||
* after a specified scaling has been applied.
|
||||
* The scaling is given by a divider and multiplier and is mult / div.
|
||||
*/
|
||||
struct DB_PUBLIC ScaleAndGridReducer
|
||||
: public TransformationReducer
|
||||
{
|
||||
ScaleAndGridReducer (db::Coord grid, db::Coord mult, db::Coord div);
|
||||
|
||||
virtual db::ICplxTrans reduce_trans (const db::ICplxTrans &trans) const;
|
||||
virtual db::Trans reduce_trans (const db::Trans &trans) const;
|
||||
virtual db::ICplxTrans reduce (const db::ICplxTrans &trans) const;
|
||||
virtual db::Trans reduce (const db::Trans &trans) const;
|
||||
|
||||
bool is_translation_invariant () const { return false; }
|
||||
|
||||
private:
|
||||
int64_t m_mult;
|
||||
int64_t m_grid;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -225,6 +193,11 @@ public:
|
|||
*/
|
||||
bool has_variants () const;
|
||||
|
||||
/**
|
||||
* @brief Utility: copy all shapes from one cell to another
|
||||
*/
|
||||
static void copy_shapes (db::Layout &layout, db::cell_index_type ci_to, db::cell_index_type ci_from);
|
||||
|
||||
private:
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> > m_variants;
|
||||
const TransformationReducer *mp_red;
|
||||
|
|
@ -233,7 +206,6 @@ private:
|
|||
void add_variant_non_tl_invariant (std::map<db::ICplxTrans, size_t> &variants, const db::CellInstArray &inst) const;
|
||||
void add_variant_tl_invariant (std::map<db::ICplxTrans, size_t> &variants, const db::CellInstArray &inst) const;
|
||||
void product (const std::map<db::ICplxTrans, size_t> &v1, const std::map<db::ICplxTrans, size_t> &v2, std::map<db::ICplxTrans, size_t> &prod) const;
|
||||
void copy_shapes (db::Layout &layout, db::cell_index_type ci_to, db::cell_index_type ci_from) const;
|
||||
void create_var_instances (db::Cell &in_cell, std::vector<db::CellInstArrayWithProperties> &inst, const db::ICplxTrans &for_var, const std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> > &var_table, bool tl_invariant) const;
|
||||
void create_var_instances_non_tl_invariant (db::Cell &in_cell, std::vector<db::CellInstArrayWithProperties> &inst, const db::ICplxTrans &for_var, const std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> > &var_table) const;
|
||||
void create_var_instances_tl_invariant (db::Cell &in_cell, std::vector<db::CellInstArrayWithProperties> &inst, const db::ICplxTrans &for_var, const std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> > &var_table) const;
|
||||
|
|
|
|||
|
|
@ -889,7 +889,7 @@ DeepShapeStore::issue_variants (unsigned int layout_index, const std::map<db::ce
|
|||
const db::CellMapping &
|
||||
DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout *into_layout, db::cell_index_type into_cell, const std::set<db::cell_index_type> *excluded_cells, const std::set<db::cell_index_type> *included_cells)
|
||||
{
|
||||
const db::Layout *source_layout = &m_layouts [layout_index]->layout;
|
||||
db::Layout *source_layout = &m_layouts [layout_index]->layout;
|
||||
if (source_layout->begin_top_down () == source_layout->end_top_cells ()) {
|
||||
// empty source - nothing to do.
|
||||
static db::CellMapping cm;
|
||||
|
|
@ -910,6 +910,9 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
|
|||
|
||||
cm = m_delivery_mapping_cache.insert (std::make_pair (key, db::CellMapping ())).first;
|
||||
|
||||
// collects the cell mappings we skip because they are variants (variant building or box variants)
|
||||
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::set<db::Box> > > cm_skipped_variants;
|
||||
|
||||
if (into_layout == original_builder.source ().layout () && &into_layout->cell (into_cell) == original_builder.source ().top_cell ()) {
|
||||
|
||||
// This is the case of mapping back to the original. In this case we can use the information
|
||||
|
|
@ -917,22 +920,28 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
|
|||
// create from them. We need to consider however, that the hierarchy builder is allowed to create
|
||||
// variants which we cannot map.
|
||||
|
||||
for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ++m) {
|
||||
for (HierarchyBuilder::cell_map_type::const_iterator m = original_builder.begin_cell_map (); m != original_builder.end_cell_map (); ) {
|
||||
|
||||
HierarchyBuilder::cell_map_type::const_iterator mm = m;
|
||||
++mm;
|
||||
bool skip = original_builder.is_variant (m->second); // skip variant cells
|
||||
while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first && ! skip) {
|
||||
// we have cell variants and cannot simply map
|
||||
while (mm != original_builder.end_cell_map () && mm->first.first == m->first.first) {
|
||||
// we have cell (box) variants and cannot simply map
|
||||
++mm;
|
||||
++m;
|
||||
skip = true;
|
||||
}
|
||||
|
||||
if (! skip) {
|
||||
cm->second.map (m->second, m->first.first);
|
||||
} else {
|
||||
for (HierarchyBuilder::cell_map_type::const_iterator n = m; n != mm; ++n) {
|
||||
tl_assert (cm_skipped_variants.find (n->second) == cm_skipped_variants.end ());
|
||||
cm_skipped_variants [n->second] = n->first;
|
||||
}
|
||||
}
|
||||
|
||||
m = mm;
|
||||
|
||||
}
|
||||
|
||||
} else if (into_layout->cells () == 1) {
|
||||
|
|
@ -948,7 +957,43 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
|
|||
|
||||
// Add new cells for the variants and (possible) devices which are cells added during the device
|
||||
// extraction process
|
||||
cm->second.create_missing_mapping (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells);
|
||||
std::vector<std::pair<db::cell_index_type, db::cell_index_type> > new_pairs = cm->second.create_missing_mapping2 (*into_layout, into_cell, *source_layout, source_top, excluded_cells, included_cells);
|
||||
|
||||
// the variant's originals we are going to delete
|
||||
std::set<db::cell_index_type> cells_to_delete;
|
||||
|
||||
// We now need to fix the cell map from the hierarchy builder, so we can import back from the modified layout.
|
||||
// This is in particular important if we created new cells for known variants.
|
||||
for (std::vector<std::pair<db::cell_index_type, db::cell_index_type> >::const_iterator np = new_pairs.begin (); np != new_pairs.end (); ++np) {
|
||||
|
||||
db::cell_index_type var_org = original_builder.original_target_for_variant (np->first);
|
||||
|
||||
std::map<db::cell_index_type, std::pair<db::cell_index_type, std::set<db::Box> > >::const_iterator icm = cm_skipped_variants.find (var_org);
|
||||
if (icm != cm_skipped_variants.end ()) {
|
||||
|
||||
// create the variant clone in the original layout too and delete this cell
|
||||
VariantsCollectorBase::copy_shapes (*into_layout, np->second, icm->second.first);
|
||||
cells_to_delete.insert (icm->second.first);
|
||||
|
||||
// forget the original cell (now separated into variants) and map the variants back into the
|
||||
// DSS layout
|
||||
original_builder.unmap (icm->second);
|
||||
original_builder.map (std::make_pair (np->second, icm->second.second), np->first);
|
||||
|
||||
// forget the variant as now it's a real cell in the source layout
|
||||
original_builder.unregister_variant (np->first);
|
||||
|
||||
// rename the cell because it may be a different one now
|
||||
source_layout->rename_cell (np->first, into_layout->cell_name (np->second));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// delete the variant's original cell
|
||||
if (! cells_to_delete.empty ()) {
|
||||
into_layout->delete_cells (cells_to_delete);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@ public:
|
|||
virtual EdgePairsDelegate *angle_check (double, double, bool) const;
|
||||
|
||||
virtual RegionDelegate *snapped_in_place (db::Coord, db::Coord) { return this; }
|
||||
virtual RegionDelegate *snapped (db::Coord, db::Coord) { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *snapped (db::Coord, db::Coord) { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return this; }
|
||||
virtual RegionDelegate *scaled_and_snapped (db::Coord, db::Coord, db::Coord, db::Coord, db::Coord, db::Coord) { return new EmptyRegion (); }
|
||||
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *) const;
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; }
|
||||
|
|
|
|||
|
|
@ -185,6 +185,40 @@ HierarchyBuilder::register_variant (db::cell_index_type non_var, db::cell_index_
|
|||
m_variants_to_original_target_map.insert (std::make_pair (var, non_var));
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::unregister_variant (db::cell_index_type var)
|
||||
{
|
||||
variant_to_original_target_map_type::const_iterator v = m_variants_to_original_target_map.find (var);
|
||||
if (v == m_variants_to_original_target_map.end ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
original_target_to_variants_map_type::iterator rv = m_original_targets_to_variants_map.find (v->second);
|
||||
tl_assert (rv != m_original_targets_to_variants_map.end ());
|
||||
|
||||
std::vector<db::cell_index_type> &vv = rv->second;
|
||||
std::vector<db::cell_index_type>::iterator ri = std::find (vv.begin (), vv.end (), var);
|
||||
tl_assert (ri != vv.end ());
|
||||
vv.erase (ri);
|
||||
|
||||
if (vv.empty ()) {
|
||||
m_original_targets_to_variants_map.erase (rv);
|
||||
}
|
||||
|
||||
m_variants_to_original_target_map.erase (v);
|
||||
}
|
||||
|
||||
db::cell_index_type
|
||||
HierarchyBuilder::original_target_for_variant (db::cell_index_type ci) const
|
||||
{
|
||||
variant_to_original_target_map_type::const_iterator v = m_variants_to_original_target_map.find (ci);
|
||||
if (v != m_variants_to_original_target_map.end ()) {
|
||||
return v->second;
|
||||
} else {
|
||||
return ci;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
|
||||
{
|
||||
|
|
@ -269,6 +303,7 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
|
|||
if (all) {
|
||||
|
||||
std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), std::set<db::Box> ());
|
||||
|
||||
m_cm_entry = m_cell_map.find (key);
|
||||
m_cm_new_entry = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -284,6 +284,24 @@ public:
|
|||
return m_cell_map.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unmaps an original cell/clip box version from the original-to-working copy cell map
|
||||
*
|
||||
* An unmapped cell is never again considered.
|
||||
*/
|
||||
void unmap (const cell_map_type::key_type &k)
|
||||
{
|
||||
m_cell_map.erase (k);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Maps an original cell/clip box version to a original-to-working copy cell
|
||||
*/
|
||||
void map (const cell_map_type::key_type &k, db::cell_index_type ci)
|
||||
{
|
||||
m_cell_map [k] = ci;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Marks a cell as a variant of another
|
||||
*
|
||||
|
|
@ -292,6 +310,11 @@ public:
|
|||
*/
|
||||
void register_variant (db::cell_index_type non_var, db::cell_index_type var);
|
||||
|
||||
/**
|
||||
* @brief Unregisters a cell as a variant
|
||||
*/
|
||||
void unregister_variant (db::cell_index_type var);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the given cell is a variant cell
|
||||
*/
|
||||
|
|
@ -300,6 +323,11 @@ public:
|
|||
return m_variants_to_original_target_map.find (ci) != m_variants_to_original_target_map.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the original target for a variant cell
|
||||
*/
|
||||
db::cell_index_type original_target_for_variant (db::cell_index_type ci) const;
|
||||
|
||||
private:
|
||||
tl::weak_ptr<db::Layout> mp_target;
|
||||
HierarchyBuilderShapeReceiver *mp_pipe;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "dbCellVariants.h"
|
||||
#include "dbRegionUtils.h"
|
||||
#include "tlProgress.h"
|
||||
|
||||
namespace db
|
||||
|
|
@ -431,5 +433,125 @@ ContextCache::find_layout_context (db::cell_index_type from, db::cell_index_type
|
|||
return c->second;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Scale and snap a layout
|
||||
|
||||
void
|
||||
scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d)
|
||||
{
|
||||
if (g < 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value")));
|
||||
}
|
||||
|
||||
if (m <= 0 || d <= 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Scale and snap requires positive and non-null magnification or divisor values")));
|
||||
}
|
||||
|
||||
if (! g && m == d) {
|
||||
return;
|
||||
}
|
||||
|
||||
db::cell_variants_collector<db::ScaleAndGridReducer> vars (db::ScaleAndGridReducer (g, m, d));
|
||||
|
||||
vars.collect (layout, cell);
|
||||
vars.separate_variants (layout, cell);
|
||||
|
||||
std::set<db::cell_index_type> called_cells;
|
||||
cell.collect_called_cells (called_cells);
|
||||
called_cells.insert (cell.cell_index ());
|
||||
|
||||
db::LayoutLocker layout_locker (&layout);
|
||||
layout.update ();
|
||||
|
||||
std::vector<db::Point> heap;
|
||||
|
||||
unsigned int work_layer = layout.insert_layer ();
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
if (called_cells.find (c->cell_index ()) == called_cells.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &v = vars.variants (c->cell_index ());
|
||||
tl_assert (v.size () == size_t (1));
|
||||
db::ICplxTrans tr = v.begin ()->first;
|
||||
|
||||
// NOTE: tr_disp is already multiplied with mag, so it can be an integer
|
||||
db::Vector tr_disp = tr.disp ();
|
||||
|
||||
tr.disp (db::Vector ());
|
||||
db::ICplxTrans trinv = tr.inverted ();
|
||||
|
||||
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
|
||||
|
||||
db::Shapes &s = c->shapes ((*l).first);
|
||||
db::Shapes &out = c->shapes (work_layer);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! si.at_end (); ++si) {
|
||||
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
poly.transform (tr);
|
||||
poly = scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap);
|
||||
poly.transform (trinv);
|
||||
out.insert (poly);
|
||||
|
||||
}
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) {
|
||||
|
||||
db::Text text;
|
||||
si->text (text);
|
||||
text.transform (tr);
|
||||
text.trans (db::Trans (text.trans ().rot (), scaled_and_snapped_vector (text.trans ().disp (), g, m, d, tr_disp.x (), g, m, d, tr_disp.y ())));
|
||||
text.transform (trinv);
|
||||
out.insert (text);
|
||||
|
||||
}
|
||||
|
||||
s.swap (out);
|
||||
out.clear ();
|
||||
|
||||
}
|
||||
|
||||
// Snap instance placements to grid and magnify
|
||||
// NOTE: we can modify the instances because the ScaleAndGridReducer marked every cell with children
|
||||
// as a variant cell (an effect of ScaleAndGridReducer::want_variants(cell) == true where cells have children).
|
||||
// Variant cells are not copied blindly back to the original layout.
|
||||
|
||||
std::list<db::CellInstArray> new_insts;
|
||||
|
||||
for (db::Cell::const_iterator inst = c->begin (); ! inst.at_end (); ++inst) {
|
||||
|
||||
const db::CellInstArray &ia = inst->cell_inst ();
|
||||
for (db::CellInstArray::iterator i = ia.begin (); ! i.at_end (); ++i) {
|
||||
|
||||
db::Trans ti (*i);
|
||||
db::Vector ti_disp = ti.disp ();
|
||||
ti_disp.transform (tr);
|
||||
ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
|
||||
ti_disp.transform (trinv);
|
||||
ti.disp (ti_disp);
|
||||
|
||||
if (ia.is_complex ()) {
|
||||
new_insts.push_back (db::CellInstArray (ia.object (), ia.complex_trans (ti)));
|
||||
} else {
|
||||
new_insts.push_back (db::CellInstArray (ia.object (), ti));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
c->clear_insts ();
|
||||
|
||||
for (std::list<db::CellInstArray>::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) {
|
||||
c->insert (*i);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -223,6 +223,14 @@ private:
|
|||
const db::Layout *mp_layout;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Scales and snaps the layout below the given cell
|
||||
*
|
||||
* This method will scale and snap all layers from the given cell and below to the
|
||||
* specified grid. Scaling happens by the rational factor m / d.
|
||||
*/
|
||||
DB_PUBLIC void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d);
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -389,6 +389,18 @@ Region::snapped (db::Coord gx, db::Coord gy) const
|
|||
return Region (mp_delegate->snapped (gx, gy));
|
||||
}
|
||||
|
||||
void
|
||||
Region::scale_and_snap (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy)
|
||||
{
|
||||
set_delegate (mp_delegate->scaled_and_snapped_in_place (gx, mx, dx, gy, my, dy));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) const
|
||||
{
|
||||
return Region (mp_delegate->scaled_and_snapped (gx, mx, dx, gy, my, dy));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::strange_polygon_check () const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -903,6 +903,19 @@ public:
|
|||
*/
|
||||
Region snapped (db::Coord gx, db::Coord gy) const;
|
||||
|
||||
/**
|
||||
* @brief Scales and grid-snaps the region
|
||||
*
|
||||
* This method will scale the region by mx/dx in horizontal and by my/dy in vertical
|
||||
* direction and then snape to gx and gy respectively.
|
||||
*/
|
||||
void scale_and_snap (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy);
|
||||
|
||||
/**
|
||||
* @brief Returns the scaled and snapped region
|
||||
*/
|
||||
Region scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) const;
|
||||
|
||||
/**
|
||||
* @brief Performs a check for "strange" polygons
|
||||
*
|
||||
|
|
|
|||
|
|
@ -260,6 +260,8 @@ public:
|
|||
|
||||
virtual RegionDelegate *snapped_in_place (db::Coord gx, db::Coord gy) = 0;
|
||||
virtual RegionDelegate *snapped (db::Coord gx, db::Coord gy) = 0;
|
||||
virtual RegionDelegate *scaled_and_snapped_in_place (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0;
|
||||
virtual RegionDelegate *scaled_and_snapped (db::Coord gx, db::Coord mx, db::Coord dx, db::Coord gy, db::Coord my, db::Coord dy) = 0;
|
||||
|
||||
virtual EdgesDelegate *edges (const EdgeFilterBase *filter) const = 0;
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) = 0;
|
||||
|
|
|
|||
|
|
@ -350,5 +350,92 @@ region_to_edge_interaction_filter_base<OutputType>::fill_output ()
|
|||
template class region_to_edge_interaction_filter_base<db::Polygon>;
|
||||
template class region_to_edge_interaction_filter_base<db::Edge>;
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Polygon snapping
|
||||
|
||||
db::Polygon
|
||||
snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vector<db::Point> &heap)
|
||||
{
|
||||
db::Polygon pnew;
|
||||
|
||||
for (size_t i = 0; i < poly.holes () + 1; ++i) {
|
||||
|
||||
heap.clear ();
|
||||
|
||||
db::Polygon::polygon_contour_iterator b, e;
|
||||
|
||||
if (i == 0) {
|
||||
b = poly.begin_hull ();
|
||||
e = poly.end_hull ();
|
||||
} else {
|
||||
b = poly.begin_hole ((unsigned int) (i - 1));
|
||||
e = poly.end_hole ((unsigned int) (i - 1));
|
||||
}
|
||||
|
||||
for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) {
|
||||
heap.push_back (db::Point (snap_to_grid ((*pt).x (), gx), snap_to_grid ((*pt).y (), gy)));
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
pnew.assign_hull (heap.begin (), heap.end ());
|
||||
} else {
|
||||
pnew.insert_hole (heap.begin (), heap.end ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pnew;
|
||||
}
|
||||
|
||||
db::Polygon
|
||||
scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy, std::vector<db::Point> &heap)
|
||||
{
|
||||
db::Polygon pnew;
|
||||
|
||||
int64_t dgx = int64_t (gx) * int64_t (dx);
|
||||
int64_t dgy = int64_t (gy) * int64_t (dy);
|
||||
|
||||
for (size_t i = 0; i < poly.holes () + 1; ++i) {
|
||||
|
||||
heap.clear ();
|
||||
|
||||
db::Polygon::polygon_contour_iterator b, e;
|
||||
|
||||
if (i == 0) {
|
||||
b = poly.begin_hull ();
|
||||
e = poly.end_hull ();
|
||||
} else {
|
||||
b = poly.begin_hole ((unsigned int) (i - 1));
|
||||
e = poly.end_hole ((unsigned int) (i - 1));
|
||||
}
|
||||
|
||||
for (db::Polygon::polygon_contour_iterator pt = b; pt != e; ++pt) {
|
||||
int64_t x = snap_to_grid (int64_t ((*pt).x ()) * mx + int64_t (ox), dgx) / int64_t (dx);
|
||||
int64_t y = snap_to_grid (int64_t ((*pt).y ()) * my + int64_t (oy), dgy) / int64_t (dy);
|
||||
heap.push_back (db::Point (db::Coord (x), db::Coord (y)));
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
pnew.assign_hull (heap.begin (), heap.end ());
|
||||
} else {
|
||||
pnew.insert_hole (heap.begin (), heap.end ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pnew;
|
||||
}
|
||||
|
||||
db::Vector
|
||||
scaled_and_snapped_vector (const db::Vector &v, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy)
|
||||
{
|
||||
int64_t dgx = int64_t (gx) * int64_t (dx);
|
||||
int64_t dgy = int64_t (gy) * int64_t (dy);
|
||||
|
||||
int64_t x = snap_to_grid (int64_t (v.x ()) * mx + int64_t (ox), dgx) / int64_t (dx);
|
||||
int64_t y = snap_to_grid (int64_t (v.y ()) * my + int64_t (oy), dgy) / int64_t (dy);
|
||||
|
||||
return db::Vector (db::Coord (x), db::Coord (y));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -524,6 +524,37 @@ private:
|
|||
OutputContainer *mp_output;
|
||||
};
|
||||
|
||||
template <class C>
|
||||
static inline C snap_to_grid (C c, C g)
|
||||
{
|
||||
// This form of snapping always snaps g/2 to right/top.
|
||||
if (c < 0) {
|
||||
c = -g * ((-c + (g - 1) / 2) / g);
|
||||
} else {
|
||||
c = g * ((c + g / 2) / g);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Snaps a polygon to the given grid
|
||||
* Heap is a vector of points reused for the point list
|
||||
*/
|
||||
DB_PUBLIC db::Polygon snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vector<db::Point> &heap);
|
||||
|
||||
/**
|
||||
* @brief Scales and snaps a polygon to the given grid
|
||||
* Heap is a vector of points reused for the point list
|
||||
* The coordinate transformation is q = ((p * m + o) snap (g * d)) / d.
|
||||
*/
|
||||
DB_PUBLIC db::Polygon scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy, std::vector<db::Point> &heap);
|
||||
|
||||
/**
|
||||
* @brief Scales and snaps a vector to the given grid
|
||||
* The coordinate transformation is q = ((p * m + o) snap (g * d)) / d.
|
||||
*/
|
||||
DB_PUBLIC db::Vector scaled_and_snapped_vector (const db::Vector &v, db::Coord gx, db::Coord mx, db::Coord dx, db::Coord ox, db::Coord gy, db::Coord my, db::Coord dy, db::Coord oy);
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "dbPCellDeclaration.h"
|
||||
#include "dbHash.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbLayoutUtils.h"
|
||||
#include "tlStream.h"
|
||||
|
||||
namespace gsi
|
||||
|
|
@ -812,6 +813,16 @@ static const std::string &layout_meta_get_description (const db::MetaInfo *mi)
|
|||
return mi->description;
|
||||
}
|
||||
|
||||
static void scale_and_snap1 (db::Layout *layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d)
|
||||
{
|
||||
scale_and_snap (*layout, cell, g, m, d);
|
||||
}
|
||||
|
||||
static void scale_and_snap2 (db::Layout *layout, db::cell_index_type ci, db::Coord g, db::Coord m, db::Coord d)
|
||||
{
|
||||
scale_and_snap (*layout, layout->cell (ci), g, m, d);
|
||||
}
|
||||
|
||||
Class<db::MetaInfo> decl_LayoutMetaInfo ("db", "LayoutMetaInfo",
|
||||
gsi::constructor ("new", &layout_meta_info_ctor, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("description", std::string ()),
|
||||
"@brief Creates a layout meta info object\n"
|
||||
|
|
@ -1542,6 +1553,25 @@ Class<db::Layout> decl_Layout ("db", "Layout",
|
|||
"an index in the range of 0 to layers-1 needs to be a valid layer. These layers can be either valid, "
|
||||
"special or unused. Use \\is_valid_layer? and \\is_special_layer? to test for the first two states.\n"
|
||||
) +
|
||||
gsi::method_ext ("scale_and_snap", &scale_and_snap1, gsi::arg ("cell"), gsi::arg ("grid"), gsi::arg ("mult"), gsi::arg ("div"),
|
||||
"@brief Scales and snaps the layout below a given cell by the given rational factor and snaps to the given grid\n"
|
||||
"\n"
|
||||
"This method is useful to scale a layout by a non-integer factor. The "
|
||||
"scale factor is given by the rational number mult / div. After scaling, the "
|
||||
"layout will be snapped to the given grid.\n"
|
||||
"\n"
|
||||
"Snapping happens 'as-if-flat' - that is, touching edges will stay touching, regardless of their "
|
||||
"hierarchy path. To achieve this, this method usually needs to produce cell variants.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1.\n"
|
||||
) +
|
||||
gsi::method_ext ("scale_and_snap", &scale_and_snap2, gsi::arg ("cell_index"), gsi::arg ("grid"), gsi::arg ("mult"), gsi::arg ("div"),
|
||||
"@brief Scales and snaps the layout below a given cell by the given rational factor and snaps to the given grid\n"
|
||||
"\n"
|
||||
"Like the other version of \\scale_and_snap, but taking a cell index for the argument.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1.\n"
|
||||
) +
|
||||
gsi::method ("transform", (void (db::Layout::*) (const db::Trans &t)) &db::Layout::transform,
|
||||
"@brief Transforms the layout with the given transformation\n"
|
||||
"@args trans\n"
|
||||
|
|
|
|||
|
|
@ -949,10 +949,28 @@ Class<db::Region> decl_Region ("db", "Region",
|
|||
"This method will snap the region to the given grid - each x or y coordinate is brought on the gx or gy grid by rounding "
|
||||
"to the nearest value which is a multiple of gx or gy.\n"
|
||||
"\n"
|
||||
"If gx or gy is 0 or less, no snapping happens in that direction.\n"
|
||||
"If gx or gy is 0, no snapping happens in that direction.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
) +
|
||||
method ("scaled_and_snapped", &db::Region::scaled_and_snapped, gsi::arg ("gx"), gsi::arg ("mx"), gsi::arg ("dx"), gsi::arg ("gy"),gsi::arg ("my"), gsi::arg ("dy"),
|
||||
"@brief Returns the scaled and snapped region\n"
|
||||
"This method will scale and snap the region to the given grid and return the scaled and snapped region (see \\scale_and_snap). The original region is not modified.\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1."
|
||||
) +
|
||||
method ("scale_and_snap", &db::Region::scale_and_snap, gsi::arg ("gx"), gsi::arg ("mx"), gsi::arg ("dx"), gsi::arg ("gy"),gsi::arg ("my"), gsi::arg ("dy"),
|
||||
"@brief Scales and snaps the region to the given grid\n"
|
||||
"This method will first scale the region by a rational factor of mx/dx horizontally and my/dy vertically and then "
|
||||
"snap the region to the given grid - each x or y coordinate is brought on the gx or gy grid by rounding "
|
||||
"to the nearest value which is a multiple of gx or gy.\n"
|
||||
"\n"
|
||||
"If gx or gy is 0, the result is brought on a grid of 1.\n"
|
||||
"\n"
|
||||
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.1."
|
||||
) +
|
||||
method ("grid_check", &db::Region::grid_check, gsi::arg ("gx"), gsi::arg ("gy"),
|
||||
"@brief Returns a marker for all vertices not being on the given grid\n"
|
||||
"This method will return an edge pair object for every vertex whose x coordinate is not a multiple of gx or whose "
|
||||
|
|
|
|||
|
|
@ -1490,6 +1490,114 @@ TEST(26_BreakoutCells)
|
|||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au26.gds");
|
||||
}
|
||||
|
||||
TEST(27a_snap)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
r1.set_merged_semantics (false);
|
||||
db::Region r2 = r1.snapped (19, 19);
|
||||
|
||||
r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0)));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au27.gds");
|
||||
}
|
||||
|
||||
TEST(27b_snap)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
r1.set_merged_semantics (false);
|
||||
r1.snap (19, 19);
|
||||
|
||||
r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0)));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au27.gds");
|
||||
}
|
||||
|
||||
TEST(28a_snap)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
r1.set_merged_semantics (false);
|
||||
db::Region r2 = r1.scaled_and_snapped (19, 2, 10, 19, 2, 10);
|
||||
|
||||
r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0)));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au28.gds");
|
||||
}
|
||||
|
||||
TEST(28b_snap)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss);
|
||||
r1.set_merged_semantics (false);
|
||||
r1.scale_and_snap (19, 2, 10, 19, 2, 10);
|
||||
|
||||
r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0)));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au28.gds");
|
||||
}
|
||||
|
||||
TEST(100_Integration)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
|
@ -1641,3 +1749,105 @@ TEST(issue_277)
|
|||
EXPECT_EQ (r.sized (1).merged (false, 1).to_string (), "");
|
||||
}
|
||||
|
||||
TEST(issue_400)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/gds/t10.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
// keeps a reference to the DSS
|
||||
db::Region rr (db::RecursiveShapeIterator (ly, top_cell, (*ly.begin_layers ()).first), dss);
|
||||
|
||||
for (db::Layout::layer_iterator l = ly.begin_layers (); l != ly.end_layers (); ++l) {
|
||||
|
||||
unsigned int li = (*l).first;
|
||||
db::Region r (db::RecursiveShapeIterator (ly, top_cell, li), dss);
|
||||
|
||||
r.set_merged_semantics (false);
|
||||
r.snap (19, 19);
|
||||
|
||||
ly.clear_layer (li);
|
||||
r.insert_into (&ly, top_cell_index, li);
|
||||
|
||||
}
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au400a.gds");
|
||||
}
|
||||
|
||||
TEST(issue_400_dont_keep_regions)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/gds/t10.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
for (db::Layout::layer_iterator l = ly.begin_layers (); l != ly.end_layers (); ++l) {
|
||||
|
||||
unsigned int li = (*l).first;
|
||||
db::Region r (db::RecursiveShapeIterator (ly, top_cell, li), dss);
|
||||
|
||||
r.set_merged_semantics (false);
|
||||
r.snap (19, 19);
|
||||
|
||||
ly.clear_layer (li);
|
||||
r.insert_into (&ly, top_cell_index, li);
|
||||
|
||||
}
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au400b.gds");
|
||||
}
|
||||
|
||||
TEST(issue_400_with_region)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/gds/t10.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::DBox rbox (2.61, -1.6, 12.76, 4.7);
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
for (db::Layout::layer_iterator l = ly.begin_layers (); l != ly.end_layers (); ++l) {
|
||||
|
||||
unsigned int li = (*l).first;
|
||||
db::Region r (db::RecursiveShapeIterator (ly, top_cell, li, rbox.transformed (db::CplxTrans (ly.dbu ()).inverted ())), dss);
|
||||
|
||||
r.set_merged_semantics (false);
|
||||
r.snap (19, 19);
|
||||
|
||||
ly.clear_layer (li);
|
||||
r.insert_into (&ly, top_cell_index, li);
|
||||
|
||||
}
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au400c.gds");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -615,3 +615,41 @@ TEST(16)
|
|||
|
||||
}
|
||||
|
||||
TEST(17_scale_and_snap)
|
||||
{
|
||||
db::Layout l1;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (l1);
|
||||
}
|
||||
|
||||
db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 1, 20, 19);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, l1, tl::testsrc () + "/testdata/algo/layout_utils_au_sns1.gds");
|
||||
|
||||
db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 1, 19, 20);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, l1, tl::testsrc () + "/testdata/algo/layout_utils_au_sns2.gds");
|
||||
}
|
||||
|
||||
TEST(18_scale_and_snap)
|
||||
{
|
||||
db::Layout l1;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (l1);
|
||||
}
|
||||
|
||||
db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 19, 1, 1);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, l1, tl::testsrc () + "/testdata/algo/layout_utils_au_sns3.gds");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@
|
|||
#include "dbRegionProcessors.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbReader.h"
|
||||
#include "dbTestSupport.h"
|
||||
|
||||
#include "tlStream.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
|
|
@ -1391,6 +1395,106 @@ TEST(31)
|
|||
EXPECT_EQ (db::Region (db::Box (db::Point (0, 3999), db::Point (1001, 6000))).pull_overlapping (r).to_string (), "(1000,0;1000,4000;6000,4000;6000,0)");
|
||||
}
|
||||
|
||||
TEST(32a_snap)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1));
|
||||
r1.set_merged_semantics (false);
|
||||
db::Region r2 = r1.snapped (19, 19);
|
||||
|
||||
r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0)));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au32.gds");
|
||||
}
|
||||
|
||||
TEST(32b_snap)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1));
|
||||
r1.set_merged_semantics (false);
|
||||
r1.snap (19, 19);
|
||||
|
||||
r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0)));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au32.gds");
|
||||
}
|
||||
|
||||
TEST(33a_snap)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1));
|
||||
r1.set_merged_semantics (false);
|
||||
db::Region r2 = r1.scaled_and_snapped (19, 2, 10, 19, 2, 10);
|
||||
|
||||
r2.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0)));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au33.gds");
|
||||
}
|
||||
|
||||
TEST(33b_snap)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/scale_and_snap.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1));
|
||||
r1.set_merged_semantics (false);
|
||||
r1.scale_and_snap (19, 2, 10, 19, 2, 10);
|
||||
|
||||
r1.insert_into (&ly, top_cell_index, ly.get_layer (db::LayerProperties (100, 0)));
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au33.gds");
|
||||
}
|
||||
|
||||
TEST(100_Processors)
|
||||
{
|
||||
db::Region r;
|
||||
|
|
|
|||
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.
Loading…
Reference in New Issue