From 7f8eeb3a09b099ea5145093d3e7c5c2e370dcf6a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 10 Jun 2023 09:06:56 +0200 Subject: [PATCH] Fixed issue #1281 (Layout diff should ignore shape or instance duplicates) A new option in the diff tool and strmcmp has been added (-1|--ignore-duplicates in strcmp). In RBA/pya, the "IgnoreDuplicates" flag has been added. --- src/buddies/src/bd/strmcmp.cc | 8 + src/db/db/dbLayoutDiff.cc | 81 +++++-- src/db/db/dbLayoutDiff.h | 5 +- src/db/unit_tests/dbLayoutDiffTests.cc | 211 +++++++++++++++++- .../tools/diff/lay_plugin/DiffToolDialog.ui | 138 ++++++------ .../diff/lay_plugin/layDiffToolDialog.cc | 9 + 6 files changed, 360 insertions(+), 92 deletions(-) diff --git a/src/buddies/src/bd/strmcmp.cc b/src/buddies/src/bd/strmcmp.cc index 637baaab0..aefcefe6f 100644 --- a/src/buddies/src/bd/strmcmp.cc +++ b/src/buddies/src/bd/strmcmp.cc @@ -41,6 +41,7 @@ BD_PUBLIC int strmcmp (int argc, char *argv[]) std::string infile_a, infile_b; std::string top_a, top_b; bool silent = false; + bool ignore_duplicates = false; bool no_text_orientation = true; bool no_text_details = true; bool no_properties = false; @@ -106,6 +107,10 @@ BD_PUBLIC int strmcmp (int argc, char *argv[]) << tl::arg ("--expand-arrays", &flatten_array_insts, "Expands array instances before compare", "With this option, arrays are equivalent single instances are treated identical." ) + << tl::arg ("-1|--ignore-duplicates", &ignore_duplicates, "Ignore duplicate instances and shapes", + "With this option, duplicate instances or shapes are ignored and duplication " + "does not count as a difference." + ) << tl::arg ("-l|--layer-details", &dont_summarize_missing_layers, "Prints details about differences for missing layers", "With this option, missing layers are treated as \"empty\" and details about differences to " "other, non-empty layers are printed. Essentially the content of the non-empty counterpart " @@ -155,6 +160,9 @@ BD_PUBLIC int strmcmp (int argc, char *argv[]) if (silent) { flags |= db::layout_diff::f_silent; } + if (ignore_duplicates) { + flags |= db::layout_diff::f_ignore_duplicates; + } if (no_text_orientation) { flags |= db::layout_diff::f_no_text_orientation; } diff --git a/src/db/db/dbLayoutDiff.cc b/src/db/db/dbLayoutDiff.cc index d52ec900e..be1e005e7 100644 --- a/src/db/db/dbLayoutDiff.cc +++ b/src/db/db/dbLayoutDiff.cc @@ -69,8 +69,10 @@ collect_cells (const db::Layout &l, const db::Cell *top, std::map &cci, std::vector &insts) +collect_insts_of_unmapped_cells (const db::Layout & /*l*/, const db::Cell *cell, unsigned int /*flags*/, const std::map &cci, std::vector &insts, bool no_duplicates) { + size_t n_before = insts.size (); + for (db::Cell::const_iterator i = cell->begin (); !i.at_end (); ++i) { std::map ::const_iterator ccii = cci.find (i->cell_index ()); @@ -81,6 +83,13 @@ collect_insts_of_unmapped_cells (const db::Layout & /*l*/, const db::Cell *cell, } } + + if (no_duplicates) { + + std::sort (insts.begin () + n_before, insts.end ()); + insts.erase (std::unique (insts.begin () + n_before, insts.end ()), insts.end ()); + + } } static void @@ -102,7 +111,7 @@ rewrite_instances_to (std::vector &insts, unsi } static void -collect_insts (const db::Layout & /*l*/, const db::Cell *cell, unsigned int flags, const std::map &cci, std::vector &insts, PropertyMapper &pn) +collect_insts (const db::Layout & /*l*/, const db::Cell *cell, unsigned int flags, const std::map &cci, std::vector &insts, PropertyMapper &pn, bool no_duplicates) { insts.clear (); @@ -148,6 +157,10 @@ collect_insts (const db::Layout & /*l*/, const db::Cell *cell, unsigned int flag } std::sort (insts.begin (), insts.end ()); + + if (no_duplicates) { + insts.erase (std::unique (insts.begin (), insts.end ()), insts.end ()); + } } /** @@ -178,10 +191,10 @@ int compare_seq (I b1, I e1, I b2, I e2, Op op) /** * @brief Reduces two vectors to the common objects as determined by the compare operator * If the iterate parameter is true, the reduction is repeated until no more reduction can be - * achieved. This is useful with tolerances since the sorted is not strict in that case. + * achieved. This is useful with tolerances since the sorting is not strict in that case. */ template -void reduce (std::vector &a, std::vector &b, Op op, bool iterate) +void reduce (std::vector &a, std::vector &b, Op op, bool iterate, bool no_duplicates) { do { @@ -196,12 +209,29 @@ void reduce (std::vector &a, std::vector &b, Op op, bool iterate) while (ra != a.end () && rb != b.end ()) { if (op (*ra, *rb)) { - *wa++ = *ra++; + typename std::vector::const_iterator r = ra++; + *wa = *r; + while (no_duplicates && ra != a.end () && !op (*ra, *r) && !op(*r, *ra)) { + ++ra; + } + ++wa; } else if (op (*rb, *ra)) { - *wb++ = *rb++; + typename std::vector::const_iterator r = rb++; + *wb = *r; + while (no_duplicates && rb != b.end () && !op (*rb, *r) && !op(*r, *rb)) { + ++rb; + } + ++wb; } else { - ++ra; - ++rb; + typename std::vector::const_iterator r; + r = ra++; + while (no_duplicates && ra != a.end () && !op (*ra, *r) && !op(*r, *ra)) { + ++ra; + } + r = rb++; + while (no_duplicates && rb != b.end () && !op (*rb, *r) && !op(*r, *rb)) { + ++rb; + } } } @@ -211,14 +241,22 @@ void reduce (std::vector &a, std::vector &b, Op op, bool iterate) if (ra != wa) { while (ra != a.end ()) { - *wa++ = *ra++; + typename std::vector::const_iterator r = ra++; + *wa++ = *r; + while (no_duplicates && ra != a.end () && !op (*ra, *r) && !op(*r, *ra)) { + ++ra; + } } a.erase (wa, a.end ()); } if (rb != wb) { while (rb != b.end ()) { - *wb++ = *rb++; + typename std::vector::const_iterator r = rb++; + *wb++ = *r; + while (no_duplicates && rb != b.end () && !op (*rb, *r) && !op(*r, *rb)) { + ++rb; + } } b.erase (wb, b.end ()); } @@ -405,7 +443,7 @@ struct PolygonCompareOpWithTolerance m_eb.push_back (*e); } - reduce (m_ea, m_eb, EdgeCompareOpWithTolerance (m_tolerance), m_tolerance > 0); + reduce (m_ea, m_eb, EdgeCompareOpWithTolerance (m_tolerance), m_tolerance > 0, false); return compare_seq (m_ea.begin (), m_ea.end (), m_eb.begin (), m_eb.end (), EdgeCompareOpWithTolerance (m_tolerance)) < 0; } @@ -665,6 +703,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout } bool verbose = (flags & layout_diff::f_verbose); + bool no_duplicates = (flags & layout_diff::f_ignore_duplicates); db::Layout n, na, nb; na.properties_repository () = a.properties_repository (); @@ -897,20 +936,20 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout r.bbox_differs (cell_a->bbox (), cell_b->bbox ()); } - collect_insts (a, cell_a, flags, common_cell_indices_a, insts_a, prop_normalize_a); - collect_insts (b, cell_b, flags, common_cell_indices_b, insts_b, prop_normalize_b); + collect_insts (a, cell_a, flags, common_cell_indices_a, insts_a, prop_normalize_a, no_duplicates); + collect_insts (b, cell_b, flags, common_cell_indices_b, insts_b, prop_normalize_b, no_duplicates); std::vector anotb; std::set_difference (insts_a.begin (), insts_a.end (), insts_b.begin (), insts_b.end (), std::back_inserter (anotb)); rewrite_instances_to (anotb, flags, common_cells_a, prop_remap_to_a); - collect_insts_of_unmapped_cells (a, cell_a, flags, common_cell_indices_a, anotb); + collect_insts_of_unmapped_cells (a, cell_a, flags, common_cell_indices_a, anotb, no_duplicates); std::vector bnota; std::set_difference (insts_b.begin (), insts_b.end (), insts_a.begin (), insts_a.end (), std::back_inserter (bnota)); rewrite_instances_to (bnota, flags, common_cells_b, prop_remap_to_b); - collect_insts_of_unmapped_cells (b, cell_b, flags, common_cell_indices_b, bnota); + collect_insts_of_unmapped_cells (b, cell_b, flags, common_cell_indices_b, bnota, no_duplicates); if (! anotb.empty () || ! bnota.empty ()) { @@ -979,7 +1018,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout collect_polygons (b, cell_b, layer_b, flags, polygons_b, prop_normalize_b); } - reduce (polygons_a, polygons_b, make_polygon_compare_func (tolerance), tolerance > 0); + reduce (polygons_a, polygons_b, make_polygon_compare_func (tolerance), tolerance > 0, no_duplicates); if (!polygons_a.empty () || !polygons_b.empty ()) { differs = true; @@ -1007,7 +1046,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout collect_paths (b, cell_b, layer_b, flags, paths_b, prop_normalize_b); } - reduce (paths_a, paths_b, make_path_compare_func (tolerance), tolerance > 0); + reduce (paths_a, paths_b, make_path_compare_func (tolerance), tolerance > 0, no_duplicates); if (!paths_a.empty () || !paths_b.empty ()) { differs = true; @@ -1034,7 +1073,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout collect_texts (b, cell_b, layer_b, flags, texts_b, prop_normalize_b); } - reduce (texts_a, texts_b, make_text_compare_func (tolerance), tolerance > 0); + reduce (texts_a, texts_b, make_text_compare_func (tolerance), tolerance > 0, no_duplicates); if (!texts_a.empty () || !texts_b.empty ()) { differs = true; @@ -1061,7 +1100,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout collect_boxes (b, cell_b, layer_b, flags, boxes_b, prop_normalize_b); } - reduce (boxes_a, boxes_b, make_box_compare_func (tolerance), tolerance > 0); + reduce (boxes_a, boxes_b, make_box_compare_func (tolerance), tolerance > 0, no_duplicates); if (!boxes_a.empty () || !boxes_b.empty ()) { differs = true; @@ -1088,7 +1127,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout collect_edges (b, cell_b, layer_b, flags, edges_b, prop_normalize_b); } - reduce (edges_a, edges_b, make_edge_compare_func (tolerance), tolerance > 0); + reduce (edges_a, edges_b, make_edge_compare_func (tolerance), tolerance > 0, no_duplicates); if (!edges_a.empty () || !edges_b.empty ()) { differs = true; @@ -1113,7 +1152,7 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout 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); + reduce (edge_pairs_a, edge_pairs_b, make_edge_pair_compare_func (tolerance), tolerance > 0, no_duplicates); if (!edge_pairs_a.empty () || !edge_pairs_b.empty ()) { differs = true; diff --git a/src/db/db/dbLayoutDiff.h b/src/db/db/dbLayoutDiff.h index 865883af1..56f0114b6 100644 --- a/src/db/db/dbLayoutDiff.h +++ b/src/db/db/dbLayoutDiff.h @@ -74,12 +74,15 @@ const unsigned int f_paths_as_polygons = 0x100; // Derive smart cell mapping instead of name mapping (available only if top cells are specified) const unsigned int f_smart_cell_mapping = 0x200; -// Don't summarize missing layers +// Don't summarize missing layers - print them in detail const unsigned int f_dont_summarize_missing_layers = 0x400; // Ignore text details (font, size, presentation) const unsigned int f_no_text_details = 0x800; +// Ignore duplicate instances or shapes +const unsigned int f_ignore_duplicates = 0x1000; + } /** diff --git a/src/db/unit_tests/dbLayoutDiffTests.cc b/src/db/unit_tests/dbLayoutDiffTests.cc index 011d2be8d..739b9a77d 100644 --- a/src/db/unit_tests/dbLayoutDiffTests.cc +++ b/src/db/unit_tests/dbLayoutDiffTests.cc @@ -105,6 +105,8 @@ TestDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperties & } if (ci.properties_id () != 0) { m_os << " [" << ci.properties_id () << "]" << std::endl; + } else { + m_os << "" << std::endl; } } @@ -489,7 +491,9 @@ TEST(1) " c4 m45 *1 -10,20\n" " c4 m45 *1 -10,20\n" "Not in b but in a:\n" - " c5x r0 *1 10,-20 c5x m45 *1 -10,20Not in a but in b:\n" + " c5x r0 *1 10,-20\n" + " c5x m45 *1 -10,20\n" + "Not in a but in b:\n" ); g = h; @@ -951,7 +955,7 @@ TEST(3) c2h.shapes (0).insert (db::Polygon (db::Box (1, 2, 1003, 1006))); r.clear (); - eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 0, r); + eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 0, r); EXPECT_EQ (eq, false); EXPECT_EQ (r.text (), @@ -965,7 +969,7 @@ TEST(3) ); r.clear (); - eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 1, r); + eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 1, r); EXPECT_EQ (eq, false); EXPECT_EQ (r.text (), @@ -1499,4 +1503,205 @@ TEST(7) EXPECT_EQ (r.text (), ""); } +TEST(8) +{ + db::Layout g; + g.insert_layer (0); + g.set_properties (0, db::LayerProperties (17, 0)); + g.insert_layer (1); + g.set_properties (1, db::LayerProperties (42, 1)); + + db::cell_index_type c1i = g.add_cell ("c1"); + db::cell_index_type c2i = g.add_cell ("c2x"); + db::cell_index_type c3i = g.add_cell ("c3"); + db::cell_index_type c4i = g.add_cell ("c4"); + db::cell_index_type c5i = g.add_cell ("c5x"); + + { + + db::Cell &c1 (g.cell (c1i)); + db::Cell &c2 (g.cell (c2i)); + db::Cell &c3 (g.cell (c3i)); + db::Cell &c4 (g.cell (c4i)); + db::Cell &c5 (g.cell (c5i)); + c2.shapes (0).insert (db::Box (0, 1, 2, 3)); + + db::FTrans f (1, true); + db::Vector p (-10, 20); + db::Trans t (f.rot (), p); + db::Vector pp (10, -20); + db::Trans tt (0, pp); + + // c4->c1 (aref) + c4.insert (db::array (db::CellInst (c1.cell_index ()), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3)); + // c5->c1 + c5.insert (db::array (db::CellInst (c1.cell_index ()), t)); + // c3->c5 (3x) + c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); + c3.insert (db::array (db::CellInst (c5.cell_index ()), tt)); + c3.insert (db::array (db::CellInst (c5.cell_index ()), t)); + // c4->c3 + c4.insert (db::array (db::CellInst (c3.cell_index ()), t)); + // c4->c1 + c4.insert (db::array (db::CellInst (c1.cell_index ()), tt)); + // c2->c1 (2x) + c2.insert (db::array (db::CellInst (c1.cell_index ()), t)); + c2.insert (db::array (db::CellInst (c1.cell_index ()), tt)); + // c2->c4 (2x) + c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); + c2.insert (db::array (db::CellInst (c4.cell_index ()), t)); + + } + + db::Layout h = g; + + TestDifferenceReceiver r; + bool eq; + + g.cell (c2i).shapes (0).insert (db::Box (1, 2, 1001, 1002)); + g.cell (c2i).shapes (0).insert (db::Box (2, 3, 1002, 1003)); + g.cell (c2i).shapes (0).insert (db::Box (2, 3, 1002, 1003)); + g.cell (c2i).shapes (0).insert (db::Box (3, 4, 1003, 1004)); + g.cell (c2i).shapes (0).insert (db::Box (3, 4, 1003, 1004)); + + h.cell (c2i).shapes (0).insert (db::Box (1, 2, 1001, 1002)); + h.cell (c2i).shapes (0).insert (db::Box (1, 2, 1001, 1002)); + h.cell (c2i).shapes (0).insert (db::Box (2, 3, 1002, 1003)); + h.cell (c2i).shapes (0).insert (db::Box (4, 5, 1004, 1005)); + h.cell (c2i).shapes (0).insert (db::Box (4, 5, 1004, 1005)); + + r.clear (); + eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 0, r); + + EXPECT_EQ (eq, false); + EXPECT_EQ (r.text (), + "layout_diff: boxes differ for layer 17/0 in cell c2x\n" + "Not in b but in a:\n" + " (2,3;1002,1003)\n" + " (3,4;1003,1004)\n" + " (3,4;1003,1004)\n" + "Not in a but in b:\n" + " (1,2;1001,1002)\n" + " (4,5;1004,1005)\n" + " (4,5;1004,1005)\n" + ); + + r.clear (); + eq = db::compare_layouts (g, h, db::layout_diff::f_verbose + db::layout_diff::f_ignore_duplicates, 0, r); + + EXPECT_EQ (eq, false); + EXPECT_EQ (r.text (), + "layout_diff: boxes differ for layer 17/0 in cell c2x\n" + "Not in b but in a:\n" + " (3,4;1003,1004)\n" + "Not in a but in b:\n" + " (4,5;1004,1005)\n" + ); + + // duplicate instances + { + db::FTrans f (1, true); + db::Vector p (-10, 20); + db::Trans t (f.rot (), p); + + h.cell(c4i).insert (db::array (db::CellInst (c1i), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3)); + h.cell(c4i).insert (db::array (db::CellInst (c1i), t)); + h.cell(c4i).insert (db::array (db::CellInst (c1i), t)); + + g.cell(c5i).insert (db::array (db::CellInst (c1i), t)); + g.cell(c5i).insert (db::array (db::CellInst (c1i), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3)); + g.cell(c5i).insert (db::array (db::CellInst (c1i), t, db::Vector(1, 1), db::Vector (0, 2), 2, 3)); + + db::cell_index_type c6i = g.add_cell ("c6"); + g.cell(c5i).insert (db::array (db::CellInst (c6i), t)); + g.cell(c5i).insert (db::array (db::CellInst (c6i), t)); + + } + + r.clear (); + eq = db::compare_layouts (g, h, db::layout_diff::f_verbose, 0, r); + + EXPECT_EQ (eq, false); + EXPECT_EQ (r.text (), + "layout_diff: cell c6 is not present in layout b, but in a\n" + "layout_diff: boxes differ for layer 17/0 in cell c2x\n" + "Not in b but in a:\n" + " (2,3;1002,1003)\n" + " (3,4;1003,1004)\n" + " (3,4;1003,1004)\n" + "Not in a but in b:\n" + " (1,2;1001,1002)\n" + " (4,5;1004,1005)\n" + " (4,5;1004,1005)\n" + "layout_diff: instances differ in cell c4\n" + "list for a:\n" + " c1 r0 *1 10,-20\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c3 m45 *1 -10,20\n" + "list for b:\n" + " c1 r0 *1 10,-20\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c3 m45 *1 -10,20\n" + "Not in b but in a:\n" + "Not in a but in b:\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + "layout_diff: instances differ in cell c5x\n" + "list for a:\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + "list for b:\n" + " c1 m45 *1 -10,20\n" + "Not in b but in a:\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c6 m45 *1 -10,20\n" + " c6 m45 *1 -10,20\n" + "Not in a but in b:\n" + ); + + r.clear (); + eq = db::compare_layouts (g, h, db::layout_diff::f_verbose + db::layout_diff::f_ignore_duplicates, 0, r); + + EXPECT_EQ (eq, false); + EXPECT_EQ (r.text (), + "layout_diff: cell c6 is not present in layout b, but in a\n" + "layout_diff: boxes differ for layer 17/0 in cell c2x\n" + "Not in b but in a:\n" + " (3,4;1003,1004)\n" + "Not in a but in b:\n" + " (4,5;1004,1005)\n" + "layout_diff: instances differ in cell c4\n" + "list for a:\n" + " c1 r0 *1 10,-20\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c3 m45 *1 -10,20\n" + "list for b:\n" + " c1 r0 *1 10,-20\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c3 m45 *1 -10,20\n" + "Not in b but in a:\n" + "Not in a but in b:\n" + " c1 m45 *1 -10,20\n" + "layout_diff: instances differ in cell c5x\n" + "list for a:\n" + " c1 m45 *1 -10,20\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + "list for b:\n" + " c1 m45 *1 -10,20\n" + "Not in b but in a:\n" + " c1 m45 *1 -10,20[a=1,1, b=0,2, na=2, nb=3]\n" + " c6 m45 *1 -10,20\n" + "Not in a but in b:\n" + ); +} + diff --git a/src/plugins/tools/diff/lay_plugin/DiffToolDialog.ui b/src/plugins/tools/diff/lay_plugin/DiffToolDialog.ui index a14df4d1a..1995401fc 100644 --- a/src/plugins/tools/diff/lay_plugin/DiffToolDialog.ui +++ b/src/plugins/tools/diff/lay_plugin/DiffToolDialog.ui @@ -1,76 +1,73 @@ - + + DiffToolDialog - - + + 0 0 - 498 + 503 404 - + Diff Tool - - - 9 - - + + 6 + + 9 + - - + + Input - - + + 9 - + 6 - - - + + + Layout A - - - + + + Layout B - - - - - 7 - 5 + + + + 0 0 - + QComboBox::AdjustToContentsOnFirstShow - - - - - 7 - 5 + + + + 0 0 - + QComboBox::AdjustToContentsOnFirstShow @@ -79,77 +76,84 @@ - - + + Options - - - 9 - - + + 6 + + 9 + - - + + Don't use names to match cells (use geometrical properties) - + true - - + + Run XOR on differences - - + + Summarize missing layers - + true - - + + Detailed information - + true - - + + Expand cell arrays (compare single instance by instance) - - + + Exact compare (includes properties, text orientation and similar) + + + + Ignore duplicate instances and shapes + + + - + Qt::Vertical - + 472 16 @@ -158,12 +162,12 @@ - - + + Qt::Horizontal - - QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok @@ -187,11 +191,11 @@ DiffToolDialog accept() - + 248 254 - + 157 274 @@ -203,11 +207,11 @@ DiffToolDialog reject() - + 316 260 - + 286 274 diff --git a/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc b/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc index 1285f72bb..5ae9dcafb 100644 --- a/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc +++ b/src/plugins/tools/diff/lay_plugin/layDiffToolDialog.cc @@ -46,6 +46,7 @@ std::string cfg_diff_smart ("diff-smart"); std::string cfg_diff_summarize ("diff-summarize"); std::string cfg_diff_expand_cell_arrays ("diff-expand-cell-arrays"); std::string cfg_diff_exact ("diff-exact"); +std::string cfg_diff_ignore_duplicates ("diff-ignore-duplicates"); // ------------------------------------------------------------------------------ // RdbDifferenceReceiver definition @@ -650,6 +651,9 @@ DiffToolDialog::exec_dialog (lay::LayoutViewBase *view) if (config_root->config_get (cfg_diff_exact, f)) { mp_ui->exact_cbx->setChecked (f); } + if (config_root->config_get (cfg_diff_ignore_duplicates, f)) { + mp_ui->ignore_duplicates_cbx->setChecked (f); + } update (); @@ -686,6 +690,7 @@ BEGIN_PROTECTED config_root->config_set (cfg_diff_summarize, mp_ui->summarize_cbx->isChecked ()); config_root->config_set (cfg_diff_expand_cell_arrays, mp_ui->expand_cell_arrays_cbx->isChecked ()); config_root->config_set (cfg_diff_exact, mp_ui->exact_cbx->isChecked ()); + config_root->config_set (cfg_diff_ignore_duplicates, mp_ui->ignore_duplicates_cbx->isChecked ()); config_root->config_end (); QDialog::accept (); @@ -712,6 +717,7 @@ DiffToolDialog::run_diff () bool summarize = !run_xor && mp_ui->summarize_cbx->isChecked (); bool expand_cell_arrays = !run_xor && mp_ui->expand_cell_arrays_cbx->isChecked (); bool exact = !run_xor && mp_ui->exact_cbx->isChecked (); + bool ignore_duplicates = mp_ui->ignore_duplicates_cbx->isChecked (); int cv_index_a = mp_ui->layouta->current_cv_index (); int cv_index_b = mp_ui->layoutb->current_cv_index (); @@ -740,6 +746,9 @@ DiffToolDialog::run_diff () if (smart) { flags |= db::layout_diff::f_smart_cell_mapping; } + if (ignore_duplicates) { + flags |= db::layout_diff::f_ignore_duplicates; + } // TODO: make an parameter db::Coord tolerance = 0;