klayout/src/db/unit_tests/dbEdgeProcessorTests.cc

2741 lines
78 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2021 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 "tlUnitTest.h"
#include "dbShapeProcessor.h"
#include "dbPolygon.h"
#include "dbPolygonGenerators.h"
#include "dbLayout.h"
#include "dbReader.h"
#include "dbCommonReader.h"
#include "dbLayoutDiff.h"
#include "dbTestSupport.h"
#include "dbSaveLayoutOptions.h"
#include "dbWriter.h"
#include "dbRecursiveShapeIterator.h"
#include "tlStream.h"
#include "tlTimer.h"
#include <vector>
#include <algorithm>
#include <stdlib.h>
void run_test_bool (tl::TestBase *_this, const char *file, int mode, bool min_coherence = true, const char *au_file1 = 0, const char *au_file2 = 0, const char *au_file3 = 0)
{
db::Layout layout_org;
{
std::string fn (tl::testsrc ());
fn += "/testdata/bool/";
fn += file;
tl::InputStream stream (fn);
db::Reader reader (stream);
db::LayerMap lmap;
unsigned int index;
db::LayerProperties p;
p.layer = 1;
p.datatype = 0;
lmap.map (db::LDPair (1, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
p.layer = 2;
p.datatype = 0;
lmap.map (db::LDPair (2, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
p.layer = 100;
p.datatype = 0;
lmap.map (db::LDPair (100, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
reader.read (layout_org, options);
}
std::string au_fn1 (tl::testsrc ());
au_fn1 += "/testdata/bool/";
au_fn1 += au_file1 ? au_file1 : file;
std::string au_fn2 (tl::testsrc ());
au_fn2 += "/testdata/bool/";
au_fn2 += au_file2 ? au_file2 : (au_file1 ? au_file1 : file);
int la = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 1
&& layout_org.get_properties (l).datatype == 0) {
la = l;
break;
}
}
if (la < 0) {
la = layout_org.insert_layer ();
}
int lb = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 2
&& layout_org.get_properties (l).datatype == 0) {
lb = l;
break;
}
}
if (lb < 0) {
lb = layout_org.insert_layer ();
}
int lr = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 100
&& layout_org.get_properties (l).datatype == 0) {
lr = l;
break;
}
}
if (lr >= 0) {
layout_org.delete_layer (lr);
}
lr = layout_org.insert_layer ();
db::LayerProperties p;
p.layer = 1;
p.datatype = 0;
layout_org.set_properties (la, p);
p.layer = 2;
p.datatype = 0;
layout_org.set_properties (lb, p);
p.layer = 100;
p.datatype = 0;
layout_org.set_properties (lr, p);
db::ShapeProcessor proc;
proc.boolean (layout_org, layout_org.cell (*layout_org.begin_top_down ()), la,
layout_org, layout_org.cell (*layout_org.begin_top_down ()), lb,
layout_org.cell (*layout_org.begin_top_down ()).shapes (lr), mode, true /*hierarchical*/, true /*resolve holes*/, min_coherence);
db::LayerMap lmap;
// Note: the logical layers have to be non-existing ones because we read to a layout that has been
// configured with layers already
lmap.map (db::LDPair (1, 0), 1000);
lmap.map (db::LDPair (2, 0), 1001);
lmap.map (db::LDPair (100, 0), 1002);
db::compare_layouts (_this, layout_org, au_fn1, lmap, false /*skip other layers*/, db::WriteOAS);
layout_org.cell (*layout_org.begin_top_down ()).shapes (lr).clear ();
unsigned int lr2 = layout_org.insert_layer ();
// temporarily disable compression for the boolean step to acchieve identical results with the previous test
db::PolygonGenerator::enable_compression_global (false);
proc.boolean (layout_org, layout_org.cell (*layout_org.begin_top_down ()), la,
layout_org, layout_org.cell (*layout_org.begin_top_down ()), lb,
layout_org.cell (*layout_org.begin_top_down ()).shapes (lr2), mode, true /*hierarchical*/, false /*resolve holes*/);
db::PolygonGenerator::enable_compression_global (true);
proc.merge (layout_org, layout_org.cell (*layout_org.begin_top_down ()), lr2,
layout_org.cell (*layout_org.begin_top_down ()).shapes (lr), true /*hierarchical*/, 0 /*all polygons*/, true /*resolve holes*/, min_coherence);
db::compare_layouts (_this, layout_org, au_fn2, lmap, false /*skip other layers*/, db::WriteOAS);
// Use this opportunity to test trapezoid decomposition
if (au_file3) {
std::string au_fn3 (tl::testsrc ());
au_fn3 += "/testdata/bool/";
au_fn3 += au_file3;
db::EdgeProcessor ep;
db::Shapes &shapes = layout_org.cell (*layout_org.begin_top_down ()).shapes (lr);
for (db::ShapeIterator s = shapes.begin (db::ShapeIterator::All); !s.at_end (); ++s) {
ep.insert (s->polygon ());
}
db::MergeOp op;
db::ShapeGenerator sg (shapes, true /*clear shapes*/);
db::TrapezoidGenerator out (sg);
ep.process (out, op);
db::compare_layouts (_this, layout_org, au_fn3, lmap, false /*skip other layers*/, db::WriteOAS);
}
}
TEST(1and)
{
run_test_bool (_this, "and1.oas", db::BooleanOp::And, true, 0, 0, "and1_tz.oas");
}
TEST(2and)
{
run_test_bool (_this, "and2.oas", db::BooleanOp::And, true, 0, 0, "and2_tz.oas");
}
TEST(3and)
{
run_test_bool (_this, "and3.oas", db::BooleanOp::And, true, 0, 0, "and3_tz.oas");
}
TEST(4and)
{
run_test_bool (_this, "and4.oas", db::BooleanOp::And, true, 0, 0, "and4_tz.oas");
}
TEST(5and)
{
run_test_bool (_this, "and5.oas", db::BooleanOp::And, true, 0, 0, "and5_tz.oas");
}
TEST(6and)
{
run_test_bool (_this, "and6.oas", db::BooleanOp::And, true, 0, 0, "and6_tz.oas");
}
TEST(1xor)
{
run_test_bool (_this, "xor1.oas", db::BooleanOp::Xor, true, 0, 0, "xor1_tz.oas");
}
TEST(2xor)
{
run_test_bool (_this, "xor2.oas", db::BooleanOp::Xor, true, 0, 0, "xor2_tz.oas");
}
TEST(3xor)
{
run_test_bool (_this, "xor3.oas", db::BooleanOp::Xor, true, 0, 0, "xor3_tz.oas");
}
TEST(4xor)
{
run_test_bool (_this, "xor4.oas", db::BooleanOp::Xor, true, 0, 0, "xor4_tz.oas");
}
TEST(5xor)
{
run_test_bool (_this, "xor5.oas", db::BooleanOp::Xor, true, 0, 0, "xor5_tz.oas");
}
TEST(6xor)
{
run_test_bool (_this, "xor6.oas", db::BooleanOp::Xor, true, 0, 0, "xor6_tz.oas");
}
TEST(7xor)
{
run_test_bool (_this, "xor7.oas", db::BooleanOp::Xor, true, "xor7_au1.oas", "xor7_au2.oas", "xor7_au_tz.oas");
}
TEST(8xor)
{
run_test_bool (_this, "xor8.oas", db::BooleanOp::Xor, true, "xor8_au1.oas", "xor8_au2.oas", "xor8_au_tz.oas");
}
TEST(1xor_max)
{
run_test_bool (_this, "xor1_max.oas", db::BooleanOp::Xor, false);
}
TEST(2xor_max)
{
run_test_bool (_this, "xor2_max.oas", db::BooleanOp::Xor, false);
}
TEST(3xor_max)
{
run_test_bool (_this, "xor3_max.oas", db::BooleanOp::Xor, false);
}
TEST(4xor_max)
{
run_test_bool (_this, "xor4_max.oas", db::BooleanOp::Xor, false);
}
TEST(5xor_max)
{
run_test_bool (_this, "xor5_max.oas", db::BooleanOp::Xor, false);
}
TEST(6xor_max)
{
run_test_bool (_this, "xor6_max.oas", db::BooleanOp::Xor, false);
}
TEST(7xor_max)
{
run_test_bool (_this, "xor7_max.oas", db::BooleanOp::Xor, false, "xor7_max_au1.oas", "xor7_max_au2.oas");
}
TEST(1or)
{
run_test_bool (_this, "or1.oas", db::BooleanOp::Or);
}
TEST(2or)
{
run_test_bool (_this, "or2.oas", db::BooleanOp::Or);
}
TEST(3or)
{
run_test_bool (_this, "or3.oas", db::BooleanOp::Or);
}
TEST(4or)
{
run_test_bool (_this, "or4.oas", db::BooleanOp::Or);
}
TEST(5or)
{
run_test_bool (_this, "or5.oas", db::BooleanOp::Or);
}
TEST(6or)
{
run_test_bool (_this, "or6.oas", db::BooleanOp::Or);
}
TEST(1anotb)
{
run_test_bool (_this, "anotb1.oas", db::BooleanOp::ANotB);
}
TEST(2anotb)
{
run_test_bool (_this, "anotb2.oas", db::BooleanOp::ANotB);
}
TEST(3anotb)
{
run_test_bool (_this, "anotb3.oas", db::BooleanOp::ANotB);
}
TEST(4anotb)
{
run_test_bool (_this, "anotb4.oas", db::BooleanOp::ANotB);
}
TEST(5anotb)
{
run_test_bool (_this, "anotb5.oas", db::BooleanOp::ANotB);
}
TEST(6anotb)
{
run_test_bool (_this, "anotb6.oas", db::BooleanOp::ANotB);
}
TEST(1bnota)
{
run_test_bool (_this, "bnota1.oas", db::BooleanOp::BNotA);
}
TEST(2bnota)
{
run_test_bool (_this, "bnota2.oas", db::BooleanOp::BNotA);
}
TEST(3bnota)
{
run_test_bool (_this, "bnota3.oas", db::BooleanOp::BNotA);
}
TEST(4bnota)
{
run_test_bool (_this, "bnota4.oas", db::BooleanOp::BNotA);
}
TEST(5bnota)
{
run_test_bool (_this, "bnota5.oas", db::BooleanOp::BNotA);
}
TEST(6bnota)
{
run_test_bool (_this, "bnota6.oas", db::BooleanOp::BNotA);
}
TEST(1special)
{
run_test_bool (_this, "special1.oas", db::BooleanOp::Xor, true, 0, 0, "special1_tz.oas");
}
TEST(2special)
{
test_is_long_runner ();
tl::SelfTimer timer ("special2 test");
run_test_bool (_this, "special2.oas", db::BooleanOp::Xor, true, "special2_au1.oas", 0, "special2_au1_tz.oas");
run_test_bool (_this, "special2.oas", db::BooleanOp::And, true, "special2_au2.oas", 0, "special2_au2_tz.oas");
run_test_bool (_this, "special2.oas", db::BooleanOp::ANotB, true, "special2_au3.oas", 0, "special2_au3_tz.oas");
run_test_bool (_this, "special2.oas", db::BooleanOp::BNotA, true, "special2_au4.oas", 0, "special2_au4_tz.oas");
run_test_bool (_this, "special2.oas", db::BooleanOp::Or, true, "special2_au5.oas", 0, "special2_au5_tz.oas");
}
TEST(3special)
{
test_is_long_runner ();
tl::SelfTimer timer ("special3 test");
run_test_bool (_this, "special3.oas", db::BooleanOp::Xor, true, "special3_au1.oas");
run_test_bool (_this, "special3.oas", db::BooleanOp::And, true, "special3_au2.oas");
run_test_bool (_this, "special3.oas", db::BooleanOp::ANotB, true, "special3_au3.oas");
run_test_bool (_this, "special3.oas", db::BooleanOp::BNotA, true, "special3_au4.oas");
run_test_bool (_this, "special3.oas", db::BooleanOp::Or, true, "special3_au5.oas");
}
void run_test_size (tl::TestBase *_this, const char *file, const char *au_file, int mode, db::Coord dx, db::Coord dy, bool min_coherence = true, bool flat = true)
{
db::Manager m (true);
db::Layout layout_org (&m);
db::Layout layout_au (&m);
{
std::string fn (tl::testsrc ());
fn += "/testdata/bool/";
fn += file;
tl::InputStream stream (fn);
db::Reader reader (stream);
db::LayerMap lmap;
unsigned int index;
db::LayerProperties p;
p.layer = 1;
p.datatype = 0;
lmap.map (db::LDPair (1, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
p.layer = 100;
p.datatype = 0;
lmap.map (db::LDPair (100, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
reader.read (layout_org, options);
}
std::string au_fn (tl::testsrc ());
au_fn += "/testdata/bool/";
au_fn += au_file;
int la = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 1
&& layout_org.get_properties (l).datatype == 0) {
la = l;
break;
}
}
if (la < 0) {
la = layout_org.insert_layer ();
}
int lr = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 100
&& layout_org.get_properties (l).datatype == 0) {
lr = l;
break;
}
}
if (lr >= 0) {
layout_org.delete_layer (lr);
}
lr = layout_org.insert_layer ();
db::LayerProperties p;
p.layer = 1;
p.datatype = 0;
layout_org.set_properties (la, p);
p.layer = 100;
p.datatype = 0;
layout_org.set_properties (lr, p);
db::ShapeProcessor proc;
proc.size (layout_org, layout_org.cell (*layout_org.begin_top_down ()), la,
layout_org.cell (*layout_org.begin_top_down ()).shapes (lr), dx, dy, mode, flat /*hierarchical*/, true /*resolve holes*/, min_coherence);
db::LayerMap lmap;
lmap.map (db::LDPair (1, 0), 1);
lmap.map (db::LDPair (100, 0), 2);
db::compare_layouts (_this, layout_org, au_fn, lmap, false /*skip other layers*/, db::WriteOAS);
}
void run_test_twobool (tl::TestBase *_this, const char *file, const char *au_file)
{
db::Manager m (true);
db::Layout layout_org (&m);
db::Layout layout_au (&m);
{
std::string fn (tl::testsrc ());
fn += "/testdata/bool/";
fn += file;
tl::InputStream stream (fn);
db::Reader reader (stream);
db::LayerMap lmap;
unsigned int index;
db::LayerProperties p;
p.layer = 1;
p.datatype = 0;
lmap.map (db::LDPair (1, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
p.layer = 2;
p.datatype = 0;
lmap.map (db::LDPair (2, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
p.layer = 100;
p.datatype = 0;
lmap.map (db::LDPair (100, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
p.layer = 101;
p.datatype = 0;
lmap.map (db::LDPair (101, 0), index = layout_org.insert_layer ());
layout_org.set_properties (index, p);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
reader.read (layout_org, options);
}
std::string au_fn (tl::testsrc ());
au_fn += "/testdata/bool/";
au_fn += au_file;
int la = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 1
&& layout_org.get_properties (l).datatype == 0) {
la = l;
break;
}
}
if (la < 0) {
la = layout_org.insert_layer ();
}
int lb = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 2
&& layout_org.get_properties (l).datatype == 0) {
lb = l;
break;
}
}
if (lb < 0) {
lb = layout_org.insert_layer ();
}
int lra = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 100
&& layout_org.get_properties (l).datatype == 0) {
lra = l;
break;
}
}
if (lra >= 0) {
layout_org.delete_layer (lra);
}
lra = layout_org.insert_layer ();
int lrb = -1;
for (unsigned int l = 0; l < layout_org.layers (); ++l) {
if (layout_org.is_valid_layer (l) && layout_org.get_properties (l).layer == 101
&& layout_org.get_properties (l).datatype == 0) {
lrb = l;
break;
}
}
if (lrb >= 0) {
layout_org.delete_layer (lrb);
}
lrb = layout_org.insert_layer ();
db::LayerProperties p;
p.layer = 1;
p.datatype = 0;
layout_org.set_properties (la, p);
p.layer = 2;
p.datatype = 0;
layout_org.set_properties (lb, p);
p.layer = 100;
p.datatype = 0;
layout_org.set_properties (lra, p);
p.layer = 101;
p.datatype = 0;
layout_org.set_properties (lrb, p);
db::EdgeProcessor ep;
size_t pn = 0;
for (db::RecursiveShapeIterator iter (layout_org, layout_org.cell (*layout_org.begin_top_down ()), la); ! iter.at_end (); ++iter) {
db::Polygon p;
iter.shape ().polygon (p);
p.transform (iter.trans ());
ep.insert (p, pn);
pn += 2;
}
pn = 1;
for (db::RecursiveShapeIterator iter (layout_org, layout_org.cell (*layout_org.begin_top_down ()), lb); ! iter.at_end (); ++iter) {
db::Polygon p;
iter.shape ().polygon (p);
p.transform (iter.trans ());
ep.insert (p, pn);
pn += 2;
}
db::ShapeGenerator sg1 (layout_org.cell (*layout_org.begin_top_down ()).shapes (lra), true /*clear shapes*/);
db::PolygonGenerator pg1 (sg1, true /*resolve holes*/, false /*min. coherence*/);
db::BooleanOp op1 (db::BooleanOp::And);
db::ShapeGenerator sg2 (layout_org.cell (*layout_org.begin_top_down ()).shapes (lrb), true /*clear shapes*/);
db::PolygonGenerator pg2 (sg2, true /*resolve holes*/, false /*min. coherence*/);
db::BooleanOp op2 (db::BooleanOp::ANotB);
std::vector<std::pair<db::EdgeSink *, db::EdgeEvaluatorBase *> > procs;
procs.push_back (std::make_pair (&pg1, &op1));
procs.push_back (std::make_pair (&pg2, &op2));
ep.process (procs);
db::LayerMap lmap;
lmap.map (db::LDPair (1, 0), la);
lmap.map (db::LDPair (2, 0), lb);
lmap.map (db::LDPair (100, 0), lra);
lmap.map (db::LDPair (101, 0), lrb);
db::compare_layouts (_this, layout_org, au_fn, lmap, false /*skip other layers*/, db::WriteOAS);
}
TEST(1size)
{
run_test_size (_this, "size1.oas", "size1_au.oas", 2, -1, -1);
}
TEST(2size)
{
run_test_size (_this, "size2.oas", "size2_au.oas", 2, 1, 1);
}
//size5: 100: 0.002 (mode 0), 101: mode 1, 102: mode 2, .. 105; 200: -0.002 (mode 0), 201: mode 1, 202: mode2
//size6: 100: 0.002 (flat), 101: 0.002 (top cell), 102: 0.002 (cell by cell)
TEST(3size)
{
run_test_size (_this, "size3.oas", "size3_au1.oas", 2, 10, 0);
run_test_size (_this, "size3.oas", "size3_au2.oas", 2, -10, -50);
}
TEST(4size)
{
run_test_size (_this, "size4.oas", "size4_au1.oas", 2, -10, -50);
run_test_size (_this, "size4.oas", "size4_au2.oas", 2, 50, 10);
}
TEST(5size)
{
run_test_size (_this, "size5.oas", "size5_au1.oas", 0, 2, 2);
run_test_size (_this, "size5.oas", "size5_au2.oas", 1, 2, 2);
run_test_size (_this, "size5.oas", "size5_au3.oas", 2, 2, 2);
run_test_size (_this, "size5.oas", "size5_au4.oas", 3, 2, 2);
run_test_size (_this, "size5.oas", "size5_au5.oas", 4, 2, 2);
run_test_size (_this, "size5.oas", "size5_au6.oas", 5, 2, 2);
run_test_size (_this, "size5.oas", "size5_au10.oas", 0, -2, -2);
run_test_size (_this, "size5.oas", "size5_au11.oas", 1, -2, -2);
run_test_size (_this, "size5.oas", "size5_au12.oas", 2, -2, -2);
}
TEST(6size)
{
run_test_size (_this, "size6.oas", "size6_au1.oas", 2, 2, 2);
run_test_size (_this, "size6.oas", "size6_au2.oas", 2, 2, 2, true, false/*top cell only*/);
// not tested: layer 102 (cell by cell)
}
TEST(7size)
{
run_test_size (_this, "size7.oas", "size7_au1.oas", 2, -40, -40);
run_test_size (_this, "size7.oas", "size7_au2.oas", 2, -50, -50);
run_test_size (_this, "size7.oas", "size7_au3.oas", 2, -60, -60);
run_test_size (_this, "size7.oas", "size7_au4.oas", 2, -80, -80);
run_test_size (_this, "size7.oas", "size7_au5.oas", 2, -100, -100);
run_test_size (_this, "size7.oas", "size7_au6.oas", 2, 0, -100);
}
TEST(8size)
{
run_test_size (_this, "size8.oas", "size8_au1.oas", 2, 0, 100);
run_test_size (_this, "size8.oas", "size8_au2.oas", 2, 100, 50);
run_test_size (_this, "size8.oas", "size8_au3.oas", 2, -100, -100);
run_test_size (_this, "size8.oas", "size8_au4.oas", 2, 100, 100);
}
TEST(9twobool)
{
run_test_twobool (_this, "twobool9.oas", "twobool9_au1.oas");
}
void write (const std::vector<db::Polygon> &q1, const std::vector<db::Polygon> &q2,
const std::vector<db::Edge> &e1, const std::vector<db::Edge> &e2,
const std::string &fn)
{
db::Layout out;
db::Cell *cell = &out.cell (out.add_cell ("TOP"));
unsigned int l1 = out.insert_layer ();
db::LayerProperties lp1;
lp1.layer = 1;
lp1.datatype = 0;
out.set_properties (l1, lp1);
unsigned int l2 = out.insert_layer ();
db::LayerProperties lp2;
lp2.layer = 2;
lp2.datatype = 0;
out.set_properties (l2, lp2);
unsigned int la = out.insert_layer ();
db::LayerProperties lpa;
lpa.layer = 100;
lpa.datatype = 0;
out.set_properties (la, lpa);
unsigned int lb = out.insert_layer ();
db::LayerProperties lpb;
lpb.layer = 101;
lpb.datatype = 0;
out.set_properties (lb, lpb);
for (std::vector <db::Polygon>::const_iterator p = q1.begin (); p != q1.end (); ++p) {
cell->shapes (l1).insert (*p);
}
for (std::vector <db::Polygon>::const_iterator p = q2.begin (); p != q2.end (); ++p) {
cell->shapes (l2).insert (*p);
}
db::SimpleMerge sm_op;
db::EdgeProcessor ep;
db::PolygonContainer p1;
db::PolygonGenerator pp1 (p1, false);
ep.clear ();
ep.insert_sequence (e1.begin (), e1.end (), 0);
ep.process (pp1, sm_op);
for (std::vector <db::Polygon>::const_iterator p = p1.polygons ().begin (); p != p1.polygons ().end (); ++p) {
cell->shapes (la).insert (*p);
}
db::PolygonContainer p2;
db::PolygonGenerator pp2 (p2, false);
ep.clear ();
ep.insert_sequence (e2.begin (), e2.end (), 0);
ep.process (pp2, sm_op);
for (std::vector <db::Polygon>::const_iterator p = p2.polygons ().begin (); p != p2.polygons ().end (); ++p) {
cell->shapes (lb).insert (*p);
}
db::SaveLayoutOptions options;
options.set_format ("GDS2");
db::Writer writer (options);
tl::OutputStream stream (fn);
writer.write (out, stream);
printf ("%s written.\n", fn.c_str ());
}
TEST(10)
{
std::vector<db::Edge> edges;
db::Point plast (rand () / 2 - RAND_MAX / 4, rand () / 2 - RAND_MAX / 4);
for (unsigned int i = 0; i < 100; ++i) {
db::Point pnext (rand () / 2 - RAND_MAX / 4, rand () / 2 - RAND_MAX / 4);
edges.push_back (db::Edge (plast, pnext));
plast = pnext;
}
edges.push_back (db::Edge (plast, edges.front ().p1 ()));
std::vector<db::Edge> edges2;
db::Trans t (db::Vector (100, -200));
for (std::vector<db::Edge>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
edges2.push_back (e->transformed (t));
}
db::EdgeContainer anotb;
db::EdgeContainer bnota;
db::EdgeContainer xor_tmp;
db::PolygonContainer xor_res;
db::PolygonContainer anotb_or_bnota;
db::EdgeProcessor ep;
ep.clear ();
db::BooleanOp anotb_op (db::BooleanOp::ANotB);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
ep.process (anotb, anotb_op);
ep.clear ();
db::BooleanOp bnota_op (db::BooleanOp::BNotA);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
ep.process (bnota, bnota_op);
ep.clear ();
ep.insert_sequence (anotb.edges ().begin (), anotb.edges ().end ());
ep.insert_sequence (bnota.edges ().begin (), bnota.edges ().end ());
db::SimpleMerge sm_op;
db::PolygonGenerator pg1 (anotb_or_bnota, false);
ep.process (pg1, sm_op);
ep.clear ();
db::BooleanOp xor_op (db::BooleanOp::Xor);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
db::PolygonGenerator pg2 (xor_res, false);
ep.process (pg2, xor_op);
std::sort (anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end ());
std::sort (xor_res.polygons ().begin (), xor_res.polygons ().end ());
std::vector <db::Polygon> diff1, diff2;
std::set_difference (anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end (),
xor_res.polygons ().begin (), xor_res.polygons ().end (),
std::back_inserter (diff1));
std::set_difference (xor_res.polygons ().begin (), xor_res.polygons ().end (),
anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end (),
std::back_inserter (diff2));
#if 1
EXPECT_EQ (diff1.empty (), true);
EXPECT_EQ (diff2.empty (), true);
#else
// for debugging
printf ("pg1.size () == %d\n", anotb_or_bnota.polygons ().size ());
printf ("pg2.size () == %d\n", xor_res.polygons ().size ());
printf ("diff1:\n");
for (std::vector<db::Polygon>::const_iterator d = diff1.begin (); d != diff1.end (); ++d) {
printf ("%s\n", d->to_string().c_str ());
}
printf ("diff2:\n");
for (std::vector<db::Polygon>::const_iterator d = diff2.begin (); d != diff2.end (); ++d) {
printf ("%s\n", d->to_string().c_str ());
}
write (anotb_or_bnota.polygons (), xor_res.polygons (), edges, edges2, "x10.gds");
#endif
}
TEST(11)
{
std::vector<db::Edge> edges;
db::Point plast ((rand () % 20) * 100 - 1000, (rand () % 20) * 100 - 1000);
for (unsigned int i = 0; i < 100; ++i) {
db::Point pnext ((rand () % 20) * 100 - 1000, (rand () % 20) * 100 - 1000);
edges.push_back (db::Edge (plast, pnext));
plast = pnext;
}
edges.push_back (db::Edge (plast, edges.front ().p1 ()));
std::vector<db::Edge> edges2;
db::Trans t (db::Vector (100, -200));
for (std::vector<db::Edge>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
edges2.push_back (e->transformed (t));
}
db::EdgeContainer anotb;
db::EdgeContainer bnota;
db::EdgeContainer xor_tmp;
db::PolygonContainer xor_res;
db::PolygonContainer anotb_or_bnota;
db::EdgeProcessor ep;
ep.clear ();
db::BooleanOp anotb_op (db::BooleanOp::ANotB);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
ep.process (anotb, anotb_op);
ep.clear ();
db::BooleanOp bnota_op (db::BooleanOp::BNotA);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
ep.process (bnota, bnota_op);
ep.clear ();
ep.insert_sequence (anotb.edges ().begin (), anotb.edges ().end ());
ep.insert_sequence (bnota.edges ().begin (), bnota.edges ().end ());
db::SimpleMerge sm_op;
db::PolygonGenerator pg1 (anotb_or_bnota, false);
ep.process (pg1, sm_op);
ep.clear ();
db::BooleanOp xor_op (db::BooleanOp::Xor);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
db::PolygonGenerator pg2 (xor_res, false);
ep.process (pg2, xor_op);
std::sort (anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end ());
std::sort (xor_res.polygons ().begin (), xor_res.polygons ().end ());
std::vector <db::Polygon> diff1, diff2;
std::set_difference (anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end (),
xor_res.polygons ().begin (), xor_res.polygons ().end (),
std::back_inserter (diff1));
std::set_difference (xor_res.polygons ().begin (), xor_res.polygons ().end (),
anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end (),
std::back_inserter (diff2));
#if 1
EXPECT_EQ (diff1.empty (), true);
EXPECT_EQ (diff2.empty (), true);
#else
// for debugging
printf ("pg1.size () == %d\n", anotb_or_bnota.polygons ().size ());
printf ("pg2.size () == %d\n", xor_res.polygons ().size ());
printf ("diff1:\n");
for (std::vector<db::Polygon>::const_iterator d = diff1.begin (); d != diff1.end (); ++d) {
printf ("%s\n", d->to_string().c_str ());
}
printf ("diff2:\n");
for (std::vector<db::Polygon>::const_iterator d = diff2.begin (); d != diff2.end (); ++d) {
printf ("%s\n", d->to_string().c_str ());
}
write (anotb_or_bnota.polygons (), xor_res.polygons (), edges, edges2, "x11.gds");
#endif
}
TEST(12)
{
std::vector<db::Edge> edges;
// manhattan test case
db::Point plast ((rand () % 20) * 100 - 1000, (rand () % 20) * 100 - 1000);
for (unsigned int i = 0; i < 100; ++i) {
{
db::Point pnext ((rand () % 20) * 100 - 1000, plast.y ());
edges.push_back (db::Edge (plast, pnext));
plast = pnext;
}
{
db::Point pnext (plast.x (), (rand () % 20) * 100 - 1000);
edges.push_back (db::Edge (plast, pnext));
plast = pnext;
}
}
edges.push_back (db::Edge (plast, db::Point (edges.front ().p1 ().x (), plast.y ())));
edges.push_back (db::Edge (db::Point (edges.front ().p1 ().x (), plast.y ()), edges.front ().p1 ()));
std::vector<db::Edge> edges2;
db::Trans t (db::Vector (100, -200));
for (std::vector<db::Edge>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
edges2.push_back (e->transformed (t));
}
db::EdgeContainer anotb;
db::EdgeContainer bnota;
db::EdgeContainer xor_tmp;
db::PolygonContainer xor_res;
db::PolygonContainer anotb_or_bnota;
db::EdgeProcessor ep;
ep.clear ();
db::BooleanOp anotb_op (db::BooleanOp::ANotB);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
ep.process (anotb, anotb_op);
ep.clear ();
db::BooleanOp bnota_op (db::BooleanOp::BNotA);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
ep.process (bnota, bnota_op);
ep.clear ();
ep.insert_sequence (anotb.edges ().begin (), anotb.edges ().end ());
ep.insert_sequence (bnota.edges ().begin (), bnota.edges ().end ());
db::SimpleMerge sm_op;
db::PolygonGenerator pg1 (anotb_or_bnota, false);
ep.process (pg1, sm_op);
ep.clear ();
db::BooleanOp xor_op (db::BooleanOp::Xor);
ep.insert_sequence (edges.begin (), edges.end (), 0);
ep.insert_sequence (edges2.begin (), edges2.end (), 1);
db::PolygonGenerator pg2 (xor_res, false);
ep.process (pg2, xor_op);
std::sort (anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end ());
std::sort (xor_res.polygons ().begin (), xor_res.polygons ().end ());
std::vector <db::Polygon> diff1, diff2;
std::set_difference (anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end (),
xor_res.polygons ().begin (), xor_res.polygons ().end (),
std::back_inserter (diff1));
std::set_difference (xor_res.polygons ().begin (), xor_res.polygons ().end (),
anotb_or_bnota.polygons ().begin (), anotb_or_bnota.polygons ().end (),
std::back_inserter (diff2));
#if 1
EXPECT_EQ (diff1.empty (), true);
EXPECT_EQ (diff2.empty (), true);
#else
// for debugging
printf ("pg1.size () == %d\n", anotb_or_bnota.polygons ().size ());
printf ("pg2.size () == %d\n", xor_res.polygons ().size ());
printf ("diff1:\n");
for (std::vector<db::Polygon>::const_iterator d = diff1.begin (); d != diff1.end (); ++d) {
printf ("%s\n", d->to_string().c_str ());
}
printf ("diff2:\n");
for (std::vector<db::Polygon>::const_iterator d = diff2.begin (); d != diff2.end (); ++d) {
printf ("%s\n", d->to_string().c_str ());
}
write (anotb_or_bnota.polygons (), xor_res.polygons (), edges, edges2, "x12.gds");
#endif
}
TEST(13)
{
std::vector<db::Polygon> in;
std::vector<db::Polygon> out;
db::Box box (0, 0, 100, 100);
in.push_back (db::Polygon (box));
db::EdgeProcessor ep;
ep.size (in, -75, out);
EXPECT_EQ (out.size (), size_t (0));
out.clear();
ep.size (in, -25, out);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(25,25;25,75;75,75;75,25)");
}
TEST(14)
{
// This has been a problem which was solved with R228 - it was taking too many iterations
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (71012503, 113882497),
db::Point (70124103, 114770787),
db::Point (70124097, 114875997),
db::Point (70198487, 114950397),
db::Point (70303697, 114950403),
db::Point (71192097, 114062113),
db::Point (71192103, 113956903),
db::Point (71117713, 113882503)
};
db::Point p2[] = {
db::Point (71060295, 113834700),
db::Point (70938100, 113956895),
db::Point (70938100, 114062105),
db::Point (71012495, 114136500),
db::Point (71117705, 114136500),
db::Point (71239900, 114014305),
db::Point (71239900, 113909095),
db::Point (71165505, 113834700)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
db::Point p3[] = {
db::Point (71060295, 113834700),
db::Point (70972121, 113922874),
db::Point (70198499, 114696400),
db::Point (70198495, 114696400),
db::Point (70164485, 114730410),
db::Point (70124103, 114770787),
db::Point (70124103, 114770792),
db::Point (70124100, 114770795),
db::Point (70124100, 114823392),
db::Point (70124097, 114875997),
db::Point (70124100, 114876000),
db::Point (70124100, 115107255),
db::Point (71239900, 115107255),
db::Point (71239900, 113909095),
db::Point (71165505, 113834700)
};
in2.push_back (db::Polygon ());
in2.back ().assign_hull (p3, p3 + sizeof (p3) / sizeof (p3[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.boolean (in1, in2, out, db::BooleanOp::Xor, false, false);
EXPECT_EQ (out.size (), size_t (3));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(71239900,114014305;71192097,114062108;71192097,114062113;71151715,114102490;71117705,114136500;71117701,114136500;70303697,114950403;70198487,114950397;70124100,114876000;70124100,115107255;71239900,115107255)");
EXPECT_EQ (out[1].to_string (), "(70198495,114696400;70164485,114730410;70198499,114696400)");
// before R787 was:
// EXPECT_EQ (out[1].to_string (), "(70972040,113922955;70198499,114696400;70198495,114696400;70164485,114730410;70124103,114770787)");
EXPECT_EQ (out[2].to_string (), "(70124103,114770792;70124100,114770795;70124100,114823392)");
}
TEST(15)
{
// large coordinate handling
// This has been a problem which was solved with R228 - it was taking too many iterations
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (1514900, 9767),
db::Point (9080, 17031),
db::Point (1467712, 245710),
};
db::Point p2[] = {
db::Point (0, 22388),
db::Point (1467712, 245710),
db::Point (1510912, 29731),
db::Point (1511726, 25637),
db::Point (1512360, 22467),
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in2.push_back (db::Polygon ());
in2.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.boolean (in1, in2, out, db::BooleanOp::And, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(43264,22390;1467712,245710;1511719,25671;1511726,25637;1512360,22467)");
}
TEST(16)
{
// large coordinate handling
// This has been a problem which was solved with R228 - it was taking too many iterations
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (23, 2345),
db::Point (4, 9832),
db::Point (10592, 2485)
};
db::Point p2[] = {
db::Point (13, 0),
db::Point (13, 7486),
db::Point (10873, 6)
};
db::Point p3[] = {
db::Point (0, 2818),
db::Point (27, 10304),
db::Point (8643, 2823)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p3 + 0, p3 + sizeof (p3) / sizeof (p3[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(13,0;13,2818;0,2818;13,6286;13,6422;4,9832;25,9817;27,10304;2825,7874;10592,2485;7336,2442;10873,6)");
}
TEST(17)
{
// large coordinate handling
// This has been a problem which was solved with R228 - it was taking too many iterations
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (113, 64),
db::Point (1293, 469),
db::Point (1293, 64)
};
db::Point p2[] = {
db::Point (204, 100),
db::Point (1388, 495),
db::Point (1387, 101)
};
db::Point p3[] = {
db::Point (0, 18),
db::Point (1177, 434),
db::Point (1178, 18)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p3 + 0, p3 + sizeof (p3) / sizeof (p3[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(0,18;130,64;113,64;218,100;204,100;700,266;706,268;1177,434;1177,429;1293,469;1293,463;1388,495;1387,101;1293,101;1293,64;1178,64;1178,18)");
}
TEST(18)
{
// large coordinate handling
// This has been a problem which was solved with R228 - it was taking too many iterations
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (419, 1400.00),
db::Point (2281, 1589.00),
db::Point (2281, 1400.00)
};
db::Point p2[] = {
db::Point (419, 1400.00),
db::Point (2284, 1589.00),
db::Point (2284, 1400.00)
};
db::Point p3[] = {
db::Point (453, 1405.00),
db::Point (2316, 1588.00),
db::Point (2316, 1405.00)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p3 + 0, p3 + sizeof (p3) / sizeof (p3[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(419,1400;468,1405;453,1405;926,1451;953,1454;2281,1589;2284,1589;2284,1585;2316,1588;2316,1405;2284,1405;2284,1400)");
}
TEST(19)
{
// large coordinate handling
// This has been a problem which was solved with R228 - it was taking too many iterations
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (26029700, 19931900),
db::Point (11944600, 24988200),
db::Point (16663400, 48582400),
db::Point (31607400, 45593600)
};
db::Point p2[] = {
db::Point (12654800, 0),
db::Point (0, 8492100),
db::Point (13371200, 28417800),
db::Point (27109200, 23471400)
};
db::Point p3[] = {
db::Point (145086300, 20050900),
db::Point (12705400, 28790300),
db::Point (12851400, 29524600),
db::Point (145086300, 35290900)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p3 + 0, p3 + sizeof (p3) / sizeof (p3[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(12654800,0;0,8492100;12316037,26845401;12771101,29120740;12851400,29524600;12851876,29524621;16663400,48582400;31607400,45593600;28260773,30196549;145086300,35290900;145086300,20050900;27739393,27797800;26821540,23574973;27109200,23471400;26629840,22693003;26029700,19931900;25128663,20255356)");
}
TEST(20)
{
// TOPIC: catching of an edge by a close one.
// This has been a problem which was solved with R228 - it was taking too many iterations
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (7394, 2768),
db::Point (7533, 2826),
db::Point (7404, 2768)
};
db::Point p2[] = {
db::Point (7427, 2768),
db::Point (7533, 2826),
db::Point (7434, 2768)
};
db::Point p3[] = {
db::Point (7362, 2768),
db::Point (7532, 2826),
db::Point (7374, 2768)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p3 + 0, p3 + sizeof (p3) / sizeof (p3[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
EXPECT_EQ (out.size (), size_t (2));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(7362,2768;7532,2826;7374,2768)");
EXPECT_EQ (out[1].to_string (), "(7394,2768;7533,2826;7434,2768;7427,2768;7533,2826;7404,2768)");
}
TEST(21)
{
// Recurring edge and similar other edge problem
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (2696, 0),
db::Point (5297, 13339),
db::Point (6592, 2603),
db::Point (4217, 5014)
};
db::Point p2[] = {
db::Point (2696, 0),
db::Point (4217, 5015),
db::Point (890, 1381),
db::Point (0, 11887),
db::Point (4217, 5015)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in2.push_back (db::Polygon ());
in2.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.boolean (in1, in2, out, db::BooleanOp::And, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(3527,4261;3805,5687;4217,5015;4217,5014)");
}
TEST(22)
{
// Recurring edge and similar other edge problem
std::vector<db::Polygon> in1;
std::vector<db::Polygon> in2;
db::Point p1[] = {
db::Point (9985, 0),
db::Point (0, 2236),
db::Point (13710, 3746),
db::Point (12442, 2457),
};
db::Point p2[] = {
db::Point (9985, 0),
db::Point (0, 2236),
db::Point (13710, 3747),
db::Point (12443, 2458),
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
in2.push_back (db::Polygon ());
in2.back ().assign_hull (p2 + 0, p2 + sizeof (p2) / sizeof (p2[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.boolean (in1, in2, out, db::BooleanOp::And, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(9985,0;0,2236;13709,3746;12464,2479)");
}
TEST(23)
{
std::vector<db::Polygon> in1;
db::Point p1[] = {
db::Point (0, 0),
db::Point (1, 1),
db::Point (0, 1),
db::Point (1, 0),
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(0,0;0,1;1,1)");
}
TEST(24)
{
std::vector<db::Polygon> in1;
{
db::Point p1[] = {
db::Point (0, -9),
db::Point (1, 10),
db::Point (0, 10),
db::Point (1, -9)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
}
{
db::Point p1[] = {
db::Point (1, 1),
db::Point (-2, 2),
db::Point (-2, 3)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
}
{
db::Point p1[] = {
db::Point (3, -1),
db::Point (0, 1),
db::Point (3, 0)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
}
{
db::Point p1[] = {
db::Point (1, 0),
db::Point (-2, 1),
db::Point (-2, 2)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
}
{
db::Point p1[] = {
db::Point (3, -2),
db::Point (0, 0),
db::Point (3, -1)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
}
{
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false);
EXPECT_EQ (out.size (), size_t (1));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(0,-9;0,0;-2,1;-2,3;0,1;0,10;1,10;1,1;0,0;3,0;3,-2;1,0;1,-9)");
}
{
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, true);
EXPECT_EQ (out.size (), size_t (3));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(0,-9;0,0;1,0;1,-9)");
EXPECT_EQ (out[1].to_string (), "(3,-2;1,0;3,0)");
EXPECT_EQ (out[2].to_string (), "(0,0;-2,1;-2,3;0,1;0,10;1,10;1,1)");
}
}
TEST(25)
{
std::vector<db::Polygon> in1;
{
db::Point p1[] = {
db::Point (-471, 2264),
db::Point (-471, 2367),
db::Point (-345, 2367),
db::Point (-333, 2391),
db::Point (-327, 2402),
db::Point (-329, 2400),
db::Point (-327, 2399),
db::Point (-329, 2400),
db::Point (-323, 2407),
db::Point (-332, 2407),
db::Point (-332, 2391),
db::Point (-318, 2393),
db::Point (-328, 2397),
db::Point (-323, 2390),
db::Point (-332, 2394),
db::Point (-330, 2387),
db::Point (-326, 2387),
db::Point (-333, 2394),
db::Point (-333, 2388),
db::Point (-328, 2402),
db::Point (-339, 2402),
db::Point (-353, 2367),
db::Point (-353, 2264)
};
in1.push_back (db::Polygon ());
in1.back ().assign_hull (p1 + 0, p1 + sizeof (p1) / sizeof (p1[0]));
}
std::vector<db::Polygon> out;
db::EdgeProcessor ep;
ep.simple_merge (in1, out, false, false, 1);
EXPECT_EQ (out.size (), size_t (2));
std::sort (out.begin (), out.end ());
EXPECT_EQ (out[0].to_string (), "(-471,2264;-471,2367;-353,2367;-353,2264)");
EXPECT_EQ (out[1].to_string (), "(-323,2390;-327,2392;-324,2392)");
}
TEST(26a)
{
db::EdgeProcessor ep;
ep.insert (db::Polygon (db::Box (db::Point (0, 0), db::Point (100, 100))), 0);
ep.insert (db::Polygon (db::Box (db::Point (40, 0), db::Point (140, 100))), 1);
ep.insert (db::Polygon (db::Box (db::Point (60, 20), db::Point (160, 120))), 2);
ep.insert (db::Polygon (db::Box (db::Point (110, 50), db::Point (210, 150))), 3);
ep.insert (db::Polygon (db::Box (db::Point (-100, -100), db::Point (1000, 1000))), 4);
db::InteractionDetector id;
db::EdgeSink es;
ep.process (es, id);
id.finish ();
std::string s;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) {
if (! s.empty ()) {
s += ",";
}
s += tl::to_string (i->first) + ":" + tl::to_string (i->second);
}
EXPECT_EQ (s, "0:1,0:2,0:4,1:2,1:3,1:4,2:3,2:4,3:4");
}
TEST(26b)
{
db::EdgeProcessor ep;
ep.insert (db::Polygon (db::Box (db::Point (0, 0), db::Point (100, 100))), 0);
ep.insert (db::Polygon (db::Box (db::Point (40, 0), db::Point (140, 100))), 1);
ep.insert (db::Polygon (db::Box (db::Point (60, 20), db::Point (160, 120))), 2);
ep.insert (db::Polygon (db::Box (db::Point (110, 50), db::Point (210, 150))), 3);
ep.insert (db::Polygon (db::Box (db::Point (-100, -100), db::Point (1000, 1000))), 4);
ep.insert (db::Polygon (db::Box (db::Point (1000, 1100), db::Point (1100, 1200))), 5);
db::InteractionDetector id (1, 4); // outside with background #4
db::EdgeSink es;
ep.process (es, id);
id.finish ();
std::string s;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) {
if (! s.empty ()) {
s += ",";
}
s += tl::to_string (i->first) + ":" + tl::to_string (i->second);
}
EXPECT_EQ (s, "4:5");
}
TEST(26c)
{
db::EdgeProcessor ep;
ep.insert (db::Polygon (db::Box (db::Point (-100, -100), db::Point (1000, 1000))), 0);
ep.insert (db::Polygon (db::Box (db::Point (1000, 1100), db::Point (1100, 1200))), 1);
ep.insert (db::Polygon (db::Box (db::Point (0, 0), db::Point (100, 100))), 2);
ep.insert (db::Polygon (db::Box (db::Point (40, 0), db::Point (140, 100))), 3);
ep.insert (db::Polygon (db::Box (db::Point (60, 20), db::Point (160, 120))), 4);
ep.insert (db::Polygon (db::Box (db::Point (110, 50), db::Point (210, 150))), 5);
ep.insert (db::Polygon (db::Box (db::Point (1000, 1100), db::Point (1010, 1110))), 6);
db::InteractionDetector id (-1, 0); // inside with background #0
db::EdgeSink es;
ep.process (es, id);
id.finish ();
std::string s;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) {
if (! s.empty ()) {
s += ",";
}
s += tl::to_string (i->first) + ":" + tl::to_string (i->second);
}
// does not work yet!
EXPECT_EQ (s, "0:2,0:3,0:4,0:5");
}
TEST(26d)
{
db::EdgeProcessor ep;
ep.insert (db::Polygon (db::Box (db::Point (-100, -100), db::Point (1000, 1000))), 0);
ep.insert (db::Polygon (db::Box (db::Point (1000, 1100), db::Point (1100, 1200))), 1);
ep.insert (db::Polygon (db::Box (db::Point (0, 0), db::Point (100, 100))), 2);
ep.insert (db::Polygon (db::Box (db::Point (40, 0), db::Point (140, 100))), 3);
ep.insert (db::Polygon (db::Box (db::Point (60, 20), db::Point (160, 120))), 4);
ep.insert (db::Polygon (db::Box (db::Point (110, 50), db::Point (210, 150))), 5);
ep.insert (db::Polygon (db::Box (db::Point (1000, 1100), db::Point (1010, 1110))), 6);
db::InteractionDetector id (-1, 1); // inside with background #0 and #1
db::EdgeSink es;
ep.process (es, id);
id.finish ();
std::string s;
for (db::InteractionDetector::iterator i = id.begin (); i != id.end (); ++i) {
if (! s.empty ()) {
s += ",";
}
s += tl::to_string (i->first) + ":" + tl::to_string (i->second);
}
// does not work yet!
EXPECT_EQ (s, "0:2,0:3,0:4,0:5,1:6");
}
TEST(27)
{
db::Polygon poly (db::Box (db::Point (0, 0), db::Point (1000, 1000)));
db::Polygon p2 (poly);
p2.size (-100, -100, 2);
// because we don't use mode 1 merging for p2, we get loops at the corners of p2
{
db::EdgeProcessor ep;
ep.insert (poly, 0);
ep.insert (p2, 1);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, true);
db::BooleanOp op (db::BooleanOp::Xor);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (4));
EXPECT_EQ (out[0].to_string (), "(100,0;100,100;900,100;900,0)");
EXPECT_EQ (out[1].to_string (), "(0,100;0,900;100,900;100,100)");
EXPECT_EQ (out[2].to_string (), "(900,100;900,900;1000,900;1000,100)");
EXPECT_EQ (out[3].to_string (), "(100,900;100,1000;900,1000;900,900)");
}
// BooleanOp2 behaves the same with modes -1
{
db::EdgeProcessor ep;
ep.insert (poly, 0);
ep.insert (p2, 1);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, false);
db::BooleanOp2 op (db::BooleanOp::Xor, -1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(100,0;100,100;0,100;0,900;100,900;100,1000;900,1000;900,900;1000,900;1000,100;900,100;900,0/100,100;900,100;900,900;100,900)");
}
// with BooleanOp2 we can solve this issue
{
db::EdgeProcessor ep;
ep.insert (poly, 0);
ep.insert (p2, 1);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, true);
db::BooleanOp2 op (db::BooleanOp::Xor, -1, 1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(0,0;0,1000;1000,1000;1000,0/100,100;900,100;900,900;100,900)");
}
{
db::EdgeProcessor ep;
ep.insert (poly, 1);
ep.insert (p2, 0);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, false);
db::BooleanOp2 op (db::BooleanOp::Xor, -1, 1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(100,0;100,100;0,100;0,900;100,900;100,1000;900,1000;900,900;1000,900;1000,100;900,100;900,0/100,100;900,100;900,900;100,900)");
}
{
db::EdgeProcessor ep;
ep.insert (poly, 1);
ep.insert (p2, 0);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, true);
db::BooleanOp2 op (db::BooleanOp::Xor, 1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(0,0;0,1000;1000,1000;1000,0/100,100;900,100;900,900;100,900)");
}
}
// #594
TEST(28)
{
std::vector<db::Polygon> b;
db::Point b1[] = {
db::Point (-518003,-792684),
db::Point (-489451,-724867),
db::Point (-487680,-724734),
db::Point (-485180,-757934),
db::Point (-501151,-775469)
};
b.push_back (db::Polygon ());
b.back ().assign_hull (b1 + 0, b1 + sizeof (b1) / sizeof (b1[0]));
std::vector<db::Polygon> a;
db::Point a1[] = {
db::Point (-488720,-758200),
db::Point (-491220,-725000),
db::Point (-487680,-724734),
db::Point (-485180,-757934)
};
a.push_back (db::Polygon ());
a.back ().assign_hull (a1 + 0, a1 + sizeof (a1) / sizeof (a1[0]));
db::Point a2[] = {
db::Point (-490953,-726224),
db::Point (-505953,-709625),
db::Point (-502948,-706909),
db::Point (-487948,-723509)
};
a.push_back (db::Polygon ());
a.back ().assign_hull (a2 + 0, a2 + sizeof (a2) / sizeof (a2[0]));
db::Point a3[] = {
db::Point (-491225,-724867),
db::Point (-491225,-691667),
db::Point (-487675,-691667),
db::Point (-487675,-724867)
};
a.push_back (db::Polygon ());
a.back ().assign_hull (a3 + 0, a3 + sizeof (a3) / sizeof (a3[0]));
db::EdgeProcessor ep;
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
for (std::vector<db::Polygon>::const_iterator i = b.begin (); i != b.end (); ++i) {
ep.insert (*i, 1);
}
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, true);
db::BooleanOp op (db::BooleanOp::And);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(-488720,-758200;-490960,-728451;-489451,-724867;-489450,-724867;-487680,-724734;-487675,-724800;-485180,-757934)");
}
// #644
TEST(29)
{
std::vector<db::Polygon> b;
db::Point b1[] = {
db::Point (0, 0),
db::Point (0, 608),
db::Point (172, 602),
db::Point (572, 588),
db::Point (573, 588),
db::Point (710, 583),
db::Point (710, 0)
};
b.push_back (db::Polygon ());
b.back ().assign_hull (b1 + 0, b1 + sizeof (b1) / sizeof (b1[0]));
std::vector<db::Polygon> a;
db::Point a1[] = {
db::Point (140, 140),
db::Point (140, 603),
db::Point (167, 602),
db::Point (372, 595),
db::Point (580, 588),
db::Point (580, 140)
};
a.push_back (db::Polygon ());
a.back ().assign_hull (a1 + 0, a1 + sizeof (a1) / sizeof (a1[0]));
db::EdgeProcessor ep;
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
for (std::vector<db::Polygon>::const_iterator i = b.begin (); i != b.end (); ++i) {
ep.insert (*i, 1);
}
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, true);
db::BooleanOp op (db::BooleanOp::Or);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(0,0;0,608;172,602;572,588;580,588;710,583;710,0)");
}
TEST(30)
{
std::vector<db::Polygon> a;
db::Point a1[] = {
db::Point (0, 0),
db::Point (0, 500),
db::Point (300, 500),
db::Point (500, 300),
db::Point (500, 0)
};
a.push_back (db::Polygon ());
a.back ().assign_hull (a1 + 0, a1 + sizeof (a1) / sizeof (a1[0]));
db::EdgeProcessor ep;
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
ep.insert (db::Edge (-100, 400, 600, 420), 1);
ep.insert (db::Edge (-100, 400, 600, 400), 1);
std::vector<db::Edge> out;
db::EdgeContainer ec (out);
db::EdgePolygonOp op;
ep.process (ec, op);
EXPECT_EQ (out.size (), size_t (2));
EXPECT_EQ (out[0].to_string (), "(0,400;400,400)");
EXPECT_EQ (out[1].to_string (), "(0,403;386,414)");
}
TEST(31)
{
std::vector<db::Polygon> a;
db::Point a1[] = {
db::Point (0, 0),
db::Point (0, 500),
db::Point (300, 500),
db::Point (500, 300),
db::Point (500, 0)
};
a.push_back (db::Polygon ());
a.back ().assign_hull (a1 + 0, a1 + sizeof (a1) / sizeof (a1[0]));
db::EdgeProcessor ep;
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
ep.insert (db::Edge (600, 400, -100, 420), 1);
ep.insert (db::Edge (600, 400, -100, 400), 1);
ep.insert (db::Edge (-100, 0, 600, 0), 1);
ep.insert (db::Edge (0, -100, 0, 600), 1);
ep.insert (db::Edge (500, -100, 500, 600), 1);
std::vector<db::Edge> out;
db::EdgeContainer ec (out);
db::EdgePolygonOp op;
ep.process (ec, op);
std::string s;
for (size_t i = 0; i < out.size (); ++i) {
if (i > 0) {
s += ";";
}
s += out[i].to_string ();
}
EXPECT_EQ (s, "(0,0;0,400);(0,0;500,0);(500,0;500,300);(0,400;0,417);(400,400;0,400);(394,406;0,417);(0,417;0,500)");
ep.clear ();
out.clear ();
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
ep.insert (db::Edge (-100, 500, 600, 500), 1);
ep.insert (db::Edge (400, -100, 400, 600), 1);
ep.insert (db::Edge (-100, -100, -100, 600), 1);
ep.insert (db::Edge (600, -100, 600, 600), 1);
ep.insert (db::Edge (-100, -100, 600, -100), 1);
ep.process (ec, op);
s.clear ();
for (size_t i = 0; i < out.size (); ++i) {
if (i > 0) {
s += ";";
}
s += out[i].to_string ();
}
EXPECT_EQ (s, "(400,0;400,400);(0,500;300,500)");
}
TEST(32)
{
std::vector<db::Polygon> a;
db::Point a1[] = {
db::Point (0, 0),
db::Point (0, 500),
db::Point (300, 500),
db::Point (500, 300),
db::Point (500, 0)
};
a.push_back (db::Polygon ());
a.back ().assign_hull (a1 + 0, a1 + sizeof (a1) / sizeof (a1[0]));
db::EdgeProcessor ep;
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
ep.insert (db::Edge (600, 400, -100, 420), 1);
ep.insert (db::Edge (600, 400, -100, 400), 1);
ep.insert (db::Edge (-100, 0, 600, 0), 1);
ep.insert (db::Edge (0, -100, 0, 600), 1);
ep.insert (db::Edge (500, -100, 500, 600), 1);
std::vector<db::Edge> out;
db::EdgeContainer ec (out);
db::EdgePolygonOp op (false, false /*not including touch*/);
ep.process (ec, op);
std::string s;
for (size_t i = 0; i < out.size (); ++i) {
if (i > 0) {
s += ";";
}
s += out[i].to_string ();
}
EXPECT_EQ (s, "(400,400;0,400);(394,406;0,417)");
ep.clear ();
out.clear ();
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
ep.insert (db::Edge (-100, 500, 600, 500), 1);
ep.insert (db::Edge (400, -100, 400, 600), 1);
ep.insert (db::Edge (-100, -100, -100, 600), 1);
ep.insert (db::Edge (600, -100, 600, 600), 1);
ep.insert (db::Edge (-100, -100, 600, -100), 1);
ep.process (ec, op);
s.clear ();
for (size_t i = 0; i < out.size (); ++i) {
if (i > 0) {
s += ";";
}
s += out[i].to_string ();
}
EXPECT_EQ (s, "(400,0;400,400)");
}
TEST(33)
{
std::vector<db::Polygon> a;
db::Point a1[] = {
db::Point (0, 0),
db::Point (0, 500),
db::Point (300, 500),
db::Point (500, 300),
db::Point (500, 0)
};
a.push_back (db::Polygon ());
a.back ().assign_hull (a1 + 0, a1 + sizeof (a1) / sizeof (a1[0]));
db::EdgeProcessor ep;
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
ep.insert (db::Edge (600, 400, -100, 420), 1);
ep.insert (db::Edge (600, 400, -100, 400), 1);
ep.insert (db::Edge (-100, 0, 600, 0), 1);
ep.insert (db::Edge (0, -100, 0, 600), 1);
ep.insert (db::Edge (500, -100, 500, 600), 1);
std::vector<db::Edge> out;
db::EdgeContainer ec (out);
db::EdgePolygonOp op (true, true /*including touch*/);
ep.process (ec, op);
std::string s;
for (size_t i = 0; i < out.size (); ++i) {
if (i > 0) {
s += ";";
}
s += out[i].to_string ();
}
EXPECT_EQ (s, "(0,-100;0,0);(500,-100;500,0);(-100,0;0,0);(500,0;600,0);(500,300;500,400);"
"(0,400;-100,400);(500,400;400,400);(500,400;500,403);(600,400;500,400);"
"(600,400;500,403);(500,403;394,406);(500,403;500,600);(0,417;-100,420);"
"(0,500;0,600)");
ep.clear ();
out.clear ();
for (std::vector<db::Polygon>::const_iterator i = a.begin (); i != a.end (); ++i) {
ep.insert (*i, 0);
}
ep.insert (db::Edge (-100, 500, 600, 500), 1);
ep.insert (db::Edge (400, -100, 400, 600), 1);
ep.insert (db::Edge (-100, -100, -100, 600), 1);
ep.insert (db::Edge (600, -100, 600, 600), 1);
ep.insert (db::Edge (-100, -100, 600, -100), 1);
ep.process (ec, op);
s.clear ();
for (size_t i = 0; i < out.size (); ++i) {
if (i > 0) {
s += ";";
}
s += out[i].to_string ();
}
EXPECT_EQ (s, "(-100,-100;-100,500);(-100,-100;400,-100);(400,-100;400,0);(400,-100;600,-100);"
"(600,-100;600,500);(400,400;400,500);(-100,500;-100,600);(-100,500;0,500);"
"(300,500;400,500);(400,500;400,600);(400,500;600,500);(600,500;600,600)");
}
// TrapezoidGenerator
// Basic
TEST(40)
{
db::EdgeProcessor ep;
ep.insert (db::Polygon (db::Box (0, 0, 1000, 1000)), 0);
ep.insert (db::Polygon (db::Box (100, 100, 800, 800)), 1);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::TrapezoidGenerator pg (pc);
db::BooleanOp2 op (db::BooleanOp::Xor, 1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (4));
EXPECT_EQ (out[0].to_string (), "(0,0;0,100;1000,100;1000,0)");
EXPECT_EQ (out[1].to_string (), "(0,100;0,800;100,800;100,100)");
EXPECT_EQ (out[2].to_string (), "(800,100;800,800;1000,800;1000,100)");
EXPECT_EQ (out[3].to_string (), "(0,800;0,1000;1000,1000;1000,800)");
}
TEST(41)
{
db::EdgeProcessor ep;
ep.insert (db::Polygon (db::Box (0, 0, 1000, 1000)), 0);
ep.insert (db::Polygon (db::Box (100, 100, 400, 400)), 1);
ep.insert (db::Polygon (db::Box (400, 400, 800, 800)), 1);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::TrapezoidGenerator pg (pc);
db::BooleanOp2 op (db::BooleanOp::Xor, 1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (6));
EXPECT_EQ (out[0].to_string (), "(0,0;0,100;1000,100;1000,0)");
EXPECT_EQ (out[1].to_string (), "(0,100;0,400;100,400;100,100)");
EXPECT_EQ (out[2].to_string (), "(400,100;400,400;1000,400;1000,100)");
EXPECT_EQ (out[3].to_string (), "(0,400;0,800;400,800;400,400)");
EXPECT_EQ (out[4].to_string (), "(800,400;800,800;1000,800;1000,400)");
EXPECT_EQ (out[5].to_string (), "(0,800;0,1000;1000,1000;1000,800)");
}
TEST(42)
{
db::EdgeProcessor ep;
ep.insert (db::Polygon (db::Box (400, 0, 1000, 600)), 0);
ep.insert (db::Polygon (db::Box (0, 400, 600, 1000)), 1);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::TrapezoidGenerator pg (pc);
db::BooleanOp2 op (db::BooleanOp::Xor, 1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (4));
EXPECT_EQ (out[0].to_string (), "(400,0;400,400;1000,400;1000,0)");
EXPECT_EQ (out[1].to_string (), "(0,400;0,600;400,600;400,400)");
EXPECT_EQ (out[2].to_string (), "(600,400;600,600;1000,600;1000,400)");
EXPECT_EQ (out[3].to_string (), "(0,600;0,1000;600,1000;600,600)");
}
TEST(43)
{
db::EdgeProcessor ep;
ep.insert (db::Edge (0, 0, 500, 1000), 0);
ep.insert (db::Edge (500, 1000, 1000, 500), 0);
ep.insert (db::Edge (1000, 500, 1000, 0), 0);
ep.insert (db::Edge (1000, 0, 0, 0), 0);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::TrapezoidGenerator pg (pc);
db::BooleanOp2 op (db::BooleanOp::Xor, 1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (2));
EXPECT_EQ (out[0].to_string (), "(0,0;250,500;1000,500;1000,0)");
EXPECT_EQ (out[1].to_string (), "(250,500;500,1000;1000,500)");
}
TEST(44)
{
db::EdgeProcessor ep;
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 4000),
db::Point (2000, 4000),
db::Point (2500, 3000),
db::Point (3000, 2500),
db::Point (6500, 2000),
db::Point (8000, 4000),
db::Point (9000, 4000),
db::Point (9000, 0)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::TrapezoidGenerator pg (pc);
db::BooleanOp2 op (db::BooleanOp::Xor, 1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (5));
EXPECT_EQ (out[0].to_string (), "(0,0;0,2000;9000,2000;9000,0)");
EXPECT_EQ (out[1].to_string (), "(0,2000;0,2500;3000,2500;6500,2000)");
EXPECT_EQ (out[2].to_string (), "(0,2500;0,3000;2500,3000;3000,2500)");
EXPECT_EQ (out[3].to_string (), "(0,3000;0,4000;2000,4000;2500,3000)");
EXPECT_EQ (out[4].to_string (), "(6500,2000;8000,4000;9000,4000;9000,2000)");
}
TEST(45)
{
db::EdgeProcessor ep;
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 200),
db::Point (200, 150),
db::Point (250, 150),
db::Point (300, 100),
db::Point (800, 50),
db::Point (900, 200),
db::Point (1000, 200),
db::Point (1000, 0)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::TrapezoidGenerator pg (pc);
db::BooleanOp2 op (db::BooleanOp::Xor, 1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (5));
EXPECT_EQ (out[0].to_string (), "(0,0;0,50;1000,50;1000,0)");
EXPECT_EQ (out[1].to_string (), "(0,50;0,100;300,100;800,50)");
EXPECT_EQ (out[2].to_string (), "(0,100;0,150;250,150;300,100)");
EXPECT_EQ (out[3].to_string (), "(0,150;0,200;200,150)");
EXPECT_EQ (out[4].to_string (), "(800,50;900,200;1000,200;1000,50)");
}
TEST(46)
{
db::EdgeProcessor ep;
db::Point pts[] = {
db::Point (0, 0),
db::Point (300, 500),
db::Point (800, 100),
db::Point (300, 250),
db::Point (350, 0),
db::Point (400, 150)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::TrapezoidGenerator pg (pc);
db::BooleanOp2 op (db::BooleanOp::Xor, -1, -1);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (6));
EXPECT_EQ (out[0].to_string (), "(0,0;73,122;326,122)");
EXPECT_EQ (out[1].to_string (), "(350,0;326,122;391,122)");
EXPECT_EQ (out[2].to_string (), "(326,122;400,150;391,122)");
EXPECT_EQ (out[3].to_string (), "(73,122;150,250;300,250;326,122)");
EXPECT_EQ (out[4].to_string (), "(800,100;300,250;613,250)");
EXPECT_EQ (out[5].to_string (), "(150,250;300,500;613,250)");
}
// # 880
TEST(100)
{
db::Layout layout_1, layout_2;
db::Layout layout_au;
unsigned int l1_l1d0 = 0, l1_l2d0 = 0;
unsigned int l2_l1d0 = 0, l2_l2d0 = 0;
{
std::string fn (tl::testsrc ());
fn += "/testdata/bool/";
fn += "sp1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
db::LayerMap lmap;
db::LayerProperties p;
p.layer = 1;
p.datatype = 0;
lmap.map (db::LDPair (1, 0), l1_l1d0 = layout_1.insert_layer ());
layout_1.set_properties (l1_l1d0, p);
p.layer = 2;
p.datatype = 0;
lmap.map (db::LDPair (2, 0), l1_l2d0 = layout_1.insert_layer ());
layout_1.set_properties (l1_l2d0, p);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
reader.read (layout_1, options);
}
{
std::string fn (tl::testsrc ());
fn += "/testdata/bool/";
fn += "sp2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
db::LayerMap lmap;
db::LayerProperties p;
p.layer = 1;
p.datatype = 0;
lmap.map (db::LDPair (1, 0), l2_l1d0 = layout_2.insert_layer ());
layout_2.set_properties (l2_l1d0, p);
p.layer = 2;
p.datatype = 0;
lmap.map (db::LDPair (2, 0), l2_l2d0 = layout_2.insert_layer ());
layout_2.set_properties (l2_l2d0, p);
db::LoadLayoutOptions options;
options.get_options<db::CommonReaderOptions> ().layer_map = lmap;
options.get_options<db::CommonReaderOptions> ().create_other_layers = false;
reader.read (layout_2, options);
}
db::ShapeProcessor proc;
db::Layout lr;
lr.dbu (0.0001);
db::Cell *lr_top = &lr.cell (lr.add_cell ("TOP"));
unsigned int lr_l100d0 = lr.insert_layer (db::LayerProperties (100, 0));
proc.boolean (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l1_l1d0,
layout_2, layout_2.cell (*layout_2.begin_top_down ()), l2_l1d0,
lr_top->shapes (lr_l100d0), db::BooleanOp::Xor, true /*hierarchical*/, true /*resolve holes*/, true /*min coherence*/);
unsigned int lr_l101d0 = lr.insert_layer (db::LayerProperties (101, 0));
proc.boolean (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l1_l1d0,
layout_2, layout_2.cell (*layout_2.begin_top_down ()), l2_l1d0,
lr_top->shapes (lr_l101d0), db::BooleanOp::Xor, false /*hierarchical*/, true /*resolve holes*/, true /*min coherence*/);
unsigned int lr_l110d0 = lr.insert_layer (db::LayerProperties (110, 0));
proc.size (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l1_l1d0,
lr_top->shapes (lr_l110d0), 100, 200, 2, true /*hierarchical*/, true /*resolve holes*/, true /*min coherence*/);
unsigned int lr_l111d0 = lr.insert_layer (db::LayerProperties (111, 0));
proc.size (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l1_l1d0,
lr_top->shapes (lr_l111d0), 100, 200, 2, false /*hierarchical*/, true /*resolve holes*/, true /*min coherence*/);
unsigned int lr_l120d0 = lr.insert_layer (db::LayerProperties (120, 0));
proc.merge (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l1_l1d0,
lr_top->shapes (lr_l120d0), true /*hierarchical*/, 0, true /*resolve holes*/, true /*min coherence*/);
unsigned int lr_l121d0 = lr.insert_layer (db::LayerProperties (121, 0));
proc.merge (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l1_l1d0,
lr_top->shapes (lr_l121d0), false /*hierarchical*/, 0, true /*resolve holes*/, true /*min coherence*/);
unsigned int lr_l122d0 = lr.insert_layer (db::LayerProperties (122, 0));
proc.merge (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l1_l1d0,
lr_top->shapes (lr_l122d0), true /*hierarchical*/, 1, true /*resolve holes*/, true /*min coherence*/);
unsigned int lr_l123d0 = lr.insert_layer (db::LayerProperties (123, 0));
proc.merge (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l1_l1d0,
lr_top->shapes (lr_l123d0), false /*hierarchical*/, 1, true /*resolve holes*/, true /*min coherence*/);
std::string au_fn (tl::testsrc ());
au_fn += "/testdata/bool/";
au_fn += "sp_au.gds";
db::compare_layouts (_this, lr, au_fn);
}
// #74 (GitHub)
std::string run_test101 (tl::TestBase *_this, const db::Trans &t)
{
db::EdgeProcessor ep;
{
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 10),
db::Point (10, 10),
db::Point (10, 0)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
p.transform (t);
ep.insert (p, 0);
}
{
db::Point pts[] = {
db::Point (-1, -1),
db::Point (-1, 8),
db::Point (2, 11),
db::Point (2, -1)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
p.transform (t);
ep.insert (p, 1);
}
{
db::Point pts[] = {
db::Point (2, -1),
db::Point (2, 11),
db::Point (11, 11),
db::Point (11, -1)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
p.transform (t);
ep.insert (p, 1);
}
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, false, true);
db::BooleanOp op (db::BooleanOp::And);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
return out.empty () ? std::string () : out.front ().to_string ();
}
TEST(101)
{
EXPECT_EQ (run_test101 (_this, db::Trans (db::Trans::r0)), "(0,0;0,9;1,10;10,10;10,0)");
EXPECT_EQ (run_test101 (_this, db::Trans (db::Trans::r90)), "(-9,0;-10,1;-10,10;0,10;0,0)");
EXPECT_EQ (run_test101 (_this, db::Trans (db::Trans::r180)), "(-10,-10;-10,0;0,0;0,-9;-1,-10)");
EXPECT_EQ (run_test101 (_this, db::Trans (db::Trans::r270)), "(0,-10;0,0;9,0;10,-1;10,-10)");
}
TEST(102)
{
db::EdgeProcessor ep;
{
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 1000),
db::Point (1000, 1000),
db::Point (1000, 0)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 0);
}
{
db::Point pts[] = {
db::Point (100, 100),
db::Point (100, 200),
db::Point (200, 200),
db::Point (200, 100)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 1);
}
{
db::Point pts[] = {
db::Point (500, 100),
db::Point (500, 200),
db::Point (600, 200),
db::Point (600, 100)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 1);
}
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, true, true);
db::BooleanOp op (db::BooleanOp::ANotB);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
EXPECT_EQ (out[0].to_string (), "(0,0;0,200;100,200;100,100;200,100;200,200;500,200;500,100;600,100;600,200;0,200;0,1000;1000,1000;1000,0)");
}
TEST(103)
{
db::EdgeProcessor ep;
{
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 500),
db::Point (1500, 500),
db::Point (1500, 0),
db::Point (1000, 0),
db::Point (1000, 400),
db::Point (500, 400),
db::Point (500, 0)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 0);
}
{
db::Point pts[] = {
db::Point (100, 100),
db::Point (100, 400),
db::Point (400, 400),
db::Point (400, 100)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 1);
}
{
db::Point pts[] = {
db::Point (1100, 100),
db::Point (1100, 400),
db::Point (1400, 400),
db::Point (1400, 100)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
ep.insert (p, 1);
}
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc, true, true);
db::BooleanOp op (db::BooleanOp::ANotB);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (1));
#if 1
// fast hole treatment
EXPECT_EQ (out[0].to_string (), "(0,0;0,400;100,400;100,100;400,100;400,400;1100,400;1100,100;1400,100;1400,400;0,400;0,500;1500,500;1500,0;1000,0;1000,400;500,400;500,0)");
#else
// elaborate hole treatment
EXPECT_EQ (out[0].to_string (), "(0,0;0,400;100,400;100,100;400,100;400,400;0,400;0,500;1500,500;1500,0;1000,0;1000,400;1100,400;1100,100;1400,100;1400,400;500,400;500,0)");
#endif
}
// Bug 134
TEST(134)
{
const char *pd = "(30,-7957;0,0;56,-4102;30,-7921)";
db::Coord dx = 0;
db::Coord dy = -3999;
unsigned int mode = 3;
db::Polygon p;
tl::from_string (pd, p);
db::EdgeProcessor ep;
db::Polygon ps (p.sized (dx, dy, mode));
ep.insert (ps);
db::SimpleMerge op (1 /*wc>0*/);
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg (pc);
ep.process (pg, op);
EXPECT_EQ (out.size (), size_t (0));
}
void run_test135a (tl::TestBase *_this, const db::Trans &t)
{
db::EdgeProcessor ep;
db::Point pts[] = {
db::Point (0, 0),
db::Point (19, 19),
db::Point (19, 18),
db::Point (43, 32),
db::Point (37, 27)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
p.transform (t);
p.size (-2, -2, 2);
ep.insert (p);
// this is just supposed to work and not fail with internal error "m_open.empty()"
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg2 (pc, false /*don't resolve holes*/, true /*min. coherence*/);
db::SimpleMerge op (1 /*wc>0*/);
ep.process (pg2, op);
EXPECT_EQ (out.size (), size_t (0));
}
TEST(135a)
{
run_test135a (_this, db::Trans (db::Trans::r0));
run_test135a (_this, db::Trans (db::Trans::r90));
run_test135a (_this, db::Trans (db::Trans::r180));
run_test135a (_this, db::Trans (db::Trans::r270));
run_test135a (_this, db::Trans (db::Trans::m0));
run_test135a (_this, db::Trans (db::Trans::m45));
run_test135a (_this, db::Trans (db::Trans::m90));
run_test135a (_this, db::Trans (db::Trans::m135));
}
std::string run_test135b (tl::TestBase *_this, const db::Trans &t)
{
db::EdgeProcessor ep;
db::Point pts[] = {
db::Point (215, 0),
db::Point (145, 11),
db::Point (37, 31),
db::Point (36, 31),
db::Point (0, 43)
};
db::Polygon p;
p.assign_hull (&pts[0], &pts[sizeof(pts) / sizeof(pts[0])]);
p.transform (t);
p.size (-2, -2, 2);
ep.insert (p);
// this is just supposed to work and not fail with internal error "m_open.empty()"
std::vector<db::Polygon> out;
db::PolygonContainer pc (out);
db::PolygonGenerator pg2 (pc, false /*don't resolve holes*/, true /*min. coherence*/);
db::SimpleMerge op (1 /*wc>0*/);
ep.process (pg2, op);
EXPECT_EQ (out.size (), size_t (1));
return out.empty () ? std::string () : out.front ().to_string ();
}
TEST(135b)
{
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::r0)), "(36,33;32,34;37,33)");
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::r90)), "(-35,32;-26,77;-33,37;-33,36)");
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::r180)), "(-33,-35;-78,-26;-37,-33;-36,-33)");
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::r270)), "(25,-78;33,-37;33,-36;34,-33)");
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m0)), "(32,-35;36,-33;37,-33;77,-26)");
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m45)), "(34,32;33,36;33,37)");
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m90)), "(-78,25;-33,34;-36,33;-37,33)");
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m135)), "(-26,-78;-35,-33;-33,-36;-33,-37)");
}