Bug fixes, enhancements, tests for snap and scale improvements.

This commit is contained in:
Matthias Koefferlein 2022-02-18 14:22:16 +01:00
parent e9d86822df
commit 834dfa6614
9 changed files with 300 additions and 103 deletions

View File

@ -511,19 +511,52 @@ VariantsCollectorBase::create_var_instances_non_tl_invariant (db::Cell &in_cell,
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> >::const_iterator f = var_table.find (i->object ().cell_index ());
if (f == var_table.end ()) {
in_cell.insert (*i);
in_cell.insert (*i);
} else {
const std::map<db::ICplxTrans, db::cell_index_type> &vt = f->second;
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
bool need_explode = false;
bool first = true;
db::cell_index_type ci = 0;
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end () && ! need_explode; ++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 ());
in_cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (v->second), i->complex_trans (*ia)), i->properties_id ()));
if (first) {
ci = v->second;
first = false;
} else {
need_explode = (ci != v->second);
}
}
if (need_explode) {
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++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 ());
in_cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (v->second), i->complex_trans (*ia)), i->properties_id ()));
}
} else if (ci != i->object ().cell_index ()) {
db::CellInstArray new_array = *i;
new_array.object () = db::CellInst (ci);
in_cell.insert (db::CellInstArrayWithProperties (new_array, i->properties_id ()));
} else {
in_cell.insert (*i);
}

View File

@ -287,6 +287,32 @@ private:
db::Coord m_tolerance;
};
/**
* @brief A fuzzy compare operator for edge pairs
* Compares two edge pair objects applying a tolerance between them. The tolerance is the allowed deviation
* of points in database units.
*/
struct EdgePairCompareOpWithTolerance
{
EdgePairCompareOpWithTolerance (db::Coord tolerance)
: m_ec (tolerance)
{ }
bool operator() (const db::EdgePair &a, const db::EdgePair &b) const
{
if (m_ec (a.first (), b.first ())) {
return true;
} else if (m_ec (b.first (), a.first ())) {
return false;
} else {
return m_ec (a.second (), b.second ());
}
}
private:
EdgeCompareOpWithTolerance m_ec;
};
/**
* @brief A fuzzy compare operator for boxes
* Compares two box objects applying a tolerance between them. The tolerance is the allowed deviation
@ -492,6 +518,12 @@ make_edge_compare_func (db::Coord tolerance)
return pair_compare_func<db::Edge, db::properties_id_type, EdgeCompareOpWithTolerance, std_compare_func<db::properties_id_type> > (EdgeCompareOpWithTolerance (tolerance), std_compare_func<db::properties_id_type> ());
}
pair_compare_func<db::EdgePair, db::properties_id_type, EdgePairCompareOpWithTolerance, std_compare_func<db::properties_id_type> >
make_edge_pair_compare_func (db::Coord tolerance)
{
return pair_compare_func<db::EdgePair, db::properties_id_type, EdgePairCompareOpWithTolerance, std_compare_func<db::properties_id_type> > (EdgePairCompareOpWithTolerance (tolerance), std_compare_func<db::properties_id_type> ());
}
pair_compare_func<db::Box, db::properties_id_type, BoxCompareOpWithTolerance, std_compare_func<db::properties_id_type> >
make_box_compare_func (db::Coord tolerance)
{
@ -540,6 +572,21 @@ collect_edges (const db::Layout & /*l*/, const db::Cell *c, unsigned int layer,
}
}
static void
collect_edge_pairs (const db::Layout & /*l*/, const db::Cell *c, unsigned int layer, unsigned int flags, std::vector< std::pair<db::EdgePair, db::properties_id_type> > &shapes, PropertyMapper &pn)
{
shapes.clear ();
for (db::ShapeIterator s = c->shapes (layer).begin (db::ShapeIterator::EdgePairs); !s.at_end (); ++s) {
db::properties_id_type prop_id = 0;
if (! (flags & layout_diff::f_no_properties)) {
prop_id = pn (s->prop_id ());
}
shapes.push_back (std::make_pair (db::EdgePair (), prop_id));
s->edge_pair (shapes.back ().first);
}
}
static void
collect_boxes (const db::Layout &, const db::Cell *c, unsigned int layer, unsigned int flags, std::vector< std::pair<db::Box, db::properties_id_type> > &shapes, PropertyMapper &pn)
{
@ -828,6 +875,8 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
std::vector <std::pair <db::Box, db::properties_id_type> > boxes_b;
std::vector <std::pair <db::Edge, db::properties_id_type> > edges_a;
std::vector <std::pair <db::Edge, db::properties_id_type> > edges_b;
std::vector <std::pair <db::EdgePair, db::properties_id_type> > edge_pairs_a;
std::vector <std::pair <db::EdgePair, db::properties_id_type> > edge_pairs_b;
for (unsigned int cci = 0; cci < common_cells.size (); ++cci) {
@ -1053,6 +1102,31 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
r.end_edge_differences ();
}
// compare edge pairs
edge_pairs_a.clear();
edge_pairs_b.clear();
if (is_valid_a) {
collect_edge_pairs (a, cell_a, layer_a, flags, edge_pairs_a, prop_normalize_a);
}
if (is_valid_b) {
collect_edge_pairs (b, cell_b, layer_b, flags, edge_pairs_b, prop_normalize_b);
}
reduce (edge_pairs_a, edge_pairs_b, make_edge_pair_compare_func (tolerance), tolerance > 0);
if (!edge_pairs_a.empty () || !edge_pairs_b.empty ()) {
differs = true;
if (flags & layout_diff::f_silent) {
return false;
}
r.begin_edge_pair_differences ();
if (verbose) {
r.detailed_diff (n.properties_repository (), edge_pairs_a, edge_pairs_b);
}
r.end_edge_pair_differences ();
}
r.end_layer ();
}
@ -1130,6 +1204,9 @@ public:
void begin_edge_differences ();
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Edge, db::properties_id_type> > &a, const std::vector <std::pair <db::Edge, db::properties_id_type> > &b);
void end_edge_differences ();
void begin_edge_pair_differences ();
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b);
void end_edge_pair_differences ();
void begin_text_differences ();
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Text, db::properties_id_type> > &a, const std::vector <std::pair <db::Text, db::properties_id_type> > &b);
void end_text_differences ();
@ -1525,6 +1602,34 @@ PrintingDifferenceReceiver::end_edge_differences ()
{
}
void
PrintingDifferenceReceiver::begin_edge_pair_differences ()
{
try {
enough (tl::error) << "Edge pairs differ for layer " << m_layer.to_string () << " in cell " << m_cellname;
} catch (tl::CancelException &) {
// ignore cancel exceptions
}
}
void
PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b)
{
try {
enough (tl::info) << "Not in b but in a:";
print_diffs (pr, a, b);
enough (tl::info) << "Not in a but in b:";
print_diffs (pr, b, a);
} catch (tl::CancelException &) {
// ignore cancel exceptions
}
}
void
PrintingDifferenceReceiver::end_edge_pair_differences ()
{
}
void
PrintingDifferenceReceiver::begin_text_differences ()
{

View File

@ -119,6 +119,9 @@ public:
virtual void begin_edge_differences () { }
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::Edge, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::Edge, db::properties_id_type> > & /*b*/) { }
virtual void end_edge_differences () { }
virtual void begin_edge_pair_differences () { }
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > & /*b*/) { }
virtual void end_edge_pair_differences () { }
virtual void begin_text_differences () { }
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::Text, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::Text, db::properties_id_type> > & /*b*/) { }
virtual void end_text_differences () { }

View File

@ -507,9 +507,6 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
std::vector<db::Point> heap;
std::vector<db::Vector> iterated_array_vectors;
std::vector<db::CellInstArrayWithProperties> new_insts_with_props;
std::vector<db::CellInstArray> new_insts;
std::vector<db::Instance> instances_to_replace;
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
@ -530,8 +527,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) {
db::Shapes &s = c->shapes ((*l).first);
// TODO: properties, edges, edge pairs
db::Shapes new_shapes;
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! si.at_end (); ++si) {
@ -541,7 +537,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
poly = scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap);
poly.transform (trinv);
s.replace (*si, poly);
if (si->is_box () && poly.is_box ()) {
new_shapes.insert (db::BoxWithProperties (poly.box (), si->prop_id ()));
} else {
new_shapes.insert (db::PolygonWithProperties (poly, si->prop_id ()));
}
}
@ -553,7 +553,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
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);
s.replace (*si, text);
new_shapes.insert (db::TextWithProperties (text, si->prop_id ()));
}
@ -565,7 +565,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
edge = scaled_and_snapped_edge (edge, g, m , d, tr_disp.x (), tr_disp.y ());
edge.transform (trinv);
s.replace (*si, edge);
new_shapes.insert (db::EdgeWithProperties (edge, si->prop_id ()));
}
@ -578,127 +578,56 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db
scaled_and_snapped_edge (edge_pair.second (), g, m , d, tr_disp.x (), tr_disp.y ()));
edge_pair.transform (trinv);
s.replace (*si, edge_pair);
new_shapes.insert (db::EdgePairWithProperties (edge_pair, si->prop_id ()));
}
s.swap (new_shapes);
}
// 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.
new_insts.clear ();
new_insts_with_props.clear ();
instances_to_replace.clear ();
// The variant formation also made sure the iterated and regular arrays are exploded where required.
for (db::Cell::const_iterator inst = c->begin (); ! inst.at_end (); ++inst) {
const db::CellInstArray &ia = inst->cell_inst ();
// shortcut if we do not need to explode the array
iterated_array_vectors.clear ();
db::Vector a, b;
unsigned long na, nb;
bool need_explode = false;
db::CellInstArray new_array (ia);
if (tr.is_complex ()) {
if (ia.is_iterated_array (&iterated_array_vectors)) {
need_explode = ia.size () > 1;
} else if (ia.is_iterated_array (&iterated_array_vectors)) {
for (std::vector<db::Vector>::const_iterator i = iterated_array_vectors.begin (); ! need_explode && i != iterated_array_vectors.end (); ++i) {
need_explode = ! is_on_grid (*i, g, m, d);
bool needs_update = false;
for (std::vector<db::Vector>::iterator i = iterated_array_vectors.begin (); i != iterated_array_vectors.end (); ++i) {
db::Vector v = scaled_and_snapped_vector (*i, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
if (v != *i) {
needs_update = true;
*i = v;
}
}
if (! need_explode) {
bool needs_update = false;
for (std::vector<db::Vector>::iterator i = iterated_array_vectors.begin (); ! need_explode && i != iterated_array_vectors.end (); ++i) {
db::Vector v = scaled_and_snapped_vector (*i, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
if (v != *i) {
needs_update = true;
*i = v;
}
}
if (needs_update) {
if (ia.is_complex ()) {
new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), iterated_array_vectors.begin (), iterated_array_vectors.end ());
} else {
new_array = db::CellInstArray (ia.object (), ia.front (), iterated_array_vectors.begin (), iterated_array_vectors.end ());
}
}
if (needs_update) {
new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), iterated_array_vectors.begin (), iterated_array_vectors.end ());
}
} else if (ia.is_regular_array (a, b, na, nb)) {
need_explode = (na > 1 && ! is_on_grid (a, g, m, d)) && (nb > 1 && ! is_on_grid (b, g, m, d));
a = scaled_and_snapped_vector (a, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
b = scaled_and_snapped_vector (b, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
if (! need_explode) {
a = scaled_and_snapped_vector (a, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
b = scaled_and_snapped_vector (b, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ());
if (ia.is_complex ()) {
new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), a, b, na, nb);
} else {
new_array = db::CellInstArray (ia.object (), ia.front (), a, b, na, nb);
}
}
new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), a, b, na, nb);
}
if (! need_explode) {
scale_and_snap_cell_instance (new_array, tr, trinv, tr_disp, g, m, d);
c->replace (*inst, new_array);
scale_and_snap_cell_instance (new_array, tr, trinv, tr_disp, g, m, d);
c->replace (*inst, new_array);
} else {
instances_to_replace.push_back (*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);
db::CellInstArray new_array;
if (ia.is_complex ()) {
new_array = db::CellInstArray (ia.object (), ia.complex_trans (ti));
} else {
new_array = db::CellInstArray (ia.object (), ti);
}
if (inst->prop_id () > 0) {
new_insts_with_props.push_back (db::CellInstArrayWithProperties (new_array, inst->prop_id ()));
} else {
new_insts.push_back (new_array);
}
}
}
}
c->erase_insts (instances_to_replace);
for (std::vector<db::CellInstArray>::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) {
c->insert (*i);
}
for (std::vector<db::CellInstArrayWithProperties>::const_iterator i = new_insts_with_props.begin (); i != new_insts_with_props.end (); ++i) {
c->insert (*i);
}
}

View File

@ -138,7 +138,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std::
equal = db::compare_layouts (*subject, layout_au,
(n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose)
| ((norm & AsPolygons) != 0 ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0)
| db::layout_diff::f_flatten_array_insts
| ((norm & WithArrays) != 0 ? 0 : db::layout_diff::f_flatten_array_insts)
/*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/
, tolerance, 100 /*max diff lines*/);
if (equal && n > 0) {

View File

@ -56,7 +56,8 @@ enum NormalizationMode
WriteOAS = 2, // normalize subject by writing to OASIS and reading back
NormFileMask = 7, // bits the extract for file mode
NoContext = 8, // write tmp file without context
AsPolygons = 16 // paths and boxes are treated as polygons
AsPolygons = 16, // paths and boxes are treated as polygons
WithArrays = 32 // do not flatten arrays
};
/**

View File

@ -25,6 +25,8 @@
#include "dbCellMapping.h"
#include "dbTestSupport.h"
#include "dbReader.h"
#include "dbLayoutDiff.h"
#include "dbPropertiesRepository.h"
#include "tlString.h"
#include "tlUnitTest.h"
@ -653,3 +655,127 @@ TEST(18_scale_and_snap)
CHECKPOINT();
db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns3.gds");
}
TEST(19_scale_and_snap_basic)
{
db::Layout l1;
db::Layout l2;
db::PropertiesRepository::properties_set ps1;
ps1.insert (std::make_pair (l1.properties_repository ().prop_name_id (tl::Variant ("p")), tl::Variant (17)));
db::properties_id_type pid1 = l1.properties_repository ().properties_id (ps1);
db::PropertiesRepository::properties_set ps2;
ps2.insert (std::make_pair (l2.properties_repository ().prop_name_id (tl::Variant ("p")), tl::Variant (17)));
db::properties_id_type pid2 = l2.properties_repository ().properties_id (ps2);
db::Cell &top1 = l1.cell (l1.add_cell ("TOP"));
db::Cell &top2 = l2.cell (l2.add_cell ("TOP"));
db::Cell &a1 = l1.cell (l1.add_cell ("A"));
db::Cell &a2a = l2.cell (l2.add_cell ("A"));
unsigned int layer1 = l1.insert_layer (db::LayerProperties (1, 0));
unsigned int layer2 = l2.insert_layer (db::LayerProperties (1, 0));
a1.shapes (layer1).insert (db::Box (0, 0, 100, 100));
a2a.shapes (layer2).insert (db::Box (0, 0, 100, 100));
top1.shapes (layer1).insert (db::Box (11, 21, 31, 41));
top2.shapes (layer2).insert (db::Box (10, 20, 30, 40));
top1.shapes (layer1).insert (db::BoxWithProperties (db::Box (11, 21, 31, 41), pid1));
top2.shapes (layer2).insert (db::BoxWithProperties (db::Box (10, 20, 30, 40), pid2));
top1.shapes (layer1).insert (db::Edge (11, 21, 31, 41));
top2.shapes (layer2).insert (db::Edge (10, 20, 30, 40));
top1.shapes (layer1).insert (db::EdgeWithProperties (db::Edge (11, 21, 31, 41), pid1));
top2.shapes (layer2).insert (db::EdgeWithProperties (db::Edge (10, 20, 30, 40), pid2));
top1.shapes (layer1).insert (db::EdgePair (db::Edge (11, 21, 31, 41), db::Edge (111, 121, 131, 141)));
top2.shapes (layer2).insert (db::EdgePair (db::Edge (10, 20, 30, 40), db::Edge (110, 120, 130, 140)));
top1.shapes (layer1).insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (11, 21, 31, 41), db::Edge (111, 121, 131, 141)), pid1));
top2.shapes (layer2).insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (10, 20, 30, 40), db::Edge (110, 120, 130, 140)), pid2));
top1.shapes (layer1).insert (db::Polygon (db::Box (11, 21, 31, 41)));
top2.shapes (layer2).insert (db::Polygon (db::Box (10, 20, 30, 40)));
top1.shapes (layer1).insert (db::PolygonWithProperties (db::Polygon (db::Box (11, 21, 31, 41)), pid1));
top2.shapes (layer2).insert (db::PolygonWithProperties (db::Polygon (db::Box (10, 20, 30, 40)), pid2));
db::Point pts1[] = {
db::Point (1, 101),
db::Point (101, 101),
db::Point (101, 201)
};
db::Point pts2[] = {
db::Point (0, 100),
db::Point (100, 100),
db::Point (100, 200)
};
top1.shapes (layer1).insert (db::Path (&pts1 [0], &pts1 [sizeof (pts1) / sizeof(pts1 [0])], 20));
top2.shapes (layer2).insert (db::Path (&pts2 [0], &pts2 [sizeof (pts2) / sizeof(pts2 [0])], 20));
top1.shapes (layer1).insert (db::PathWithProperties (db::Path (&pts1 [0], &pts1 [sizeof (pts1) / sizeof(pts1 [0])], 20), pid1));
top2.shapes (layer2).insert (db::PathWithProperties (db::Path (&pts2 [0], &pts2 [sizeof (pts2) / sizeof(pts2 [0])], 20), pid2));
top1.shapes (layer1).insert (db::Text ("t1", db::Trans (db::Vector (11, 21))));
top2.shapes (layer2).insert (db::Text ("t1", db::Trans (db::Vector (10, 20))));
top1.shapes (layer1).insert (db::TextWithProperties (db::Text ("t1", db::Trans (db::Vector (11, 21))), pid1));
top2.shapes (layer2).insert (db::TextWithProperties (db::Text ("t1", db::Trans (db::Vector (10, 20))), pid2));
top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21))));
top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20))));
top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21))), pid1));
top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20))), pid2));
top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), db::Vector (0, 10), db::Vector (10, 0), 2, 3));
top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), db::Vector (0, 10), db::Vector (10, 0), 2, 3));
top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), db::Vector (0, 10), db::Vector (10, 0), 2, 3), pid1));
top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), db::Vector (0, 10), db::Vector (10, 0), 2, 3), pid2));
std::vector<db::Vector> ia;
ia.push_back (db::Vector (0, 0));
ia.push_back (db::Vector (10, 0));
ia.push_back (db::Vector (0, 10));
top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), ia.begin (), ia.end ()));
top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), ia.begin (), ia.end ()));
top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), ia.begin (), ia.end ()), pid1));
top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), ia.begin (), ia.end ()), pid2));
db::scale_and_snap (l1, top1, 10, 1, 1);
bool equal = db::compare_layouts (l1, l2,
db::layout_diff::f_verbose
| db::layout_diff::f_boxes_as_polygons
| db::layout_diff::f_paths_as_polygons
, 0, 100 /*max diff lines*/);
EXPECT_EQ (equal, true);
}
TEST(20_scale_and_snap)
{
db::Layout l1;
{
std::string fn (tl::testdata ());
fn += "/algo/scale_and_snap4.oas";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (l1);
}
db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 10, 95, 100);
CHECKPOINT();
db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns4.oas", db::NormalizationMode (db::WriteOAS + db::WithArrays));
}

BIN
testdata/algo/layout_utils_au_sns4.oas vendored Normal file

Binary file not shown.

BIN
testdata/algo/scale_and_snap4.oas vendored Normal file

Binary file not shown.