mirror of https://github.com/KLayout/klayout.git
269 lines
9.8 KiB
C++
269 lines
9.8 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2017 Matthias Koefferlein
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
#include "dbCellHullGenerator.h"
|
|
#include "dbEdgeProcessor.h"
|
|
#include "tlString.h"
|
|
#include "utHead.h"
|
|
|
|
static std::string h2s (const std::vector<db::Polygon> &hull)
|
|
{
|
|
std::string r;
|
|
for (std::vector<db::Polygon>::const_iterator h = hull.begin (); h != hull.end (); ++h) {
|
|
if (!r.empty ()) {
|
|
r += ";";
|
|
}
|
|
r += h->to_string ();
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static bool check_hull (const std::vector<db::Polygon> &hull, const db::Shapes &shapes)
|
|
{
|
|
std::vector<db::Polygon> sp;
|
|
for (db::ShapeIterator s = shapes.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Boxes | db::ShapeIterator::Paths); ! s.at_end (); ++s) {
|
|
sp.push_back (db::Polygon ());
|
|
s->polygon (sp.back ());
|
|
}
|
|
|
|
db::EdgeProcessor ep;
|
|
std::vector<db::Polygon> out;
|
|
ep.boolean (hull, sp, out, db::BooleanOp::BNotA, false, false);
|
|
|
|
if (! out.empty ()) {
|
|
std::cout << "check_hull(): not empty" << std::endl;
|
|
for (std::vector<db::Polygon>::const_iterator p = out.begin (); p != out.end (); ++p) {
|
|
std::cout << " " << p->to_string () << std::endl;
|
|
}
|
|
}
|
|
return out.empty ();
|
|
}
|
|
|
|
TEST(1)
|
|
{
|
|
db::Manager m;
|
|
db::Layout g (&m);
|
|
unsigned int l1 = g.insert_layer (db::LayerProperties (1, 0));
|
|
unsigned int l2 = g.insert_layer (db::LayerProperties (2, 0));
|
|
db::Cell &c1 (g.cell (g.add_cell ()));
|
|
|
|
c1.shapes (l1).insert (db::Box (0, 0, 2100, 2100));
|
|
c1.shapes (l2).insert (db::Box (-100, -100, 2000, 2000));
|
|
|
|
db::CellHullGenerator chg (g);
|
|
|
|
std::vector <db::Polygon> hull;
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(-100,-100;-100,2000;0,2000;0,2100;2100,2100;2100,0;2000,0;2000,-100)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
c1.shapes (l1).clear ();
|
|
c1.shapes (l2).clear ();
|
|
|
|
c1.shapes (l1).insert (db::Box (0, 0, 2000, 200));
|
|
c1.shapes (l1).insert (db::Box (0, 0, 200, 2000));
|
|
|
|
hull.clear ();
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,2000;200,2000;200,200;2000,200;2000,0)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
c1.shapes (l1).clear ();
|
|
c1.shapes (l2).clear ();
|
|
|
|
c1.shapes (l1).insert (db::Box (0, 0, 2000, 200));
|
|
c1.shapes (l1).insert (db::Box (0, 1800, 2000, 2000));
|
|
c1.shapes (l1).insert (db::Box (0, 0, 200, 2000));
|
|
|
|
hull.clear ();
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,2000;2000,2000;2000,1800;200,1800;200,200;2000,200;2000,0)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
c1.shapes (l1).clear ();
|
|
c1.shapes (l2).clear ();
|
|
|
|
c1.shapes (l1).insert (db::Box (0, 0, 2000, 200));
|
|
c1.shapes (l1).insert (db::Box (0, 1800, 2000, 2000));
|
|
c1.shapes (l1).insert (db::Box (1800, 0, 2000, 2000));
|
|
c1.shapes (l1).insert (db::Box (0, 0, 200, 2000));
|
|
|
|
hull.clear ();
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,2000;2000,2000;2000,0/200,200;1800,200;1800,1800;200,1800)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
c1.shapes (l1).clear ();
|
|
c1.shapes (l2).clear ();
|
|
|
|
c1.shapes (l1).insert (db::Box (0, 0, 2000, 100));
|
|
c1.shapes (l1).insert (db::Box (0, 150, 2000, 200));
|
|
c1.shapes (l1).insert (db::Box (0, 1800, 2000, 1900));
|
|
c1.shapes (l1).insert (db::Box (0, 1950, 2000, 2000));
|
|
c1.shapes (l1).insert (db::Box (1800, 0, 2000, 1900));
|
|
c1.shapes (l1).insert (db::Box (1950, 0, 2000, 2000));
|
|
c1.shapes (l1).insert (db::Box (0, 0, 100, 2000));
|
|
c1.shapes (l1).insert (db::Box (150, 0, 200, 2000));
|
|
|
|
hull.clear ();
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,2000;2000,2000;2000,0/200,100;1800,100;1800,150;200,150/100,200;150,200;150,1800;100,1800/200,200;1800,200;1800,1800;200,1800/200,1900;1950,1900;1950,1950;200,1950)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
c1.shapes (l1).clear ();
|
|
c1.shapes (l2).clear ();
|
|
|
|
c1.shapes (l1).insert (db::Box (0, 0, 200, 200));
|
|
c1.shapes (l1).insert (db::Box (1800, 1800, 2000, 2000));
|
|
|
|
hull.clear ();
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,200;200,200;200,0);(1800,1800;1800,2000;2000,2000;2000,1800)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
c1.shapes (l1).clear ();
|
|
c1.shapes (l2).clear ();
|
|
|
|
{
|
|
db::Point pts[3] = { db::Point(0, 0), db::Point(0, 200), db::Point(200, 200) };
|
|
db::Polygon poly;
|
|
poly.assign_hull (&pts[0], &pts[0] + 3);
|
|
c1.shapes (l1).insert (poly);
|
|
}
|
|
{
|
|
db::Point pts[3] = { db::Point(1800, 1800), db::Point(1800, 2000), db::Point(2000, 2000) };
|
|
db::Polygon poly;
|
|
poly.assign_hull (&pts[0], &pts[0] + 3);
|
|
c1.shapes (l1).insert (poly);
|
|
}
|
|
|
|
hull.clear ();
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,200;200,200;200,0);(1800,1800;1800,2000;2000,2000;2000,1800)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
c1.shapes (l1).clear ();
|
|
c1.shapes (l2).clear ();
|
|
|
|
c1.shapes (l1).insert (db::Box (0, 0, 200, 200));
|
|
c1.shapes (l1).insert (db::Box (1800, 1800, 2000, 2000));
|
|
c1.shapes (l1).insert (db::Box (1500, 1800, 1700, 2000));
|
|
c1.shapes (l1).insert (db::Box (1500, 1500, 1700, 1700));
|
|
|
|
hull.clear ();
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,200;200,200;200,0);(1500,1500;1500,2000;2000,2000;2000,1800;1700,1800;1700,1500)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
c1.shapes (l1).clear ();
|
|
c1.shapes (l2).clear ();
|
|
|
|
c1.shapes (l1).insert (db::Box (1900, 0, 2000, 2000));
|
|
c1.shapes (l1).insert (db::Box (1800, 0, 1900, 1950));
|
|
c1.shapes (l1).insert (db::Box (1700, 0, 1800, 1900));
|
|
c1.shapes (l1).insert (db::Box (1600, 0, 1700, 1950));
|
|
c1.shapes (l1).insert (db::Box (1500, 0, 1600, 1850));
|
|
c1.shapes (l1).insert (db::Box (1400, 0, 1500, 1950));
|
|
c1.shapes (l1).insert (db::Box (1300, 0, 1400, 1900));
|
|
c1.shapes (l1).insert (db::Box (1200, 0, 1300, 1750));
|
|
c1.shapes (l1).insert (db::Box (1100, 0, 1200, 1800));
|
|
c1.shapes (l1).insert (db::Box (1000, 0, 1100, 1950));
|
|
c1.shapes (l1).insert (db::Box ( 900, 0, 1000, 1800));
|
|
c1.shapes (l1).insert (db::Box ( 800, 0, 900, 1750));
|
|
c1.shapes (l1).insert (db::Box ( 700, 0, 800, 1700));
|
|
c1.shapes (l1).insert (db::Box ( 600, 0, 700, 1750));
|
|
c1.shapes (l1).insert (db::Box ( 500, 0, 600, 1850));
|
|
c1.shapes (l1).insert (db::Box ( 400, 0, 500, 1900));
|
|
c1.shapes (l1).insert (db::Box ( 300, 0, 400, 1950));
|
|
c1.shapes (l1).insert (db::Box ( 200, 0, 300, 1750));
|
|
c1.shapes (l1).insert (db::Box ( 100, 0, 200, 1800));
|
|
c1.shapes (l1).insert (db::Box ( 0, 0, 100, 1950));
|
|
|
|
hull.clear ();
|
|
chg.set_complexity (0);
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,1950;1000,1950;1000,2000;2000,2000;2000,0)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
hull.clear ();
|
|
chg.set_complexity (20);
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,1950;400,1950;400,1900;600,1900;600,1800;1000,1800;1000,1950;1900,1950;1900,2000;2000,2000;2000,0)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
hull.clear ();
|
|
chg.set_complexity (40);
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,1950;400,1950;400,1900;500,1900;500,1850;600,1850;600,1800;1000,1800;1000,1950;1200,1950;1200,1900;1400,1900;1400,1950;1900,1950;1900,2000;2000,2000;2000,0)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
|
|
hull.clear ();
|
|
chg.set_complexity (1000);
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (h2s (hull), "(0,0;0,1950;100,1950;100,1800;200,1800;200,1750;300,1750;300,1950;400,1950;400,1900;500,1900;500,1850;600,1850;600,1750;700,1750;700,1700;800,1700;800,1750;900,1750;900,1800;1000,1800;1000,1950;1100,1950;1100,1800;1200,1800;1200,1750;1300,1750;1300,1900;1400,1900;1400,1950;1500,1950;1500,1850;1600,1850;1600,1950;1700,1950;1700,1900;1800,1900;1800,1950;1900,1950;1900,2000;2000,2000;2000,0)");
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l2)), true);
|
|
}
|
|
|
|
TEST(2)
|
|
{
|
|
db::Manager m;
|
|
db::Layout g (&m);
|
|
unsigned int l1 = g.insert_layer (db::LayerProperties (1, 0));
|
|
db::Cell &c1 (g.cell (g.add_cell ()));
|
|
|
|
for (size_t i = 0; i < 10000; ++i) {
|
|
db::Coord x = rand () % 2000;
|
|
db::Coord y = rand () % 2000;
|
|
c1.shapes (l1).insert (db::Box (x, y, x + 100, y + 100));
|
|
}
|
|
|
|
db::CellHullGenerator chg (g);
|
|
|
|
std::vector <db::Polygon> hull;
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
|
|
hull.clear ();
|
|
chg.set_complexity (0);
|
|
chg.generate_hull (c1, hull);
|
|
EXPECT_EQ (hull.size (), size_t (1));
|
|
EXPECT_EQ (hull.front ().holes (), size_t (0));
|
|
EXPECT_EQ (hull.front ().hull ().size () <= 8, true);
|
|
EXPECT_EQ (check_hull (hull, c1.shapes (l1)), true);
|
|
}
|
|
|
|
|
|
|