From 1740523092f5d9d09e3cbe4fd0e1adce34390348 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 2 May 2026 15:46:29 +0200 Subject: [PATCH] Introducing a number of convenience methods for Layout * Layout#delete_cells with a list of cell object * Layout#delete_cell_rec with a cell object * Layout#prune_cell with a cell object * Layout#prune_cells for pruning multiple cells in one call * Layout#prune_subcells with a cell object * Layout#prune_subcells with multiple root cells * Layout#flatten with a cell object * Layout#flatten_into with cell objects * Layout#delete_cell with a cell object * Default value "all" for "levels" argument in "prune_subcells" and "prune_cell" * Default value "all" for "levels" and "true" for "prune" argument in "flatten" * Default value "all" for "levels" and "unity" for "trans" argument in "flatten_into" --- src/db/db/gsiDeclDbLayout.cc | 266 ++++++++++++++++++++++++++++++-- testdata/ruby/dbLayoutTests1.rb | 164 +++++++++++++++++--- 2 files changed, 395 insertions(+), 35 deletions(-) diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 9d76ae5e9..46329ec13 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -642,12 +642,22 @@ static tl::Variant get_property_from_id (db::properties_id_type id, const tl::Va } static void -delete_cells (db::Layout *layout, const std::vector &cell_indices) +delete_cells (db::Layout *layout, const std::vector &cell_indexes) { - for (auto ci = cell_indices.begin (); ci != cell_indices.end (); ++ci) { + for (auto ci = cell_indexes.begin (); ci != cell_indexes.end (); ++ci) { check_cell_index (layout, *ci); } - layout->delete_cells (cell_indices.begin (), cell_indices.end ()); + layout->delete_cells (cell_indexes.begin (), cell_indexes.end ()); +} + +static void +delete_cells_ptr (db::Layout *layout, const std::vector &cells) +{ + std::set cell_indexes; + for (auto c = cells.begin (); c != cells.end (); ++c) { + cell_indexes.insert ((*c)->cell_index ()); + } + layout->delete_cells (cell_indexes); } static void @@ -657,20 +667,76 @@ delete_cell_rec (db::Layout *layout, db::cell_index_type cell_index) layout->delete_cell_rec (cell_index); } -static void +static void +delete_cell_rec_ptr (db::Layout *layout, db::Cell *cell) +{ + layout->delete_cell_rec (cell->cell_index ()); +} + +static void prune_cell (db::Layout *layout, db::cell_index_type cell_index, int levels) { check_cell_index (layout, cell_index); layout->prune_cell (cell_index, levels); } -static void +static void +prune_cell_ptr (db::Layout *layout, db::Cell *cell, int levels) +{ + layout->prune_cell (cell->cell_index (), levels); +} + +static void +prune_cells (db::Layout *layout, const std::vector &cell_indexes, int levels) +{ + for (auto ci = cell_indexes.begin (); ci != cell_indexes.end (); ++ci) { + check_cell_index (layout, *ci); + } + layout->prune_cells (cell_indexes.begin (), cell_indexes.end (), levels); +} + +static void +prune_cells_ptr (db::Layout *layout, const std::vector &cells, int levels) +{ + std::set cell_indexes; + for (auto c = cells.begin (); c != cells.end (); ++c) { + cell_indexes.insert ((*c)->cell_index ()); + } + layout->prune_cells (cell_indexes, levels); +} + +static void prune_subcells (db::Layout *layout, db::cell_index_type cell_index, int levels) { check_cell_index (layout, cell_index); layout->prune_subcells (cell_index, levels); } +static void +prune_subcells_ptr (db::Layout *layout, db::Cell *cell, int levels) +{ + layout->prune_subcells (cell->cell_index (), levels); +} + +static void +prune_subcells_many (db::Layout *layout, const std::vector &cell_indexes, int levels) +{ + for (auto ci = cell_indexes.begin (); ci != cell_indexes.end (); ++ci) { + check_cell_index (layout, *ci); + } + layout->prune_subcells (cell_indexes.begin (), cell_indexes.end (), levels); +} + +static void +prune_subcells_many_ptr (db::Layout *layout, const std::vector &cells, int levels) +{ + std::set cell_indexes; + for (auto c = cells.begin (); c != cells.end (); ++c) { + cell_indexes.insert ((*c)->cell_index ()); + } + layout->prune_subcells (cell_indexes, levels); +} + static void flatten (db::Layout *layout, db::cell_index_type cell_index, int levels, bool prune) { @@ -678,7 +744,16 @@ flatten (db::Layout *layout, db::cell_index_type cell_index, int levels, bool pr layout->flatten (layout->cell (cell_index), levels, prune); } -static void +static void +flatten_ptr (db::Layout *layout, db::Cell *cell, int levels, bool prune) +{ + if (! cell) { + return; + } + layout->flatten (*cell, levels, prune); +} + +static void flatten_into (db::Layout *layout, db::cell_index_type cell_index, db::cell_index_type target_cell_index, const db::ICplxTrans &t, int levels) { check_cell_index (layout, cell_index); @@ -686,7 +761,16 @@ flatten_into (db::Layout *layout, db::cell_index_type cell_index, db::cell_index layout->flatten (layout->cell (cell_index), layout->cell (target_cell_index), t, levels); } -static void +static void +flatten_into_ptr (db::Layout *layout, db::Cell *cell, db::Cell *target_cell, const db::ICplxTrans &t, int levels) +{ + if (! cell || ! target_cell) { + return; + } + layout->flatten (*cell, *target_cell, t, levels); +} + +static void write_simple (db::Layout *layout, const std::string &filename) { db::SaveLayoutOptions options; @@ -866,6 +950,11 @@ static void delete_cell (db::Layout *ly, db::cell_index_type ci) ly->delete_cell (ci); } +static void delete_cell_ptr (db::Layout *ly, db::Cell *cell) +{ + ly->delete_cell (cell->cell_index ()); +} + static void rename_cell (db::Layout *ly, db::cell_index_type ci, const std::string &name) { check_cell_index (ly, ci); @@ -1655,6 +1744,20 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.20.\n" ) + + gsi::method_ext ("delete_cell", &delete_cell_ptr, gsi::arg ("cell"), + "@brief Deletes a cell\n" + "\n" + "This deletes a cell but not the sub cells of the cell.\n" + "These subcells will likely become new top cells unless they are used\n" + "otherwise.\n" + "All instances of this cell are deleted as well.\n" + "Hint: to delete multiple cells, use \"delete_cells\" which is \n" + "far more efficient in this case.\n" + "\n" + "@param cell The cell to delete\n" + "\n" + "This convenience variant taking a cell object has been introduced in version 0.30.9.\n" + ) + gsi::method_ext ("delete_cells", &delete_cells, gsi::arg ("cell_index_list"), "@brief Deletes multiple cells\n" "\n" @@ -1667,19 +1770,73 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.20.\n" ) + - gsi::method_ext ("prune_subcells", &prune_subcells, gsi::arg ("cell_index"), gsi::arg ("levels"), + gsi::method_ext ("delete_cells", &delete_cells_ptr, gsi::arg ("cell_list"), + "@brief Deletes multiple cells\n" + "\n" + "This deletes the cells but not the sub cells of these cells.\n" + "These subcells will likely become new top cells unless they are used\n" + "otherwise.\n" + "All instances of these cells are deleted as well.\n" + "\n" + "@param cell_list An list of cells to delete\n" + "\n" + "This convenience variant taking a list of cell objects has been introduced in version 0.30.9.\n" + ) + + gsi::method_ext ("prune_subcells", &prune_subcells, gsi::arg ("cell_index"), gsi::arg ("levels", -1), "@brief Deletes all sub cells of the cell which are not used otherwise down to the specified level of hierarchy\n" "\n" "This deletes all sub cells of the cell which are not used otherwise.\n" "All instances of the deleted cells are deleted as well.\n" "It is possible to specify how many levels of hierarchy below the given root cell are considered.\n" "\n" + "A variant exists that takes a list of cell indexes and which is more efficient than calling\n" + "'prune_subcells' multiple times on a single cell.\n" + "\n" "@param cell_index The root cell from which to delete a sub cells\n" "@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n" "\n" "This method has been introduced in version 0.20.\n" ) + - gsi::method_ext ("prune_cell", &prune_cell, gsi::arg ("cell_index"), gsi::arg ("levels"), + gsi::method_ext ("prune_subcells", &prune_subcells_ptr, gsi::arg ("cell"), gsi::arg ("levels", -1), + "@brief Deletes all sub cells of the cell which are not used otherwise down to the specified level of hierarchy\n" + "\n" + "This deletes all sub cells of the cell which are not used otherwise.\n" + "All instances of the deleted cells are deleted as well.\n" + "It is possible to specify how many levels of hierarchy below the given root cell are considered.\n" + "\n" + "A variant exists that takes a list of cells and which is more efficient than calling\n" + "'prune_subcells' multiple times on a single cell.\n" + "\n" + "@param cell The root cell from which to delete a sub cells\n" + "@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n" + "\n" + "This convenience variant taking a list of cell objects has been introduced in version 0.30.9.\n" + ) + + gsi::method_ext ("prune_subcells", &prune_subcells_many, gsi::arg ("cell_index_list"), gsi::arg ("levels", -1), + "@brief Deletes all sub cells of the given cells which are not used otherwise down to the specified level of hierarchy\n" + "\n" + "This deletes all sub cells of the given cells which are not used otherwise.\n" + "All instances of the deleted cells are deleted as well.\n" + "It is possible to specify how many levels of hierarchy below the given root cell are considered.\n" + "\n" + "@param cell_index_list The root cells from which to delete the sub cells\n" + "@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n" + "\n" + "This method has been introduced in version 0.30.9.\n" + ) + + gsi::method_ext ("prune_subcells", &prune_subcells_many_ptr, gsi::arg ("cell_list"), gsi::arg ("levels", -1), + "@brief Deletes all sub cells of the given cells which are not used otherwise down to the specified level of hierarchy\n" + "\n" + "This deletes all sub cells of the given cells which are not used otherwise.\n" + "All instances of the deleted cells are deleted as well.\n" + "It is possible to specify how many levels of hierarchy below the given root cell are considered.\n" + "\n" + "@param cell_list The root cells from which to delete the sub cells\n" + "@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n" + "\n" + "This method has been introduced in version 0.30.9.\n" + ) + + gsi::method_ext ("prune_cell", &prune_cell, gsi::arg ("cell_index"), gsi::arg ("levels", -1), "@brief Deletes a cell plus subcells not used otherwise\n" "\n" "This deletes a cell and also all sub cells of the cell which are not used otherwise.\n" @@ -1687,10 +1844,53 @@ Class decl_Layout ("db", "Layout", "only the direct children of the cell are deleted with the cell itself.\n" "All instances of this cell are deleted as well.\n" "\n" + "A version that allows pruning multiple cells in one call is \\prune_cells.\n" + "\n" "@param cell_index The index of the cell to delete\n" "@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n" "\n" - "This method has been introduced in version 0.20.\n" + "This method has been introduced in version 0.20. The 'levels' argument was made optional in version 0.30.9.\n" + ) + + gsi::method_ext ("prune_cell", &prune_cell_ptr, gsi::arg ("cell"), gsi::arg ("levels", -1), + "@brief Deletes a cell plus subcells not used otherwise\n" + "\n" + "This deletes a cell and also all sub cells of the cell which are not used otherwise.\n" + "The number of hierarchy levels to consider can be specified as well. One level of hierarchy means that " + "only the direct children of the cell are deleted with the cell itself.\n" + "All instances of this cell are deleted as well.\n" + "\n" + "A version that allows pruning multiple cells in one call is \\prune_cells.\n" + "\n" + "@param cell The cell to delete\n" + "@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n" + "\n" + "This convenience variant taking a cell object has been introduced in version 0.30.9.\n" + ) + + gsi::method_ext ("prune_cells", &prune_cells, gsi::arg ("cell_indexes"), gsi::arg ("levels", -1), + "@brief Deletes cells plus subcells not used otherwise\n" + "\n" + "This deletes the given cells and also all sub cells of the cells which are not used otherwise.\n" + "The number of hierarchy levels to consider can be specified as well. One level of hierarchy means that " + "only the direct children of the cell are deleted with the cell itself.\n" + "All instances of the pruned cells are deleted as well.\n" + "\n" + "@param cell_indexes The indexes of the cells to delete\n" + "@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n" + "\n" + "This method has been introduced in version 0.30.9.\n" + ) + + gsi::method_ext ("prune_cells", &prune_cells_ptr, gsi::arg ("cells"), gsi::arg ("levels", -1), + "@brief Deletes cells plus subcells not used otherwise\n" + "\n" + "This deletes the given cells and also all sub cells of the cells which are not used otherwise.\n" + "The number of hierarchy levels to consider can be specified as well. One level of hierarchy means that " + "only the direct children of the cell are deleted with the cell itself.\n" + "All instances of the pruned cells are deleted as well.\n" + "\n" + "@param cells The cells to delete\n" + "@param levels The number of hierarchy levels to consider (-1: all, 0: none, 1: one level etc.)\n" + "\n" + "This method has been introduced in version 0.30.9.\n" ) + gsi::method_ext ("delete_cell_rec", &delete_cell_rec, gsi::arg ("cell_index"), "@brief Deletes a cell plus all subcells\n" @@ -1702,6 +1902,16 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.20.\n" ) + + gsi::method_ext ("delete_cell_rec", &delete_cell_rec_ptr, gsi::arg ("cell"), + "@brief Deletes a cell plus all subcells\n" + "\n" + "This deletes a cell and also all sub cells of the cell.\n" + "In contrast to \\prune_cell, all cells are deleted together with their instances even if they are used otherwise.\n" + "\n" + "@param cell The cell to delete\n" + "\n" + "This convenience variant taking a cell object has been introduced in version 0.30.9.\n" + ) + gsi::method_ext ("insert", &insert_region, gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("region"), "@brief Inserts a region into the given cell and layer\n" @@ -1750,7 +1960,7 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.27.\n" ) + - gsi::method_ext ("flatten", &flatten, gsi::arg ("cell_index"), gsi::arg ("levels"), gsi::arg ("prune"), + gsi::method_ext ("flatten", &flatten, gsi::arg ("cell_index"), gsi::arg ("levels", -1), gsi::arg ("prune", true), "@brief Flattens the given cell\n" "\n" "This method propagates all shapes and instances from the specified number of hierarchy levels below into the given cell.\n" @@ -1761,9 +1971,22 @@ Class decl_Layout ("db", "Layout", "@param levels The number of hierarchy levels to flatten (-1: all, 0: none, 1: one level etc.)\n" "@param prune Set to true to remove orphan cells.\n" "\n" - "This method has been introduced in version 0.20.\n" + "This method has been introduced in version 0.20. The 'levels' and 'prune' arguments have been made optional in version 0.30.9.\n" ) + - gsi::method_ext ("flatten_into", &flatten_into, gsi::arg ("source_cell_index"), gsi::arg ("target_cell_index"), gsi::arg ("trans"), gsi::arg ("levels"), + gsi::method_ext ("flatten", &flatten_ptr, gsi::arg ("cell"), gsi::arg ("levels", -1), gsi::arg ("prune", true), + "@brief Flattens the given cell\n" + "\n" + "This method propagates all shapes and instances from the specified number of hierarchy levels below into the given cell.\n" + "It also removes the instances of the cells from which the shapes came from, but does not remove the cells themselves if prune is set to false.\n" + "If prune is set to true, these cells are removed if not used otherwise.\n" + "\n" + "@param cell The cell which should be flattened\n" + "@param levels The number of hierarchy levels to flatten (-1: all, 0: none, 1: one level etc.)\n" + "@param prune Set to true to remove orphan cells.\n" + "\n" + "This convenience variant taking a cell object has been introduced in version 0.30.9.\n" + ) + + gsi::method_ext ("flatten_into", &flatten_into, gsi::arg ("source_cell_index"), gsi::arg ("target_cell_index"), gsi::arg ("trans", db::ICplxTrans (), "unity"), gsi::arg ("levels", -1), "@brief Flattens the given cell into another cell\n" "\n" "This method works like 'flatten', but allows specification of a target cell which can be different from the source cell plus " @@ -1776,7 +1999,22 @@ Class decl_Layout ("db", "Layout", "@param trans The transformation to apply on the output shapes and instances\n" "@param levels The number of hierarchy levels to flatten (-1: all, 0: none, 1: one level etc.)\n" "\n" - "This method has been introduced in version 0.24.\n" + "This method has been introduced in version 0.24. The 'trans' and 'levels' arguments have been made optional is version 0.30.9.\n" + ) + + gsi::method_ext ("flatten_into", &flatten_into_ptr, gsi::arg ("source_cell"), gsi::arg ("target_cell"), gsi::arg ("trans", db::ICplxTrans (), "unity"), gsi::arg ("levels", -1), + "@brief Flattens the given cell into another cell\n" + "\n" + "This method works like 'flatten', but allows specification of a target cell which can be different from the source cell plus " + "a transformation which is applied for all shapes and instances in the target cell.\n" + "\n" + "In contrast to the 'flatten' method, the source cell is not modified.\n" + "\n" + "@param source_cell The source cell which should be flattened\n" + "@param target_cell The target cell into which the resulting objects are written\n" + "@param trans The transformation to apply on the output shapes and instances\n" + "@param levels The number of hierarchy levels to flatten (-1: all, 0: none, 1: one level etc.)\n" + "\n" + "This convenience variant taking a cell objects has been introduced in version 0.30.9.\n" ) + gsi::method ("start_changes", &db::Layout::start_changes, "@brief Signals the start of an operation bringing the layout into invalid state\n" diff --git a/testdata/ruby/dbLayoutTests1.rb b/testdata/ruby/dbLayoutTests1.rb index ecf2fa19b..97c903762 100644 --- a/testdata/ruby/dbLayoutTests1.rb +++ b/testdata/ruby/dbLayoutTests1.rb @@ -335,34 +335,21 @@ class DBLayoutTests1_TestClass < TestBase c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) assert_equal(c0.is_empty?, false) + c0_index = c0.cell_index + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - c0_index = c0.cell_index + ll = l.dup assert_equal(l.is_valid_cell_index?(c0_index), true) - l.delete_cell(c0.cell_index) + l.delete_cell(c0_index) assert_equal(l.is_valid_cell_index?(c0_index), false) assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); assert_equal(c3.is_empty?, true) - l = RBA::Layout.new - l.insert_layer_at(0, RBA::LayerInfo.new(1, 0)) - c0 = l.cell(l.add_cell("c0")) - c1 = l.cell(l.add_cell("c1")) - c2 = l.cell(l.add_cell("c2")) - c3 = l.cell(l.add_cell("c3")) - assert_equal(c0.is_empty?, true) + l = ll + ll = l.dup - tt = RBA::Trans.new - c0.insert(RBA::CellInstArray.new(c1.cell_index, tt)) - c0.insert(RBA::CellInstArray.new(c2.cell_index, RBA::Trans.new(RBA::Point.new(100, -100)))) - c0.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(1))) - c2.insert(RBA::CellInstArray.new(c3.cell_index, RBA::Trans.new(RBA::Point.new(1100, 0)))) - assert_equal(c0.is_empty?, false) - - assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)"); - - c0_index = c0.cell_index assert_equal(l.is_valid_cell_index?(c0_index), true) l.cell(c0_index).delete assert_equal(l.is_valid_cell_index?(c0_index), false) @@ -370,6 +357,16 @@ class DBLayoutTests1_TestClass < TestBase assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); assert_equal(c3.is_empty?, true) + l = ll + ll = l.dup + + assert_equal(l.is_valid_cell_index?(c0_index), true) + # with cell object + l.delete_cell(l.cell(c0_index)) + assert_equal(l.is_valid_cell_index?(c0_index), false) + assert_equal(collect_hier(l), "[c1](P=)(C=)/[c2](P=)(C=c3)/[c3](P=c2)(C=)"); + assert_equal(c3.is_empty?, true) + end def test_5b @@ -413,10 +410,17 @@ class DBLayoutTests1_TestClass < TestBase assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)"); l = ll + ll = l.dup # Hint: even though we deleted c0 and c2, their indices are still valid l.delete_cells([c2_index, c0_index]) assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)"); + l = ll + ll = l.dup + # with cell objects + l.delete_cells([l.cell(c2_index), l.cell(c0_index)]) + assert_equal(collect_hier(l), "[c1](P=)(C=)/[c3](P=)(C=)"); + end def test_5d @@ -487,6 +491,7 @@ class DBLayoutTests1_TestClass < TestBase c0_index = c0.cell_index c2_index = c2.cell_index + c3_index = c3.cell_index ll = l.dup @@ -499,6 +504,42 @@ class DBLayoutTests1_TestClass < TestBase l.cell(c2_index).prune_cell(-1) assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); + l = ll + ll = l.dup + # As method of Layout + l.prune_cell(c2_index, -1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with default argument + l.prune_cell(c2_index) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with cell object + l.prune_cell(l.cell(c2_index), -1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with cell object and default argument + l.prune_cell(l.cell(c2_index), -1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c3)/[c1](P=c0)(C=)/[c3](P=c0)(C=)"); + + l = ll + ll = l.dup + # prune c2 and c3 + l.prune_cells([ c2_index, c3_index ], -1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)"); + + l = ll + ll = l.dup + # prune c2 and c3 with cell objects + l.prune_cells([ l.cell(c2_index), l.cell(c3_index) ], -1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)"); + end def test_5e @@ -546,6 +587,12 @@ class DBLayoutTests1_TestClass < TestBase l.delete_cell_rec(c2_index) assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)"); + l = ll + ll = l.dup + # with cell object + l.delete_cell_rec(l.cell(c2_index)) + assert_equal(collect_hier(l), "[c0](P=)(C=c1)/[c1](P=c0)(C=)"); + end def test_5f @@ -589,12 +636,38 @@ class DBLayoutTests1_TestClass < TestBase l = ll ll = l.dup - l.flatten(c0_index, -1, true) + l.flatten(c0_index) assert_equal(collect_hier(l), "[c0](P=)(C=)"); ii = l.begin_shapes(c0_index, 0); assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); + l = ll + ll = l.dup + c0flat = l.create_cell("c0flat") + l.flatten_into(c0_index, c0flat.cell_index) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)/[c0flat](P=)(C=)"); + + ii = l.begin_shapes(c0flat, 0); + assert_equal(collect(ii, l), "[c0flat](0,100;1000,1200)/[c0flat](0,100;1000,1200)/[c0flat](100,0;1100,1100)/[c0flat](1200,0;2200,1100)/[c0flat](-1200,0;-100,1000)"); + + l = ll + ll = l.dup + l.flatten(l.cell(c0_index), -1, true) # with cell object + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + + ii = l.begin_shapes(c0_index, 0); + assert_equal(collect(ii, l), "[c0](0,100;1000,1200)/[c0](0,100;1000,1200)/[c0](100,0;1100,1100)/[c0](1200,0;2200,1100)/[c0](-1200,0;-100,1000)"); + + l = ll + ll = l.dup + c0flat = l.create_cell("c0flat") + l.flatten_into(l.cell(c0_index), c0flat, RBA::ICplxTrans::new(2.0), -1) + assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=c3)/[c3](P=c0,c2)(C=)/[c0flat](P=)(C=)"); + + ii = l.begin_shapes(c0flat, 0); + assert_equal(collect(ii, l), "[c0flat](0,200;2000,2400)/[c0flat](0,200;2000,2400)/[c0flat](200,0;2200,2200)/[c0flat](2400,0;4400,2200)/[c0flat](-2400,0;-200,2000)"); + l = ll ll = l.dup l.flatten(c0_index, 0, false) @@ -748,10 +821,59 @@ class DBLayoutTests1_TestClass < TestBase assert_equal(collect_hier(l), "[c0](P=)(C=c1,c2,c3)/[c1](P=c0)(C=)/[c2](P=c0)(C=)/[c3](P=c0)(C=)"); l = ll + ll = l.dup # Hint: even though we deleted c0 and c2, their indices are still valid l.cell(c0_index).prune_subcells(1) assert_equal(collect_hier(l), "[c0](P=)(C=)"); + l = ll + ll = l.dup + # As method of Layout + l.prune_subcells(c0_index, -1) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with default argument + l.prune_subcells(c0_index) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with Cell object + l.prune_subcells(l.cell(c0_index), -1) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with Cell object and default argument + l.prune_subcells(l.cell(c0_index)) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with multiple cells + l.prune_subcells([ c0_index ], -1) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with multiple cells and default argument + l.prune_subcells([ c0_index ]) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with multiple cells and Cell object + l.prune_subcells([ l.cell(c0_index) ], -1) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + + l = ll + ll = l.dup + # As method of Layout with multiple cells and Cell object and default argument + l.prune_subcells([ l.cell(c0_index) ]) + assert_equal(collect_hier(l), "[c0](P=)(C=)"); + end def test_6 @@ -2365,7 +2487,7 @@ class DBLayoutTests1_TestClass < TestBase end # Properties IDs - def test_issue1549 + def test_propertyIDs ly = RBA::Layout::new