mirror of https://github.com/KLayout/klayout.git
2741 lines
78 KiB
C++
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)");
|
|
}
|