Files
secondo/Algebras/SPart2/KDTree3D.cpp
2026-01-23 17:03:45 +08:00

2304 lines
58 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2020,
University in Hagen,
Faculty of Mathematics and Computer Science,
Database Systems for New Applications.
SECONDO 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.
SECONDO 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 SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
*/
#include "KDTree3D.h"
#include "Algebras/Relation-C++/RelationAlgebra.h"
#include "Algebras/Collection/IntSet.h"
#include <iterator>
#include <map>
/*
Class Cell3DTree
*/
Cell3DTree::Cell3DTree() {
cellId = -1;
x1 = -1;
x2 = -1;
y1 = -1;
y2 = -1;
z1 = -1;
z2 = -1;
}
void
Cell3DTree::setCellId(int cell_id) {
this->cellId = cell_id;
}
int
Cell3DTree::getCellId() {
return cellId;
}
void
Cell3DTree::setValFromX(double x_1) {
x1 = x_1;
}
double
Cell3DTree::getValFromX() {
return x1;
}
void
Cell3DTree::setValToX(double x_2) {
x2 = x_2;
}
double
Cell3DTree::getValToX() {
return x2;
}
void
Cell3DTree::setValFromY(double y_1) {
y1 = y_1;
}
double
Cell3DTree::getValFromY() {
return y1;
}
void
Cell3DTree::setValToY(double y_2) {
y2 = y_2;
}
double
Cell3DTree::getValToY() {
return y2;
}
void
Cell3DTree::setValFromZ(double z_1) {
z1 = z_1;
}
double
Cell3DTree::getValFromZ() {
return z1;
}
void
Cell3DTree::setValToZ(double z_2) {
z2 = z_2;
}
double
Cell3DTree::getValToZ() {
return z2;
}
Cell3DTree::~Cell3DTree() { }
/*
Class Tree3DStructure
*/
Tree3DStructure::Tree3DStructure() {
x = -1;
y = -1;
z = -1;
axis = -1;
depth = -1;
left = nullptr;
right = nullptr;
cellId = -1;
leaf = false;
}
void
Tree3DStructure::setCellId(int cell_id) {
this->cellId = cell_id;
}
int
Tree3DStructure::getCellId() {
return cellId;
}
void Tree3DStructure::setAxis(int axis_) {
this->axis = axis_;
}
int Tree3DStructure::getAxis() {
return axis;
}
void Tree3DStructure::setDepth(int depth_) {
this->depth = depth_;
}
int Tree3DStructure::getDepth() {
return depth;
}
void Tree3DStructure::setValx(double x_) {
this->x = x_;
}
double Tree3DStructure::getValx() {
return x;
}
void Tree3DStructure::setValy(double y_) {
this->y = y_;
}
double Tree3DStructure::getValy() {
return y;
}
void Tree3DStructure::setValz(double z_) {
this->z = z_;
}
double Tree3DStructure::getValz() {
return z;
}
void Tree3DStructure::setLeft(Tree3DStructure* left_) {
this->left = left_;
}
Tree3DStructure* Tree3DStructure::getLeft() {
return left;
}
void Tree3DStructure::setRight(Tree3DStructure* right_) {
this->right = right_;
}
Tree3DStructure* Tree3DStructure::getRight() {
return right;
}
void Tree3DStructure::setIsLeaf(bool leaf_) {
this->leaf = leaf_;
}
bool Tree3DStructure::isLeaf() {
return leaf;
}
Tree3DStructure::~Tree3DStructure() {}
/*
Class Tree3DMedStructure
Uses median of list of points to create 3dtree
*/
Tree3DMedStructure::Tree3DMedStructure() {
val = -1;
axis = -1;
depth = -1;
left = nullptr;
right = nullptr;
cellId = -1;
leaf = false;
}
void Tree3DMedStructure::setVal(double val_) {
this->val = val_;
}
double Tree3DMedStructure::getVal() {
return val;
}
void Tree3DMedStructure::setAxis(int axis_) {
this->axis = axis_;
}
int Tree3DMedStructure::getAxis() {
return axis;
}
void Tree3DMedStructure::setCellId(int cell_id) {
this->cellId = cell_id;
}
int Tree3DMedStructure::getCellId() {
return cellId;
}
void Tree3DMedStructure::setDepth(int depth_) {
this->depth = depth_;
}
int Tree3DMedStructure::getDepth() {
return depth;
}
void Tree3DMedStructure::setIsLeaf(bool leaf_) {
this->leaf = leaf_;
}
bool Tree3DMedStructure::isLeaf() {
return leaf;
}
void Tree3DMedStructure::setLeft(Tree3DMedStructure* left_) {
this->left = left_;
}
Tree3DMedStructure* Tree3DMedStructure::getLeft() {
return left;
}
void Tree3DMedStructure::setRight(Tree3DMedStructure* right_) {
this->right = right_;
}
Tree3DMedStructure* Tree3DMedStructure::getRight() {
return right;
}
Tree3DMedStructure::~Tree3DMedStructure() {}
/*
Class KDTree3D
*/
KDTree3D::KDTree3D() {
boundingBox = nullptr;
}
KDTree3D::KDTree3D(const KDTree3D& g) {
boundingBox = g.boundingBox;
}
KDTree3D::KDTree3D(Rectangle<3> &bounding_box) {
boundingBox = &bounding_box;
}
void KDTree3D::Set(Stream<Rectangle<3>> rStream,
Rectangle<3> &bounding_box, int mode_) {
boundingBox = &bounding_box;
mode = mode_;
create3DTree(rStream);
}
void KDTree3D::SetVector(std::vector<Rectangle<3>>* rVector,
Rectangle<3> &bounding_box) {
boundingBox = &bounding_box;
create3DTreeVector(rVector);
}
void KDTree3D::create3DTree(Stream<Rectangle<3>> rStream) {
processInput(rStream);
// create 3dtree
build3DTree();
}
void KDTree3D::create3DTreeVector(std::vector<Rectangle<3>>* rVector) {
processInputVector(rVector);
// create kdtree
build3DTree();
}
Rectangle<3> *
KDTree3D::getBoundingBox() {
return boundingBox;
}
int
KDTree3D::getMode() {
return mode;
}
void
KDTree3D::setPointsVector(std::vector<Tree3DStructure*> points_vect) {
this->pointsVector = points_vect;
}
std::vector<Tree3DStructure*>&
KDTree3D::getPointsVector() {
return this->pointsVector;
}
void
KDTree3D::setPointsMedVector(std::vector<Tree3DMedStructure*> points_vect) {
this->kd3dmedListVec = points_vect;
}
std::vector<Tree3DMedStructure*>&
KDTree3D::getPointsMedVector() {
return this->kd3dmedListVec;
}
void
KDTree3D::setCellVector(std::vector<Cell3DTree> cell_vect) {
this->cellVector = cell_vect;
}
std::vector<Cell3DTree>&
KDTree3D::getCellVector() {
return this->cellVector;
}
T3DPoint
getCuboidCentre3DTree(Rectangle<3>* r) {
double a = (r->getMaxY() - r->getMinY()) / (double)2;
double b = (r->getMaxX() - r->getMinX()) / (double)2;
double c = (r->getMaxZ() - r->getMinZ()) / (double)2;
T3DPoint r_c { (r->getMinX())+b, (r->getMinY())+a, (r->getMinZ())+c};
return r_c;
}
/*
checks if a rectangle <3> is inside the irgrid3d bounding box
*/
bool
insideRectangle3DTree(Rectangle<3>* bbox, Rectangle<3>* r) {
double le = bbox->getMinX();
double ri = bbox->getMaxX();
double bo = bbox->getMinY();
double to = bbox->getMaxY();
double fr = bbox->getMinZ();
double ba = bbox->getMaxZ();
if (r->getMinX() >= le && r->getMaxX() <= ri
&& r->getMinY() >= bo && r->getMaxY() <=to
&& r->getMinZ() >= fr && r->getMaxZ() <= ba) {
return true;
}
return false;
}
bool
pointComparisonX(T3DPoint p1, T3DPoint p2) {
return p1.x < p2.x;
}
bool
xValueComparison(Cell3DTree x1, Cell3DTree x2) {
return x1.getValFromX() < x2.getValFromX();
}
bool
yValueComparison(Cell3DTree y1, Cell3DTree y2) {
return y1.getValFromY() < y2.getValFromY();
}
bool
zValueComparison(Cell3DTree z1, Cell3DTree z2) {
return z1.getValFromZ() < z2.getValFromZ();
}
bool
pointComparisonY(T3DPoint p1, T3DPoint p2) {
return p1.y < p2.y;
}
bool
pointComparisonZ(T3DPoint p1, T3DPoint p2) {
return p1.z < p2.z;
}
std::vector<T3DPoint> slice(std::vector<T3DPoint> const &v, int m, int n)
{
auto first = v.cbegin() + m;
auto last = v.cbegin() + n + 1;
std::vector<T3DPoint> vec(first, last);
return vec;
}
/*
Creates 3DTree recursive with median of points
*/
Tree3DMedStructure*
KDTree3D::KDTreeMedRec3D(std::vector<T3DPoint> point_list,
int depth)
{
int axis = depth % 3; // dim = 3
double median;
std::vector<T3DPoint> point_list_left;
std::vector<T3DPoint> point_list_right;
if (point_list_left.size() > 0) {
point_list_left.clear();
}
if (point_list_right.size() > 0) {
point_list_right.clear();
}
int mid = point_list.size()/2;
// x-axis
if(axis == 0) {
std::sort(point_list.begin(), point_list.end(),
pointComparisonX);
// calculate median
if(point_list.size() % 2 == 0)
{
median = 0.5*(point_list.at(mid-1).x + point_list.at(mid).x);
} else {
median = point_list.at(mid).x;
}
for(size_t i=0; i < point_list.size(); i++)
{
if(point_list.at(i).x < median)
{
point_list_left.push_back(point_list.at(i));
} else {
point_list_right.push_back(point_list.at(i));
}
}
// repartition if size of point_list_left or point_list_right
// corresponds to size of (old) point_list from input
// in case take middle position as median
if(point_list_left.size() == point_list.size()
|| point_list_right.size() == point_list.size())
{
if (point_list_left.size() > 0) {
point_list_left.clear();
}
if (point_list_right.size() > 0) {
point_list_right.clear();
}
median = point_list[mid].x;
for(int l=0; l < mid; l++)
{
point_list_left.push_back(point_list[l]);
}
for(size_t r=mid; r < point_list.size(); r++)
{
point_list_right.push_back(point_list[r]);
}
}
} else if (axis == 1) { // y-axis
std::sort(point_list.begin(), point_list.end(),
pointComparisonY);
if(point_list.size() % 2 == 0)
{
median = 0.5*(point_list.at(mid-1).y + point_list.at(mid).y);
} else {
median = point_list.at(mid).y;
}
for(size_t i=0; i < point_list.size(); i++)
{
if(point_list.at(i).y < median)
{
point_list_left.push_back(point_list.at(i));
} else {
point_list_right.push_back(point_list.at(i));
}
}
// repartition if size of point_list_left or point_list_right
// corresponds to size of (old) point_list from input
// in case take middle position as median
if(point_list_left.size() == point_list.size()
|| point_list_right.size() == point_list.size())
{
if (point_list_left.size() > 0) {
point_list_left.clear();
}
if (point_list_right.size() > 0) {
point_list_right.clear();
}
median = point_list[mid].y;
for(int l=0; l < mid; l++)
{
point_list_left.push_back(point_list[l]);
}
for(size_t r=mid; r < point_list.size(); r++)
{
point_list_right.push_back(point_list[r]);
}
}
} else if( axis == 2) { // z-axis
std::sort(point_list.begin(), point_list.end(),
pointComparisonZ);
if(point_list.size() % 2 == 0)
{
median = 0.5*(point_list.at(mid-1).z + point_list.at(mid).z);
} else {
median = point_list.at(mid).z;
}
for(size_t i=0; i < point_list.size(); i++)
{
if(point_list.at(i).z < median)
{
point_list_left.push_back(point_list.at(i));
} else {
point_list_right.push_back(point_list.at(i));
}
}
// repartition if size of point_list_left or point_list_right
// corresponds to size of (old) point_list from input
// in case take middle position as median
if(point_list_left.size() == point_list.size()
|| point_list_right.size() == point_list.size())
{
if (point_list_left.size() > 0) {
point_list_left.clear();
}
if (point_list_right.size() > 0) {
point_list_right.clear();
}
median = point_list[mid].z;
for(int l=0; l < mid; l++)
{
point_list_left.push_back(point_list[l]);
}
for(size_t r=mid; r < point_list.size(); r++)
{
point_list_right.push_back(point_list[r]);
}
}
} else {
return 0;
}
Tree3DMedStructure* tmp = new Tree3DMedStructure();
tmp->setAxis(axis);
tmp->setDepth(depth);
tmp->setVal(median);
if(point_list_left.size() > 1) {
tmp->left = KDTreeMedRec3D(point_list_left, depth+1);
}
if(point_list_right.size() > 1) {
tmp->right = KDTreeMedRec3D(point_list_right, depth+1);
}
// push current node in vector
kd3dmedListVec.push_back(tmp);
if (point_list_left.size() > 0) {
point_list_left.clear();
}
if (point_list_right.size() > 0) {
point_list_right.clear();
}
return tmp;
}
/*
Creates 3DTree recursive with the middle of the list of points
*/
Tree3DStructure*
KDTree3D::KDTreeRec3D(std::vector<T3DPoint> point_list, int begin,
int end, int depth) {
if(begin == end) {
// only one element in list: leaf
Tree3DStructure* lastNode = new Tree3DStructure();
if(!point_list.empty()) {
lastNode->setValx(point_list[0].x);
lastNode->setValy(point_list[0].y);
lastNode->setValz(point_list[0].z);
lastNode->setAxis(depth%3); // dim = 3
lastNode->setDepth(depth);
// left and right for cellIds
Tree3DStructure* leftl = new Tree3DStructure();
leftl->setCellId(-1);
leftl->setIsLeaf(true);
Tree3DStructure* rightl = new Tree3DStructure();
rightl->setCellId(-1);
rightl->setIsLeaf(true);
lastNode->setLeft(leftl);
lastNode->setRight(rightl);
pointsVector.push_back(lastNode);
}
return lastNode;
}
if(end < begin) {
return nullptr;
}
int axis = depth % 3; // dim = 3
if(axis == 0) {
// points sorted by x
std::sort(point_list.begin(), point_list.end(),
pointComparisonX);
} else if (axis == 1) {
std::sort(point_list.begin(), point_list.end(),
pointComparisonY);
} else if( axis == 2) {
std::sort(point_list.begin(), point_list.end(),
pointComparisonZ);
}
int medianpos = point_list.size() / 2;
T3DPoint middle = point_list[medianpos];
Tree3DStructure* curr = new Tree3DStructure();
if(!point_list[medianpos].used) {
curr->setValx(middle.x);
curr->setValy(middle.y);
curr->setValz(middle.z);
curr->setAxis(axis);
curr->setDepth(depth);
std::vector<T3DPoint> point_list_left;
std::vector<T3DPoint> point_list_right;
point_list[medianpos].used = true;
// divide list of points in right and left part
for(int l = 0; l <= medianpos-1; l++)
{
point_list_left.push_back(point_list[l]);
}
int pos = 0;
for(int r = medianpos+1; r <= (int)point_list.size()-1; r++)
{
point_list_right.push_back(point_list[r]);
pos++;
}
// in case left/right is empty: prepare leaf
Tree3DStructure* leftk = new Tree3DStructure();
leftk->setCellId(-1);
leftk->setIsLeaf(true);
Tree3DStructure* rightk = new Tree3DStructure();
rightk->setCellId(-1);
rightk->setIsLeaf(true);
// recursive call with left and right lists
if(!point_list_left.empty()) {
curr->left = KDTreeRec3D(point_list_left, 0, medianpos-1, depth+1);
} else {
curr->setLeft(leftk);
}
if(!point_list_right.empty()) {
curr->right = KDTreeRec3D(point_list_right,
medianpos+1, (int)point_list.size(), depth+1);
} else {
curr->setRight(rightk);
}
// push current node
pointsVector.push_back(curr);
// clear aux. vectors
if (point_list_left.size() > 0) {
point_list_left.clear();
}
if (point_list_right.size() > 0) {
point_list_right.clear();
}
}
return curr;
}
/*
Order points in preoder
*/
void
KDTree3D::preorder3D (Tree3DStructure* root)
{
if (root == nullptr ) {
return;
}
pointsPreorder.push_back(root);
if(root->left != nullptr) {
preorder3D(root->left);
}
if(root->right != nullptr) {
preorder3D(root->right);
}
return;
}
/*
order points of median version in preoder
*/
void
KDTree3D::preorder3DMed(Tree3DMedStructure* root)
{
if (root == nullptr) {
return;
}
pointsPreorderMed.push_back(root);
if(root->left != nullptr) {
preorder3DMed(root->left);
}
if(root->right != nullptr) {
preorder3DMed(root->right);
}
return;
}
/*
create grid with points of median version
*/
void
KDTree3D::preorderMedGrid3D(Cell3DT* boundBox,
Tree3DMedStructure* node)
//std::vector<Tree3DMedStructure*> pointsPreOrdered)
{
boundBox->left = new Cell3DT();
Cell3DT* cell_left = boundBox->left;
boundBox->right = new Cell3DT();
Cell3DT* cell_right = boundBox->right;
if(node->getAxis() == 0)
{
cell_left->value.x1 = boundBox->value.x1;
cell_left->value.x2 = node->getVal();
cell_left->value.y1 = boundBox->value.y1;
cell_left->value.y2 = boundBox->value.y2;
cell_left->value.z1 = boundBox->value.z1;
cell_left->value.z2 = boundBox->value.z2;
cell_left->final = true;
cell_right->value.x1 = node->getVal();
cell_right->value.x2 = boundBox->value.x2;
cell_right->value.y1 = boundBox->value.y1;
cell_right->value.y2 = boundBox->value.y2;
cell_right->value.z1 = boundBox->value.z1;
cell_right->value.z2 = boundBox->value.z2;
cell_right->final = true;
boundBox->final = false;
//cellsPreorder.push_back(boundBox);
cellsPreorder.push_back(cell_right);
cellsPreorder.push_back(cell_left);
} else if(node->getAxis() == 1)
{
cell_left->value.y1 = boundBox->value.y1;
cell_left->value.y2 = node->getVal();
cell_left->value.x1 = boundBox->value.x1;
cell_left->value.x2 = boundBox->value.x2;
cell_left->value.z1 = boundBox->value.z1;
cell_left->value.z2 = boundBox->value.z2;
cell_left->final = true;
cell_right->value.y1 = node->getVal();
cell_right->value.y2 = boundBox->value.y2;
cell_right->value.x1 = boundBox->value.x1;
cell_right->value.x2 = boundBox->value.x2;
cell_right->value.z1 = boundBox->value.z1;
cell_right->value.z2 = boundBox->value.z2;
cell_right->final = true;
boundBox->final = false;
//cellsPreorder.push_back(boundBox);
cellsPreorder.push_back(cell_right);
cellsPreorder.push_back(cell_left);
} else {
cell_left->value.y1 = boundBox->value.y1;
cell_left->value.y2 = boundBox->value.y2;
cell_left->value.x1 = boundBox->value.x1;
cell_left->value.x2 = boundBox->value.x2;
cell_left->value.z2 = node->getVal();
cell_left->value.z1 = boundBox->value.z1;
cell_left->final = true;
cell_right->value.y1 = boundBox->value.y1;
cell_right->value.y2 = boundBox->value.y2;
cell_right->value.x1 = boundBox->value.x1;
cell_right->value.x2 = boundBox->value.x2;
cell_right->value.z1 = node->getVal();
cell_right->value.z2 = boundBox->value.z2;
cell_right->final = true;
boundBox->final = false;
//cellsPreorder.push_back(boundBox);
cellsPreorder.push_back(cell_right);
cellsPreorder.push_back(cell_left);
}
if(node->getLeft() != nullptr) {
preorderMedGrid3D(cell_left, node->getLeft());
}
if(node->getRight() != nullptr) {
preorderMedGrid3D(cell_right, node->getRight());
}
}
/*
create grid of 3dtree values
*/
void
KDTree3D::preorderGrid3D (Cell3DT* boundBox,
Tree3DStructure* node)
//std::vector<Tree3DStructure*> pointsPreOrdered)
{
boundBox->left = new Cell3DT();
Cell3DT* cell_left = boundBox->left;
boundBox->right = new Cell3DT();
Cell3DT* cell_right = boundBox->right;
if(node->getAxis() == 0)
{
cell_left->value.x1 = boundBox->value.x1;
cell_left->value.x2 = node->x;
cell_left->value.y1 = boundBox->value.y1;
cell_left->value.y2 = boundBox->value.y2;
cell_left->value.z1 = boundBox->value.z1;
cell_left->value.z2 = boundBox->value.z2;
cell_left->final = true;
cell_right->value.x1 = node->x;
cell_right->value.x2 = boundBox->value.x2;
cell_right->value.y1 = boundBox->value.y1;
cell_right->value.y2 = boundBox->value.y2;
cell_right->value.z1 = boundBox->value.z1;
cell_right->value.z2 = boundBox->value.z2;
cell_right->final = true;
boundBox->final = false;
//cellsPreorder.push_back(boundBox);
cellsPreorder.push_back(cell_right);
cellsPreorder.push_back(cell_left);
} else if(node->getAxis() == 1)
{
cell_left->value.y1 = boundBox->value.y1;
cell_left->value.y2 = node->y;
cell_left->value.x1 = boundBox->value.x1;
cell_left->value.x2 = boundBox->value.x2;
cell_left->value.z1 = boundBox->value.z1;
cell_left->value.z2 = boundBox->value.z2;
cell_left->final = true;
cell_right->value.y1 = node->y;
cell_right->value.y2 = boundBox->value.y2;
cell_right->value.x1 = boundBox->value.x1;
cell_right->value.x2 = boundBox->value.x2;
cell_right->value.z1 = boundBox->value.z1;
cell_right->value.z2 = boundBox->value.z2;
cell_right->final = true;
boundBox->final = false;
//cellsPreorder.push_back(boundBox);
cellsPreorder.push_back(cell_right);
cellsPreorder.push_back(cell_left);
} else if(node->getAxis() == 2)
{
cell_left->value.y1 = boundBox->value.y1;
cell_left->value.y2 = boundBox->value.y2;
cell_left->value.x1 = boundBox->value.x1;
cell_left->value.x2 = boundBox->value.x2;
cell_left->value.z2 = node->z;
cell_left->value.z1 = boundBox->value.z1;
cell_left->final = true;
cell_right->value.y1 = boundBox->value.y1;
cell_right->value.y2 = boundBox->value.y2;
cell_right->value.x1 = boundBox->value.x1;
cell_right->value.x2 = boundBox->value.x2;
cell_right->value.z1 = node->z;
cell_right->value.z2 = boundBox->value.z2;
cell_right->final = true;
boundBox->final = false;
//cellsPreorder.push_back(boundBox);
cellsPreorder.push_back(cell_right);
cellsPreorder.push_back(cell_left);
} else {
return;
}
if(node->getLeft() != nullptr && !node->getLeft()->isLeaf()) {
preorderGrid3D(cell_left, node->getLeft());
}
if(node->getRight() != nullptr && !node->getRight()->isLeaf()) {
preorderGrid3D(cell_right, node->getRight());
}
}
/*
get cell id of a given cell and set it in the corresponding
element in vector of nodes
*/
void
KDTree3D::setCellId3D(Cell3DTree cell, Tree3DMedStructure* kdNode)
{
Tree3DMedStructure* node = new Tree3DMedStructure();
while(kdNode != nullptr) {
if(kdNode->axis == 0) {
// check x1 value of cell
if(cell.getValFromX() < kdNode->getVal()) {
if(kdNode->left != nullptr) {
kdNode = kdNode->left;
} else {
node->leaf = true;
kdNode->left = node;
kdNode->left->setCellId(cell.getCellId());
return;
}
} else {
if(kdNode->right != nullptr) {
kdNode = kdNode->right;
} else {
node->leaf = true;
kdNode->right = node;
kdNode->right->setCellId(cell.getCellId());
return; }
}
} else if(kdNode->axis == 1) {
// check y1 value of cell
if(cell.getValFromY() < kdNode->getVal()) {
if(kdNode->left != nullptr) {
kdNode = kdNode->left;
} else {
node->leaf = true;
kdNode->left = node;
kdNode->left->setCellId(cell.getCellId());
return;
}
} else {
if(kdNode->right != nullptr) {
kdNode = kdNode->right;
} else {
node->leaf = true;
kdNode->right = node;
kdNode->right->setCellId(cell.getCellId());
return; }
}
} else if(kdNode->axis == 2) {
// check y1 value of cell
if(cell.getValFromZ() < kdNode->getVal()) {
if(kdNode->left != nullptr) {
kdNode = kdNode->left;
} else {
node->leaf = true;
kdNode->left = node;
kdNode->left->setCellId(cell.getCellId());
return;
}
} else {
if(kdNode->right != nullptr) {
kdNode = kdNode->right;
} else {
node->leaf = true;
kdNode->right = node;
kdNode->right->setCellId(cell.getCellId());
return; }
}
} else {
return;
}
}
kdNode->setCellId(cell.getCellId());
return;
}
/*
set cell id in corresponding element to given cell
in vector of tree nodes
*/
void
KDTree3D::setCellId3D(Cell3DTree cell, Tree3DStructure* kdNode)
{
while(kdNode != nullptr) {
if(kdNode->isLeaf()) {
break;
}
if(kdNode->axis == 0) {
// check x1 value of cell
if(cell.getValFromX() < kdNode->x) {
kdNode = kdNode->left;
} else {
kdNode = kdNode->right;
}
} else if(kdNode->axis == 1) { // check y-values
if(cell.getValFromY() < kdNode->y) {
kdNode = kdNode->left;
} else {
kdNode = kdNode->right;
}
} else if(kdNode->axis == 2) { // check z-values
if(cell.getValFromZ() < kdNode->z) {
kdNode = kdNode->left;
} else {
kdNode = kdNode->right;
}
} else {
return;
}
}
kdNode->setCellId(cell.getCellId());
return;
}
void
KDTree3D::build3DTree() {
// create grid structure
Cell3DT* boundBox = new Cell3DT();
boundBox->value.x1 = boundingBox->getMinX();
boundBox->value.x2 = boundingBox->getMaxX();
boundBox->value.y1 = boundingBox->getMinY();
boundBox->value.y2 = boundingBox->getMaxY();
boundBox->value.z1 = boundingBox->getMinZ();
boundBox->value.z2 = boundingBox->getMaxZ();
Tree3DStructure* root;
Tree3DMedStructure* rootMed;
int mode_ = mode; // 1 => middle of list for partition, 2 => median
if(mode_ == 1) {
// build 3dtree recursive, push elements in pointsVector
KDTreeRec3D(points, 0, (int)points.size()-1,0);
root = pointsVector.back();
//order elements and prepare cells
preorder3D(root);
preorderGrid3D(boundBox, pointsPreorder[0]);
} else {
KDTreeMedRec3D(points,0);
rootMed = kd3dmedListVec.back();
// order elements and prepare cells
preorder3DMed(rootMed);
preorderMedGrid3D(boundBox, pointsPreorderMed[0]);
}
Cell3DTree cell = Cell3DTree();
// filter finale cells
for(int r = 0; r < (int)cellsPreorder.size(); r++) {
if(cellsPreorder.at(r)->final == 1) {
cell.setValFromX(cellsPreorder.at(r)->value.x1);
cell.setValToX(cellsPreorder.at(r)->value.x2);
cell.setValFromY(cellsPreorder.at(r)->value.y1);
cell.setValToY(cellsPreorder.at(r)->value.y2);
cell.setValFromZ(cellsPreorder.at(r)->value.z1);
cell.setValToZ(cellsPreorder.at(r)->value.z2);
cellVector.push_back(cell);
}
}
// first sort by x-value then by y-value and z-value
sort(cellVector.begin(), cellVector.end(), zValueComparison);
sort(cellVector.begin(), cellVector.end(), xValueComparison);
sort(cellVector.begin(), cellVector.end(), yValueComparison);
int cellId = 0;
// set cellIds of elements in cellVector
for(int e = 0; e < (int)cellVector.size(); e++)
{
cellId++;
cellVector.at(e).setCellId(cellId);
if(mode_ == 1) {
setCellId3D(cellVector.at(e), root);
} else {
setCellId3D(cellVector.at(e), rootMed);
}
}
const double min[] { boundingBox->getMinX(),
boundingBox->getMinY(), boundingBox->getMinZ() };
const double max[] { boundingBox->getMaxX(),
boundingBox->getMaxY(), boundingBox->getMaxZ() };
box.Set(true, min, max);
}
bool
KDTree3D::duplicateP(T3DPoint p)
{
for(size_t i = 0; i < points.size(); i++)
{
if(points[i].x == p.x && points[i].y == p.y
&& points[i].z == p.z)
{
return true;
}
}
return false;
}
void
KDTree3D::processInput(Stream<Rectangle<3>> rStream) {
rStream.open();
Rectangle<3>* next = rStream.request();
while(next != 0){
if (!insideRectangle3DTree(boundingBox, next)) {
// rectangle (partially) outside the bounding box is discarded
next = rStream.request();
continue;
}
T3DPoint p = getCuboidCentre3DTree(next);
if(!duplicateP(p)) {
points.push_back(getCuboidCentre3DTree(next));
}
next = rStream.request();
}
rStream.close();
}
void
KDTree3D::processInputVector(std::vector<Rectangle<3>>* rVector) {
for (Rectangle<3> bbox : *rVector) {
if (!insideRectangle3DTree(boundingBox, &bbox)) {
// rectangle (partially) outside the bounding box is discarded
continue;
}
points.push_back(getCuboidCentre3DTree(&bbox));
}
}
KDTree3D::~KDTree3D() {}
ListExpr
KDTree3D::Property3DTree()
{
ListExpr desclst = nl->TextAtom();
nl->AppendText(desclst,
"A <rectangle> bounding box "
"followed by list of lists of cell and cell id.\n"
"A cell consists of a six-element list\n(<from x> "
"<to x> <from y> <to y> <from z> <to z>). ");
ListExpr formatlst = nl->TextAtom();
nl->AppendText(formatlst,
"(0.0 2.0 0.0 2.0 0.0 2.0) (((0.0 0.9 0.0 0.7 0.0 0.25) 1) "
"((0.0 0.9 0.0 0.7 0.25 2.0) 2) ((0.9 2.0 0.0 1.5 0.0 0.75) 3) "
" ((0.9 2.0 0.0 1.5 0.75 2.0) 4) ((0.0 0.9 0.7 2.0 0.0 2.0) 5)"
" ((0.9 2.0 1.5 2.0 0.0 2.0) 6)))");
return (nl->TwoElemList(
nl->FourElemList(nl->StringAtom("Signature"),
nl->StringAtom("Example Type List"),
nl->StringAtom("List Rep"),
nl->StringAtom("Example List")),
nl->FourElemList(nl->StringAtom("-> DATA"),
nl->StringAtom(KDTree3D::BasicType()),
desclst,
formatlst)));
}
// Out function
ListExpr
KDTree3D::Out3DTree( ListExpr typeInfo, Word value ) {
KDTree3D* kdtree3d = static_cast<KDTree3D*>( value.addr );
if (kdtree3d != nullptr) {
Rectangle<3> * b_box = kdtree3d->getBoundingBox();
ListExpr bboxLstExpr = nl->SixElemList(
nl->RealAtom(b_box->getMinX()),
nl->RealAtom(b_box->getMaxX()),
nl->RealAtom(b_box->getMinY()),
nl->RealAtom(b_box->getMaxY()),
nl->RealAtom(b_box->getMinZ()),
nl->RealAtom(b_box->getMaxZ()));
//ListExpr rowLstExpr = nl->Empty();
ListExpr cellLstExpr = nl->Empty();
std::vector<Cell3DTree>* cells = &kdtree3d->getCellVector();
if (cells->size() > 0) {
ListExpr lastCellLstExpr;
for(size_t cellIdx = 0; cellIdx < cells->size(); cellIdx++) {
Cell3DTree* curr_cell = &cells->at(cellIdx);
if (cellIdx > 0) {
lastCellLstExpr = nl->Append(lastCellLstExpr,
nl->TwoElemList(
nl->SixElemList(nl->RealAtom(curr_cell->getValFromX()),
nl->RealAtom(curr_cell->getValToX()),
nl->RealAtom(curr_cell->getValFromY()),
nl->RealAtom(curr_cell->getValToY()),
nl->RealAtom(curr_cell->getValFromZ()),
nl->RealAtom(curr_cell->getValToZ())),
nl->OneElemList(
nl->IntAtom(curr_cell->getCellId()))));
} else {
cellLstExpr = nl->OneElemList(nl->TwoElemList(
nl->SixElemList(nl->RealAtom(curr_cell->getValFromX()),
nl->RealAtom(curr_cell->getValToX()),
nl->RealAtom(curr_cell->getValFromY()),
nl->RealAtom(curr_cell->getValToY()),
nl->RealAtom(curr_cell->getValFromZ()),
nl->RealAtom(curr_cell->getValToZ())),
nl->OneElemList(
nl->IntAtom(curr_cell->getCellId()))));
lastCellLstExpr = cellLstExpr;
}
}
}
ListExpr kdtree3dLstExpr = nl->TwoElemList(bboxLstExpr, cellLstExpr);
return kdtree3dLstExpr;
} else {
return (nl->SymbolAtom(Symbol::UNDEFINED()));
}
}
// In function
Word
KDTree3D::In3DTree( const ListExpr typeInfo, const ListExpr instance,
const int errorPos, ListExpr& errorInfo, bool& correct ) {
Word w = SetWord(Address(0));
try {
Rectangle<3>* bbox;
ListExpr bboxLstExpr;
ListExpr cellLstExpr;
if ( nl->ListLength( instance ) == 2 ) {
bboxLstExpr = nl->First(instance);
cellLstExpr = nl->Second(instance);
} else {
throw 1;
}
// fetch bounding box information from input
if (nl->ListLength( bboxLstExpr ) == 6 ) {
ListExpr left = nl->First(bboxLstExpr);
ListExpr right = nl->Second(bboxLstExpr);
ListExpr bottom = nl->Third(bboxLstExpr);
ListExpr top = nl->Fourth(bboxLstExpr);
ListExpr front = nl->Fifth(bboxLstExpr);
ListExpr back = nl->Sixth(bboxLstExpr);
if ( nl->IsAtom(left) && nl->AtomType(left) == RealType
&& nl->IsAtom(right) && nl->AtomType(right) == RealType
&& nl->IsAtom(bottom) && nl->AtomType(bottom) == RealType
&& nl->IsAtom(top) && nl->AtomType(top) == RealType
&& nl->IsAtom(front) && nl->AtomType(front) == RealType
&& nl->IsAtom(back) && nl->AtomType(back) == RealType) {
double min[3], max[3];
min[0] = nl->RealValue(left);
min[1] = nl->RealValue(bottom);
max[0] = nl->RealValue(right);
max[1] = nl->RealValue(top);
min[2] = nl->RealValue(front);
max[2] = nl->RealValue(back);
bbox = new Rectangle<3>(true, min, max);
} else {
throw 3;
}
} else {
throw 2;
}
// temporary support structures
std::map<int, int> cellRef;
std::map<int, Cell3DTree*> cellIds;
std::vector<Cell3DTree> cell_vec {};
int cell_cnt = 0;
Cell3DTree c;
//Cell3DTree* c_ptr;
if (nl->ListLength( cellLstExpr ) > 1 ) {
while(!nl->IsEmpty(cellLstExpr)) {
ListExpr cellElem = nl->First(cellLstExpr);
if(nl->ListLength(cellElem) == 2) {
while(!nl->IsEmpty(cellElem)) {
ListExpr lstElem = nl->First(cellElem);
if (nl->ListLength( lstElem ) == 6) {
// a six-element list initiates a new cell
ListExpr cv1Lst = nl->First(lstElem);
ListExpr cv2Lst = nl->Second(lstElem);
ListExpr cv3Lst = nl->Third(lstElem);
ListExpr cv4Lst = nl->Fourth(lstElem);
ListExpr cv5Lst = nl->Fifth(lstElem);
ListExpr cv6Lst = nl->Sixth(lstElem);
//ListExpr cv7Lst = nl->Seventh(lstElem);
cell_cnt++;
if ( nl->IsAtom(cv1Lst) && nl->AtomType(cv1Lst) == RealType
&& nl->IsAtom(cv2Lst) && nl->AtomType(cv2Lst) == RealType
&& nl->IsAtom(cv3Lst) && nl->AtomType(cv3Lst) == RealType
&& nl->IsAtom(cv4Lst) && nl->AtomType(cv4Lst) == RealType
&& nl->IsAtom(cv5Lst) && nl->AtomType(cv5Lst) == RealType
&& nl->IsAtom(cv6Lst) && nl->AtomType(cv6Lst) == RealType
){
c = Cell3DTree();
c.setValFromX(nl->RealValue(cv1Lst));
c.setValToX(nl->RealValue(cv2Lst));
c.setValFromY(nl->RealValue(cv3Lst));
c.setValToY(nl->RealValue(cv4Lst));
c.setValFromZ(nl->RealValue(cv5Lst));
c.setValToZ(nl->RealValue(cv6Lst));
cell_vec.push_back(c);
} else {
throw 4;
}
} else { // only cellid
if(nl->ListLength(lstElem) == 1) {
ListExpr clLst1 = nl->First(lstElem);
if(nl->IsAtom(clLst1) && nl->AtomType(clLst1) == IntType) {
Cell3DTree ce = cell_vec.back();
cell_vec.pop_back();
ce.setCellId(nl->IntValue(clLst1));
cell_vec.push_back(ce);
cellIds.insert(std::make_pair(
((int)nl->IntValue(clLst1)), &ce));
}
}
}
cellElem = nl->Rest(cellElem);
}
}
cellLstExpr = nl->Rest(cellLstExpr);
}
}
std::vector<Tree3DStructure*> points_vec {};
correct = true;
KDTree3D* kdtree = new KDTree3D(*bbox);
kdtree->setPointsVector(points_vec);
kdtree->setCellVector(cell_vec);
kdtree->box = *bbox;
w.addr = kdtree;
return w;
} catch (int e) {
correct = false;
cmsg.inFunError("Expecting a 3dtree list representation. Exit code "
+ std::to_string(e));
return w;
}
}
bool
KDTree3D::Open3DTree(SmiRecord& valueRecord,
size_t& offset, const ListExpr typeInfo, Word& value)
{
size_t size = sizeof(int);
size_t sizeD = sizeof(double);
size_t vsize = 0;
std::vector<Cell3DTree> cell_vec {};
double xmin=0.0, xmax=0.0, ymin=0.0, ymax=0.0, zmin=0.0, zmax=0.0;
double vxf=0.0, vxt=0.0, vyf=0.0, vyt=0.0, vzf=0.0, vzt=0.0;
int cId = 0;
bool ok = true;
ok = ok && valueRecord.Read( &xmin, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &xmax, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &ymin, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &ymax, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &zmin, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &zmax, sizeD, offset );
offset += sizeD;
double min[3], max[3];
min[0] = xmin;
min[1] = ymin;
min[2] = zmin;
max[0] = xmax;
max[1] = ymax;
max[2] = zmax;
Rectangle<3>* bbox = new Rectangle<3>(true, min, max);
// size of vector
ok = ok && valueRecord.Read( &vsize, sizeof(size_t), offset );
offset += sizeof(size_t);
for(size_t i = 0; i < vsize; i++)
{
Cell3DTree c;
ok = ok && valueRecord.Read( &vxf, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &vxt, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &vyf, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &vyt, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &vzf, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &vzt, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Read( &cId, size, offset );
offset += size;
c.setValFromX(vxf);
c.setValToX(vxt);
c.setValFromY(vyf);
c.setValToY(vyt);
c.setValFromZ(vzf);
c.setValToZ(vzt);
c.setCellId(cId);
cell_vec.push_back(c);
}
KDTree3D* kdtree = new KDTree3D(*bbox);
kdtree->setCellVector(cell_vec);
kdtree->mode = 3;
value.addr = kdtree;
return ok;
}
bool
KDTree3D::Save3DTree (SmiRecord& valueRecord, size_t& offset,
const ListExpr typeInfo, Word& value)
{
KDTree3D* kdtree3d = static_cast<KDTree3D*>( value.addr );
size_t size = sizeof(int);
size_t sizeD = sizeof(double);
size_t lsize = 0;
bool ok = true;
double minx = kdtree3d->box.getMinX();
double maxx = kdtree3d->box.getMaxX();
double miny = kdtree3d->box.getMinY();
double maxy = kdtree3d->box.getMaxY();
double minz = kdtree3d->box.getMinZ();
double maxz = kdtree3d->box.getMaxZ();
ok = ok && valueRecord.Write(&minx, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&maxx, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&miny, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&maxy, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&minz, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&maxz, sizeD, offset );
offset += sizeD;
std::vector<Cell3DTree>* cells = &kdtree3d->getCellVector();
lsize = cells->size();
ok = ok && valueRecord.Write(&lsize, sizeof(size_t), offset );
offset += sizeof(size_t);
for(size_t i = 0; i < lsize; i++)
{
Cell3DTree* curr_cell = &cells->at(i);
double vfx = curr_cell->getValFromX();
double vtx = curr_cell->getValToX();
double vfy = curr_cell->getValFromY();
double vty = curr_cell->getValToY();
double vfz = curr_cell->getValFromZ();
double vtz = curr_cell->getValToZ();
int cellId = curr_cell->getCellId();
ok = ok && valueRecord.Write(&vfx, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&vtx, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&vfy, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&vty, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&vfz, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&vtz, sizeD, offset );
offset += sizeD;
ok = ok && valueRecord.Write(&cellId, size, offset );
offset += size;
}
return ok;
}
// This function checks whether the type constructor is applied correctly.
bool
KDTree3D::KindCheck3DTree( ListExpr type, ListExpr& errorInfo )
{
return (nl->IsEqual( type, KDTree3D::BasicType() ));
}
// Close -function
void
KDTree3D::Close3DTree( const ListExpr typeInfo, Word& w )
{
delete (KDTree3D *)w.addr;
w.addr = 0;
}
// Clone function
Word
KDTree3D::Clone3DTree( const ListExpr typeInfo, const Word& w )
{
KDTree3D *g = new KDTree3D( *((KDTree3D *)w.addr) );
return SetWord( g );
}
// Create function
Word
KDTree3D::Create3DTree( const ListExpr typeInfo )
{
return SetWord( new KDTree3D() );
}
// Delete function
void
KDTree3D::Delete3DTree( const ListExpr typeInfo, Word& w )
{
delete (KDTree3D *)w.addr;
w.addr = 0;
}
// SizeOf function
int
KDTree3D::SizeOf3DTree()
{
return sizeof(KDTree3D);
}
ListExpr
KDTree3D::KdTree3dFeedTypeMap( ListExpr args )
{
if(nl->HasLength(args, 1)) {
ListExpr first = nl->First(args);
if (KDTree3D::checkType(first)) {
ListExpr resAttrList = nl->TwoElemList(
nl->TwoElemList(
nl->SymbolAtom("Id"),
nl->SymbolAtom(CcInt::BasicType())),
nl->TwoElemList(
nl->SymbolAtom("Cell3DTree"),
nl->SymbolAtom(Rectangle<3>::BasicType())));
return nl->TwoElemList(listutils::basicSymbol<Stream<Tuple>>(),
nl->TwoElemList(
listutils::basicSymbol<Tuple>(),
resAttrList));
}
}
const std::string errMsg = "The following argument is expected:"
" 3dtree";
return listutils::typeError(errMsg);
}
std::vector<CellInfo3DTree*>
KDTree3D::getCellInfoVector(KDTree3D *in_kdtree3d) {
std::vector<CellInfo3DTree*> cell_info_vect {};
std::vector<Cell3DTree>* cells = &in_kdtree3d->getCellVector();
for(size_t cellIdx = 0; cellIdx < cells->size(); cellIdx++) {
Cell3DTree* cell = &cells->at(cellIdx);
double cfx = cell->getValFromX();
double ctx = cell->getValToX();
double cfy = cell->getValFromY();
double cty = cell->getValToY();
double cfz = cell->getValFromZ();
double ctz = cell->getValToZ();
int cid = cell->getCellId();
CellInfo3DTree* ci = new CellInfo3DTree(cid, cfx, ctx, cfy, cty, cfz, ctz);
cell_info_vect.push_back(ci);
}
return cell_info_vect;
}
// for value mapping function of ~feed~ operator
struct KDTRee3DTupleInfo
{
std::vector<CellInfo3DTree*> cell_info_vect;
unsigned int currentTupleIdx;
ListExpr numTupleTypeList;
void init(KDTree3D *kdtree3d_in) {
currentTupleIdx = 0;
cell_info_vect = KDTree3D::getCellInfoVector(kdtree3d_in);
ListExpr tupleTypeLst = nl->TwoElemList(
nl->SymbolAtom(Tuple::BasicType()),
nl->TwoElemList(
nl->TwoElemList(
nl->SymbolAtom("Id"),
nl->SymbolAtom(CcInt::BasicType())),
nl->TwoElemList(
nl->SymbolAtom("Cell3DTree"),
nl->SymbolAtom(Rectangle<3>::BasicType()))));
SecondoCatalog* sc = SecondoSystem::GetCatalog();
numTupleTypeList = sc->NumericType(tupleTypeLst);
}
TupleType* getTupleType() {
TupleType *tupleType = new TupleType(numTupleTypeList);
return tupleType;
}
Tuple* getNext(TupleType *ttype) {
if (currentTupleIdx < cell_info_vect.size()) {
CellInfo3DTree * cell_info = cell_info_vect.at(currentTupleIdx);
int tp_p1 = cell_info->cellId;
Rectangle<3> tp_p2 = *cell_info->cell;
Tuple *tuple = new Tuple(ttype);
tuple->PutAttribute(0, new CcInt(true, tp_p1));
tuple->PutAttribute(1, new Rectangle<3> (tp_p2));
currentTupleIdx++;
return tuple;
} else {
return nullptr;
}
}
};
/*
Value mapping function of operator ~feed~
*/
int
KDTree3D::KdTree3dValueMapFeed( Word* args, Word& result, int message,
Word& local, Supplier s ) {
KDTree3D *input_kdtree3d_ptr =
static_cast<KDTree3D*>( args[0].addr );
KDTRee3DTupleInfo* tp_info = static_cast<KDTRee3DTupleInfo*>(local.addr);
TupleType* tupleType = nullptr;
Tuple* tuple = nullptr;
switch (message) {
case OPEN: {
tp_info = new KDTRee3DTupleInfo();
tp_info->init(input_kdtree3d_ptr);
local.addr = tp_info;
return 0;
}
case REQUEST: {
if (local.addr) {
tp_info = ((KDTRee3DTupleInfo*)local.addr);
tupleType = tp_info->getTupleType();
} else {
return CANCEL;
}
// get next tuple
tuple = tp_info->getNext(tupleType);
if (tuple != nullptr) {
result.addr = tuple;
return YIELD;
} else {
result.addr = 0;
return CANCEL;
}
}
case CLOSE: {
if (local.addr) {
tp_info = ((KDTRee3DTupleInfo*)local.addr);
delete tp_info;
local.addr = 0;
}
return 0;
}
}
return -1;
}
/*
Type mapping function ~KDTree3dCellnosTypeMap~
It is used for the ~cellnos\_kd~ operator.
*/
ListExpr
KDTree3D::Kdtree3dCellnosTypeMap( ListExpr args )
{
if(nl->HasLength(args, 2)) {
ListExpr first = nl->First(args);
ListExpr second = nl->Second(args);
if (KDTree3D::checkType(first) && Rectangle<3>::checkType(second)) {
return nl->SymbolAtom(collection::IntSet::BasicType());
}
}
const std::string errMsg = "The following two arguments are expected:"
" 3dtree x rect<3>";
return listutils::typeError(errMsg);
}
ListExpr
KDTree3D::Kdtree3dSCCTypeMap( ListExpr args )
{
if(nl->HasLength(args, 4)) {
ListExpr first = nl->First(args);
ListExpr second = nl->Second(args);
ListExpr third = nl->Third(args);
ListExpr fourth = nl->Fourth(args);
if (KDTree3D::checkType(first) && Rectangle<3>::checkType(second)
&& Rectangle<3>::checkType(third) && CcInt::checkType(fourth)) {
return nl->SymbolAtom(CcBool::BasicType());
}
}
const std::string errMsg = "The following four arguments are expected:"
" 3dtree x rect<3> x rect<3> x int";
return listutils::typeError(errMsg);
}
ListExpr
KDTree3D::Kdtree3dGetCellTypeMap( ListExpr args )
{
if(nl->HasLength(args, 2)) {
ListExpr first = nl->First(args);
ListExpr second = nl->Second(args);
if (KDTree3D::checkType(first) && CcInt::checkType(second)) {
return nl->SymbolAtom(Rectangle<3>::BasicType());
}
}
const std::string errMsg = "The following two arguments are expected:"
" 3dtree x int";
return listutils::typeError(errMsg);
}
bool
InCell(Cell3DTree cell, double valy, double valx, double valz) {
return (valx >= cell.getValFromX()
&& valx < cell.getValToX()
&& valy >= cell.getValFromY()
&& valy < cell.getValToY()
&& valz >= cell.getValFromZ()
&& valz < cell.getValToZ());
}
//template <class C>
int
CellBS(std::vector<Cell3DTree>* c_vec, int start, int end,
const double valy, const double valx, const double valz) {
if (start >= end) {
return -1;
}
const int mid = start;
if (InCell(c_vec->at(mid), valy, valx, valz)) {
return mid;
}
return CellBS(c_vec, mid+1, end, valy, valx, valz);
}
void
GetLeaf(Tree3DMedStructure* node, double le, double ri,
double bo, double to, double fr, double ba, std::set<int> *cell_ids)
{
// reached the end of the branch: cell id is in leaf
if(node->isLeaf()) {
cell_ids->insert(node->getCellId());
return;
}
if(node->getAxis() == 0) {
// check x1 value
if(le < node->getVal() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
// check x2 value
if(ri < node->getVal() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
}
if (node->getAxis() == 1) {
// check y1 value
if(bo < node->getVal() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
// check y2 value
if(to < node->getVal() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
}
if (node->getAxis() == 2) {
// check z1 value
if(fr < node->getVal() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
// check z2 value
if(ba < node->getVal() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
}
return;
}
void
GetLeaf(Tree3DStructure* node, double le, double ri,
double bo, double to, double fr, double ba,
std::set<int> *cell_ids)
{
// reached the end of the branch: cell id is in leaf
if(node->isLeaf()) {
cell_ids->insert(node->getCellId());
return;
}
if(node->getAxis() == 0) {
// check x1 value
if(le < node->getValx() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
// check x2 value
if(ri < node->getValx() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
}
if (node->getAxis() == 1) {
// check y1 value
if(bo < node->getValy() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
// check y2 value
if(to < node->getValy() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
}
if (node->getAxis() == 2) {
// check z1 value
if(fr < node->getValz() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
// check z2 value
if(ba < node->getValz() && node->getLeft() != nullptr) {
GetLeaf(node->getLeft(), le, ri, bo, to, fr, ba, cell_ids);
} else {
if(node->getRight() != nullptr) {
GetLeaf(node->getRight(), le, ri, bo, to, fr, ba, cell_ids);
}
}
}
return;
}
bool cuboidOverlap(double toleX1, double toleY1, double boriX1,
double boriY1, double toleX2, double toleY2, double boriX2,
double boriY2, double fr1, double ba1, double fr2, double ba2)
{
// If one rectangle is on left side of other
if (toleX1 > boriX2 || toleX2 > boriX1)
return false;
// If one rectangle is above other
if (toleY1 < boriY2 || toleY2 < boriY1)
return false;
if(fr1 > ba2 || fr2 > ba1)
return false;
return true;
}
void
cellnumber(double le, double ri,
double bo, double to, double fr, double ba,
std::set<int> *cell_ids,
std::vector<Cell3DTree>* cells)
{
for(size_t ce=0; ce < cells->size(); ce++)
{
Cell3DTree* curr_cell = &cells->at(ce);
if(cuboidOverlap(curr_cell->getValFromX(), curr_cell->getValToY(),
curr_cell->getValToX(), curr_cell->getValFromY(), le, to, ri, bo,
curr_cell->getValFromZ(), curr_cell->getValToZ(), ba, fr))
{
cell_ids->insert(curr_cell->getCellId());
}
}
return;
}
/*
Value mapping function of operator ~cellnos\_ir~
*/
int
KDTree3D::Kdtree3dValueMapCellnos( Word* args, Word& result,
int message, Word& local, Supplier s ) {
KDTree3D *input_kdtree3d_ptr
= static_cast<KDTree3D*>( args[0].addr );
Rectangle<3> *search_window_ptr
= static_cast<Rectangle<3>*>( args[1].addr );
if (input_kdtree3d_ptr != nullptr && search_window_ptr != nullptr) {
std::set<int> cell_ids;
result = qp->ResultStorage(s);
collection::IntSet* res = (collection::IntSet*) result.addr;
Rectangle<3> * b_box = input_kdtree3d_ptr->getBoundingBox();
int mode_ = input_kdtree3d_ptr->getMode();
if (!search_window_ptr->Intersects(*b_box)) {
cell_ids.insert(0);
res->setTo(cell_ids);
return 0;
}
// 'truncate' search window in case of partial cutting
if (!b_box->Contains(*search_window_ptr)) {
search_window_ptr = new Rectangle<3>(
search_window_ptr->Intersection(*b_box));
cell_ids.insert(0);
}
double le = search_window_ptr->getMinX();
double ri = search_window_ptr->getMaxX();
double bo = search_window_ptr->getMinY();
double to = search_window_ptr->getMaxY();
double fr = search_window_ptr->getMinZ();
double ba = search_window_ptr->getMaxZ();
// mode not set
if(mode_ != 1 && mode_ != 2) {
// use different cellnum method!
cell_ids.clear();
std::vector<Cell3DTree>* cells = &input_kdtree3d_ptr->getCellVector();
cellnumber(le, ri, bo, to, fr, ba, &cell_ids, cells);
//cell_ids.insert(0);
res->setTo(cell_ids);
return 0;
}
// find leaf with cellIds recursive and insert cell ids in cell_ids
if(mode_ == 1) {
std::vector<Tree3DStructure*> nodes =
input_kdtree3d_ptr->getPointsVector();
Tree3DStructure* root = nodes.back();
GetLeaf(root, le, ri, bo, to, fr, ba, &cell_ids);
} else {
std::vector<Tree3DMedStructure*> nodes =
input_kdtree3d_ptr->getPointsMedVector();
Tree3DMedStructure* root = nodes.back();
GetLeaf(root, le, ri, bo, to, fr, ba, &cell_ids);
}
res->setTo(cell_ids);
return 0;
}
return -1;
}
/*
returns cell to a given id
*/
int
KDTree3D::Kdtree3dValueMapGetCell( Word* args, Word& result, int message,
Word& local, Supplier s )
{
KDTree3D *input_kdtree3d_ptr
= static_cast<KDTree3D*>( args[0].addr );
CcInt* cellno_ptr = static_cast<CcInt*>(args[1].addr);
int cellno = cellno_ptr->GetIntval();
if (input_kdtree3d_ptr != nullptr)
{
result = qp->ResultStorage( s );
Rectangle<3> *res = (Rectangle<3>*) result.addr;
std::vector<Cell3DTree>* cells =
&input_kdtree3d_ptr->getCellVector();
for(size_t i = 0; i < cells->size(); i++)
{
Cell3DTree cell = cells->at(i);
if(cell.getCellId() == cellno)
{
double min[3], max[3];
min[0] = cell.getValFromX();
min[1] = cell.getValFromY();
min[2] = cell.getValFromZ();
max[0] = cell.getValToX();
max[1] = cell.getValToY();
max[2] = cell.getValToZ();
res->Set(true, min, max);
return 0;
}
}
}
return -1;
}
/*
Value mapping function for operator ~scc\_3d~
*/
int
KDTree3D::Kdtree3dValueMapSCC( Word* args, Word& result, int message,
Word& local, Supplier s ) {
KDTree3D *input_kdtree3d_ptr
= static_cast<KDTree3D*>( args[0].addr );
Rectangle<3> *search_window_ptr
= static_cast<Rectangle<3>*>( args[1].addr );
Rectangle<3> *search_window_ptr_2
= static_cast<Rectangle<3>*>( args[2].addr );
CcInt* cellno_ptr = static_cast<CcInt*>(args[3].addr);
int cellno = cellno_ptr->GetIntval();
if (input_kdtree3d_ptr != nullptr && search_window_ptr != nullptr
&& search_window_ptr_2 != nullptr) {
std::set<int> cell_ids;
std::set<int> cell_ids_2;
int mode_ = input_kdtree3d_ptr->getMode();
result = qp->ResultStorage( s );
CcBool *res = (CcBool*) result.addr;
bool boolval = false;
std::vector<Tree3DStructure*> nodes = input_kdtree3d_ptr->getPointsVector();
double le = search_window_ptr->getMinX();
double ri = search_window_ptr->getMaxX();
double bo = search_window_ptr->getMinY();
double to = search_window_ptr->getMaxY();
double fr = search_window_ptr->getMinZ();
double ba = search_window_ptr->getMaxZ();
double le_2 = search_window_ptr_2->getMinX();
double ri_2 = search_window_ptr_2->getMaxX();
double bo_2 = search_window_ptr_2->getMinY();
double to_2 = search_window_ptr_2->getMaxY();
double fr_2 = search_window_ptr_2->getMinZ();
double ba_2 = search_window_ptr_2->getMaxZ();
// find leaf with cellIds recursive and insert cell ids in cell_ids
if(mode_ == 1) {
std::vector<Tree3DStructure*> nodes =
input_kdtree3d_ptr->getPointsVector();
Tree3DStructure* root = nodes.back();
GetLeaf(root, le, ri, bo, to, fr, ba, &cell_ids);
GetLeaf(root, le_2, ri_2, bo_2, to_2, fr_2, ba_2, &cell_ids_2);
} else if(mode_ == 2){
std::vector<Tree3DMedStructure*> nodes =
input_kdtree3d_ptr->getPointsMedVector();
Tree3DMedStructure* root = nodes.back();
GetLeaf(root, le, ri, bo, to, fr, ba, &cell_ids);
GetLeaf(root, le_2, ri_2, bo_2, to_2, fr_2, ba_2, &cell_ids_2);
} else {
// use different cellnum method!
cell_ids.clear();
std::vector<Cell3DTree>* cells = &input_kdtree3d_ptr->getCellVector();
cellnumber(le, ri, bo, to, fr, ba, &cell_ids, cells);
cellnumber(le_2, ri_2, bo_2, to_2, fr_2, ba_2, &cell_ids_2, cells);
}
std::vector<int> v(sizeof(cell_ids)+ sizeof(cell_ids_2));
std::vector<int>::iterator it;
it=std::set_intersection (cell_ids.begin(), cell_ids.end(),
cell_ids_2.begin(), cell_ids_2.end(), v.begin());
v.resize(it-v.begin());
if(v.empty()) {
//no intersection between rectangles
res->Set( true, boolval);
return 0;
}
if(v[0] == cellno)
{
boolval = true;
res->Set( true, boolval);
return 0;
}
res->Set( true, boolval);
return 0;
}
return -1;
}