Implemented issue #598 (Cell#transform) (#600)

This commit is contained in:
Matthias Köfferlein 2020-07-03 23:41:09 +02:00 committed by GitHub
parent 4bd2672134
commit dcd0476efc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 214 additions and 0 deletions

View File

@ -301,6 +301,30 @@ public:
return m_instances.transform_into (ref, t);
}
/**
* @brief Transforms the cell by the given transformation.
*
* The transformation is applied to all instances and shapes. Magnified transformations will
* render magnified instances. See \transform_into for a version which avoids this.
*
* @param t The transformation to apply
*/
template <class Trans>
void transform (const Trans &t)
{
m_instances.transform (t);
for (typename shapes_map::iterator s = m_shapes_map.begin (); s != m_shapes_map.end (); ++s) {
if (! s->second.empty ()) {
// Note: don't use the copy ctor here - it will copy the attachment to the manager
// and create problems when destroyed. Plus: swap would be more efficient. But by using
// assign_transformed we get undo support for free.
shapes_type d;
d = s->second;
s->second.assign_transformed (d, t);
}
}
}
/**
* @brief Transforms the cell into a new coordinate system.
*

View File

@ -1563,6 +1563,28 @@ static db::Instance cell_inst_dtransform_into_cplx (db::Cell *cell, const db::In
return cell->transform_into (inst, dbu_trans.inverted () * t * dbu_trans);
}
static void cell_dtransform_simple (db::Cell *cell, const db::DTrans &t)
{
const db::Layout *layout = cell->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer-unit transformation")));
}
db::CplxTrans dbu_trans (layout->dbu ());
cell->transform (db::Trans (dbu_trans.inverted () * db::DCplxTrans (t) * dbu_trans));
}
static void cell_dtransform_cplx (db::Cell *cell, const db::DCplxTrans &t)
{
const db::Layout *layout = cell->layout ();
if (! layout) {
throw tl::Exception (tl::to_string (tr ("Cell does not reside inside a layout - cannot use a micrometer-unit transformation")));
}
db::CplxTrans dbu_trans (layout->dbu ());
cell->transform (dbu_trans.inverted () * t * dbu_trans);
}
static void cell_dtransform_into_simple (db::Cell *cell, const db::DTrans &t)
{
const db::Layout *layout = cell->layout ();
@ -2347,6 +2369,46 @@ Class<db::Cell> decl_Cell ("db", "Cell",
"\n"
"This variant has been introduced in version 0.25."
) +
gsi::method ("transform", (void (db::Cell::*)(const db::Trans &)) &db::Cell::transform, gsi::arg ("trans"),
"@brief Transforms the cell by the given integer transformation\n"
"\n"
"This method transforms all instances and all shapes by the given transformation. "
"There is a variant called \\transform_into which applies the transformation to instances "
"in a way such that it can be applied recursively to the child cells.\n"
"\n"
"This method has been introduced in version 0.26.7."
) +
gsi::method ("transform", (void (db::Cell::*)(const db::ICplxTrans &)) &db::Cell::transform, gsi::arg ("trans"),
"@brief Transforms the cell by the given complex integer transformation\n"
"\n"
"This method transforms all instances and all shapes by the given transformation. "
"There is a variant called \\transform_into which applies the transformation to instances "
"in a way such that it can be applied recursively to the child cells. The difference is important in "
"the presence of magnifications: \"transform\" will leave magnified instances while \"transform_into\" "
"will not do so but expect the magnification to be applied inside the called cells too.\n"
"\n"
"This method has been introduced in version 0.26.7."
) +
gsi::method_ext ("transform", &cell_dtransform_simple, gsi::arg ("trans"),
"@brief Transforms the cell by the given, micrometer-unit transformation\n"
"\n"
"This method transforms all instances and all shapes by the given transformation. "
"There is a variant called \\transform_into which applies the transformation to instances "
"in a way such that it can be applied recursively to the child cells.\n"
"\n"
"This method has been introduced in version 0.26.7."
) +
gsi::method_ext ("transform", &cell_dtransform_cplx, gsi::arg ("trans"),
"@brief Transforms the cell by the given, micrometer-unit transformation\n"
"\n"
"This method transforms all instances and all shapes by the given transformation. "
"There is a variant called \\transform_into which applies the transformation to instances "
"in a way such that it can be applied recursively to the child cells. The difference is important in "
"the presence of magnifications: \"transform\" will leave magnified instances while \"transform_into\" "
"will not do so but expect the magnification to be applied inside the called cells too.\n"
"\n"
"This method has been introduced in version 0.26.7."
) +
gsi::method_ext ("transform_into", &cell_dtransform_into_simple, gsi::arg ("trans"),
"@brief Transforms the cell into a new coordinate system with the given transformation where the transformation is in micrometer units\n"
"This method is identical to the corresponding \\transform_into method with a \\Trans argument. For this variant "

View File

@ -722,6 +722,14 @@ TEST(3a)
c0.transform_into (db::ICplxTrans (ti));
inst = *c0.begin ();
EXPECT_EQ (inst.to_string (), "cell_index=1 m90 -334,0");
c0.transform (db::Trans (5));
inst = *c0.begin ();
EXPECT_EQ (inst.to_string (), "cell_index=1 r270 0,-334");
c0.transform (db::ICplxTrans (ti));
inst = *c0.begin ();
EXPECT_EQ (inst.to_string (), "cell_index=1 r315 *2.5 600,-570");
}
TEST(3b)
@ -791,6 +799,73 @@ TEST(3b)
}
}
TEST(3c)
{
::pi = 0;
db::Manager m (true);
db::Layout g (&m);
db::Cell &c0 (g.cell (g.add_cell ()));
db::Cell &c1 (g.cell (g.add_cell ()));
db::Trans t (db::Vector (100, -100));
c0.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (c1.cell_index ()), t), 5));
db::Box b (0, 100, 1000, 1200);
c0.shapes (0).insert (db::BoxWithProperties (b, 17));
c1.shapes (1).insert (b);
// Note: this requires editable mode since db::Shapes::erase is permitted in editable mode only
// (erase is triggered by undo)
if (db::default_editable_mode ()) {
m.transaction ("t");
c0.transform (db::ICplxTrans (2.5));
m.commit ();
EXPECT_EQ (c1.cell_instances (), size_t (0));
EXPECT_EQ (c0.cell_instances (), size_t (1));
EXPECT_EQ (c0.begin ()->to_string (), "cell_index=1 r0 *2.5 250,-250 prop_id=5");
EXPECT_EQ (c0.shapes (0).size (), size_t (1));
EXPECT_EQ (c0.shapes (1).size (), size_t (0));
EXPECT_EQ (c1.shapes (0).size (), size_t (0));
EXPECT_EQ (c1.shapes (1).size (), size_t (1));
EXPECT_EQ (c0.shapes (0).begin (db::ShapeIterator::All)->to_string (), "box (0,250;2500,3000) prop_id=17");
EXPECT_EQ (c1.shapes (1).begin (db::ShapeIterator::All)->to_string (), "box (0,100;1000,1200)");
m.undo ();
EXPECT_EQ (c1.cell_instances (), size_t (0));
EXPECT_EQ (c0.cell_instances (), size_t (1));
EXPECT_EQ (c0.begin ()->to_string (), "cell_index=1 r0 100,-100 prop_id=5");
EXPECT_EQ (c0.shapes (0).size (), size_t (1));
EXPECT_EQ (c0.shapes (1).size (), size_t (0));
EXPECT_EQ (c1.shapes (0).size (), size_t (0));
EXPECT_EQ (c1.shapes (1).size (), size_t (1));
EXPECT_EQ (c0.shapes (0).begin (db::ShapeIterator::All)->to_string (), "box (0,100;1000,1200) prop_id=17");
EXPECT_EQ (c1.shapes (1).begin (db::ShapeIterator::All)->to_string (), "box (0,100;1000,1200)");
m.redo ();
EXPECT_EQ (c1.cell_instances (), size_t (0));
EXPECT_EQ (c0.cell_instances (), size_t (1));
EXPECT_EQ (c0.begin ()->to_string (), "cell_index=1 r0 *2.5 250,-250 prop_id=5");
EXPECT_EQ (c0.shapes (0).size (), size_t (1));
EXPECT_EQ (c0.shapes (1).size (), size_t (0));
EXPECT_EQ (c1.shapes (0).size (), size_t (0));
EXPECT_EQ (c1.shapes (1).size (), size_t (1));
EXPECT_EQ (c0.shapes (0).begin (db::ShapeIterator::All)->to_string (), "box (0,250;2500,3000) prop_id=17");
EXPECT_EQ (c1.shapes (1).begin (db::ShapeIterator::All)->to_string (), "box (0,100;1000,1200)");
}
}
struct map1
{
db::cell_index_type operator() (db::cell_index_type i) const { return 3-i; }

View File

@ -1122,6 +1122,59 @@ class DBLayout_TestClass < TestBase
end
# Cell#transform and Cell#transform_into
def test_14
g = RBA::Layout::new
c0 = g.create_cell("c0")
c1 = g.create_cell("c1")
t = RBA::Trans::new(RBA::Vector::new(100, -100))
inst = c0.insert(RBA::CellInstArray::new(c1.cell_index, t))
ti = RBA::ICplxTrans::new(2.5, 45.0, false, RBA::Vector::new(10, 20))
t = RBA::Trans::new(1)
assert_equal(inst.to_s, "cell_index=1 r0 100,-100")
c0.transform_into(t)
assert_equal(inst.to_s, "cell_index=1 r0 100,100")
c0.transform_into(ti)
assert_equal(inst.to_s, "cell_index=1 r0 0,354")
c0.transform(t)
assert_equal(inst.to_s, "cell_index=1 r90 -354,0")
c0.transform(ti)
assert_equal(inst.to_s, "cell_index=1 r135 *2.5 -616,-606")
g = RBA::Layout::new
c0 = g.create_cell("c0")
c1 = g.create_cell("c1")
t = RBA::Trans::new(RBA::Vector::new(100, -100))
inst = c0.insert(RBA::CellInstArray::new(c1.cell_index, t))
ti = RBA::DCplxTrans::new(2.5, 45.0, false, RBA::DVector::new(0.01, 0.02))
t = RBA::DTrans::new(1)
assert_equal(inst.to_s, "cell_index=1 r0 100,-100")
c0.transform_into(t)
assert_equal(inst.to_s, "cell_index=1 r0 100,100")
c0.transform_into(ti)
assert_equal(inst.to_s, "cell_index=1 r0 0,354")
c0.transform(t)
assert_equal(inst.to_s, "cell_index=1 r90 -354,0")
c0.transform(ti)
assert_equal(inst.to_s, "cell_index=1 r135 *2.5 -616,-606")
end
end
load("test_epilogue.rb")