diff --git a/genlib/bspnode.cpp b/genlib/bspnode.cpp
deleted file mode 100644
index f380446b..00000000
--- a/genlib/bspnode.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-// genlib - a component of the depthmapX - spatial network analysis platform
-// Copyright (C) 2000-2010 University College London, Alasdair Turner
-// Copyright (C) 2011-2012, Tasos Varoudis
-
-// 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 3 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, see .
-
-#include "bspnode.h"
-
-// Binary Space Partition
-
-void BSPNode::make(Communicator *communicator, time_t atime, const prefvec& lines, BSPNode *par)
-{
- m_count++;
-
- if (communicator)
- {
- if (communicator->IsCancelled()) {
- throw Communicator::CancelledException();
- }
- if (qtimer( atime, 500 )) {
- communicator->CommPostMessage( Communicator::CURRENT_RECORD, m_count );
- }
- }
-
- prefvec leftlines;
- prefvec rightlines;
-
- parent = par;
-
- // for optimization of the tree (this reduced a six-minute gen time to a 38 second gen time)
- size_t chosen = paftl::npos;
- if (lines.size() > 3) {
- size_t i;
- Point2f midpoint;
- for (i = 0; i < lines.size(); i++) {
- midpoint += lines[i].line.start() + lines[i].line.end();
- }
- midpoint /= 2.0 * lines.size();
- bool ver = true;
- if (par && par->line.height() > par->line.width()) {
- ver = false;
- }
- double chosendist = -1.0;
- for (i = 0; i < lines.size(); i++) {
- const Line& line = lines[i].line;
- if (ver) {
- if (line.height() > line.width() && (chosen == paftl::npos || dist(line.midpoint(),midpoint) < chosendist)) {
- chosen = i;
- chosendist = dist(line.midpoint(),midpoint);
- }
- }
- else {
- if (line.width() > line.height() && (chosen == paftl::npos || dist(line.midpoint(),midpoint) < chosendist)) {
- chosen = i;
- chosendist = dist(line.midpoint(),midpoint);
- }
- }
- }
- // argh... and again... there weren't any hoz / ver:
- if (chosen == paftl::npos) {
- for (size_t i = 0; i < lines.size(); i++) {
- if (chosen == paftl::npos || dist(lines[i].line.midpoint(),midpoint) < chosendist) {
- chosen = i;
- chosendist = dist(lines[i].line.midpoint(),midpoint);
- }
- }
- }
- }
- else {
- chosen = pafrand() % lines.size();
- }
-
- line = lines[chosen].line;
- m_tag = lines[chosen].tag;
-
- Point2f v0 = line.end() - line.start();
- v0.normalise();
-
- for (size_t i = 0; i < lines.size(); i++) {
- if (i == chosen) {
- continue;
- }
- const Line& testline = lines[i].line;
- int tag = lines[i].tag;
- Point2f v1 = testline.start()-line.start();
- v1.normalise();
- Point2f v2 = testline.end()-line.start();
- v2.normalise();
- // should use approxeq here:
- double a = testline.start() == line.start() ? 0 : det(v0,v1);
- double b = testline.end() == line.start() ? 0 : det(v0,v2);
- // note sure what to do if a == 0 and b == 0 (i.e., it's parallel... this test at least ensures on the line is one or the other side)
- if (a >= 0 && b >= 0) {
- leftlines.push_back(TaggedLine(testline,tag));
- }
- else if (a <= 0 && b <= 0) {
- rightlines.push_back(TaggedLine(testline,tag));
- }
- else {
- Point2f p = intersection_point(line,testline);
- Line x = Line(testline.start(),p);
- Line y = Line(p,testline.end());
- if (a >= 0) {
- if (x.length() > 0.0) // should use a tolerance here too
- leftlines.push_back(TaggedLine(x,tag));
- if (y.length() > 0.0) // should use a tolerance here too
- rightlines.push_back(TaggedLine(y,tag));
- }
- else {
- if (x.length() > 0.0) // should use a tolerance here too
- rightlines.push_back(TaggedLine(x,tag));
- if (y.length() > 0.0) // should use a tolerance here too
- leftlines.push_back(TaggedLine(y,tag));
- }
- }
- }
-
- if (leftlines.size()) {
- left = new BSPNode();
- left->make(communicator,atime,leftlines,this);
- }
- if (rightlines.size()) {
- right = new BSPNode();
- right->make(communicator,atime,rightlines,this);
- }
-}
-
-int BSPNode::classify(const Point2f& p)
-{
- Point2f v0 = line.end() - line.start();
- v0.normalise();
- Point2f v1 = p - line.start();
- v1.normalise();
- if (det(v0,v1) >= 0) {
- return BSPLEFT;
- }
- else {
- return BSPRIGHT;
- }
-}
diff --git a/genlib/bspnode.h b/genlib/bspnode.h
deleted file mode 100644
index 40a1421e..00000000
--- a/genlib/bspnode.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// genlib - a component of the depthmapX - spatial network analysis platform
-// Copyright (C) 2000-2010 University College London, Alasdair Turner
-// Copyright (C) 2011-2012, Tasos Varoudis
-
-// 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 3 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, see .
-
-#pragma once
-
-#include "genlib/paftl.h"
-#include "p2dpoly.h"
-
-// Binary Space Partition
-
-struct BSPNode
-{
-public:
- enum { BSPLEFT, BSPRIGHT };
- BSPNode *left;
- BSPNode *right;
- BSPNode *parent;
- Line line;
- int m_tag;
- int m_count;
- //
-public:
- BSPNode()
- { left = NULL; right = NULL; parent = NULL; m_count = 0; m_tag = -1; }
- virtual ~BSPNode()
- { if (left) delete left; left = NULL; if (right) delete right; right = NULL; }
- //
- bool isLeaf() {
- return left == NULL && right == NULL;
- }
- void make(Communicator *communicator, time_t atime, const prefvec& lines, BSPNode *par);
- int classify(const Point2f& p);
- const Line& getLine() const { return line; }
- const int getTag() const { return m_tag; }
-};
diff --git a/genlib/bsptree.cpp b/genlib/bsptree.cpp
new file mode 100644
index 00000000..611330b2
--- /dev/null
+++ b/genlib/bsptree.cpp
@@ -0,0 +1,191 @@
+// genlib - a component of the depthmapX - spatial network analysis platform
+// Copyright (C) 2000-2010 University College London, Alasdair Turner
+// Copyright (C) 2011-2012, Tasos Varoudis
+
+// 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 3 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, see .
+
+#include "bsptree.h"
+#include
+
+// Binary Space Partition
+
+/* Takes a set of lines and creates a binary-space-partition tree by starting from a
+ * root node, setting its left and right nodes and recursively doing the same process
+ * over those. Through this process the set of lines is split in two (one set for each
+ * left and right nodes) and those are split and passed again further down the recursion.
+ * While the original implementation was actually recursive it was hitting the recursion
+ * limit when the input was a large number of lines that fell on the same side (i.e. an
+ * arc divided in 500 pieces). It has been refactored here to an iterative solution, where
+ * the current node (left or right) is pushed to a stack along with the relevant set of lines.
+ */
+
+void BSPTree::make(Communicator *communicator, time_t atime, const std::vector& lines, BSPNode* root)
+{
+
+ typedef std::pair, std::vector > TagLineVecPair;
+
+ std::stack nodeStack;
+ std::stack lineStack;
+
+ nodeStack.push(root);
+ lineStack.push(makeLines(communicator, atime, lines, root));
+
+ int progress = 0;
+ while(!nodeStack.empty()) {
+ progress++; // might need to increase by 2 because it was one for each left/right in the previous iteration
+
+ if (communicator)
+ {
+ if (communicator->IsCancelled()) {
+ throw Communicator::CancelledException();
+ }
+ if (qtimer( atime, 500 )) {
+ communicator->CommPostMessage( Communicator::CURRENT_RECORD, progress );
+ }
+ }
+ BSPNode *currNode = nodeStack.top();
+ nodeStack.pop();
+ TagLineVecPair currLines = lineStack.top();
+ lineStack.pop();
+
+ if (!currLines.first.empty()) {
+ currNode->m_left = new BSPNode(currNode);
+ nodeStack.push(currNode->m_left);
+ lineStack.push(makeLines(communicator,atime,currLines.first,currNode->m_left));
+ }
+ if (!currLines.second.empty()) {
+ currNode->m_right = new BSPNode(currNode);
+ nodeStack.push(currNode->m_right);
+ lineStack.push(makeLines(communicator,atime,currLines.second,currNode->m_right));
+ }
+ }
+}
+
+/* Finds the midpoint from all the lines given and returns the index of the line
+ * closest to it.
+ */
+
+int BSPTree::pickMidpointLine(const std::vector &lines, BSPNode *par) {
+ int chosen = -1;
+ size_t i;
+ Point2f midpoint;
+ for (i = 0; i < lines.size(); i++) {
+ midpoint += lines[i].line.start() + lines[i].line.end();
+ }
+ midpoint /= 2.0 * lines.size();
+ bool ver = true;
+ if (par && par->getLine().height() > par->getLine().width()) {
+ ver = false;
+ }
+ double chosendist = -1.0;
+ for (i = 0; i < lines.size(); i++) {
+ const Line& line = lines[i].line;
+ if (ver) {
+ if (line.height() > line.width() && (chosen == -1 || dist(line.midpoint(),midpoint) < chosendist)) {
+ chosen = i;
+ chosendist = dist(line.midpoint(),midpoint);
+ }
+ }
+ else {
+ if (line.width() > line.height() && (chosen == -1 || dist(line.midpoint(),midpoint) < chosendist)) {
+ chosen = i;
+ chosendist = dist(line.midpoint(),midpoint);
+ }
+ }
+ }
+ // argh... and again... there weren't any hoz / ver:
+ if (chosen == -1) {
+ for (size_t i = 0; i < lines.size(); i++) {
+ if (chosen == -1 || dist(lines[i].line.midpoint(),midpoint) < chosendist) {
+ chosen = i;
+ chosendist = dist(lines[i].line.midpoint(),midpoint);
+ }
+ }
+ }
+ return chosen;
+}
+
+/* Breaks a set of lines in two (left-right). First chooses a line closest to the midpoint
+ * of the set ("chosen") and then classifies lines left or right depending on whether they
+ * lie clockwise or anti-clockwise of the chosen one (with chosen start as centre, angles
+ * from the chosen end up to 180 are clockwise, down to -180 anti-clockwise). Lines that cross
+ * from one side of the chosen to the other are split in two and each part goes to the relevant set.
+ */
+
+std::pair, std::vector > BSPTree::makeLines(Communicator *communicator,
+ time_t atime,
+ const std::vector &lines,
+ BSPNode *base)
+{
+ std::vector leftlines;
+ std::vector rightlines;
+
+ // for optimization of the tree (this reduced a six-minute gen time to a 38 second gen time)
+ int chosen = -1;
+ if (lines.size() > 3) {
+ chosen = BSPTree::pickMidpointLine(lines, base->m_parent);
+ }
+ else {
+ chosen = pafrand() % lines.size();
+ }
+
+ Line chosenLine = lines[chosen].line;
+ int chosenTag = lines[chosen].tag;
+ base->setLine(chosenLine);
+ base->setTag(chosenTag);
+
+ Point2f v0 = chosenLine.end() - chosenLine.start();
+ v0.normalise();
+
+ for (size_t i = 0; i < lines.size(); i++) {
+ if (i == chosen) {
+ continue;
+ }
+ const Line& testline = lines[i].line;
+ int tag = lines[i].tag;
+ Point2f v1 = testline.start()-chosenLine.start();
+ v1.normalise();
+ Point2f v2 = testline.end()-chosenLine.start();
+ v2.normalise();
+ // should use approxeq here:
+ double a = testline.start() == chosenLine.start() ? 0 : det(v0,v1);
+ double b = testline.end() == chosenLine.start() ? 0 : det(v0,v2);
+ // note sure what to do if a == 0 and b == 0 (i.e., it's parallel... this test at least ensures on the line is one or the other side)
+ if (a >= 0 && b >= 0) {
+ leftlines.push_back(TaggedLine(testline,tag));
+ }
+ else if (a <= 0 && b <= 0) {
+ rightlines.push_back(TaggedLine(testline,tag));
+ }
+ else {
+ Point2f p = intersection_point(chosenLine,testline);
+ Line x = Line(testline.start(),p);
+ Line y = Line(p,testline.end());
+ if (a >= 0) {
+ if (x.length() > 0.0) // should use a tolerance here too
+ leftlines.push_back(TaggedLine(x,tag));
+ if (y.length() > 0.0) // should use a tolerance here too
+ rightlines.push_back(TaggedLine(y,tag));
+ }
+ else {
+ if (x.length() > 0.0) // should use a tolerance here too
+ rightlines.push_back(TaggedLine(x,tag));
+ if (y.length() > 0.0) // should use a tolerance here too
+ leftlines.push_back(TaggedLine(y,tag));
+ }
+ }
+ }
+
+ return std::make_pair(leftlines, rightlines);
+}
diff --git a/genlib/bsptree.h b/genlib/bsptree.h
new file mode 100644
index 00000000..379bcd16
--- /dev/null
+++ b/genlib/bsptree.h
@@ -0,0 +1,70 @@
+// genlib - a component of the depthmapX - spatial network analysis platform
+// Copyright (C) 2000-2010 University College London, Alasdair Turner
+// Copyright (C) 2011-2012, Tasos Varoudis
+
+// 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 3 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, see .
+
+#pragma once
+
+#include "p2dpoly.h"
+
+// Binary Space Partition
+
+struct BSPNode
+{
+
+private:
+ Line m_line;
+ int m_tag;
+
+public:
+ enum { BSPLEFT, BSPRIGHT };
+ BSPNode *m_left;
+ BSPNode *m_right;
+ BSPNode *m_parent;
+
+ BSPNode(BSPNode *parent = NULL)
+ { m_left = NULL; m_right = NULL; m_parent = parent; m_tag = -1; }
+ virtual ~BSPNode()
+ { if (m_left) delete m_left; m_left = NULL; if (m_right) delete m_right; m_right = NULL; }
+ //
+ bool isLeaf() {
+ return m_left == NULL && m_right == NULL;
+ }
+ int classify(const Point2f& p) {
+ Point2f v0 = m_line.end() - m_line.start();
+ v0.normalise();
+ Point2f v1 = p - m_line.start();
+ v1.normalise();
+ if (det(v0,v1) >= 0) {
+ return BSPLEFT;
+ }
+ else {
+ return BSPRIGHT;
+ }
+ }
+ const Line& getLine() const { return m_line; }
+ void setLine(const Line& line) { m_line = line; }
+ int getTag() const { return m_tag; }
+ void setTag(const int tag) { m_tag = tag; }
+};
+
+namespace BSPTree {
+void make(Communicator *communicator, time_t atime, const std::vector &lines, BSPNode *root);
+int pickMidpointLine(const std::vector &lines, BSPNode *par);
+std::pair, std::vector > makeLines(Communicator *communicator,
+ time_t atime,
+ const std::vector& lines,
+ BSPNode *base);
+}
diff --git a/genlib/genlib.pro b/genlib/genlib.pro
index 63bf69ff..fbfbbc97 100644
--- a/genlib/genlib.pro
+++ b/genlib/genlib.pro
@@ -31,7 +31,7 @@ SOURCES += \
pafmath.cpp \
xmlparse.cpp \
stringutils.cpp \
- bspnode.cpp
+ bsptree.cpp
HEADERS += \
comm.h \
@@ -46,4 +46,4 @@ HEADERS += \
stringutils.h \
containerutils.h \
linreg.h \
- bspnode.h
+ bsptree.h
diff --git a/genlibTest/genlibTest.pro b/genlibTest/genlibTest.pro
index 13ce0693..47406033 100644
--- a/genlibTest/genlibTest.pro
+++ b/genlibTest/genlibTest.pro
@@ -8,7 +8,8 @@ INCLUDEPATH += ../ThirdParty/Catch
SOURCES += convertertest.cpp \
main.cpp \
dxfptest.cpp \
- teststringutils.cpp
+ teststringutils.cpp \
+ testbspnode.cpp
HEADERS +=
diff --git a/genlibTest/testbspnode.cpp b/genlibTest/testbspnode.cpp
new file mode 100644
index 00000000..3e8b34bb
--- /dev/null
+++ b/genlibTest/testbspnode.cpp
@@ -0,0 +1,219 @@
+// Copyright (C) 2017 Petros Koutsolampros
+
+// 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 3 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, see .
+
+#include "catch.hpp"
+#include "genlib/comm.h"
+#include "genlib/p2dpoly.h"
+#include "genlib/bsptree.h"
+
+TEST_CASE("BSPTree::pickMidpointLine")
+{
+ std::vector lines;
+ lines.push_back(TaggedLine(Line(Point2f(1, 2), Point2f(2, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(2, 2), Point2f(3, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(3, 2), Point2f(4, 2)), 0));
+
+ BSPNode node;
+
+ REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 1);
+
+ SECTION("Additional lines") {
+ lines.push_back(TaggedLine(Line(Point2f(4, 2), Point2f(5, 2)), 0));
+ REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 1);
+
+ lines.push_back(TaggedLine(Line(Point2f(5, 1), Point2f(6, 1)), 0));
+ REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 2);
+
+ // the only line with height > width becomes chosen
+ lines.push_back(TaggedLine(Line(Point2f(15, 4), Point2f(15, 0)), 0));
+ REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 5);
+ }
+ SECTION("rotated middle") {
+
+ // height > width, rotated, close to midpoint
+ lines.push_back(TaggedLine(Line(Point2f(4.5, 1), Point2f(4.5, 3)), 0));
+
+ lines.push_back(TaggedLine(Line(Point2f(5, 2), Point2f(6, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(6, 2), Point2f(7, 2)), 0));
+
+ // height > width, rotated, not close to midpoint
+ lines.push_back(TaggedLine(Line(Point2f(6.5, 1), Point2f(6.5, 3)), 0));
+
+ REQUIRE(BSPTree::pickMidpointLine(lines, 0) == 3);
+ }
+}
+
+void compareLines(Line l1, Line l2, float EPSILON) {
+ REQUIRE(l1.start().x == Approx(l2.start().x).epsilon(EPSILON));
+ REQUIRE(l1.start().y == Approx(l2.start().y).epsilon(EPSILON));
+ REQUIRE(l1.end().x == Approx(l2.end().x).epsilon(EPSILON));
+ REQUIRE(l1.end().y == Approx(l2.end().y).epsilon(EPSILON));
+}
+
+TEST_CASE("BSPTree::makeLines")
+{
+ const float EPSILON = 0.001;
+ typedef std::pair, std::vector > TagLineVecPair;
+
+ std::vector lines;
+ lines.push_back(TaggedLine(Line(Point2f(1, 2), Point2f(2, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(2, 2), Point2f(3, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(3, 2), Point2f(4, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(4, 2), Point2f(5, 2)), 0));
+
+ std::unique_ptr node(new BSPNode());
+
+ TagLineVecPair result = BSPTree::makeLines(0, 0, lines, node.get());
+
+ REQUIRE(result.first.size() == 3);
+ REQUIRE(result.second.size() == 0);
+
+ compareLines(result.first[0].line, lines[0].line, EPSILON);
+ compareLines(result.first[1].line, lines[2].line, EPSILON);
+ compareLines(result.first[2].line, lines[3].line, EPSILON);
+
+
+ SECTION("One on the right")
+ {
+ lines.push_back(TaggedLine(Line(Point2f(5, 1), Point2f(6, 1)), 0));
+
+ result = BSPTree::makeLines(0, 0, lines, node.get());
+
+ REQUIRE(result.first.size() == 3);
+ REQUIRE(result.second.size() == 1);
+
+ compareLines(result.second[0].line, lines[4].line, EPSILON);
+ }
+ SECTION("One line with height > width becomes chosen")
+ {
+ // height > width, rotated, not close to midpoint
+ lines.push_back(TaggedLine(Line(Point2f(5.5, 1), Point2f(5.5, 3)), 0));
+
+ lines.push_back(TaggedLine(Line(Point2f(6, 2), Point2f(7, 2)), 0));
+
+ result = BSPTree::makeLines(0, 0, lines, node.get());
+
+ REQUIRE(result.first.size() == 4);
+ REQUIRE(result.second.size() == 1);
+
+ compareLines(result.first[0].line, lines[0].line, EPSILON);
+ compareLines(result.first[1].line, lines[1].line, EPSILON);
+ compareLines(result.first[2].line, lines[2].line, EPSILON);
+ compareLines(result.first[3].line, lines[3].line, EPSILON);
+ compareLines(result.second[0].line, lines[5].line, EPSILON);
+ }
+
+ SECTION("One broken between")
+ {
+ // height > width, rotated, close to midpoint
+ lines.push_back(TaggedLine(Line(Point2f(5.5, 1), Point2f(5.5, 3)), 0));
+
+ lines.push_back(TaggedLine(Line(Point2f(6, 2), Point2f(7, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(7, 2), Point2f(8, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(8, 2), Point2f(9, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(9, 2), Point2f(10, 2)), 0));
+
+ // line with two points at different sides of chosen
+ lines.push_back(TaggedLine(Line(Point2f(3, -2), Point2f(6, -2)), 0));
+
+ result = BSPTree::makeLines(0, 0, lines, node.get());
+
+ // adds one on each side
+ REQUIRE(result.first.size() == 5);
+ REQUIRE(result.second.size() == 5);
+
+ compareLines(result.first[0].line, lines[0].line, EPSILON);
+ compareLines(result.first[1].line, lines[1].line, EPSILON);
+ compareLines(result.first[2].line, lines[2].line, EPSILON);
+ compareLines(result.first[3].line, lines[3].line, EPSILON);
+
+ compareLines(result.second[0].line, lines[5].line, EPSILON);
+ compareLines(result.second[1].line, lines[6].line, EPSILON);
+ compareLines(result.second[2].line, lines[7].line, EPSILON);
+ compareLines(result.second[3].line, lines[8].line, EPSILON);
+
+ compareLines(result.first[4].line, Line(Point2f(3, -2), Point2f(5.5, -2)), EPSILON);
+ compareLines(result.second[4].line, Line(Point2f(5.5, -2), Point2f(6, -2)), EPSILON);
+ }
+}
+
+TEST_CASE("BSPTree::make (all horizontal lines)", "all-left tree")
+{
+ const float EPSILON = 0.001;
+
+ std::vector lines;
+ lines.push_back(TaggedLine(Line(Point2f(1, 2), Point2f(2, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(2, 2), Point2f(3, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(3, 2), Point2f(4, 2)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(4, 2), Point2f(5, 2)), 0));
+
+ std::unique_ptr node(new BSPNode());
+
+ BSPTree::make(0, 0, lines, node.get());
+
+ compareLines(node->getLine(), lines[1].line, EPSILON);
+
+ REQUIRE(node->m_left != NULL);
+ REQUIRE(node->m_right == NULL);
+
+ compareLines(node->m_left->getLine(), lines[2].line, EPSILON);
+
+ REQUIRE(node->m_left->m_left != NULL);
+ REQUIRE(node->m_left->m_right == NULL);
+
+ compareLines(node->m_left->m_left->getLine(), lines[3].line, EPSILON);
+
+ REQUIRE(node->m_left->m_left->m_left != NULL);
+ REQUIRE(node->m_left->m_left->m_right == NULL);
+
+ compareLines(node->m_left->m_left->m_left->getLine(), lines[0].line, EPSILON);
+
+ REQUIRE(node->m_left->m_left->m_left->m_left == NULL);
+ REQUIRE(node->m_left->m_left->m_left->m_right == NULL);
+}
+
+TEST_CASE("BSPTree::make (all vertical lines)", "split tree")
+{
+ const float EPSILON = 0.001;
+
+ std::vector lines;
+ lines.push_back(TaggedLine(Line(Point2f(1.5, 1), Point2f(1.5, 3)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(2.5, 1), Point2f(2.5, 3)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(3.5, 1), Point2f(3.5, 3)), 0));
+ lines.push_back(TaggedLine(Line(Point2f(4.5, 1), Point2f(4.5, 3)), 0));
+
+ std::unique_ptr node(new BSPNode());
+
+ BSPTree::make(0, 0, lines, node.get());
+
+ compareLines(node->getLine(), lines[1].line, EPSILON);
+
+ REQUIRE(node->m_left != NULL);
+ REQUIRE(node->m_right != NULL);
+
+ compareLines(node->m_left->getLine(), lines[0].line, EPSILON);
+ compareLines(node->m_right->getLine(), lines[3].line, EPSILON);
+
+ REQUIRE(node->m_left->m_left == NULL);
+ REQUIRE(node->m_left->m_right == NULL);
+
+ REQUIRE(node->m_right->m_left != NULL);
+ REQUIRE(node->m_right->m_right == NULL);
+
+ compareLines(node->m_right->m_left->getLine(), lines[2].line, EPSILON);
+
+ REQUIRE(node->m_right->m_left->m_left == NULL);
+ REQUIRE(node->m_right->m_left->m_right == NULL);
+}
diff --git a/salalib/isovist.cpp b/salalib/isovist.cpp
index 2e7caa51..3c6fa833 100644
--- a/salalib/isovist.cpp
+++ b/salalib/isovist.cpp
@@ -148,18 +148,18 @@ void Isovist::make(BSPNode *here)
if (m_gaps.size()) {
int which = here->classify(m_centre);
if (which == BSPNode::BSPLEFT) {
- if (here->left)
- make(here->left);
- drawnode(here->line,here->m_tag);
- if (here->right)
- make(here->right);
+ if (here->m_left)
+ make(here->m_left);
+ drawnode(here->getLine(),here->getTag());
+ if (here->m_right)
+ make(here->m_right);
}
else {
- if (here->right)
- make(here->right);
- drawnode(here->line,here->m_tag);
- if (here->left)
- make(here->left);
+ if (here->m_right)
+ make(here->m_right);
+ drawnode(here->getLine(),here->getTag());
+ if (here->m_left)
+ make(here->m_left);
}
}
}
diff --git a/salalib/isovist.h b/salalib/isovist.h
index c0deb965..0939a0f0 100644
--- a/salalib/isovist.h
+++ b/salalib/isovist.h
@@ -21,7 +21,7 @@
#ifndef __ISOVIST_H__
#define __ISOVIST_H__
-#include "genlib/bspnode.h"
+#include "genlib/bsptree.h"
// this is very much like sparksieve:
diff --git a/salalib/mgraph.cpp b/salalib/mgraph.cpp
index 5bee3ecc..618f762c 100644
--- a/salalib/mgraph.cpp
+++ b/salalib/mgraph.cpp
@@ -646,7 +646,7 @@ bool MetaGraph::makeBSPtree(Communicator *communicator)
return true;
}
- prefvec partitionlines;
+ std::vector partitionlines;
for (size_t i = 0; i < SuperSpacePixel::size(); i++) {
for (size_t j = 0; j < SuperSpacePixel::at(i).size(); j++) {
// chooses the first editable layer it can find:
@@ -694,7 +694,7 @@ bool MetaGraph::makeBSPtree(Communicator *communicator)
qtimer( atime, 0 );
try {
- m_bsp_root->make(communicator,atime,partitionlines,NULL);
+ BSPTree::make(communicator,atime,partitionlines,m_bsp_root);
m_bsp_tree = true;
}
catch (Communicator::CancelledException) {
diff --git a/salalib/shapemap.cpp b/salalib/shapemap.cpp
index e9126bfb..56c9aa0e 100644
--- a/salalib/shapemap.cpp
+++ b/salalib/shapemap.cpp
@@ -3378,7 +3378,7 @@ bool ShapeMap::makeBSPtree() const
return true;
}
- prefvec partitionlines;
+ std::vector partitionlines;
for (size_t i = 0; i < m_shapes.size(); i++) {
if (m_shapes[i].isLine()) {
partitionlines.push_back(TaggedLine(m_shapes.value(i).getLine(),m_shapes.key(i)));
@@ -3395,7 +3395,7 @@ bool ShapeMap::makeBSPtree() const
}
m_bsp_root = new BSPNode();
- m_bsp_root->make(NULL,0,partitionlines,NULL);
+ BSPTree::make(NULL,0,partitionlines,m_bsp_root);
m_bsp_tree = true;
}
diff --git a/salalib/shapemap.h b/salalib/shapemap.h
index 79438f87..b0848bf0 100644
--- a/salalib/shapemap.h
+++ b/salalib/shapemap.h
@@ -25,7 +25,7 @@
#include
#include
#include "salalib/importtypedefs.h"
-#include "genlib/bspnode.h"
+#include "genlib/bsptree.h"
#include
/////////////////////////////////////////////////////////////////////////////////////////////////