/* ---- This file is part of SECONDO. Copyright (C) 2019, 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 "Convex2.h" #include "Attribute.h" #include #include #include "NestedList.h" #include "Algebras/Spatial/SpatialAlgebra.h" #include #include #include #include "ListUtils.h" #include "NList.h" #include "StandardTypes.h" #include "Stream.h" #include "Algebras/FText/FTextAlgebra.h" #include #include "AlmostEqual.h" #include #include "math.h" #include "Algebras/Collection/IntSet.h" #include "predicates.c" #include using boost::polygon::voronoi_builder; using boost::polygon::voronoi_diagram; using boost::polygon::x; using boost::polygon::y; using boost::polygon::low; using boost::polygon::high; using boost::polygon::construct_voronoi; /* 1.1 boost definitions needed for constructing the voronoi diag */ namespace boost { namespace polygon { struct VoronoiPoint { double a; double b; VoronoiPoint(double x, double y) : a(x), b(y) {} }; template<> struct geometry_concept{typedef point_concept type;}; template <> struct point_traits { typedef double coordinate_type; static inline coordinate_type get( const VoronoiPoint& point, orientation_2d orient) { return (orient == HORIZONTAL) ? point.a : point.b; } }; }} using namespace std; extern NestedList* nl; using boost::polygon::VoronoiPoint; namespace convex { /* 2.1 constructors */ Convex::Convex(const Convex& src):Attribute(src),value(0), size(src.size),cellId(0){ if(size>0){ value = new Point[size]; memcpy((char*)value, src.value,size*sizeof(Point)); memcpy(&cellId, &src.cellId, sizeof(int)); } } Convex::Convex(Convex&& src): Attribute(src), value(src.value), size(src.size), cellId(src.cellId) { src.size = 0; src.value = 0; src.cellId = 0; } Convex::Convex(const std::vector>& src, int id_):Attribute(true), value(0){ setTo(src, id_); } Convex::Convex(const std::vector>& src):Attribute(true), value(0){ setTo(src, -1); } Convex& Convex::operator=(const Convex& src) { Attribute::operator=(src); if(this->size != src.size){ delete[] value; value = 0; cellId = 0; this->size = src.size; if(size > 0){ value = new Point[size]; } } if(size > 0){ memcpy((char*)value, src.value,size*sizeof(Point)); memcpy(&cellId, &src.cellId, sizeof(int)); } return *this; } Convex& Convex::operator=(Convex&& src) { Attribute::operator=(src); size = src.size; value = src.value; cellId = src.cellId; src.size = 0; src.value = 0; src.cellId = 0; return *this; } void Convex::setCellId(int cell_id) { this->cellId = cell_id; } int Convex::getCellId() { return cellId; } void Convex::setTo(const std::vector>& src, int id_){ clear(); SetDefined(true); if(src.size()>0){ size = src.size(); value = new Point[size]; setCellId(id_); auto it = src.begin(); size_t pos = 0; std::tuple temptup; double tempxval; double tempyval; Point poi; /* converting the right tuple vector into point sequence */ while(it!=src.end()) { temptup = *it; tempxval = std::get<0>(temptup); tempyval = std::get<1>(temptup); poi.Set(true, tempxval, tempyval); value[pos] = poi; it++; pos++; } } } /* 3.1 auxillary functions */ bool insideRect(Rectangle<2>* r, std::tuple center) { double x = get<0>(center); double y = get<1>(center); if (r->getMinX() <= x && r->getMaxX() >= x && r->getMinY() <= y && r->getMaxY() >= y) { return true; } return false; } Point getRectCentre(Rectangle<2>* r) { Point rc; double a = (r->getMaxY() - r->getMinY()) / (double)2; double b = (r->getMaxX() - r->getMinX()) / (double)2; rc.Set(r->getMinX()+ b, r->getMinY() + a); return rc; } /* Returns bounding box of a convex polygon */ Rectangle<2> createBBox(Convex* convex) { Rectangle<2> bbox; double minx = convex->value[0].GetX(); double maxx = convex->value[0].GetX(); double miny = convex->value[0].GetY(); double maxy = convex->value[0].GetY(); for(int c=1; c < (int)convex->size; c++) { double x_val = convex->value[c].GetX(); double y_val = convex->value[c].GetY(); if(x_val < minx) { minx = x_val; } else if (x_val > maxx) { maxx = x_val; } if(y_val < miny) { miny = y_val; } else if(y_val > maxy) { maxy = y_val; } } double min[2], max[2]; min[0] = minx; min[1] = miny; max[0] = maxx; max[1] = maxy; bbox = Rectangle<2>(true, min, max); return bbox; } /* Returns true if point is inside of convex polygon */ bool PointInPolygon(Point point, Convex* conv) { std::vector poly; for(int a = 0; a < (int)conv->size; a++) { Point p1; p1.Set(conv->value[a].GetX(), conv->value[a].GetY()); poly.insert(poly.begin() + a, p1); } Rectangle<2> bbox = createBBox(conv); /* Precheck: if point is not in bbox of polygon, then it is not in polygon either */ if(!insideRect(&bbox, std::make_tuple(point.GetX(), point.GetY()))) { return false; } /* go through every segment and check on which side point lies */ double detO; Point a,b; a = poly[0]; b = poly[1]; /* P0 (x0,y0) and P1 (x1,y1), another point P (x,y) (y - y0) (x1 - x0) - (x - x0) (y1 - y0) */ detO = (point.GetY() - a.GetY())*(b.GetX() - a.GetX()) - (point.GetX() - a.GetX())*(b.GetY() - a.GetY()); for(int e = 1; e < (int)poly.size()-1; e++) { Point a,b; a = poly[e]; b = poly[e+1]; double det = (point.GetY() - a.GetY())*(b.GetX() - a.GetX()) - (point.GetX() - a.GetX())*(b.GetY() - a.GetY()); if(signbit(detO) != signbit(det)) { return false; } } return true; } /* Calculates point of intersection between two segments */ int getLineIntersection(Point p0, Point p1, Point p2, Point p3, double *i_x, double *i_y) { // Points x and y values double p0_x = p0.GetX(); double p0_y = p0.GetY(); double p1_x = p1.GetX(); double p1_y = p1.GetY(); double p2_x = p2.GetX(); double p2_y = p2.GetY(); double p3_x = p3.GetX(); double p3_y = p3.GetY(); double xp0p2, yp0p2, xp1p0, yp1p0, xp3p2, yp3p2, u_numrator, t_numerator, denominator, t; xp1p0 = p1_x - p0_x; yp1p0 = p1_y - p0_y; xp3p2 = p3_x - p2_x; yp3p2 = p3_y - p2_y; denominator = xp1p0 * yp3p2 - xp3p2 * yp1p0; if (denominator == 0) return 0; // parallel bool denomPositive = denominator > 0; xp0p2 = p0_x - p2_x; yp0p2 = p0_y - p2_y; u_numrator = xp1p0 * yp0p2 - yp1p0 * xp0p2; if ((u_numrator < 0) == denomPositive) return 0; // No intersection t_numerator = xp3p2 * yp0p2 - yp3p2 * xp0p2; if ((t_numerator < 0) == denomPositive) return 0; // No intersection if (((u_numrator > denominator) == denomPositive) || ((t_numerator > denominator) == denomPositive)) return 0; // No intersection // Intersection t = t_numerator / denominator; if (i_x != NULL) *i_x = p0_x + (t * xp1p0); if (i_y != NULL) *i_y = p0_y + (t * yp1p0); return 1; } /* Calculates center of a given polygon */ std::tuple calcPolyCentroid(std::vector> vertices, int vertexNumb) { std::tuple centroid = {0, 0}; double signedArea = 0.0; double x0 = 0.0; // current x value double y0 = 0.0; // current y value double x1 = 0.0; // next x value double y1 = 0.0; // next y value double a = 0.0; // area int i; // Calculate area of polygon with Gaußsche Trapezformel for(i=0; i(vertices[i]); y0 = get<1>(vertices[i]); x1 = get<0>(vertices[i+1]); y1 = get<1>(vertices[i+1]); a = x0*y1 - x1*y0; signedArea += a; get<0>(centroid) += (x0 + x1)*a; get<1>(centroid) += (y0 + y1)*a; } // last vertex x0 = get<0>(vertices[i]); y0 = get<1>(vertices[i]); x1 = get<0>(vertices[0]); y1 = get<1>(vertices[0]); a = x0*y1 - x1*y0; signedArea += a; get<0>(centroid) += (x0 + x1)*a; get<1>(centroid) += (y0 + y1)*a; signedArea *= 0.5; // calculate centroid with formula get<0>(centroid) /= (6.0*signedArea); get<1>(centroid) /= (6.0*signedArea); return centroid; } /* Returns true if two rectangles (l1, r1) and (l2, r2) overlap */ bool rectOverlap(Point tole1, Point bori1, Point tole2, Point bori2) { // If one rectangle is on left side of other if (tole1.GetX() > bori2.GetX() || tole2.GetX() > bori1.GetX()) return false; // If one rectangle is above other if (tole1.GetY() < bori2.GetY() || tole2.GetY() < bori1.GetY()) return false; return true; } /* Returns true if two cuboids (l1, r1) and (l2, r2) overlap */ bool cuboidOverlap(Point3D tolefr1, Point3D boriba1, Point3D tolefr2, Point3D boriba2) { // If one cuboid is on left side of other if (tolefr1.x > boriba2.x || tolefr2.x > boriba1.x) return false; // If one cuboid is above other if (tolefr1.y < boriba2.y || tolefr2.y < boriba1.y) return false; if(tolefr1.z > boriba2.z || tolefr2.z > boriba1.z) return false; return true; } /* Returns bounding box of a convex polyhedron */ Rectangle<3> createBBox3D(Polyhedron* poly) { Rectangle<3> bbox; double minx = poly->faces.at(0).at(0).x; double maxx = poly->faces.at(0).at(0).x; double miny = poly->faces.at(0).at(0).y; double maxy = poly->faces.at(0).at(0).y; double minz = poly->faces.at(0).at(0).z; double maxz = poly->faces.at(0).at(0).z; for(size_t c=1; c < poly->faces.size(); c++) { for(size_t v=0; v < poly->faces.at(c).size(); v++) { double x_val = poly->faces.at(c).at(v).x; double y_val = poly->faces.at(c).at(v).y; double z_val = poly->faces.at(c).at(v).z; if(x_val < minx) { minx = x_val; } else if (x_val > maxx) { maxx = x_val; } if(y_val < miny) { miny = y_val; } else if(y_val > maxy) { maxy = y_val; } if(z_val < minz) { minz = z_val; } else if(z_val > maxz) { maxz = z_val; } } } double min[3], max[3]; min[0] = minx; min[1] = miny; min[2] = minz; max[0] = maxx; max[1] = maxy; max[2] = maxz; bbox = Rectangle<3>(true, min, max); return bbox; } /* Returns all cellnumbers of cells which intersect with a given rectangle Two modes are possible: intersections with the exact cell and intersection with the bounding box of a cell */ void cellNum(Rectangle<2>* search_window_ptr, int mode, std::set *cell_ids) { int bbox = 2; int precise = 1; // Rectangle points Point lebo, ribo, leto, rito; lebo.Set(search_window_ptr->getMinX(), search_window_ptr->getMinY()); ribo.Set(search_window_ptr->getMaxX(), search_window_ptr->getMinY()); leto.Set(search_window_ptr->getMinX(), search_window_ptr->getMaxY()); rito.Set(search_window_ptr->getMaxX(), search_window_ptr->getMaxY()); Point center = getRectCentre(search_window_ptr); // intersection with exact cell if(mode == precise) { for(int i = 0; i < (int)voroVec.size(); i++) { Convex* tmp = &voroVec[i]; if(tmp->size > 0) { /* -1. Precheck if object has an intersection with bbox of voronoi cell - if yes: go on with further tests - if not: go to next cell */ Rectangle<2> bbox = createBBox(tmp); // see if bbox intersects with rectangle // top left and bottom right of bbox Point tole, bori; tole.Set(bbox.getMinX(), bbox.getMaxY()); bori.Set(bbox.getMaxX(), bbox.getMinY()); if(rectOverlap(tole, bori, leto, ribo)) { std::vector> polygon {}; std::tuple point; /* 1. Check if middle of cell intersects with rectangle (get middle of cell, check if it lies in rectangle) - if yes: add cell\_id to cell\_ids - if no: check if edges intersect with rectangle - build edges from points (ordered clockwise), check intersection - if one intersect: add cell\_id to cell\_ids - if no edge intersects: check if rectangle is small and does not intersects with edges or centroid at all, but lies in cell - if no intersects: go to next cell, don't add cell\_id */ double firstX = tmp->value[0].GetX(); double firstY = tmp->value[0].GetY(); point = std::make_tuple(firstX, firstY); polygon.insert(polygon.begin(), point); for(int a = 1; a < (int)tmp->size; a++) { point = std::make_tuple(tmp->value[a].GetX(), tmp->value[a].GetY()); polygon.insert(polygon.begin() + a, point); } std::tuple centroid = calcPolyCentroid(polygon, polygon.size()); if(insideRect(search_window_ptr, centroid)){ cell_ids->insert(tmp->getCellId()); } else if (PointInPolygon(center, tmp)) { cell_ids->insert(tmp->getCellId()); } else { for(int e = 0; e < (int)tmp->size; e++) { Point a,b; a.Set(tmp->value[e].GetX(), tmp->value[e].GetY()); if(e == (int)tmp->size-1) { b.Set(firstX, firstY); } else { b.Set(tmp->value[e+1].GetX(), tmp->value[e+1].GetY()); } // Point of intersection i\_x, i\_y w double i_x = 0.0; double i_y = 0.0; /* call to getlineintersection with 2 points of line and two points of side of rectangle (for each side of rectangle) */ if(getLineIntersection(a,b, lebo, ribo, &i_x, &i_y) == 1 || getLineIntersection(a,b, lebo, leto, &i_x, &i_y) == 1 || getLineIntersection(a,b, ribo, rito, &i_x, &i_y) == 1 || getLineIntersection(a,b, leto, rito, &i_x, &i_y) == 1) { cell_ids->insert(tmp->getCellId()); break; } } } if(polygon.size() > 0) { polygon.clear(); } } } } } else if (mode== bbox) { for(int b = 0; b < (int)voroVec.size(); b++) { Convex* tmp = &voroVec[b]; if(tmp->size > 0) { Rectangle<2> bbox = createBBox(tmp); // see if bbox intersects with rectangle // top left and bottom right of bbox Point tole, bori; tole.Set(bbox.getMinX(), bbox.getMaxY()); bori.Set(bbox.getMaxX(), bbox.getMinY()); if(rectOverlap(tole, bori, leto, ribo)) { cell_ids->insert(tmp->getCellId()); } } } } else { cell_ids->insert(0); } return; } bool sortyupxup(const tuple& a, const tuple& b) { if ( (get<1>(a) < get<1>(b)) || ( ( get<1>(a) == get<1>(b)) && (get<0>(a) <= get<0>(b))) ) return true; return false; } bool sortyupxdown(const tuple& a, const tuple& b) { if ( (get<1>(a) < get<1>(b)) || ( ( get<1>(a) == get<1>(b)) && (get<0>(a) >= get<0>(b))) ) return true; return false; } bool sortxupyup(const tuple& a, const tuple& b) { if ( (get<0>(a) < get<0>(b)) || ( ( get<0>(a) == get<0>(b)) && (get<1>(a) <= get<1>(b))) ) return true; return false; } bool sortxdownydown (const tuple& a, const tuple& b) { if ( (get<0>(a) > get<0>(b)) || ( ( get<0>(a) == get<0>(b)) && (get<1>(a) >= get<1>(b))) ) return true; return false; } bool sortxdownyup (const tuple& a, const tuple& b) { if ( (get<0>(a) > get<0>(b)) || ( ( get<0>(a) == get<0>(b)) && (get<1>(a) <= get<1>(b))) ) return true; return false; } bool sortxupydown (const tuple& a, const tuple& b) { if ( (get<0>(a) < get<0>(b)) || ( ( get<0>(a) == get<0>(b)) && (get<1>(a) >= get<1>(b))) ) return true; return false; } void rmvredundpoints (std::vector>& ppoi) { std::set > setme; std::set > tempvec; for (unsigned int i = 0; i < ppoi.size(); i++) { setme.insert(ppoi[i]); } ppoi.assign(setme.begin(), setme.end()); sort(ppoi.begin(), ppoi.end(), sortxupyup); } /* 3.2 checkme function */ int checkme(std::vector>& src, bool checkactive){ std::vector> finalcheckedvec; std::vector> tmp; std::vector> xysortedvecasc; std::vector> yxsortedvecasc; std::vector> xysortedvecdesc; std::vector> ydownsortedvec; std::tuple leftpoint; std::tuple rightpoint; std::tuple downpoint; std::tuple uppoint; std::tuple actpoint; std::tuple intermpoint; std::vector> above; std::vector> below; std::vector> aboveleft; std::vector> belowleft; std::vector> aboveright; std::vector> belowright; std::vector> temp1, temp2; unsigned int iter, sectorflag; unsigned int aboveleftsize; unsigned int aboverightsize; unsigned int belowleftsize; unsigned int belowrightsize; unsigned int tmpsize; bool okflag = true; bool firstperpend = false; bool secondperpend = false; bool setfperflag = false; bool firstmflag = false; double m, b, mlast, mnew; if (src.size() <= 2) { return 0; } tmp = src; xysortedvecasc = tmp; yxsortedvecasc = tmp; /* sorting vecs by x resp. y coord */ sort(yxsortedvecasc.begin(), yxsortedvecasc.end(), sortyupxdown); /* eliminate redundant points */ rmvredundpoints(xysortedvecasc); /* get leftpoint and right point of polygon */ leftpoint = xysortedvecasc[0]; rightpoint = xysortedvecasc[xysortedvecasc.size() - 1]; downpoint = yxsortedvecasc[0]; uppoint = yxsortedvecasc[yxsortedvecasc.size() - 1]; /* get points above and below the imagenary "line" from leftpoint to rightpoint */ m = (get<1>(rightpoint) - get<1>(leftpoint)) / (get<0>(rightpoint) - get<0>(leftpoint)); b = get<1>(rightpoint) - (m * get<0>(rightpoint)); below.clear(); above.clear(); for (unsigned int i = 0; i < xysortedvecasc.size(); i++) { double fuval = (m * get<0>(xysortedvecasc[i])) + b; if ( fuval > get<1>(xysortedvecasc[i]) && !(AlmostEqual (fuval, get<1>(xysortedvecasc[i])))) { below.push_back (xysortedvecasc[i]); } else { above.push_back (xysortedvecasc[i]); } } /* move points above and below to aboveleft, aboveright, belowleft and belowright. using the "line" from downpoint to uppoint get points above and below the imagenary "line" from downpoint to uppoint first: testing if point are perpendicular */ belowright.clear(); aboveright.clear(); belowleft.clear(); aboveleft.clear(); if (get<0>(uppoint) != get<0>(downpoint) ){ m = (get<1>(uppoint) - get<1>(downpoint)) / (get<0>(uppoint) - get<0>(downpoint)); b = get<1>(uppoint) - (m * get<0>(uppoint)); } if (get<0>(uppoint) != get<0>(downpoint)) { for (unsigned int i = 0; i < above.size(); i++) { double fval = (m * get<0>(above[i])) + b; if ( (fval > get<1>(above[i])) && !(AlmostEqual (fval, get<1>(above[i])))) { aboveright.push_back (above[i]); } else { aboveleft.push_back (above[i]); } } for (unsigned int i = 0; i < below.size(); i++) { if ( ((m * get<0>(below[i])) + b) > get<1>(below[i]) ) { belowright.push_back (below[i]); } else { belowleft.push_back (below[i]); } } if (m < 0) { temp1 = aboveright; temp2 = belowright; aboveright = aboveleft; belowright = belowleft; aboveleft = temp1; belowleft = temp2; } } /* uppoint and downpoint are perpendicular */ if (get<0>(uppoint) == get<0>(downpoint) ) { for (unsigned int i = 0; i < above.size(); i++) { if ( (get<0>(above[i])) > get<0>(uppoint)) { aboveright.push_back (above[i]); } else { aboveleft.push_back (above[i]); } } for (unsigned int i = 0; i < below.size(); i++) { if ( (get<0>(below[i])) > get<0>(uppoint)) { belowright.push_back (below[i]); } else { belowleft.push_back (below[i]); } } } /* sorting aboveleft, ab aboveright, belowright and belowleft... */ /* aboveleft is already sorted: x up , y up */ sort(aboveleft.begin(), aboveleft.end(), sortxupyup); /* sorting aboveright: x up, y down */ sort(aboveright.begin(), aboveright.end(), sortxupydown); /* sorting belowright: x down, y down */ sort(belowright.begin(), belowright.end(), sortxdownydown); /* sorting belowleft: x down, y up */ sort(belowleft.begin(), belowleft.end(), sortxdownyup); /* constructing the final vector */ finalcheckedvec.clear(); aboveleftsize = aboveleft.size(); aboverightsize = aboveright.size(); belowleftsize = belowleft.size(); belowrightsize = belowright.size(); tmpsize = tmp.size(); for (unsigned int i = 0; i < aboveleftsize; i++) { finalcheckedvec.push_back(aboveleft[i]); } for (unsigned int i = 0; i < aboverightsize; i++) { finalcheckedvec.push_back(aboveright[i]); } for (unsigned int i = 0; i < belowrightsize; i++) { finalcheckedvec.push_back(belowright[i]); } for (unsigned int i = 0; i < belowleftsize; i++) { finalcheckedvec.push_back(belowleft[i]); } if (tmpsize == finalcheckedvec.size()) { } if (checkactive == false) { src = finalcheckedvec; return 2;} /* put left point at the end of the final vec for testing purposes */ finalcheckedvec.push_back(leftpoint); actpoint = leftpoint; intermpoint = uppoint; sectorflag = 1; iter = 1; if ((get<0>(leftpoint) == get<0>(finalcheckedvec[iter])) && (get<0>(leftpoint) == get<0>(finalcheckedvec[iter+1]))) { ErrorReporter::ReportError( "The coordinates do not form a convex polygon"); return 0; } if ((get<0>(leftpoint) == get<0>(finalcheckedvec[iter])) && (get<0>(leftpoint) != get<0>(finalcheckedvec[iter+1]))) { firstperpend = true; setfperflag = true; /* set mlast > mnew as start value */ mlast = 1; mnew = 0; } else { mlast = (get<1>(finalcheckedvec[iter] ) - get<1>(leftpoint)) / (get<0>(finalcheckedvec[iter]) - get<0>(leftpoint)); firstmflag = true; mnew = mlast - 1; /* just a dummy value */ } while ( (iter < finalcheckedvec.size()) && (okflag == true)) { /* begin sector 2 case */ if (actpoint == uppoint) { intermpoint = rightpoint; sectorflag = 2; firstperpend = false; setfperflag = false; } if (sectorflag == 2) { if ( (iter+1 < finalcheckedvec.size()) && (get<0>(actpoint) == get<0>(finalcheckedvec[iter])) && (get<0>(actpoint) == get<0>(finalcheckedvec[iter+1]))) { ErrorReporter::ReportError( "3The coordinates do not form a convex polygon"); return 0; } if (get<0>(actpoint) == get<0>(finalcheckedvec[iter]) && (actpoint != rightpoint) ) { ErrorReporter::ReportError( "4The coordinates do not form a convex polygon"); return 0;; } if (get<0>(actpoint) != get<0>(finalcheckedvec[iter]) && actpoint == uppoint) { mlast = (get<1>(finalcheckedvec[iter] ) - get<1>(uppoint)) / (get<0>(finalcheckedvec[iter]) - get<0>(uppoint)); firstmflag = true; mnew = mlast - 1; /* just a dummy value */ } } /* end of sectorflag == 2 case */ /* begin sector 3 case */ if (actpoint == rightpoint){ intermpoint = downpoint; sectorflag = 3; firstperpend = false; setfperflag = false; secondperpend = false; firstmflag = false; } if (sectorflag == 3) { if ( (iter+1 < finalcheckedvec.size()) && (get<0>(actpoint) == get<0>(finalcheckedvec[iter])) && (get<0>(actpoint) == get<0>(finalcheckedvec[iter+1])) && (actpoint == rightpoint) ) { ErrorReporter::ReportError( "4The coordinates do not form a convex polygon"); return 0;; } if ((iter+1 < finalcheckedvec.size()) && (get<0>(rightpoint) == get<0>(finalcheckedvec[iter])) && (get<0>(rightpoint) != get<0>(finalcheckedvec[iter+1])) && (actpoint == rightpoint) ) { firstperpend = true; setfperflag = true; /* set mlast > mnew as start value; */ mlast = 1; mnew = 0; } else if (actpoint == rightpoint) { mlast = (get<1>(finalcheckedvec[iter] ) - get<1>(rightpoint)) / (get<0>(finalcheckedvec[iter]) - get<0>(rightpoint)); firstmflag = true; mnew = mlast - 1; /* just a dummy value */ } } /* end of sectorflag == 3 case */ /* begin sector 4 case */ if ((actpoint == downpoint) && (downpoint != leftpoint)) { intermpoint = leftpoint; sectorflag = 4; } if ( (sectorflag == 4) && (actpoint != leftpoint) ) { if ( (iter+1 < finalcheckedvec.size()) && (get<0>(actpoint) == get<0>(finalcheckedvec[iter])) && (get<0>(actpoint) == get<0>(finalcheckedvec[iter+1]))) { ErrorReporter::ReportError( "5The coordinates do not form a convex polygon"); return 0;; } if (get<0>(actpoint) == get<0>(finalcheckedvec[iter]) && (actpoint != uppoint) ) { ErrorReporter::ReportError( "6The coordinates do not form a convex polygon"); return 0;; } if (get<0>(actpoint) != get<0>(finalcheckedvec[iter]) && actpoint == downpoint) { mlast = (get<1>(finalcheckedvec[iter] ) - get<1>(downpoint)) / (get<0>(finalcheckedvec[iter]) - get<0>(downpoint)); firstmflag = true; mnew = mlast - 1; /* just a dummy value */ } /* end of sector 4 case */ } switch (sectorflag) { case 1: { if (get<0>(actpoint) == get<0>(finalcheckedvec[iter])&& (setfperflag == false) ) {secondperpend = true; } if (! ( (get<0>(actpoint) <= get<0>(finalcheckedvec[iter])) && (get<1>(actpoint) <= get<1>(finalcheckedvec[iter])) ) || (setfperflag == false && secondperpend == true) || mlast <= mnew) { okflag = false; break; } if ((iter+1 < finalcheckedvec.size()) && (firstperpend == true) && (setfperflag == true) && (get<0>(finalcheckedvec[iter+1]) != get<0>(finalcheckedvec[iter]))) { actpoint = finalcheckedvec[iter]; mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); mlast = mnew + 1; setfperflag = false; } else { actpoint = finalcheckedvec[iter]; if ( (iter+1 < finalcheckedvec.size() ) && (get<0>(finalcheckedvec[iter+1]) != get<0>(actpoint))&& (firstmflag == false) ) { mlast = mnew; mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); } else { /* mlast ist the first m value */ mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); firstmflag = false; } } break;} case 2:{ if (! ((get<0>(actpoint) <= get<0>(finalcheckedvec[iter])) && (get<1>(actpoint) >= get<1>(finalcheckedvec[iter])) ) || mlast <= mnew ) { okflag = false; break; } if ( (iter+1 < finalcheckedvec.size() ) && (get<0>(finalcheckedvec[iter+1]) != get<0>(actpoint)) && (firstmflag == true) ) { actpoint = finalcheckedvec[iter]; mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); firstmflag = false; } else { actpoint = finalcheckedvec[iter]; mlast = mnew; mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); } break;} case 3:{ if (get<0>(actpoint) == get<0>(finalcheckedvec[iter])&& (setfperflag == false) ) { secondperpend = true; } if (! ( (get<0>(actpoint) >= get<0>(finalcheckedvec[iter])) && (get<1>(actpoint) >= get<1>(finalcheckedvec[iter])) ) || (setfperflag == false && secondperpend == true) || mlast <= mnew) { okflag = false; break; } if ((iter+1 < finalcheckedvec.size() ) && (firstperpend == true) && (setfperflag == true) && (get<0>(finalcheckedvec[iter+1]) != get<0>(finalcheckedvec[iter]))) { actpoint = finalcheckedvec[iter]; mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); mlast = mnew + 1; setfperflag = false; } else { actpoint = finalcheckedvec[iter]; if ((iter+1 < finalcheckedvec.size()) && (get<0>(finalcheckedvec[iter+1]) != get<0>(actpoint)) && (firstmflag == false) ) { mlast = mnew; mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); } else { /* mlast ist the first m value */ if (get<0>(finalcheckedvec[iter+1]) != get<0>(actpoint)) { mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); } firstmflag = false; } } break;} case 4: { if (! ((get<0>(actpoint) >= get<0>(finalcheckedvec[iter])) && (get<1>(actpoint) <= get<1>(finalcheckedvec[iter])) ) || mlast <= mnew ) { okflag = false; break; } if ( (iter+1 < finalcheckedvec.size() ) && (get<0>(finalcheckedvec[iter+1]) != get<0>(actpoint)) && (firstmflag == true) ) { actpoint = finalcheckedvec[iter]; mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); firstmflag = false; } else if (iter+1 < finalcheckedvec.size()) { actpoint = finalcheckedvec[iter]; mlast = mnew; mnew = (get<1>(finalcheckedvec[iter+1] ) - get<1>(actpoint)) / (get<0>(finalcheckedvec[iter+1]) - get<0>(actpoint)); } break;} } /* end of switch */ if (okflag == false) break; iter++; } /* end of while */ finalcheckedvec.pop_back(); src = finalcheckedvec; if (okflag == true) return 1; else return 0;; } /* the end of checkme */ /* 4.1 Compare and HasValue */ int Convex::Compare(const Convex& arg) const { if(!IsDefined()){ return arg.IsDefined()?-1:0; } if(!arg.IsDefined()){ return 1; } if(size != arg.size){ return size < arg.size ? -1 : 1; } for(size_t i=0;i arg.value[i].GetY()) return 1; if(value[i].GetX() == arg.value[i].GetX() && (value[i].GetY() < arg.value[i].GetY())) return -1; } return 0; } size_t Convex::HashValue() const { if(!IsDefined() ) return 0; if(value==nullptr) return 42; unsigned int step = size / 2; if(step<1) step = 1; size_t pos = 0; size_t res = 0; while(pos < size){ res = res + value[pos].HashValue(); pos += step; } return res; } /* 5.1 In functions */ Word Convex::In(const ListExpr typeInfo, const ListExpr le1, const int errorPos, ListExpr& errorInfo, bool& correct) { ListExpr le = le1; ListExpr f, fxpoi, fypoi; std::vector> tmpo; int checkokflag; string lexprstr; Word res = SetWord(Address(0)); if(listutils::isSymbolUndefined(le)){ Convex* co = new Convex(false); co->SetDefined(false); res.addr = co; correct = true; return res; } if(nl->ListLength(le) <= 2){ Convex* co = new Convex(false); correct = true; co->SetDefined(false); res.addr = co; return res; } while(!nl->IsEmpty(le)){ f = nl->First(le); le = nl->Rest(le); if(nl->ListLength(f) != 2) { correct = true; nl->WriteToString(lexprstr, f); Convex* co = new Convex(false); co->SetDefined(false); res.addr = co; return res; } fxpoi = nl->First(f); fypoi = nl->Second(f); if ( ( nl->IsAtom(fxpoi) && nl->IsAtom(fypoi)) == false) { Convex* co = new Convex(false); correct = true; co->SetDefined(false); res.addr = co; return res; } if ( ( (nl->IsAtom(fxpoi) && nl->IsAtom(fypoi)) && ( (nl->AtomType(fxpoi) == RealType) && (nl->AtomType(fypoi) == RealType) ) == false)) { Convex* co = new Convex(false); correct = true; co->SetDefined(false); res.addr = co; return res; } /* contructing the vektor of tuples */ tmpo.push_back(std::make_tuple(nl->RealValue(fxpoi), nl->RealValue(fypoi))); } /* end of while */ /* CHECKME Call */ checkokflag = checkme(tmpo, true); if (checkokflag == 0) { ErrorReporter::ReportError( "1The coordinates do not form a convex polygon"); correct = false; return res; } else { Convex* r = new Convex(tmpo); res.addr = r; correct = true; //voroVec.push_back(r); return res; } } /* 5.1 Out function */ ListExpr Convex::Out(const ListExpr typeInfo, Word value) { Convex* is = (Convex*) value.addr; if(!is->IsDefined()){ return listutils::getUndefined(); } if(is->size == 0){ return nl->TheEmptyList(); } ListExpr res = nl->OneElemList( nl->TwoElemList( nl->RealAtom(is->value[0].GetX()), nl->RealAtom(is->value[0].GetY()))); ListExpr last = res; for(unsigned int i=1;isize;i++){ last = nl->Append( last, nl->TwoElemList ( nl->RealAtom(is->value[i].GetX()), nl->RealAtom(is->value[i].GetY()) ) ); } last = nl->Append(last, nl->OneElemList(nl->RealAtom(is->getCellId()))); return res; } /* 6.1 Open and save function */ bool Convex::Open( SmiRecord& valueRecord, size_t& offset, const ListExpr typeInfo, Word& value){ bool def; if(!valueRecord.Read(&def, sizeof(bool), offset)){ return false; } offset += sizeof(bool); if(!def){ value.addr = new Convex(false); return true; } size_t size; if(!valueRecord.Read(&size, sizeof(size_t), offset)){ return false; } offset+=sizeof(size_t); if(size==0){ value.addr = new Convex(0,0,0); return true; } Point* v = new Point[size]; if(!valueRecord.Read(v,size*sizeof(Point),offset)){ return false; } for(size_t i=0;iIsDefined(); if(!valueRecord.Write(&def, sizeof(bool), offset)){ return false; } offset += sizeof(bool); if(!def){ return true; } size_t size = is->size; if(!valueRecord.Write(&size, sizeof(size_t), offset)){ return false; } offset += sizeof(size_t); if(is->size>0){ if(!valueRecord.Write(is->value, sizeof(Point) * is->size, offset)){ return false; } offset += sizeof(int) * is->size; } return true; } void Convex::Rebuild(char* buffer, size_t sz) { if(value!=nullptr){ delete[] value; value = nullptr; } size = 0; bool def; size_t offset = 0; memcpy(&def,buffer + offset, sizeof(bool)); offset += sizeof(bool); if(!def){ SetDefined(false); return; } SetDefined(true); memcpy(&size, buffer+offset, sizeof(size_t)); offset += sizeof(size_t); if(size > 0){ value = new Point[size]; memcpy((char*)value, buffer+offset, size * sizeof(Point)); offset += size * sizeof(Point); } for(size_t i=0;i0) os << ", "; os << value[i]; } os << "}"; return os; } /* 8 Operator Definitions */ /* 8.1 TypeMapping Definitions */ /* 8.1.1 createconvextypemap */ ListExpr createconvextypemap( ListExpr args) { if(!nl->HasLength(args,2)) { return listutils::typeError("two arguments expected"); } ListExpr arg1 = nl->First(args); ListExpr arg2 = nl->Second(args); if(!Stream::checkType(arg1)) { return listutils::typeError("first argument must be a stream of points"); } if(!CcBool::checkType(arg2)) { return listutils::typeError("second argument must be a Bool Value"); } return nl->SymbolAtom(Convex::BasicType()); } /* 8.1.2 voronoitypemap */ ListExpr voronoitypemap ( ListExpr args) { ListExpr extendconv, stream, namenewattr, attrtype; ListExpr second, third, secondname, thirdname; string secondnamestr, thirdnamestr; int posit1, posit2; if(nl->ListLength(args)!=5){ ErrorReporter::ReportError("five args expected"); return nl->TypeError(); } if(nl->AtomType(nl->Second(args))!=SymbolType){ return listutils::typeError("second arg does not represent a valid " "attribute name"); } if(nl->AtomType(nl->Third(args))!=SymbolType){ return listutils::typeError("third arg does not represent a valid " "attribute name"); } if(!Rectangle<2>::checkType(nl->Fourth(args))){ return listutils::typeError("fourth arg is not a rectangle"); } if(!CcBool::checkType(nl->Fifth(args))){ return listutils::typeError("fifth arg is not a Bool value"); } second = nl->Second(args); third = nl->Third(args); if ((nl->ListLength(second) != -1 ) || (nl->ListLength(third) != -1) ) { ErrorReporter::ReportError("two attribute name arguments expected"); return nl->TypeError(); } if(!IsStreamDescription(nl->First(args))){ ErrorReporter::ReportError("first argument is not a tuple stream"); return nl->TypeError(); } stream = nl->First(args); namenewattr = nl->Third(args); /* copy attrlist to newattrlist */ ListExpr attrList = nl->Second(nl->Second(stream)); ListExpr newAttrList = nl->OneElemList(nl->First(attrList)); ListExpr lastlistn = newAttrList; attrList = nl->Rest(attrList); while (!(nl->IsEmpty(attrList))) { lastlistn = nl->Append(lastlistn,nl->First(attrList)); attrList = nl->Rest(attrList); } /* reset attrList */ attrList = nl->Second(nl->Second(stream)); secondname = second; secondnamestr = nl->SymbolValue(secondname); thirdname = third; thirdnamestr = nl->SymbolValue(thirdname); posit1 = FindAttribute(attrList,secondnamestr,attrtype); if(posit1==0){ ErrorReporter::ReportError("Attribute "+ secondnamestr + " must be a member of the tuple"); return nl->TypeError(); } posit2 = FindAttribute(attrList,thirdnamestr,attrtype); if(posit2!=0){ ErrorReporter::ReportError("Attribute "+ thirdnamestr + " is already a member of the tuple"); return nl->TypeError(); } extendconv = nl->SymbolAtom(Convex::BasicType()); lastlistn = nl->Append(lastlistn, (nl->TwoElemList(namenewattr, extendconv))); return nl->ThreeElemList( nl->SymbolAtom(Symbol::APPEND()), nl->OneElemList(nl->IntAtom(posit1)), nl->TwoElemList(nl->SymbolAtom(Symbol::STREAM()), nl->TwoElemList(nl->SymbolAtom(Tuple::BasicType()), newAttrList))); } /* 8.1.3 cellNumber Typemapping */ ListExpr cellnumvoronoitypemap ( ListExpr args) { if(nl->HasLength(args, 3)) { ListExpr first = nl->First(args); ListExpr second = nl->Second(args); ListExpr third = nl->Third(args); if(Stream::checkType(first) && CcInt::checkType(third) && Rectangle<2>::checkType(second)) { return nl->SymbolAtom(collection::IntSet::BasicType()); } } const std::string errMsg = "The following three arguments are expected:" " Stream x rect x int"; return listutils::typeError(errMsg); } /* 8.1.4 smallest common cellnumber typemapping */ ListExpr sccvoronoitypemap (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(Stream::checkType(first) && Rectangle<2>::checkType(second) && Rectangle<2>::checkType(third) && CcInt::checkType(fourth)) { return nl->SymbolAtom(CcBool::BasicType()); } } const std::string errMsg = "The following four arguments are expected:" " Stream x rect x rect x int"; return listutils::typeError(errMsg); } /* 8.1.5 getcell typemapping */ ListExpr getcellvoronoitypemap ( ListExpr args) { if(nl->HasLength(args, 2)) { ListExpr first = nl->First(args); ListExpr second = nl->Second(args); if(Stream::checkType(first) && CcInt::checkType(second)) { return nl->SymbolAtom(Rectangle<2>::BasicType()); } } const std::string errMsg = "The following two arguments are expected:" " Stream x int"; return listutils::typeError(errMsg); } /* 8.1.6 voronoi3dtypemap */ ListExpr voronoi3dtypemap( ListExpr args ) { if(nl->HasLength(args, 2)) { ListExpr first = nl->First(args); ListExpr second = nl->Second(args); if (Stream>::checkType(first) && Rectangle<3>::checkType(second)) { return nl->SymbolAtom(Convex3D::BasicType()); } } const string errMsg = "The following two arguments are expected:" " stream(rect3) x rect3"; return listutils::typeError(errMsg); } /* 8.1.7 cellnum 3d typemapping */ ListExpr cellnumvoronoi3dtypemap ( ListExpr args) { if(nl->HasLength(args, 3)) { ListExpr first = nl->First(args); ListExpr second = nl->Second(args); ListExpr third = nl->Third(args); if (Convex3D::checkType(first) && CcInt::checkType(third) && Rectangle<3>::checkType(second)) { return nl->SymbolAtom(collection::IntSet::BasicType()); } } const std::string errMsg = "The following two arguments are expected:" " Convex3D x rect3 x int"; return listutils::typeError(errMsg); } int voronoi3DCreateSelect( ListExpr args ) { ListExpr first = nl->First(args); ListExpr second = nl->Second(args); if (Stream>::checkType(first) && Rectangle<3>::checkType(second)) { return 0; } return -1; } /* 8.1.8 smallest common cellnumber typemapping */ ListExpr sccvoronoi3dtypemap (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(Convex3D::checkType(first) && Rectangle<3>::checkType(second) && Rectangle<3>::checkType(third) && CcInt::checkType(fourth)) { return nl->SymbolAtom(CcBool::BasicType()); } } const std::string errMsg = "The following two arguments are expected:" " Convex3D x rect3 x rect3 x int"; return listutils::typeError(errMsg); } /* 8.1.9 getcell 3d typemapping */ ListExpr getcellvoronoi3dtypemap ( ListExpr args) { if(nl->HasLength(args, 2)) { ListExpr first = nl->First(args); ListExpr second = nl->Second(args); if(Convex3D::checkType(first) && CcInt::checkType(second)) { return nl->SymbolAtom(Rectangle<3>::BasicType()); } } const std::string errMsg = "The following two arguments are expected:" " Convex3D x int"; return listutils::typeError(errMsg); } /* 8.2 ValueMapping Definitions */ /* 8.2.1 cellNumVM */ int cellNumVM( Word* args, Word& result, int message, Word& local, Supplier s ) { if(voroVec.size() == 0) { Stream input_convex(args[0]); input_convex.open(); Convex* next = input_convex.request(); while(next != 0){ voroVec.push_back(*next); // free memory delete next; next = input_convex.request(); } input_convex.close(); } Rectangle<2> *search_window_ptr = static_cast*>( args[1].addr ); /* mode == 1 => precise allocation; mode == 2 => use Bboxes of convex cells In case the user did not specify the mode of allocation, use Bboxes */ int mode = ((CcInt*)args[2].addr)->GetIntval(); std::set cell_ids; int bbox = 2; int precise = 1; result = qp->ResultStorage(s); collection::IntSet* res = (collection::IntSet*) result.addr; if(search_window_ptr == nullptr) { return 1; } if(mode > bbox || mode < precise) { mode = bbox; } cellNum(search_window_ptr, mode, &cell_ids); res->setTo(cell_ids); if(voroVec.size() > 0) { voroVec.clear(); } return 0; } /* 8.2.2 smallestCommonCellnumVM */ int smallestCommonCellnumVM( Word* args, Word& result, int message, Word& local, Supplier s ) { Stream input_convex(args[0]); input_convex.open(); Convex* next = input_convex.request(); while(next != 0){ voroVec.push_back(*next); delete next; next = input_convex.request(); } input_convex.close(); Rectangle<2> *search_window_ptr = static_cast*>( args[1].addr ); Rectangle<2> *search_window_ptr_2 = static_cast*>( args[2].addr ); CcInt* cellno_ptr = static_cast(args[3].addr); int cellno = cellno_ptr->GetIntval(); if(search_window_ptr == nullptr || search_window_ptr_2 == nullptr) { return -1; } result = qp->ResultStorage( s ); CcBool *res = (CcBool*) result.addr; bool boolval = false; std::set intsetRect1; std::set intsetRect2; cellNum(search_window_ptr, 1, &intsetRect1); if (intsetRect1.find(cellno) != intsetRect1.end()) { cellNum(search_window_ptr_2, 1, &intsetRect2); std::vector v(sizeof(intsetRect1)+ sizeof(intsetRect2)); std::vector::iterator it; it=std::set_intersection (intsetRect1.begin(), intsetRect1.end(), intsetRect2.begin(), intsetRect2.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; } if(v.size() > 0) { v.clear(); } } if(intsetRect1.size() > 0) { intsetRect1.clear(); } if(intsetRect2.size() > 0) { intsetRect2.clear(); } if(voroVec.size() > 0) { voroVec.clear(); } res->Set( true, boolval); return 0; } /* 8.2.3 getCellVM */ int getcellvoronoiVM(Word* args, Word& result, int message, Word& local, Supplier s) { Stream input_convex(args[0]); input_convex.open(); Convex* next = input_convex.request(); while(next != 0){ voroVec.push_back(*next); delete next; next = input_convex.request(); } input_convex.close(); CcInt* cellno_ptr = static_cast(args[1].addr); int cellno = cellno_ptr->GetIntval(); if (voroVec.size() > 0 ) { result = qp->ResultStorage( s ); Rectangle<2> *res = (Rectangle<2>*) result.addr; for(size_t i = 0; i < voroVec.size(); i++) { if(voroVec[i].getCellId() == cellno) { double min[2], max[2]; Rectangle<2> bbox = createBBox(&voroVec[i]); min[0] = bbox.getMinX(); min[1] = bbox.getMinY(); max[0] = bbox.getMaxX(); max[1] = bbox.getMaxY(); res->Set(true, min, max); return 0; } } } return -1; } /* 8.2.4 createconvexVM */ int createconvexVM (Word* args, Word& result, int message, Word& local, Supplier s) { qp->DeleteResultStorage(s); qp->ReInitResultStorage(s); result = qp->ResultStorage(s); Stream stream(args[0]); Convex* res = static_cast(result.addr); Point* elem; vector points; std::vector> temp; int checkgood; CcBool* checkonp = ((CcBool*)args[1].addr); if (!checkonp->IsDefined()) { res->SetDefined(false); return 0; } bool checkon = checkonp->GetBoolval(); stream.open(); while ( (elem = stream.request() ) ){ if (!elem->IsDefined()) { res->SetDefined(false); return 0; } /* contructing the vektor of tuples */ temp.push_back(std::make_tuple(elem->GetX(), elem->GetY())); } if (checkon == true) { checkgood = checkme(temp, true); } else { checkgood = checkme(temp, false); } if ((checkgood == 1) || (checkgood == 2)) { res -> setTo(temp, -1);; stream.close(); return 0; } else { stream.close(); return 0; } } /* 8.2.3 voronoiVM */ struct voronoiInfo { map, std::vector> > center2vorpoi; TupleBuffer *rel; GenericRelationIterator *reliter; int attrcount; int pointposition; bool checkon; int cellId; }; int voronoiVM (Word* args, Word& result, int message, Word& local, Supplier s) { Word tee; Tuple* tup; voronoiInfo* localInfo = (voronoiInfo*) qp->GetLocal2(s).addr; std::vector voropoints; voronoi_diagram vorodiag; double xval, yval; switch (message) { /* voronoiVM-open */ case OPEN: { localInfo = new voronoiInfo; qp->GetLocal2(s).addr = localInfo; ListExpr resultType = GetTupleResultType(s); TupleType *tupleType = new TupleType(nl->Second(resultType)); local.addr = tupleType; ListExpr attrsave = qp->GetType(qp->GetSon(s,0)); ListExpr attrsave2 = nl->Second(nl->Second(attrsave)); int counter = 0; int counttup = 0; localInfo->reliter = 0; int pointpos = ((CcInt*)args[5].addr)->GetIntval(); Rectangle<2>* rectme = (Rectangle<2>*) args[3].addr; double belowleftx,belowlefty, belowrightx, belowrighty, aboveleftx, abovelefty, aboverightx, aboverighty, miny, minx, maxx, maxy; double scale = 50; double stretchx = 0; double stretchy = 0; double diaglenght; double testpointstretch; bool scalereset = false; std::tuple center; std::tuple testcenter; std::vector> voropoi; std::vector> allpoints; std::vector> infedgecenter; std::vector> voropoitemp; std::vector> infedgepoints; std::vector> normaledgepoints; map, std::tuple> infcenter2firstinfedgepoi; map, std::tuple> infcenter2secondinfedgepoi; map, std::vector> > infedgepoi2lineparam; map, std::vector> > infcenter2neighborcenters; map, std::vector>> normaledgepoints2normalcenters; map, std::vector> > infedgepoints2centers; std::tuple aboveleft, aboveright, belowleft, belowright; std::tuple testpoint1, testpoint2; std::tuple newpoint1, newpoint2; map, std::vector>>:: iterator iterone = normaledgepoints2normalcenters.begin(); map, std::vector>>:: iterator itedge = infedgepoints2centers.begin(); map, std::vector>>:: iterator itlineparam = infedgepoi2lineparam.begin(); /* storing pointpos in localInfo */ localInfo->pointposition = pointpos; if (!((CcBool*)args[4].addr)->IsDefined()) { localInfo->checkon = true; } else { /* storing bool in localInfo */ localInfo->checkon = ((CcBool*)args[4].addr)->GetBoolval(); } while (!(nl->IsEmpty(attrsave2))) { attrsave2 = nl->Rest(attrsave2); /* counting the attributes */ counter++; } /* Init localInfo */ localInfo->attrcount = counter; qp->Open(args[0].addr); qp->Request(args[0].addr, tee); if(qp->Received(args[0].addr)) { localInfo->rel = new TupleBuffer( ); } else { localInfo->rel = 0; } while(qp->Received(args[0].addr)) { /* storing tuples in localInfo */ Tuple *tup2 = (Tuple*)tee.addr; localInfo->rel->AppendTuple( tup2 ); counttup++; /* Setting up the VoroPoint vector */ Point* pointval = static_cast(tup2->GetAttribute(pointpos-1)); if(pointval->IsDefined()) { xval = pointval->GetX(); yval = pointval->GetY(); voropoints.push_back(VoronoiPoint(xval, yval)); allpoints.push_back(std::make_tuple(xval, yval)); } tup2->DeleteIfAllowed(); qp->Request(args[0].addr, tee); } if( localInfo->rel) { localInfo->reliter = localInfo->rel->MakeScan(); } else { localInfo->reliter = 0; } /* constructing the voronoi diagramm using the boost library */ construct_voronoi(voropoints.begin(), voropoints.end(), &vorodiag); int contzell = 0; unsigned int cell_index = 0; for (voronoi_diagram::const_cell_iterator it = vorodiag.cells().begin(); it != vorodiag.cells().end(); ++it) { contzell++; if (it->contains_point()) { if (it->source_category() == boost::polygon::SOURCE_CATEGORY_SINGLE_POINT) { std::size_t index = it->source_index(); VoronoiPoint p = voropoints[index]; center = std::make_tuple(x(p), y(p)); voropoitemp.push_back ( std::make_tuple(x(p), y(p))); const voronoi_diagram::cell_type& cell = *it; const voronoi_diagram::edge_type* edge = cell.incident_edge(); /* iterate edges around voronoi cell */ do { if (true) { if( (edge->vertex0() != NULL) && (edge->vertex1() != NULL)) { std::tuple edgepoitemp1 = std::make_tuple((edge->vertex0())->x(), (edge->vertex0())->y()); std::tuple edgepoitemp2 = std::make_tuple((edge->vertex1())->x(), (edge->vertex1())->y()); voropoi.push_back(edgepoitemp1); voropoi.push_back(edgepoitemp2); allpoints.push_back(edgepoitemp1); allpoints.push_back(edgepoitemp2); std::tuple edgecentertemp = std::make_tuple(x(p), y(p)); std::vector> vectemp; vectemp.push_back (edgecentertemp); normaledgepoints.push_back(edgepoitemp1); normaledgepoints.push_back(edgepoitemp2); iterone = normaledgepoints2normalcenters.find(edgepoitemp1); /* edgepoint not set yet */ if (iterone == normaledgepoints2normalcenters.end()) { normaledgepoints2normalcenters.insert (pair, std::vector>> (edgepoitemp1, vectemp)); } /* edgepoint entry exists already */ else { normaledgepoints2normalcenters.at(edgepoitemp1).push_back( edgecentertemp); rmvredundpoints(normaledgepoints2normalcenters.at(edgepoitemp1)); } iterone = normaledgepoints2normalcenters.find(edgepoitemp2); /* edgepoint not set yet */ if (iterone == normaledgepoints2normalcenters.end()) { normaledgepoints2normalcenters.insert (pair, std::vector>> (edgepoitemp2, vectemp)); } /* edgepoint entry exists already */ else { normaledgepoints2normalcenters.at(edgepoitemp2).push_back (edgecentertemp); rmvredundpoints(normaledgepoints2normalcenters.at(edgepoitemp2)); } } if ( (edge->vertex0() != NULL) && (edge->vertex1() == NULL)) { std::tuple edgepoitemp4 = std::make_tuple((edge->vertex0())->x(), (edge->vertex0())->y()); std::vector> vectemp3; std::tuple twincenter; allpoints.push_back(edgepoitemp4); infedgecenter.push_back(center); infedgepoints.push_back(edgepoitemp4); voropoi.push_back(edgepoitemp4); if ( ((edge->twin())->cell())->contains_point()) { if (((edge->twin())->cell())->source_category() == boost::polygon::SOURCE_CATEGORY_SINGLE_POINT) { std::size_t index = ((edge->twin())->cell())->source_index(); VoronoiPoint q = voropoints[index]; twincenter = std::make_tuple(x(q), y(q)); } } itedge = infedgepoints2centers.find(edgepoitemp4); /* edgepoint not set yet */ if (itedge == infedgepoints2centers.end()) { vectemp3.push_back(center); vectemp3.push_back(twincenter); infedgepoints2centers.insert (pair, std::vector>> (edgepoitemp4, vectemp3)); } /* edgepoint entry exists already */ else { infedgepoints2centers.at(edgepoitemp4).push_back(center); infedgepoints2centers.at(edgepoitemp4).push_back(twincenter); } } if( (edge->vertex1() != NULL) && (edge->vertex0() == NULL)) { allpoints.push_back( std::make_tuple((edge->vertex1())->x(), (edge->vertex1())->y())); infedgecenter.push_back(std::make_tuple(x(p), y(p))); infedgepoints.push_back( std::make_tuple((edge->vertex1())->x(), (edge->vertex1())->y())); voropoi.push_back(std::make_tuple((edge->vertex1())->x(), (edge->vertex1())->y())); } } edge = edge->next(); } while (edge != cell.incident_edge()); } ++cell_index; } rmvredundpoints(voropoi); localInfo->center2vorpoi.insert (pair, std::vector>> (center, voropoi)); voropoi.clear(); /* cleared for the next cell */ } /* setting up border handling of the voronoi cells */ /* remove redundant points */ rmvredundpoints(allpoints); rmvredundpoints(infedgecenter); rmvredundpoints(infedgepoints); /* compute minx, maxx, miny and maxy from allpoints */ sort(allpoints.begin(), allpoints.end(), sortyupxup); miny = get<1>(allpoints[0]); maxy = get<1>(allpoints[allpoints.size()-1]); sort(allpoints.begin(), allpoints.end(), sortxupyup); minx = get<0>(allpoints[0]); maxx = get<0>(allpoints[allpoints.size()-1]); /* Voronoi Border handling */ /* testing if box is fitting and rectangle value defined */ if ( (rectme->IsDefined()) && ( (rectme->MinD(0) < minx) && (rectme->MaxD(0) > maxx) && (rectme->MinD(1) < miny) && (rectme->MaxD(1) > maxy) ) ) { /* receiving box points from rectangle */ belowleftx = rectme->MinD(0); belowlefty = rectme->MinD(1); belowrightx = rectme->MaxD(0); belowrighty = rectme->MinD(1); aboveleftx = rectme->MinD(0); abovelefty = rectme->MaxD(1); aboverightx = rectme->MaxD(0); aboverighty = rectme->MaxD(1); } /* use the dafault box if box is not fitting or if rectangle value is undefined */ else { stretchx = (abs(maxx - minx)) / 4; stretchy = (abs(maxy - miny)) / 4; belowleftx = minx - stretchx; belowlefty = miny - stretchy; belowrightx = maxx + stretchx; belowrighty = miny - stretchy; aboveleftx = minx - stretchx; abovelefty = maxy + stretchy; aboverightx = maxx + stretchx; aboverighty = maxy + stretchy; } /* construct box points */ aboveleft = std::make_tuple(aboveleftx, abovelefty); aboveright = std::make_tuple(aboverightx, aboverighty); belowright = std::make_tuple(belowrightx, belowrighty); belowleft = std::make_tuple(belowleftx, belowlefty); diaglenght = sqrt (pow (get<0>(belowleft) - get<0>(aboveright), 2) + pow (get<1>(belowleft) - get<1>(aboveright), 2)); /* constructing a point and the corresponding straight line equation for infinite edges */ for (unsigned int i = 0; i < infedgepoints.size(); i++) { itedge = infedgepoints2centers.find(infedgepoints[i]); if (itedge != infedgepoints2centers.end()) { std::vector> pairvec = infedgepoints2centers.at(infedgepoints[i]); if ((pairvec.size() % 2) == 0) { for (unsigned int j = 0; j < pairvec.size(); j=j+2) { std::tuple infovec5 = pairvec[j]; std::tuple infovec6 = pairvec[j+1]; double xfirst = get<0>(infovec5); double xsecond = get<0>(infovec6); double yfirst = get<1>(infovec5); double ysecond = get<1>(infovec6); /* The result point lies on the corresponding straight line equation of the infinite edge */ double resultx = (xfirst + xsecond) / 2; double resulty = (yfirst + ysecond) / 2; if ( !(xfirst == xsecond) && !(AlmostEqual(xfirst, xsecond)) && !(yfirst == ysecond) && !(AlmostEqual(yfirst, ysecond)) ) { /* m and b are the straight line equation parameters for the line that goes through the 2 center points. We only need the gradient m here. */ double m = (ysecond - yfirst) / (xsecond - xfirst); /* mm and bb are the straight line equation parameters for the line that goes through the infinte edge between the 2 centers The two straight lines are always perpendicular to each other, so you can determine mm from m. */ double mm = - 1/m; double bb = resulty - (mm * resultx); std::vector> paramvec; std::tuple param = std::make_tuple(mm ,bb); itlineparam = infedgepoi2lineparam.find(infedgepoints[i]); /* edgepointto param not set */ if (itlineparam == infedgepoi2lineparam.end()) { paramvec.push_back(param); infedgepoi2lineparam.insert (pair, std::vector>> (infedgepoints[i], paramvec)); } /* edgepoint entry exists already */ else { infedgepoi2lineparam.at(infedgepoints[i]).push_back(param); } } /* the 2 centers form a straight line with gradient 0 */ else if ( (yfirst == ysecond) || (AlmostEqual(yfirst, ysecond)) ) { double dummy = std::numeric_limits::infinity(); std::tuple dummytup = std::make_tuple(dummy ,dummy); std::vector> paramvec2; /* just pushing an infinty value for identification purposes */ itlineparam = infedgepoi2lineparam.find(infedgepoints[i]); /* edgepointto param not set */ if (itlineparam == infedgepoi2lineparam.end()) { paramvec2.push_back(dummytup); infedgepoi2lineparam.insert (pair, std::vector>> (infedgepoints[i], paramvec2)); } /* edgepoint entry exists already */ else { infedgepoi2lineparam.at(infedgepoints[i]).push_back(dummytup); } } else { /* the two centers are perpendicular */ double mmm = 0; double bbb = resulty - (mmm * resultx); std::vector> paramvec3; std::tuple para = std::make_tuple(mmm ,bbb); itlineparam = infedgepoi2lineparam.find(infedgepoints[i]); /* edgepointto param not set */ if (itlineparam == infedgepoi2lineparam.end()) { paramvec3.push_back(para); infedgepoi2lineparam.insert (pair, std::vector>> (infedgepoints[i], paramvec3)); } /* edgepoint entry exists already */ else { infedgepoi2lineparam.at(infedgepoints[i]).push_back(para); } } } /* end of second for */ } /* nothing has to be done here */ } /* no entry found, should not happen */ } /* end of first for */ /* Calculating points on the border lines and the correpondending cells */ for (unsigned int i = 0; i < infedgepoints.size(); i++) { itlineparam = infedgepoi2lineparam.find(infedgepoints[i]); if (itlineparam != infedgepoi2lineparam.end()) { std::vector> paramvector = infedgepoi2lineparam.at(infedgepoints[i]); for (unsigned int j = 0; j < paramvector.size(); j++) { std::tuple lineinfo = paramvector[j]; double m = get<0>(lineinfo); double t = get<1>(lineinfo); std::vector> vec = infedgepoints2centers.at(infedgepoints[i]); /* get center coords */ std::tuple center1 = vec[2*j]; std::tuple center2 = vec[(2*j) + 1]; double xfirst = get<0>(center1); double xsecond = get<0>(center2); double yfirst = get<1>(center1); double ysecond = get<1>(center2); double resultx = (xfirst + xsecond) / 2; double resulty = (yfirst + ysecond) / 2; std::tuple testp1 = std::make_tuple(resultx, resulty); std::tuple testp2 = infedgepoints[i]; std::tuple testpfinal = std::make_tuple ((resultx + get<0>(testp2)) / 2, (resulty + get<1>(testp2)) / 2); /* normaledgepoints2normalcenters output */ iterone = normaledgepoints2normalcenters.find(infedgepoints[i]); if (iterone != normaledgepoints2normalcenters.end()) { std::vector> centerinfovec = normaledgepoints2normalcenters.at(infedgepoints[i]); for (unsigned int j = 0; j < centerinfovec.size(); j++) { if ((centerinfovec[j] != center1) && (centerinfovec[j] != center2)) { std::tuple testc = centerinfovec[j]; testcenter = testc; } } } bool cond1 = ( ((get<0>(testcenter) >= get<0>(testp1)) && (get<0>(testcenter) <= get<0>(testpfinal)) && (get<0>(testp1) <= get<0>(testpfinal))) || ((get<0>(testcenter) <= get<0>(testp1)) && (get<0>(testcenter) >= get<0>(testpfinal)) && (get<0>(testp1) >= get<0>(testpfinal))) || ((get<1>(testcenter) >= get<1>(testp1)) && (get<1>(testcenter) <= get<1>(testpfinal)) && (get<1>(testp1) <= get<1>(testpfinal))) || ((get<1>(testcenter) <= get<1>(testp1)) && (get<1>(testcenter) >= get<1>(testpfinal)) && (get<1>(testp1) >= get<1>(testpfinal))) ); /* change testpfinal if necessary */ if (cond1 == true) { testpfinal = testp1; scale = 200; scalereset = true; } if ( ((cond1 != true) && (get<0>(testcenter) > get<0>(testp1)) && (get<1>(testcenter) > get<1>(testp1))) || ((cond1 != true) && (get<0>(testcenter) < get<0>(testp1)) && (get<1>(testcenter) < get<1>(testp1))) ) { testpfinal = testp1; scale = 30; scalereset = true; } testpointstretch = diaglenght/scale; if (scalereset == true) scale = 50; if (isinf(m) && isinf(t)) { testpoint1 = std::make_tuple(get<0>( testpfinal), get<1>( testpfinal) + testpointstretch); testpoint2 = std::make_tuple(get<0>( testpfinal), get<1>( testpfinal) - testpointstretch); } else if (m==0) { testpoint1 = std::make_tuple(get<0>( testpfinal) + testpointstretch, get<1>( testpfinal)); testpoint2 = std::make_tuple(get<0>( testpfinal) - testpointstretch, get<1>( testpfinal)); } else { testpoint1 = std::make_tuple(get<0>( testpfinal) + testpointstretch, m * (get<0>( testpfinal) + testpointstretch) + t); testpoint2 = std::make_tuple(get<0>( testpfinal) - testpointstretch, m * (get<0>( testpfinal) - testpointstretch) + t); } /* Euklidien distance to testcenter */ double distinfedgpoitotestcenter = sqrt (pow (get<0>(testpfinal) - get<0>(testcenter), 2) + pow (get<1>(testpfinal) - get<1>(testcenter), 2)); double distinfedgpoitotestpoint1 = sqrt (pow (get<0>(testpoint1) - get<0>(testcenter), 2) + pow (get<1>(testpoint1) - get<1>(testcenter), 2)); double distinfedgpoitotestpoint2 = sqrt (pow (get<0>(testpoint2) - get<0>(testcenter), 2) + pow (get<1>(testpoint2) - get<1>(testcenter), 2)); /* looking for points added to center voropoints */ if ( (distinfedgpoitotestpoint1 > distinfedgpoitotestcenter) && ( (distinfedgpoitotestpoint2 <= distinfedgpoitotestcenter) || (distinfedgpoitotestpoint1 > distinfedgpoitotestpoint2))) { if (isinf(m) && isinf(t)) { newpoint1 = std::make_tuple(get<0>(infedgepoints[i]), aboverighty); } else if (m==0) { newpoint1 = std::make_tuple(belowrightx, get<1>(infedgepoints[i])); } /* case m<0 */ else if (m<0) { std::tuple newpoint1cand1; std::tuple newpoint1cand2; double newxval = (belowrighty - t) / m; double newyval = (m * belowrightx) + t; newpoint1cand1 = std::make_tuple(belowrightx, newyval); newpoint1cand2 = std::make_tuple(newxval, belowrighty); if ( ((belowrightx == newxval) && (belowrighty == newyval)) || (AlmostEqual (belowrightx, newxval) && AlmostEqual (belowrighty, newyval)) ) { newpoint1 = std::make_tuple (belowrightx, belowrighty); } if ((newxval > belowrightx) && (newyval > belowrighty) && (newyval < aboverighty) ) { newpoint1 = newpoint1cand1; } else if ((newyval < belowrighty) && (newxval < belowrightx) && (newxval > belowleftx) ) { newpoint1 = newpoint1cand2; } } /* case m>0 */ else { std::tuple newpoint1cand1; std::tuple newpoint1cand2; double newxval = (aboverighty - t) / m; double newyval = (m * aboverightx) + t; newpoint1cand1 = std::make_tuple(aboverightx, newyval); newpoint1cand2 = std::make_tuple(newxval, aboverighty); if ( ((aboverightx == newxval) && (aboverighty == newyval)) || (AlmostEqual (aboverightx, newxval) && AlmostEqual (aboverighty, newyval)) ) { newpoint1 = std::make_tuple (aboverightx, aboverighty); } if ((newxval > aboverightx) && (newyval > belowrighty) && (newyval < aboverighty) ) { newpoint1 = newpoint1cand1; } else if ((newyval > aboverighty) && (newxval < belowrightx) && (newxval > belowleftx) ) { newpoint1 = newpoint1cand2; } } localInfo->center2vorpoi.at(center1).push_back (newpoint1); localInfo->center2vorpoi.at(center2).push_back (newpoint1); } /* case m=0 */ else if ( (distinfedgpoitotestpoint2 > distinfedgpoitotestcenter) && ( (distinfedgpoitotestpoint1 <= distinfedgpoitotestcenter) || (distinfedgpoitotestpoint2 > distinfedgpoitotestpoint1))) { if (isinf(m) && isinf(t)) { newpoint2 = std::make_tuple(get<0>(infedgepoints[i]), belowrighty); } else if (m==0) { newpoint2 = std::make_tuple(belowleftx, get<1>(infedgepoints[i])); } /* case m<0 */ else if (m<0) { std::tuple newpoint1cand1; std::tuple newpoint1cand2; double newxval = (abovelefty - t) / m; double newyval = (m * aboveleftx) + t; newpoint1cand1 = std::make_tuple(aboveleftx, newyval); newpoint1cand2 = std::make_tuple(newxval, abovelefty); if ( ((aboveleftx == newxval) && (abovelefty == newyval)) || (AlmostEqual (aboveleftx, newxval) && AlmostEqual (abovelefty, newyval)) ) { newpoint2 = std::make_tuple (aboveleftx, abovelefty); } if ((newxval < aboveleftx) && (newyval > belowlefty) && (newyval < abovelefty) ) { newpoint2 = newpoint1cand1; } else if ((newyval > abovelefty) && (newxval < belowrightx) && (newxval > belowleftx) ) { newpoint2 = newpoint1cand2; } } /* case m>0 */ else { std::tuple newpoint1cand1; std::tuple newpoint1cand2; double newxval = (belowlefty - t) / m; double newyval = (m * belowleftx) + t; newpoint1cand1 = std::make_tuple(belowleftx, newyval); newpoint1cand2 = std::make_tuple(newxval, belowlefty); if ( ((belowleftx == newxval) && (belowlefty == newyval)) || (AlmostEqual (belowleftx, newxval) && AlmostEqual (belowlefty, newyval)) ) { newpoint2 = std::make_tuple (belowleftx, belowlefty); } if ((newxval < belowleftx) && (newyval > belowlefty) && (newyval < abovelefty) ) { newpoint2 = newpoint1cand1; } else if ((newyval < belowlefty) && (newxval < belowrightx) && (newxval > belowleftx) ) { newpoint2 = newpoint1cand2; } } localInfo->center2vorpoi.at(center1).push_back (newpoint2); localInfo->center2vorpoi.at(center2).push_back (newpoint2); } /* nothing is done here */ } /* end of second for */ } /* end of first if */ } /* end of for */ /* distribute the 4 box edge points to the right voronoicells */ for (unsigned int i = 0; i < infedgecenter.size(); i++) { int countymaxvals = 0; int countyminvals = 0; int countxminvals = 0; int countxmaxvals = 0; std::vector> infovec = localInfo->center2vorpoi.at(infedgecenter[i]); /* counting the cases */ for (unsigned int j = 0; j < infovec.size(); j++) { if (get<0>(infovec[j]) == belowleftx) countxminvals++; if (get<0>(infovec[j]) == belowrightx) countxmaxvals++; if (get<1>(infovec[j]) == belowlefty) countyminvals++; if (get<1>(infovec[j]) == abovelefty) countymaxvals++; } /* distribute the new points */ if ((countxminvals == 1) && (countyminvals == 1)) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (belowleft); } else if ((countxminvals == 1) && (countymaxvals == 1)) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (aboveleft); } else if ((countxmaxvals == 1) && (countymaxvals == 1)) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (aboveright); } else if ((countxmaxvals == 1) && (countyminvals == 1)) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (belowright); } else if ((countyminvals == 1) && (countymaxvals == 1)) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (belowright); localInfo->center2vorpoi.at(infedgecenter[i]).push_back (aboveright); } /* special case */ else if ( (countyminvals == 1) && (countymaxvals == 1) && (get<0>(infedgecenter[i]) > ((belowleftx + belowrightx) / 2)) ) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (belowright); localInfo->center2vorpoi.at(infedgecenter[i]).push_back (aboveright); } /* special case */ else if ( (countyminvals == 1) && (countymaxvals == 1) && (get<0>(infedgecenter[i]) < ((belowleftx + belowrightx) / 2)) ) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (belowleft); localInfo->center2vorpoi.at(infedgecenter[i]).push_back (aboveleft); } /* special case */ else if ( (countxminvals == 1) && (countxmaxvals == 1) && (get<1>(infedgecenter[i]) < ((belowlefty + abovelefty) / 2)) ) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (belowleft); localInfo->center2vorpoi.at(infedgecenter[i]).push_back (belowright); } /* special case */ else if ( (countxminvals == 1) && (countxmaxvals == 1) && (get<1>(infedgecenter[i]) > ((belowlefty + abovelefty) / 2)) ) { localInfo->center2vorpoi.at(infedgecenter[i]).push_back (aboveleft); localInfo->center2vorpoi.at(infedgecenter[i]).push_back (aboveright); } } return 0; } /* voronoiVM-request */ case REQUEST: { TupleType *tupleType = (TupleType*)local.addr; Tuple *newTuple = new Tuple( tupleType ); map, std::vector>>:: iterator iter=localInfo->center2vorpoi.begin(); int maxattrpos = 0; std::vector> tmpo; std::vector> dummy; int checkokflag; double xv, yv; int pointposit = localInfo->pointposition; std::tuple search; /* calculate max attribute position */ maxattrpos = localInfo->attrcount - 1; /* get point coords */ if ((tup = localInfo->reliter->GetNextTuple()) != 0 ) { Point* pointval = static_cast(tup->GetAttribute(pointposit-1)); // Convex cell id corresponds to tupleId int cell_Id = (int)tup->GetTupleId(); if(pointval->IsDefined()) { xv = pointval->GetX(); yv = pointval->GetY(); } search = std::make_tuple(xv, yv); iter = localInfo->center2vorpoi.find(search); if (iter !=localInfo->center2vorpoi.end()) { /* setting up the new tuple */ for( int i = 0; i < tup->GetNoAttributes(); i++ ) { newTuple->CopyAttribute( i, tup, i ); } tmpo = localInfo->center2vorpoi.at(search); checkokflag = checkme(tmpo, localInfo->checkon); if ((checkokflag == 1) || (checkokflag == 2)) { Convex* conv = new Convex(tmpo, cell_Id); voroVec.push_back(*conv); newTuple->PutAttribute(maxattrpos+1, conv); result = SetWord(newTuple); } else { Convex* conv = new Convex(false); newTuple->PutAttribute(maxattrpos+1, conv); result = SetWord(newTuple); } return YIELD; } else { /* not possible */ Convex* conv2 = new Convex(false); for( int i = 0; i < tup->GetNoAttributes(); i++ ) { newTuple->CopyAttribute( i, tup, i ); } newTuple->PutAttribute(maxattrpos+1, conv2); result = SetWord(newTuple); return YIELD; } return YIELD; /* never happens */ } else { delete newTuple; return CANCEL; } return 0; } /* voronoiVM-close */ case CLOSE : { if(localInfo){ if( localInfo->reliter != 0 ) delete localInfo->reliter; if( localInfo->rel ) { localInfo->rel->Clear(); delete localInfo->rel; } delete localInfo; qp->GetLocal2(s).addr=0; } qp->Close(args[0].addr); if (local.addr) { ((TupleType*)local.addr)->DeleteIfAllowed(); local.setAddr(0); } return 0; } } return 0; } /* 3D Convex */ /* Class Polyhedron for result of voronoi3d */ Polyhedron::Polyhedron() {} void Polyhedron::setPolyId(int id_) { this->polyhedronId = id_; } int Polyhedron::getPolyId() { return polyhedronId; } Polyhedron::~Polyhedron() {} /* 3D Convex constructor */ Convex3D::Convex3D() { boundingBox = nullptr; } Convex3D::Convex3D(const Convex3D& g) { boundingBox = g.boundingBox; } Convex3D::Convex3D(Rectangle<3> &bounding_box) { boundingBox = &bounding_box; } Convex3D::Convex3D(std::vector &poly_vec) { polyhedronvec = poly_vec; } void Convex3D::Set(Stream> rStream) { CreateVoronoi3D(rStream); } void Convex3D::CreateVoronoi3D(Stream> rStream) { // create voronoi diagram buildVoronoi3D(rStream); } void Convex3D::setTetrahedronVector(std::vector tetra_vec) { this->tetravec = tetra_vec; } std::vector& Convex3D::getTetrahedronVector() { return this->tetravec; } void Convex3D::setPolyhedronVector(std::vector poly_vec) { this->polyhedronvec = poly_vec; } std::vector& Convex3D::getPolyhedronVector() { return this->polyhedronvec; } std::vector& Convex3D::getPointsVector() { return this->points; } void Convex3D::setPointsVector(std::vector pointsvec) { this->points = pointsvec; } std::vector& Convex3D::getVerticeVector() { return this->vertices; } void Convex3D::setVerticeVector(std::vector verticevec) { this->vertices = verticevec; } std::vector>& Convex3D::getFacesVector() { return this->faces; } void Convex3D::setFacesVector(std::vector> facevec) { this->faces = facevec; } std::vector>& Convex3D::getV2TVector(){ return this->v2t; } void Convex3D::setV2TVector(std::vector> v2tvec){ this->v2t = v2tvec; } std::vector>& Convex3D::getF2TVector(){ return this->f2t; } void Convex3D::setF2TVector(std::vector> f2tvec){ this->f2t = f2tvec; } void Convex3D::setCellId(int cell_id) { this->polyhedronId = cell_id; } int Convex3D::getCellId() { return polyhedronId; } Convex3D::~Convex3D() {} /* Calculates cross product of two vectors and returns vector */ std::vector crossProduct(std::vector va, std::vector vb) { std::vector res {va[1]*vb[2] - va[2]*vb[1], va[2]*vb[0] - va[0]*vb[2], va[0]*vb[1] - va[1]*vb[0]}; return res; } /* Calculates dot product of two vectors and returns value */ double dotProduct(std::vector va, std::vector vb) { double product = va[0]*vb[0] + va[1]*vb[1] + va[2]*vb[2]; return product; } /* Calculates centre of a cuboid */ Point3D getCentre(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; Point3D r_c; r_c.x = r->getMinX() + b; r_c.y = r->getMinY() + a; r_c.z = r->getMinZ() + c; return r_c; } /* Returns true if Point p is in given polyhedron */ bool isInPolyhedron(Point3D p, Polyhedron poly, Point3D pi) { for(size_t i = 1; i < poly.faces.size(); i++) { // calculate first orient3d to have a comparetive value std::vector face = poly.faces[i]; if(face.size() > 2) { double pa[3] = {face[0].x, face[0].y, face[0].z}; double pb[3] = {face[1].x, face[1].y, face[1].z}; double pc[3] = {face[2].x, face[2].y, face[2].z}; // take point pi (which lies definitly in cell) as a reference double pd[3] = {pi.x, pi.y, pi.z}; double d0 = orient3d(pa, pb, pc, pd); double paC[3] = {face[0].x, face[0].y, face[0].z}; double pbC[3] = {face[1].x, face[1].y, face[1].z}; double pcC[3] = {face[2].x, face[2].y, face[2].z}; double pp[3] = {p.x, p.y, p.z}; double d1 = orient3d(paC, pbC, pcC, pp); /* if values for determinants (d0,d1) have different signs, the points pi and p cannot be on the same side of the checked face. In this case p cannot be inside of the polyhedron */ if(signbit(d0) != signbit(d1)) { return false; } } } return true; } /* Returns true if point lies in cuboid */ bool insideCuboid(Rectangle<3>* r, Point3D center) { double x = center.x; double y = center.y; double z = center.z; if (r->getMinX() <= x && r->getMaxX() >= x && r->getMinY() <= y && r->getMaxY() >= y && r->getMinZ() <= z && r->getMaxZ() >= z) { return true; } return false; } /* Returns true if one of the points of the given polyhedron lies in cuboid */ bool insideCuboid(Rectangle<3>* r, Polyhedron poly) { for(size_t t = 0; t < poly.faces.size(); t++) { std::vector face = poly.faces[t]; for(size_t f = 0; f < face.size(); f++) { double x = face[f].x; double y = face[f].y; double z = face[f].z; if (r->getMinX() <= x && r->getMaxX() >= x && r->getMinY() <= y && r->getMaxY() >= y && r->getMinZ() <= z && r->getMaxZ() >= z) { return true; } } } return false; } bool sortbyX(Point3D a, Point3D b) { return a.x < b.x; } bool sortbyY(Point3D a, Point3D b) { return a.y < b.y; } bool sortbyZ(Point3D a, Point3D b) { return a.z < b.z; } ListExpr Convex3D::PropertyConvex3D() { ListExpr desclst = nl->TextAtom(); nl->AppendText(desclst, "A polyhedron id " "followed by list of faces.\n" "A face consists of a list of 3d points\n" "( ). "); ListExpr formatlst = nl->TextAtom(); nl->AppendText(formatlst, "(1 (((1.0 2.0 1.0)(1.0 3.0 1.0)(4.0 3.0 1.0)" "(1.0 1.5 2.0)(2.0 1.5 2.0))))"); 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(Convex3D::BasicType()), desclst, formatlst))); } /* Out function */ ListExpr Convex3D::OutConvex3D( ListExpr typeInfo, Word value ) { Convex3D* conv = static_cast( value.addr ); if(conv != nullptr) { std::vector polyhedronvec = conv->getPolyhedronVector(); ListExpr polyExpr = nl->Empty(); ListExpr lastPolyLstExpr; for(size_t test=0; test < polyhedronvec.size(); test++) { ListExpr facesLstExpr; ListExpr lastFacesLstExpr; Polyhedron poly = polyhedronvec.at(test); if(test > 0) { lastPolyLstExpr = nl->Append(lastPolyLstExpr, nl->IntAtom(poly.getPolyId())); } else { polyExpr = nl->OneElemList(nl->IntAtom(poly.getPolyId())); lastPolyLstExpr = polyExpr; } for(size_t fac = 0; fac < poly.faces.size(); fac++) { ListExpr faceLstExpr; ListExpr lastFaceLstExpr; if(fac > 0) { lastFacesLstExpr = nl->Append(lastFacesLstExpr, nl->Empty()); } else { facesLstExpr = nl->OneElemList(nl->Empty()); lastFacesLstExpr = facesLstExpr; } std::vector facc = poly.faces.at(fac); for(size_t poii=0; poii < facc.size(); poii++) { if(poii > 0) { lastFaceLstExpr = nl->Append(lastFaceLstExpr, nl->ThreeElemList(nl->RealAtom(facc.at(poii).x), nl->RealAtom(facc.at(poii).y), nl->RealAtom(facc.at(poii).z))); } else { faceLstExpr = nl->OneElemList(nl->ThreeElemList( nl->RealAtom(facc.at(poii).x), nl->RealAtom(facc.at(poii).y), nl->RealAtom(facc.at(poii).z))); lastFaceLstExpr = faceLstExpr; } } lastFacesLstExpr = nl->Append(lastFacesLstExpr, faceLstExpr); } lastPolyLstExpr = nl->Append(lastPolyLstExpr, facesLstExpr); } return polyExpr; } else { return (nl->SymbolAtom(Symbol::UNDEFINED())); } } /* In function */ Word Convex3D::InConvex3D( const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct ) { Word w = SetWord(Address(0)); try { Polyhedron polyhedron; std::vector face; std::vector poly_vec; std::vector> facesPoints; ListExpr polyExpr = instance; int polyId; if (nl->ListLength( polyExpr ) > 0) { while(nl->ListLength(polyExpr) > 1) { ListExpr lstElem = nl->First(polyExpr); if(nl->IsAtom(lstElem)) { polyhedron = Polyhedron(); polyId = nl->IntValue(lstElem); polyhedron.setPolyId(polyId); } ListExpr facesLst = nl->Second(polyExpr); /* list of faces */ if(nl->ListLength(facesLst) > 1) { while(nl->ListLength(facesLst) > 1) { if(nl->ListLength(facesLst) > 1) { ListExpr faceElems = nl->Second(facesLst); if(nl->ListLength(faceElems) > 0) { face.clear(); while(!nl->IsEmpty(faceElems)) { ListExpr vertex = nl->First(faceElems); ListExpr first = nl->First(vertex); ListExpr second = nl->Second(vertex); ListExpr third = nl->Third(vertex); if(nl->IsAtom(first) && nl->AtomType(first) == RealType && nl->IsAtom(second) && nl->AtomType(second) == RealType && nl->IsAtom(third) && nl->AtomType(third) == RealType) { double x = nl->RealValue(first); double y = nl->RealValue(second); double z = nl->RealValue(third); Point3D p {x,y,z}; face.push_back(p); } faceElems = nl->Rest(faceElems); } } polyhedron.faces.push_back(face); facesLst = nl->Rest(facesLst); facesLst = nl->Rest(facesLst); } } } poly_vec.push_back(polyhedron); polyExpr = nl->Rest(polyExpr); polyExpr = nl->Rest(polyExpr); } } Convex3D* conv3d = new Convex3D(); conv3d->setPolyhedronVector(poly_vec); w.addr = conv3d; correct = true; return w; } catch (int e) { correct = false; cmsg.inFunError("Expecting a 3dvoronoi list representation. Exit code " + std::to_string(e)); return w; } } // This function checks whether the type constructor is applied correctly. bool Convex3D::KindCheckConvex3D( ListExpr type, ListExpr& errorInfo ) { return (nl->IsEqual( type, Convex3D::BasicType() )); } // Clone function Word Convex3D::CloneConvex3D( const ListExpr typeInfo, const Word& w ) { Convex3D *g = new Convex3D( *((Convex3D *)w.addr) ); return SetWord( g ); } // Create function Word Convex3D::CreateConvex3D( const ListExpr typeInfo ) { return SetWord( new Convex3D() ); } // Delete function void Convex3D::DeleteConvex3D( const ListExpr typeInfo, Word& w ) { delete (Convex3D *)w.addr; w.addr = 0; } // SizeOf function int Convex3D::SizeOfConvex3D() { return sizeof(Convex3D); } /* Returns true if points are equal */ bool comparePoints3D(Point3D p1, Point3D p2) { bool res = (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z); return res; } /* Normalizes a vector */ Point3D normalize(double x, double y, double z) { const float s = 1.0f / sqrtf(x*x + y*y + z*z); Point3D p {x*s, y*s, z*s}; return p; } /* Returns the index of a point in a vector of points */ int getIndex(Point3D t1, std::vector v2) { for(int i=0; i < (int)v2.size(); i++) { Point3D t2 = v2.at(i); if(t1.x == t2.x && t1.y == t2.y && t1.z == t2.z) { return i; } } return -1; } /* Returns the centre of the sphere around a tetrahedron see Weisstein, Eric W. 'Circumsphere.' From MathWorld--A Wolfram Web Resource. for explanation */ Point3D getCircumcenter(Point3D a, Point3D b, Point3D c, Point3D d) { // calculate middle of Tetrahedron with circumsphere double fina[3] = {a.x, a.y, a.z}; double finb[3] = {b.x, b.y, b.z}; double finc[3] = {c.x, c.y, c.z}; double find[3] = {d.x, d.y, d.z}; float ax = orient3d(fina, finb, finc, find); /* build new points for Dx, Dy and Dz by discarding column xi (or yi or zi) */ float square_1 = a.x*a.x + a.y*a.y + a.z*a.z; float square_2 = b.x*b.x + b.y*b.y + b.z*b.z; float square_3 = c.x*c.x + c.y*c.y + c.z*c.z; float square_4 = d.x*d.x + d.y*d.y + d.z*d.z; double dx_1[3] = {square_1, a.y, a.z}; double dx_2[3] = {square_2, b.y, b.z}; double dx_3[3] = {square_3, c.y, c.z}; double dx_4[3] = {square_4, d.y, d.z}; float dx = orient3d(dx_1, dx_2, dx_3, dx_4); double dy_1[3] = {square_1, a.x, a.z}; double dy_2[3] = {square_2, b.x, b.z}; double dy_3[3] = {square_3, c.x, c.z}; double dy_4[3] = {square_4, d.x, d.z}; float dy = -orient3d(dy_1, dy_2, dy_3, dy_4); double dz_1[3] = {square_1, a.x, a.y}; double dz_2[3] = {square_2, b.x, b.y}; double dz_3[3] = {square_3, c.x, c.y}; double dz_4[3] = {square_4, d.x, d.y}; float dz = orient3d(dz_1, dz_2, dz_3, dz_4); if(ax < 0) { ax = orient3d(fina, finc, finb, find); dx = orient3d(dx_1, dx_3, dx_2, dx_4); dy = -orient3d(dy_1, dy_3, dy_2, dy_4); dz = orient3d(dz_1, dz_3, dz_2, dz_4); } Point3D circumcenter; circumcenter.x = (dx / (2*ax)); circumcenter.y = (dy / (2*ax)); circumcenter.z = (dz / (2*ax)); return circumcenter; } /* Returns true if line p1 to p2 is a line in tet (two tetrahedrons share a line) */ bool sameline(Point3D p1, Point3D p2, Tetrahedron tet) { std::vector tmp {tet.a, tet.b, tet.c, tet.d}; bool p1in = false; bool p2in = false; for(int i = 0; i < (int)tmp.size(); i++) { p1in = comparePoints3D(p1, tmp.at(i)); if(p1in) { for(int z=0; z<(int)tmp.size(); z++) { if(z!=i) { p2in = comparePoints3D(p2,tmp.at(z)); if(p2in) { return true; } } } } } return false; } bool sameline(int p1, int p2, std::vector tet) { bool p1in = false; bool p2in = false; for (const auto &value:tet) { if(value == p1) p1in = true; if(value == p2) p2in = true; if(p1in && p2in) { return true; } } return false; } /* Returns true if a pair of points is in a vector of pairs of points */ bool insidevec(Point3D p1, Point3D p2, std::vector> pairs) { for(int o=0; o < (int)pairs.size(); o++) { Point3D t1 = std::get<0>(pairs.at(o)); Point3D t2 = std::get<1>(pairs.at(o)); if(comparePoints3D(t1, p1) && comparePoints3D(t2, p2)) { return true; } } return false; } /* Returns true if a pair of points is in a vector of pairs of points using indices */ bool insidevec(int p1, int p2, std::vector> pairs) { for(int o=0; o < (int)pairs.size(); o++) { int t1 = std::get<0>(pairs.at(o)); int t2 = std::get<1>(pairs.at(o)); if((t1 == p1 && t2 == p2) || (t1 == p2 && t2 == p1)) { return true; } } return false; } /* Returns true if a segment pd intersects with triangle abc See Moeller-Trumbore intersection algorithm for further explanation Paper: Fast MinimumStorage RayTriangle Intersection */ bool segmentIntersectsArea(Point3D p, Point3D d, Point3D a, Point3D b, Point3D c) { double epsilon = 0.000001f; Point3D e0 {b.x-a.x, b.y-a.y, b.z-a.z}; Point3D e1 {c.x-a.x, c.y-a.y, c.z-a.z}; Point3D dir {d.x-p.x, d.y-p.y, d.z-p.z}; Point3D dir_norm = normalize(dir.x, dir.y, dir.z); std::vector dir_norm_vec {dir_norm.x, dir_norm.y, dir_norm.z}; std::vector dir_vec{dir.x, dir.y, dir.z}; std::vector e1_vec {e1.x, e1.y, e1.z}; std::vector e0_vec {e0.x, e0.y, e0.z}; /* The equation that needs to be solved is (6) (page 3 from source above) The first step is to check whether the part (dir\_norm\_vec x e1\_vec) \* e0\_vec (in the paper this would be (D x E2)\*E1) is non-zero. If the equation is not solvable we can stop. In the paper h is called P. */ std::vector h = crossProduct(dir_norm_vec, e1_vec); double dp = dotProduct(e0_vec, h); if (dp > -epsilon && dp < epsilon) { return false; } /* The next step is to check the value of u which is calculated as 1 / (P * E1) * (P * T) In this notation: h: P dp: (P * E1) s\_vec: T So: u = (1 / dp) * (s\_vec * h) */ Point3D s {p.x-a.x, p.y-a.y, p.z-a.z}; std::vector s_vec {s.x, s.y, s.z}; const float f = 1.0f / dp; const float u = f * dotProduct(s_vec, h); /* u has to be between 0 and 1 as we are looking at a unit triangle in y and z and a ray direction aligned with x. If u is not between 0 and 1 we can stop. */ if (u < 0.0f || u > 1.0f) { return false; } /* Now we look at the v in equation (6) in the paper. Here v = 1 / (P * E1) * ((T x E1) * D) In this notation: v = f * ((s\_vec x e0\_vec) * dir\_norm\_vec) */ std::vector q = crossProduct(s_vec, e0_vec); const float v = f * dotProduct(dir_norm_vec, q); /* v has to be positive and u + v cannot exceed 1 to lie in the unit triangle */ if (v < 0.0f || u + v > 1.0f) { return false; } /* Now the last value t is calculated accordingly as t = 1 / (P * E1) * ((T x E1) * E2) In this notation: t = f * (q * e1\_vec) */ const float t = f * dotProduct(e1_vec, q); /* segment intersection: the distance variable t must be between 0 and the length of the direction vector dir\_vec for the segment between the two points p and d to intersect the triangle. */ if (t > epsilon && t < sqrtf(dotProduct(dir_vec, dir_vec))) { return true; } return false; } /* Returns all cellnumbers of cells which intersect with a given rectangle Two modes are possible: intersections with the exact cell and intersection with the bounding box of a cell */ void cellNum3D(Convex3D* convex3d, Rectangle<3>* search_window_ptr, int mode, std::set *cell_ids) { // get polyvec std::vector polyvec = convex3d->getPolyhedronVector(); std::vector inputPoints = convex3d->getPointsVector(); if(inputPoints.size() < polyvec.size()) { /* calculate center of polyeder 1. calculate bbox of polyeder 2. calculate center of this bbox */ for(size_t p = 0; p < polyvec.size(); p++) { Rectangle<3> bboxP = createBBox3D(&polyvec[p]); Point3D bc = getCentre(&bboxP); inputPoints.push_back(bc); } } int bbox = 2; int precise = 1; // Rectangle points Point3D lebofr, ribofr, letofr, ritofr, leboba, riboba, letoba, ritoba; lebofr = {search_window_ptr->getMinX(), search_window_ptr->getMinY(), search_window_ptr->getMinZ()}; ribofr = {search_window_ptr->getMaxX(), search_window_ptr->getMinY(), search_window_ptr->getMinZ()}; letofr = {search_window_ptr->getMinX(), search_window_ptr->getMaxY(), search_window_ptr->getMinZ()}; ritofr = {search_window_ptr->getMaxX(), search_window_ptr->getMaxY(), search_window_ptr->getMinZ()}; leboba = {search_window_ptr->getMinX(), search_window_ptr->getMinY(), search_window_ptr->getMaxZ()}; riboba = {search_window_ptr->getMaxX(), search_window_ptr->getMinY(), search_window_ptr->getMaxZ()}; letoba = {search_window_ptr->getMinX(), search_window_ptr->getMaxY(), search_window_ptr->getMaxZ()}; ritoba = {search_window_ptr->getMaxX(), search_window_ptr->getMaxY(), search_window_ptr->getMaxZ()}; Point3D center = getCentre(search_window_ptr); // intersection with exact cell if(mode == precise) { for(size_t i = 0; i < polyvec.size(); i++) { Polyhedron tmp = polyvec[i]; if(!tmp.faces.empty()) { /* 1. Check if any point (taken from points) of polyhedron lies in cuboid: add cell id (easy, saves time) 2. Check if middle of cuboid intersects with polyhedron cell (get middle of cuboid, check if it lies in cell) - if yes: add cell\_id to cell\_ids - if no: check if edges of cuboid intersect with faces of polyhedron - get face and points of cuboid, check intersection - if one intersect: add cell\_id to cell\_ids - if no intersects: go to next cell, don't add cell\_id */ if(insideCuboid(search_window_ptr, inputPoints.at(i))) { cell_ids->insert(tmp.getPolyId()); } else if(isInPolyhedron(center, tmp, inputPoints.at(i))) { cell_ids->insert(tmp.getPolyId()); } else { // check intersection for each face for(size_t f = 0; f < tmp.faces.size(); f++) { std::vector face = tmp.faces.at(f); if(face.size() > 2) { for(size_t n=0; n < face.size()-2; n++) { /* polygon consists of x-2 (x number of vertices) triangles triangle consists of vertex v[0], v[n+1], v[n+2] n = number of triangles already formed first triangle: v[0], v[1], v[2] with n = 0 */ if(segmentIntersectsArea(lebofr, leboba, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(ribofr, riboba, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(lebofr, ribofr, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(leboba, riboba, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(lebofr, letofr, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(ribofr, ritofr, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(leboba, letoba, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(riboba, ritoba, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(letofr, letoba, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(ritofr, ritoba, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(letofr, ritofr, face[0], face[n+1], face[n+2]) || segmentIntersectsArea(letoba, ritoba, face[0], face[n+1], face[n+2])) { cell_ids->insert(tmp.getPolyId()); break; } } } } } } } } else if (mode== bbox) { for(size_t b = 0; b < polyvec.size(); b++) { Polyhedron pol = polyvec.at(b); if(!pol.faces.empty()) { Rectangle<3> bbox = createBBox3D(&pol); /* see if bbox intersects with rectangle top left and bottom right of bbox */ Point3D tolefr, boriba; tolefr = {bbox.getMinX(), bbox.getMaxY(), bbox.getMinZ()}; boriba = {bbox.getMaxX(), bbox.getMinY(), bbox.getMaxZ()}; if(cuboidOverlap(tolefr, boriba, letofr, riboba)) { cell_ids->insert(pol.getPolyId()); } } } } else { cell_ids->insert(0); } return; } /* checks if id of face is already in vector if yes: returns position */ bool Convex3D::faceIn(std::vector face, int* pos) { std::sort(face.begin(), face.end()); for(int a = 0; a < (int)faces.size(); a++) { std::sort(faces[a].begin(), faces[a].end()); if(faces[a] == face) { *pos = a; return true; } } return false; } /* check if tetrahedron exists in vector v2t */ bool Convex3D::tetExists(int a, int b, int p, int d, int* pos) { std::vector tetr {a, b, p, d}; sort(tetr.begin(), tetr.end()); for(int v=0; v < (int)v2t.size(); v++) { sort(v2t[v].begin(), v2t[v].end()); if(v2t[v] == tetr) { *pos = v; return true; } } return false; } /* Create Delaunay diagram Input: Set of points Output: Delaunay diagram Further explanation in paper of Hugo Ledoux Computing the 3D Voronoi Diagram Robustly: An Easy Explanation */ void Convex3D::createDelaunay (std::vector points, std::vector* tetravec) { // 1. Get min and max x,y,z std::vector pointsSortedbyX = points; std::vector pointsSortedbyY = points; std::vector pointsSortedbyZ = points; // Sort Points by x-value std::sort(pointsSortedbyX.begin(), pointsSortedbyX.end(), sortbyX); double xmin = pointsSortedbyX.front().x; double xmax = pointsSortedbyX[pointsSortedbyX.size() -1].x; // Sort points by y-value std::sort(pointsSortedbyY.begin(), pointsSortedbyY.end(), sortbyY); double ymin = pointsSortedbyY.front().y; double ymax = pointsSortedbyY[pointsSortedbyY.size()-1].y; // Sort points by z-value - check if it works to get z-value std::sort(pointsSortedbyZ.begin(), pointsSortedbyZ.end(), sortbyZ); double zmin = pointsSortedbyZ.front().z; double zmax = pointsSortedbyZ[pointsSortedbyZ.size()-1].z; /* 2. Build tetrahedron with min and max values 2.1 Calculate bounding box of points with min and max values 2.2 Build triangle around upper rectangle of cuboid (bounding box) 2.3 Build tetrahedron with point above triangle 2.4 Extend sides from point to triangle until it reaches height of lower rectangle of cuboid 2.5 result is the start tetrahedron */ double min[3], max[3]; min[0] = xmin; min[1] = ymin; max[0] = xmax; max[1] = ymax; min[2] = zmin; max[2] = zmax; Rectangle<3> bbox (true, min, max); double x_len = (xmax-xmin); double z_len = (zmax-zmin); // triangle points: Point3D t1 {xmin-x_len, ymax, zmin-1}; Point3D t2 {xmin+x_len, ymax, ((z_len+1)*2)}; Point3D t3 {xmax+x_len, ymax, zmin-1}; // upper tetrahedron: double y_len = (ymax-ymin); // upper point of tetrahedron Point3D t4 {xmin+(x_len/2), ymax+y_len, zmin+(z_len/2)}; Point3D t5 {t1.x-y_len, ymin-1, zmin-1}; Point3D t6 {t2.x, ymin-1, t2.z+y_len}; Point3D t7 {t3.x+y_len, ymin-1, zmin-1}; // adding vertices t4-t7 to vertice vector vertices.push_back(t4); vertices.push_back(t5); vertices.push_back(t6); vertices.push_back(t7); /* adding faces to faces vector use indices of vertice vector */ std::vector face1 {0, 1, 2}; std::vector face2 {0, 2, 3}; std::vector face3 {0, 1, 3}; std::vector face4 {1, 2, 3}; faces.push_back(face1); faces.push_back(face2); faces.push_back(face3); faces.push_back(face4); /* adding indices to tetrahedron vectors tetrahedron is build from four vertices vertices2tetrahedron (v2t) */ double dz[3] {t4.x, t4.y, t4.z}; double dx[3] {t5.x, t5.y, t5.z}; double dy[3] {t6.x, t6.y, t6.z}; double dv[3] {t7.x, t7.y, t7.z}; if(orient3d(dz, dx, dy, dv) > 0) { std::vector vert2tet {0,1,2,3}; v2t.push_back(vert2tet); vert2tet.clear(); } else { std::vector vert2tet {0,2,1,3}; v2t.push_back(vert2tet); vert2tet.clear(); } /* faces2tetrahedron (f2t) vector which has indices to faces of each tetrahedron that is inside this vector */ std::vector face2tet {0,1,2,3}; f2t.push_back(face2tet); face2tet.clear(); std::vector> tetfaces; std::vector> tetverts; /* push start tetrahedron in vector Insert point by point in initial tetrahedron */ for(int i = 0; i < (int)points.size(); i++) { Point3D p = points.at(i); /* find tetrahedron T containing p with visibility walk through diagram */ bool found_tet = false; int n = 0; int start = 0; std::vector tetStart =f2t[n]; std::vector faceStart = faces[tetStart[start]]; std::vector tStart = v2t[n]; double pit[3] = {p.x, p.y, p.z}; int a = 0; /* visited elements in v2t */ std::vector visited {}; std::vector::iterator it; while(found_tet == false) { start = 0; a++; it = std::find(visited.begin(), visited.end(), n); /* to take another starting point (and not to get stuck in visibility walk) */ if (it != visited.end()) { // random start n = std::rand() % v2t.size(); tStart = v2t[n]; } // first points at position 0,1,2 double ait[3] = {vertices[tStart[0]].x, vertices[tStart[0]].y, vertices[tStart[0]].z} ; double bit[3] = {vertices[tStart[1]].x, vertices[tStart[1]].y, vertices[tStart[1]].z}; double cit[3] = {vertices[tStart[2]].x, vertices[tStart[2]].y, vertices[tStart[2]].z}; double dit[3] = {vertices[tStart[3]].x, vertices[tStart[3]].y, vertices[tStart[3]].z}; double detTet = orient3d(ait, bit, cit, dit); if(signbit(orient3d(ait, bit, cit, pit)) != signbit(detTet)) { visited.push_back(n); // face std::vector fa {tStart[0], tStart[1], tStart[2]}; int index = -1; std::vector::iterator it; if(faceIn(fa, &index)) { /* is index in another tet in f2t */ for(int ii=0; ii < (int)f2t.size(); ii++) { if(ii != n) { it = find (f2t[ii].begin(), f2t[ii].end(), index); if (it != f2t[ii].end()) { n = ii; tStart = v2t[n]; break; } } } } } else { if(signbit(orient3d(ait, bit, pit, dit)) != signbit(detTet)) { visited.push_back(n); std::vector fa {tStart[0], tStart[1], tStart[3]}; int index = -1; std::vector::iterator it; if(faceIn(fa, &index)) { /* is index in another tet in f2t */ for(int ii=0; ii < (int)f2t.size(); ii++) { if(ii != n) { it = find (f2t[ii].begin(), f2t[ii].end(), index); if (it != f2t[ii].end()) { n = ii; tStart = v2t[n]; break; } } } } } else { if(signbit(orient3d(ait, pit, cit, dit)) != signbit(detTet)) { visited.push_back(n); std::vector fa {tStart[0], tStart[2], tStart[3]}; int index = -1; std::vector::iterator it; if(faceIn(fa, &index)) { /* is index in another tet in f2t */ for(int ii=0; ii < (int)f2t.size(); ii++) { if(ii != n) { it = find (f2t[ii].begin(), f2t[ii].end(), index); if (it != f2t[ii].end()) { n = ii; tStart = v2t[n]; break; } } } } } else { if(signbit(orient3d(pit, bit, cit, dit)) != signbit(detTet)) { visited.push_back(n); std::vector fa {tStart[1], tStart[2], tStart[3]}; int index = -1; std::vector::iterator it; if(faceIn(fa, &index)) { /* is index in another tet in f2t */ for(int ii=0; ii < (int)f2t.size(); ii++) { if(ii != n) { it = find (f2t[ii].begin(), f2t[ii].end(), index); if (it != f2t[ii].end()) { n = ii; tStart = v2t[n]; break; } } } } } else { /* point is inside */ found_tet = true; if(found_tet) { a = (int)v2t.size(); } } } } } if(a > ((int)v2t.size()*4)) { /* cannot find tetrahedron remove point */ points.erase(points.begin()+i); break; } } // end of while if(visited.size() > 0){ visited.clear(); } /* check if new point lies directly on one of the already existing vertices */ if(comparePoints3D(p, vertices[v2t[n][0]]) || comparePoints3D(p, vertices[v2t[n][1]]) || comparePoints3D(p, vertices[v2t[n][2]]) || comparePoints3D(p, vertices[v2t[n][3]])) { /* do not insert point at all */ } else { // insert point p to vertices vertices.push_back(p); /* add new v2t get current tetrahedron and remove it from vector to insert 4 new ones */ std::vector tetcrr = v2t[n]; std::vector facecrr = f2t[n]; v2t.erase(v2t.begin()+n); // (0,1,3,4), (1,2,3,4), (0,1,2,4), (0,2,3,4) double ux[3] ={vertices[tetcrr[0]].x, vertices[tetcrr[0]].y, vertices[tetcrr[0]].z}; double uy[3] ={vertices[tetcrr[1]].x, vertices[tetcrr[1]].y, vertices[tetcrr[1]].z}; double uv[3] ={vertices[tetcrr[2]].x, vertices[tetcrr[2]].y, vertices[tetcrr[2]].z}; double uw[3] ={vertices[tetcrr[3]].x, vertices[tetcrr[3]].y, vertices[tetcrr[3]].z}; double ur[3] ={vertices[vertices.size()-1].x, vertices[vertices.size()-1].y, vertices[vertices.size()-1].z}; /* check orientation of vertices before inserting */ if(orient3d(ux, uy, uw, ur) > 0) { std::vector tetnew1 {tetcrr[0], tetcrr[1], tetcrr[3], (int)vertices.size()-1}; v2t.push_back(tetnew1); tetverts.push_back(tetnew1); } else { std::vector tetnew1 {tetcrr[0], tetcrr[3], tetcrr[1], (int)vertices.size()-1}; v2t.push_back(tetnew1); tetverts.push_back(tetnew1); } if(orient3d(uy, uv, uw, ur) > 0) { std::vector tetnew2 {tetcrr[1], tetcrr[2], tetcrr[3], (int)vertices.size()-1}; v2t.push_back(tetnew2); tetverts.push_back(tetnew2); } else { std::vector tetnew2 {tetcrr[1], tetcrr[3], tetcrr[2], (int)vertices.size()-1}; v2t.push_back(tetnew2); tetverts.push_back(tetnew2); } if(orient3d(ux, uy, uv, ur) > 0) { std::vector tetnew3 {tetcrr[0], tetcrr[1], tetcrr[2], (int)vertices.size()-1}; v2t.push_back(tetnew3); tetverts.push_back(tetnew3); } else { std::vector tetnew3 {tetcrr[0], tetcrr[2], tetcrr[1], (int)vertices.size()-1}; v2t.push_back(tetnew3); tetverts.push_back(tetnew3); } if(orient3d(ux, uv, uw, ur) > 0) { std::vector tetnew4 {tetcrr[0], tetcrr[2], tetcrr[3], (int)vertices.size()-1}; v2t.push_back(tetnew4); tetverts.push_back(tetnew4); } else { std::vector tetnew4 {tetcrr[0], tetcrr[3], tetcrr[2], (int)vertices.size()-1}; v2t.push_back(tetnew4); tetverts.push_back(tetnew4); } /* add new faces (numbers behind for orientation) */ std::vector facenew1_1 {tetcrr[0], tetcrr[1], tetcrr[3] }; //013 std::vector facenew1_2 {tetcrr[0], tetcrr[1], (int)vertices.size()-1 }; //014 std::vector facenew1_3 {tetcrr[0], tetcrr[3], (int)vertices.size()-1 }; //034 std::vector facenew1_4 {tetcrr[1], tetcrr[3], (int)vertices.size()-1 }; //134 std::vector facenew2_1 {tetcrr[1], tetcrr[2], (int)vertices.size()-1 }; //124 std::vector facenew2_2 {tetcrr[1], tetcrr[2], tetcrr[3] }; //123 // 134 s.o.: 1-4 std::vector facenew2_4 {tetcrr[2], tetcrr[3], (int)vertices.size()-1 }; //234 std::vector facenew3_1 {tetcrr[0], tetcrr[1], tetcrr[2] }; //012 //014 s.o.: 1-2 std::vector facenew3_3 {tetcrr[0], tetcrr[2], (int)vertices.size()-1 }; //024 std::vector facenew3_4 {tetcrr[1], tetcrr[2], (int)vertices.size()-1 }; //124 //024 s.o.: 3-3 //034 s.o.: 1-3 std::vector facenew4_3 {tetcrr[0], tetcrr[2], tetcrr[3] }; //023 std::vector facenew4_4 {tetcrr[2], tetcrr[3], (int)vertices.size()-1 }; //234 int pos1 = 0; std::vector tetfacenew1; std::vector tetfacenew2; std::vector tetfacenew3; std::vector tetfacenew4; /* create faces - check if face exists - take position if it does */ if(!faceIn(facenew1_1, &pos1)) { faces.push_back(facenew1_1); tetfacenew1.push_back(faces.size()-1); } else { tetfacenew1.push_back(pos1); } if(!faceIn(facenew1_2, &pos1)) { faces.push_back(facenew1_2); tetfacenew1.push_back(faces.size()-1); } else { tetfacenew1.push_back(pos1); } if(!faceIn(facenew1_3, &pos1)) { faces.push_back(facenew1_3); tetfacenew1.push_back(faces.size()-1); } else { tetfacenew1.push_back(pos1); } if(!faceIn(facenew1_4, &pos1)) { faces.push_back(facenew1_4); tetfacenew1.push_back(faces.size()-1); } else { tetfacenew1.push_back(pos1); } /* faces for tetrahedron 2 */ if(!faceIn(facenew2_1, &pos1)) { faces.push_back(facenew2_1); tetfacenew2.push_back(faces.size()-1); } else { tetfacenew2.push_back(pos1); } if(!faceIn(facenew2_2, &pos1)) { faces.push_back(facenew2_2); tetfacenew2.push_back(faces.size()-1); } else { tetfacenew2.push_back(pos1); } if(!faceIn(facenew1_4, &pos1)) { faces.push_back(facenew1_4); tetfacenew2.push_back(faces.size()-1); } else { tetfacenew2.push_back(pos1); } if(!faceIn(facenew2_4, &pos1)) { faces.push_back(facenew2_4); tetfacenew2.push_back(faces.size()-1); } else { tetfacenew2.push_back(pos1); } /* faces for tetrahedron 3 */ if(!faceIn(facenew3_1, &pos1)) { faces.push_back(facenew3_1); tetfacenew3.push_back(faces.size()-1); } else { tetfacenew3.push_back(pos1); } if(!faceIn(facenew1_2, &pos1)) { faces.push_back(facenew1_2); tetfacenew3.push_back(faces.size()-1); } else { tetfacenew3.push_back(pos1); } if(!faceIn(facenew3_3, &pos1)) { faces.push_back(facenew3_3); tetfacenew3.push_back(faces.size()-1); } else { tetfacenew3.push_back(pos1); } if(!faceIn(facenew3_4, &pos1)) { faces.push_back(facenew3_4); tetfacenew3.push_back(faces.size()-1); } else { tetfacenew3.push_back(pos1); } /* faces for tetrahedron 4 */ if(!faceIn(facenew3_3, &pos1)) { faces.push_back(facenew3_3); tetfacenew4.push_back(faces.size()-1); } else { tetfacenew4.push_back(pos1); } if(!faceIn(facenew1_3, &pos1)) { faces.push_back(facenew1_3); tetfacenew4.push_back(faces.size()-1); } else { tetfacenew4.push_back(pos1); } if(!faceIn(facenew4_3, &pos1)) { faces.push_back(facenew4_3); tetfacenew4.push_back(faces.size()-1); } else { tetfacenew4.push_back(pos1); } if(!faceIn(facenew4_4, &pos1)) { faces.push_back(facenew4_4); tetfacenew4.push_back(faces.size()-1); } else { tetfacenew4.push_back(pos1); } /* push tetrahedrons in vector f2t and same tetrahedrons in temporary vector tetfaces to check delaunay criteria */ f2t.erase(f2t.begin()+n); f2t.push_back(tetfacenew1); f2t.push_back(tetfacenew2); f2t.push_back(tetfacenew3); f2t.push_back(tetfacenew4); tetfaces.push_back(tetfacenew1); tetfaces.push_back(tetfacenew2); tetfaces.push_back(tetfacenew3); tetfaces.push_back(tetfacenew4); } int f2tsize = (int)f2t.size(); /* check if the new tetrahedrons meet delaunay critera */ while((int)tetverts.size() > 0) { int siz = (int)tetverts.size(); std::vector ttt = tetverts.at(siz-1); tetverts.pop_back(); f2tsize--; /* get tetrahedron with same face opposite of p */ int index_p = getIndex(p, vertices); int faceIndx; for(int gf=0; gf < (int)tetfaces[siz-1].size(); gf++) { auto it = std::find(std::begin(faces[tetfaces[siz-1][gf]]), std::end(faces[tetfaces[siz-1][gf]]), index_p); if(it == std::end(faces[tetfaces[siz-1][gf]])) { faceIndx = tetfaces[siz-1][gf]; break; } } bool foundtet = false; int ind_tet2; int ind_d; for(int ai=0; ai < (int)f2t.size(); ai++) { auto it = std::find(std::begin(f2t[ai]), std::end(f2t[ai]), faceIndx); if(it != std::end(f2t[ai])) { if(ai != f2tsize) { ind_tet2 = ai; for(int zz=0; zz < (int)v2t[ai].size(); zz++) { if(faces[faceIndx][0] != v2t[ai][zz] && faces[faceIndx][1] != v2t[ai][zz] && faces[faceIndx][2] != v2t[ai][zz]) { ind_d = zz; foundtet = true; break; } } break; } } } tetfaces.pop_back(); /* found tet with point d */ if(foundtet) { std::vector tettt = v2t[ind_tet2]; double pti[3] {vertices[ttt[3]].x, vertices[ttt[3]].y, vertices[ttt[3]].z}; double ati[3] {vertices[ttt[0]].x, vertices[ttt[0]].y, vertices[ttt[0]].z}; double bti[3] {vertices[ttt[1]].x, vertices[ttt[1]].y, vertices[ttt[1]].z}; double cti[3] {vertices[ttt[2]].x, vertices[ttt[2]].y, vertices[ttt[2]].z}; double dti[3] {vertices[tettt[ind_d]].x, vertices[tettt[ind_d]].y, vertices[tettt[ind_d]].z}; /* Before insphere check if orientation of points is correct */ float orient_1 = orient3d(ati, bti, cti, pti); float detInSphere; if(orient_1 < 0.0) { detInSphere = insphere(ati, cti, bti, pti, dti); } else { detInSphere = insphere(ati, bti, cti, pti, dti); } /* if point d lies inside sphere of tetrahedron abcp, check if it fulfills one of four other cases. If so, change ordering of points corresponding to the face */ if(detInSphere > 0.0) { /* case 1: pd intersects area abc perform Flip23 */ if(signbit(orient3d(ati, bti, cti, pti)) != signbit(orient3d(ati,bti,cti, dti))) { /* Flip23: get 'old' tetrahedrons and push three new one in vector find ttt and tettt in v2t/f2t */ std::sort(tettt.begin(), tettt.end()); for(int comp1=0; comp1 < (int) v2t.size(); comp1++) { std::sort(v2t[comp1].begin(), v2t[comp1].end()); if(v2t[comp1] == tettt) { v2t.erase(v2t.begin()+comp1); f2t.erase(f2t.begin()+comp1); } } std::sort(ttt.begin(), ttt.end()); for(int comp=0; comp < (int)v2t.size(); comp++) { std::sort(v2t[comp].begin(), v2t[comp].end()); if(v2t[comp] == ttt) { v2t.erase(v2t.begin()+comp); f2t.erase(f2t.begin()+comp); break; } } /* remove tettt from tetfaces and tetverts */ std::sort(tettt.begin(), tettt.end()); for(int au=0; au < (int)tetfaces.size(); au++) { std::sort(tetfaces[au].begin(), tetfaces[au].end()); if(tetfaces[au] == tettt) { tetfaces.erase(tetfaces.begin()+au); tetverts.erase(tetverts.begin()+au); } } /* build new ones p = ttt[3], a = ttt[0], b = ttt[1], c = ttt[2], d = tettt[3] */ double dx1[3] {vertices[ttt[0]].x, vertices[ttt[0]].y, vertices[ttt[0]].z}; double dx2[3] {vertices[ttt[1]].x, vertices[ttt[1]].y, vertices[ttt[1]].z}; double dx3[3] {vertices[ttt[2]].x, vertices[ttt[2]].y, vertices[ttt[2]].z}; double dx4[3] {vertices[ttt[3]].x, vertices[ttt[3]].y, vertices[ttt[3]].z}; double dx5[3] {vertices[tettt[ind_d]].x, vertices[tettt[ind_d]].y, vertices[tettt[ind_d]].z}; /* abdp */ if(orient3d(dx1, dx2, dx5, dx4) > 0) { std::vector pnew1 {ttt[0], ttt[1], tettt[ind_d], ttt[3]}; v2t.push_back(pnew1); tetverts.push_back(pnew1); pnew1.clear(); } else { std::vector pnew1 {ttt[0], tettt[ind_d], ttt[1], ttt[3]}; v2t.push_back(pnew1); tetverts.push_back(pnew1); pnew1.clear(); } /* acdp */ if(orient3d(dx1, dx3, dx5, dx4) > 0) { std::vector pnew2 {ttt[0], ttt[2], tettt[ind_d], ttt[3]}; v2t.push_back(pnew2); tetverts.push_back(pnew2); pnew2.clear(); } else { std::vector pnew2 {ttt[0], tettt[ind_d], ttt[2], ttt[3]}; v2t.push_back(pnew2); tetverts.push_back(pnew2); pnew2.clear(); } /* bcdp */ if(orient3d(dx2, dx3, dx5, dx4) > 0) { std::vector pnew3 {ttt[1], ttt[2], tettt[ind_d], ttt[3]}; v2t.push_back(pnew3); tetverts.push_back(pnew3); pnew3.clear(); } else { std::vector pnew3 {ttt[1], tettt[ind_d], ttt[2], ttt[3]}; v2t.push_back(pnew3); tetverts.push_back(pnew3); pnew3.clear(); } /* first tet with faces pac, acd, pcd, pad */ std::vector fnew1 {ttt[3], ttt[0], ttt[2]}; std::vector fnew2 {ttt[0], ttt[2], tettt[ind_d]}; std::vector fnew3 {ttt[3], ttt[2], tettt[ind_d]}; std::vector fnew4 {ttt[3], ttt[0], tettt[ind_d]}; // pbc, bcd, pcd, pbd std::vector fnew5 {ttt[3], ttt[1], ttt[2]}; std::vector fnew6 {ttt[1], ttt[2], tettt[ind_d]}; // pdc s.o.: fnew3 std::vector fnew7 {ttt[3], ttt[1], tettt[ind_d]}; // pab, abd, pad, pbd std::vector fnew8 {ttt[3], ttt[0], ttt[1]}; std::vector fnew9 {ttt[0], ttt[1], tettt[ind_d]}; // pad s.o.: fnew4 // pbd s.o.: fnew7 int pos1 = 0; std::vector ftet; std::vector ftet2; std::vector ftet3; /* build new faces check if combination already exists 1. faces for tet 1 */ if(!faceIn(fnew1, &pos1)) { faces.push_back(fnew1); ftet.push_back(faces.size()-1); } else { ftet.push_back(pos1); } if(!faceIn(fnew2, &pos1)) { faces.push_back(fnew2); ftet.push_back(faces.size()-1); } else { ftet.push_back(pos1); } if(!faceIn(fnew3, &pos1)) { faces.push_back(fnew3); ftet.push_back(faces.size()-1); } else { ftet.push_back(pos1); } if(!faceIn(fnew4, &pos1)) { faces.push_back(fnew4); ftet.push_back(faces.size()-1); } else { ftet.push_back(pos1); } /* faces for tet 2 */ if(!faceIn(fnew5, &pos1)) { faces.push_back(fnew5); ftet2.push_back(faces.size()-1); } else { ftet2.push_back(pos1); } if(!faceIn(fnew6, &pos1)) { faces.push_back(fnew6); ftet2.push_back(faces.size()-1); } else { ftet2.push_back(pos1); } if(!faceIn(fnew3, &pos1)) { faces.push_back(fnew3); ftet2.push_back(faces.size()-1); } else { ftet2.push_back(pos1); } if(!faceIn(fnew7, &pos1)){ faces.push_back(fnew7); ftet2.push_back(faces.size()-1); } else { ftet2.push_back(pos1); } /* faces for tet 3 */ if(!faceIn(fnew8, &pos1)){ faces.push_back(fnew8); ftet3.push_back(faces.size()-1); } else { ftet3.push_back(pos1); } if(!faceIn(fnew9, &pos1)){ faces.push_back(fnew9); ftet3.push_back(faces.size()-1); } else { ftet3.push_back(pos1); } if(!faceIn(fnew7, &pos1)){ faces.push_back(fnew7); ftet3.push_back(faces.size()-1); } else { ftet3.push_back(pos1); } if(!faceIn(fnew4, &pos1)) { faces.push_back(fnew4); ftet3.push_back(faces.size()-1); } else { ftet3.push_back(pos1); } /* push in vectors and update f2tsize */ f2t.push_back(ftet3); f2t.push_back(ftet); f2t.push_back(ftet2); f2tsize = (int)f2t.size(); tetfaces.push_back(ftet3); tetfaces.push_back(ftet); tetfaces.push_back(ftet2); } else { /* case 2: pd does not intersect area abc and there is a third tetrahedron abpd, so all tetrahedrons share edge ab: Flip32 */ int pos; if(tetExists(ttt[0], ttt[1], ttt[3], tettt[ind_d], &pos)) { std::vector tetabpd = v2t[pos]; v2t.erase(v2t.begin() + pos); f2t.erase(f2t.begin() + pos); /* find ttt in v2t/f2t */ std::sort(ttt.begin(), ttt.end()); for(int comp=0; comp < (int)v2t.size(); comp++) { std::sort(v2t[comp].begin(), v2t[comp].end()); if(v2t[comp] == ttt) { // position is comp v2t.erase(v2t.begin()+comp); f2t.erase(f2t.begin()+comp); break; } } /* find tettt in v2t/f2t */ std::sort(tettt.begin(), tettt.end()); for(int comp=0; comp < (int)v2t.size(); comp++) { std::sort(v2t[comp].begin(), v2t[comp].end()); if(v2t[comp] == tettt) { // position is comp v2t.erase(v2t.begin()+comp); f2t.erase(f2t.begin()+comp); break; } } /* perform flip32 build two new tetrahedrons from three old ones */ double dx1[3] {vertices[ttt[0]].x, vertices[ttt[0]].y, vertices[ttt[0]].z}; double dx2[3] {vertices[ttt[1]].x, vertices[ttt[1]].y, vertices[ttt[1]].z}; double dx3[3] {vertices[ttt[2]].x, vertices[ttt[2]].y, vertices[ttt[2]].z}; double dx4[3] {vertices[ttt[3]].x, vertices[ttt[3]].y, vertices[ttt[3]].z}; double dx5[3] {vertices[tettt[ind_d]].x, vertices[tettt[ind_d]].y, vertices[tettt[ind_d]].z}; if(orient3d(dx1, dx2, dx3, dx4) > 0) { std::vector pnew1 {ttt[0], ttt[1], ttt[2], ttt[3]}; v2t.push_back(pnew1); tetverts.push_back(pnew1); pnew1.clear(); } else { std::vector pnew1 {ttt[0], ttt[2], ttt[1], ttt[3]}; v2t.push_back(pnew1); tetverts.push_back(pnew1); pnew1.clear(); } if(orient3d(dx1, dx2, dx3, dx5) > 0) { std::vector pnew2 {ttt[0], ttt[1], ttt[2], tettt[ind_d]}; v2t.push_back(pnew2); tetverts.push_back(pnew2); pnew2.clear(); } else { std::vector pnew2 {ttt[0], ttt[2], ttt[1], tettt[ind_d]}; v2t.push_back(pnew2); tetverts.push_back(pnew2); pnew2.clear(); } std::vector newf1 {ttt[3], ttt[0], ttt[2]}; std::vector newf2 {ttt[3], ttt[1], ttt[2]}; std::vector newf3 {ttt[3], ttt[0], ttt[1]}; std::vector newf4 {ttt[0], ttt[1], ttt[2]}; // in both std::vector newf5 {ttt[0], ttt[2], tettt[ind_d]}; std::vector newf6 {ttt[1], ttt[2], tettt[ind_d]}; std::vector newf7 {ttt[0], ttt[1], tettt[ind_d]}; int pos2; /* check if face already exists if yes: take position of needed face if no: create new one */ std::vector ftet32_1; std::vector ftet32_2; if(faceIn(newf1, &pos2)) { ftet32_1.push_back(pos2); } else { faces.push_back(newf1); ftet32_1.push_back(faces.size()-1); } if(faceIn(newf2, &pos2)) { ftet32_1.push_back(pos2); } else { faces.push_back(newf2); ftet32_1.push_back(faces.size()-1); } if(faceIn(newf3, &pos2)) { ftet32_1.push_back(pos2); } else { faces.push_back(newf3); ftet32_1.push_back(faces.size()-1); } if(faceIn(newf4, &pos2)) { ftet32_1.push_back(pos2); } else { faces.push_back(newf4); ftet32_1.push_back(faces.size()-1); } if(faceIn(newf4, &pos2)) { ftet32_2.push_back(pos2); } else { faces.push_back(newf4); ftet32_2.push_back(faces.size()-1); } if(faceIn(newf5, &pos2)) { ftet32_2.push_back(pos2); } else { faces.push_back(newf5); ftet32_2.push_back(faces.size()-1); } if(faceIn(newf6, &pos2)) { ftet32_2.push_back(pos2); } else { faces.push_back(newf6); ftet32_2.push_back(faces.size()-1); } if(faceIn(newf7, &pos2)) { ftet32_2.push_back(pos2); } else { faces.push_back(newf7); ftet32_2.push_back(faces.size()-1); } /* push new builded tetrahedrons from faces in vectors */ f2t.push_back(ftet32_1); f2t.push_back(ftet32_2); // update f2tsize f2tsize = (int)f2t.size(); tetfaces.push_back(ftet32_1); tetfaces.push_back(ftet32_2); } else if(orient3d(pti, ati, bti, dti) == 0.00 || orient3d(pti, bti, cti, dti) == 0.00 || orient3d(pti, ati, cti, dti) == 0.00) { /* case 3: line pd intersects edge of abc and there exist two other tetrahedrons which share edges: flip44 1. sorting the vectors */ sort(ttt.begin(), ttt.end()); sort(tettt.begin(), tettt.end()); /* declaring result vector to store the common elements */ vector v3(ttt.size() + tettt.size()); /* iterator to store return type */ vector::iterator it, end; end = set_intersection( ttt.begin(), ttt.end(), tettt.begin(), tettt.end(), v3.begin()); std::vector samep; for (it = v3.begin(); it != end; it++) { if(*it != ttt[3] && *it != tettt[ind_d]) { samep.push_back(*it); } } if((int)samep.size() == 2) { sort(samep.begin(), samep.end()); std::vector vv(4); int first = -1; int second = -1; /* find two other tetrahedrons with same points */ for(int r=0; r < (int)v2t.size(); r++) { std::vector v = v2t[r]; sort(v.begin(), v.end()); std::set_intersection(v.begin(), v.end(), samep.begin(), samep.end(), std::back_inserter(vv)); if(vv.size() == 2) { first = r; vv.clear(); for(int rr=r; rr < (int)v2t.size(); rr++) { std::vector v = v2t[rr]; sort(v.begin(), v.end()); std::set_intersection(v.begin(), v.end(), samep.begin(), samep.end(), std::back_inserter(vv)); if(vv.size() == 2) { second = rr; break; } } break; } } /* found two other tetrahedrons */ if(first >= 0 && second >= 0) { std::vector thitet = v2t[first]; std::vector foutet = v2t[second]; if(first > second) { v2t.erase(v2t.begin() + first); f2t.erase(f2t.begin() + first); v2t.erase(v2t.begin() + second); f2t.erase(f2t.begin() + second); } else { v2t.erase(v2t.begin() + second); f2t.erase(f2t.begin() + second); v2t.erase(v2t.begin() + first); f2t.erase(f2t.begin() + first); } /* find ttt in v2t/f2t find tettt in v2t/f2t */ for(int comp=0; comp < (int)v2t.size(); comp++) { if(v2t[comp] == ttt) { v2t.erase(v2t.begin()+comp); f2t.erase(f2t.begin()+comp); break; } } for(int comp=0; comp < (int)v2t.size(); comp++) { if(v2t[comp] == tettt) { v2t.erase(v2t.begin()+comp); f2t.erase(f2t.begin()+comp); break; } } /* build 4 new tetrahedrons 1 curr.a, curr.b, curr.c, t1.d 2 curr.a, curr.b, curr.d, t1.d 3 d, curr.b, curr.c, t1.d 4 d, curr.b, curr.d, t1.d */ double ux[3] ={vertices[ttt[0]].x, vertices[ttt[0]].y, vertices[ttt[0]].z}; double uy[3] ={vertices[ttt[1]].x, vertices[ttt[1]].y, vertices[ttt[1]].z}; double uv[3] ={vertices[ttt[2]].x, vertices[ttt[2]].y, vertices[ttt[2]].z}; double uw[3] ={vertices[ttt[3]].x, vertices[ttt[3]].y, vertices[ttt[3]].z}; double ur[3] ={vertices[tettt[ind_d]].x, vertices[tettt[ind_d]].y, vertices[tettt[ind_d]].z}; double ut[3] ={vertices[thitet[0]].x, vertices[thitet[0]].y, vertices[thitet[0]].z}; /* build new tetrahedrons check order of vertices before push to vector */ if(orient3d(ux, uy, ut, uw) > 0) { std::vector newt1 {ttt[0], ttt[1], thitet[0], ttt[3]}; v2t.push_back(newt1); tetverts.push_back(newt1); newt1.clear(); } else { std::vector newt1 {ttt[0], thitet[0], ttt[1], ttt[3]}; v2t.push_back(newt1); tetverts.push_back(newt1); newt1.clear(); } if(orient3d(ur, ux, uy, ut) > 0) { std::vector newt2 {tettt[ind_d], ttt[0], ttt[1], thitet[0]}; v2t.push_back(newt2); tetverts.push_back(newt2); newt2.clear(); } else { std::vector newt2 {tettt[ind_d], ttt[1], ttt[0], thitet[0]}; v2t.push_back(newt2); tetverts.push_back(newt2); newt2.clear(); } if(orient3d(ux, uv, ut, uw) > 0) { std::vector newt3 {ttt[0], ttt[2], thitet[0], ttt[3]}; v2t.push_back(newt3); tetverts.push_back(newt3); newt3.clear(); } else { std::vector newt3 {ttt[0], thitet[0], ttt[2], ttt[3]}; v2t.push_back(newt3); tetverts.push_back(newt3); newt3.clear(); } if(orient3d(ur, ux, uv, ut) > 0) { std::vector newt4 {tettt[ind_d], ttt[0], ttt[2], thitet[0]}; v2t.push_back(newt4); tetverts.push_back(newt4); newt4.clear(); } else { std::vector newt4 {tettt[ind_d], ttt[2], ttt[0], thitet[0]}; v2t.push_back(newt4); tetverts.push_back(newt4); newt4.clear(); } /* Build faces and push to vector */ std::vector newf1 {ttt[3], ttt[0], ttt[1]}; std::vector newf2 {ttt[3], ttt[1], thitet[0]}; std::vector newf3 {ttt[0], ttt[1], thitet[0]}; std::vector newf4 {ttt[3], ttt[0], thitet[0]}; std::vector newf5 {tettt[ind_d], ttt[0], ttt[1]}; std::vector newf6 {tettt[ind_d], ttt[1], thitet[0]}; std::vector newf7 {ttt[0], ttt[1], thitet[0]}; std::vector newf8 {tettt[ind_d], ttt[0], thitet[0]}; std::vector newf9 {ttt[3], ttt[0], ttt[2]}; std::vector newf10 {ttt[3], ttt[2], thitet[0]}; std::vector newf11 {ttt[0], ttt[3], thitet[0]}; std::vector newf12 {ttt[0], ttt[2], thitet[0]}; std::vector newf13 {tettt[ind_d], ttt[2], thitet[0]}; std::vector newf14 {tettt[ind_d], ttt[0], ttt[2]}; std::vector newf15 {tettt[ind_d], ttt[0], thitet[0]}; std::vector newf16 {ttt[0], ttt[2], thitet[0]}; int pos2 = 0; std::vector ftet44_1; std::vector ftet44_2; std::vector ftet44_3; std::vector ftet44_4; /* faces for tetrahedron 44-1 */ if(!faceIn(newf1, &pos2)) { faces.push_back(newf1); ftet44_1.push_back(faces.size()-1); } else { ftet44_1.push_back(pos2); } if(!faceIn(newf2, &pos2)) { faces.push_back(newf2); ftet44_1.push_back(faces.size()-1); } else { ftet44_1.push_back(pos2); } if(!faceIn(newf3, &pos2)) { faces.push_back(newf3); ftet44_1.push_back(faces.size()-1); } else { ftet44_1.push_back(pos2); } if(!faceIn(newf4, &pos2)) { faces.push_back(newf4); ftet44_1.push_back(faces.size()-1); } else { ftet44_1.push_back(pos2); } /* faces for tetrahedron 44-2 */ if(!faceIn(newf5, &pos2)) { faces.push_back(newf5); ftet44_2.push_back(faces.size()-1); } else { ftet44_2.push_back(pos2); } if(!faceIn(newf6, &pos2)) { faces.push_back(newf6); ftet44_2.push_back(faces.size()-1); } else { ftet44_2.push_back(pos2); } if(!faceIn(newf7, &pos2)) { faces.push_back(newf7); ftet44_2.push_back(faces.size()-1); } else { ftet44_2.push_back(pos2); } if(!faceIn(newf8, &pos2)) { faces.push_back(newf8); ftet44_2.push_back(faces.size()-1); } else { ftet44_2.push_back(pos2); } /* faces for tetrahedron 44-3 */ if(!faceIn(newf9, &pos2)) { faces.push_back(newf8); ftet44_3.push_back(faces.size()-1); } else { ftet44_3.push_back(pos2); } if(!faceIn(newf10, &pos2)) { faces.push_back(newf10); ftet44_3.push_back(faces.size()-1); } else { ftet44_3.push_back(pos2); } if(!faceIn(newf11, &pos2)) { faces.push_back(newf11); ftet44_3.push_back(faces.size()-1); } else { ftet44_3.push_back(pos2); } if(!faceIn(newf12, &pos2)) { faces.push_back(newf12); ftet44_3.push_back(faces.size()-1); } else { ftet44_3.push_back(pos2); } /* faces for tetrahedron 44-4 */ if(!faceIn(newf13, &pos2)) { faces.push_back(newf13); ftet44_4.push_back(faces.size()-1); } else { ftet44_4.push_back(pos2); } if(!faceIn(newf14, &pos2)) { faces.push_back(newf14); ftet44_4.push_back(faces.size()-1); } else { ftet44_4.push_back(pos2); } if(!faceIn(newf15, &pos2)) { faces.push_back(newf15); ftet44_4.push_back(faces.size()-1); } else { ftet44_4.push_back(pos2); } if(!faceIn(newf16, &pos2)) { faces.push_back(newf16); ftet44_4.push_back(faces.size()-1); } else { ftet44_4.push_back(pos2); } f2t.push_back(ftet44_1); f2t.push_back(ftet44_2); f2t.push_back(ftet44_3); f2t.push_back(ftet44_4); /* update f2tsize */ f2tsize = (int)f2t.size(); tetfaces.push_back(ftet44_1); tetfaces.push_back(ftet44_2); tetfaces.push_back(ftet44_3); tetfaces.push_back(ftet44_4); } } } else if(orient3d(ati, bti, cti, dti) == 0.00) { /* case 4: tetrahedron is flat perform Flip23 get 'old' tetrahedrons and push three new one in vector */ std::sort(tettt.begin(), tettt.end()); for(int comp1=0; comp1 < (int) v2t.size(); comp1++) { std::sort(v2t[comp1].begin(), v2t[comp1].end()); if(v2t[comp1] == tettt) { v2t.erase(v2t.begin()+comp1); f2t.erase(f2t.begin()+comp1); } } // find ttt in v2t/f2t std::sort(ttt.begin(), ttt.end()); for(int comp=0; comp < (int)v2t.size(); comp++) { std::sort(v2t[comp].begin(), v2t[comp].end()); if(v2t[comp] == ttt) { v2t.erase(v2t.begin()+comp); f2t.erase(f2t.begin()+comp); break; } } // remove tettt from tetfaces and tetverts std::sort(tettt.begin(), tettt.end()); for(int au=0; au < (int)tetfaces.size(); au++) { std::sort(tetfaces[au].begin(), tetfaces[au].end()); if(tetfaces[au] == tettt) { tetfaces.erase(tetfaces.begin()+au); tetverts.erase(tetverts.begin()+au); } } /* build new ones p = ttt[3], a = ttt[0], b = ttt[1], c = ttt[2], d = tettt[3] */ double dx1[3] {vertices[ttt[0]].x, vertices[ttt[0]].y, vertices[ttt[0]].z}; double dx2[3] {vertices[ttt[1]].x, vertices[ttt[1]].y, vertices[ttt[1]].z}; double dx3[3] {vertices[ttt[2]].x, vertices[ttt[2]].y, vertices[ttt[2]].z}; double dx4[3] {vertices[ttt[3]].x, vertices[ttt[3]].y, vertices[ttt[3]].z}; double dx5[3] {vertices[tettt[ind_d]].x, vertices[tettt[ind_d]].y, vertices[tettt[ind_d]].z}; // abdp if(orient3d(dx1, dx2, dx5, dx4) > 0) { std::vector pnew1 {ttt[0], ttt[1], tettt[ind_d], ttt[3]}; v2t.push_back(pnew1); tetverts.push_back(pnew1); pnew1.clear(); } else { std::vector pnew1 {ttt[0], tettt[ind_d], ttt[1], ttt[3]}; v2t.push_back(pnew1); tetverts.push_back(pnew1); pnew1.clear(); } // acdp if(orient3d(dx1, dx3, dx5, dx4) > 0) { std::vector pnew2 {ttt[0], ttt[2], tettt[ind_d], ttt[3]}; v2t.push_back(pnew2); tetverts.push_back(pnew2); pnew2.clear(); } else { std::vector pnew2 {ttt[0], tettt[ind_d], ttt[2], ttt[3]}; v2t.push_back(pnew2); tetverts.push_back(pnew2); pnew2.clear(); } // bcdp if(orient3d(dx2, dx3, dx5, dx4) > 0) { std::vector pnew3 {ttt[1], ttt[2], tettt[ind_d], ttt[3]}; v2t.push_back(pnew3); tetverts.push_back(pnew3); pnew3.clear(); } else { std::vector pnew3 {ttt[1], tettt[ind_d], ttt[2], ttt[3]}; v2t.push_back(pnew3); tetverts.push_back(pnew3); pnew3.clear(); } /* first tet with faces pac, acd, pcd, pad */ std::vector fnew1 {ttt[3], ttt[0], ttt[2]}; std::vector fnew2 {ttt[0], ttt[2], tettt[ind_d]}; std::vector fnew3 {ttt[3], ttt[2], tettt[ind_d]}; std::vector fnew4 {ttt[3], ttt[0], tettt[ind_d]}; // pbc, bcd, pcd, pbd std::vector fnew5 {ttt[3], ttt[1], ttt[2]}; std::vector fnew6 {ttt[1], ttt[2], tettt[ind_d]}; // pdc s.o.: fnew3 std::vector fnew7 {ttt[3], ttt[1], tettt[ind_d]}; // pab, abd, pad, pbd std::vector fnew8 {ttt[3], ttt[0], ttt[1]}; std::vector fnew9 {ttt[0], ttt[1], tettt[ind_d]}; // pad s.o.: fnew4 // pbd s.o.: fnew7 int pos1 = 0; std::vector ftet; std::vector ftet2; std::vector ftet3; /* build faces */ if(!faceIn(fnew1, &pos1)) { faces.push_back(fnew1); ftet.push_back(faces.size()-1); } else { ftet.push_back(pos1); } if(!faceIn(fnew2, &pos1)) { faces.push_back(fnew2); ftet.push_back(faces.size()-1); } else { ftet.push_back(pos1); } if(!faceIn(fnew3, &pos1)) { faces.push_back(fnew3); ftet.push_back(faces.size()-1); } else { ftet.push_back(pos1); } if(!faceIn(fnew4, &pos1)) { faces.push_back(fnew4); ftet.push_back(faces.size()-1); } else { ftet.push_back(pos1); } if(!faceIn(fnew5, &pos1)) { faces.push_back(fnew5); ftet2.push_back(faces.size()-1); } else { ftet2.push_back(pos1); } if(!faceIn(fnew6, &pos1)) { faces.push_back(fnew6); ftet2.push_back(faces.size()-1); } else { ftet2.push_back(pos1); } if(!faceIn(fnew3, &pos1)) { faces.push_back(fnew3); ftet2.push_back(faces.size()-1); } else { ftet2.push_back(pos1); } if(!faceIn(fnew7, &pos1)){ faces.push_back(fnew7); ftet2.push_back(faces.size()-1); } else { ftet2.push_back(pos1); } if(!faceIn(fnew8, &pos1)){ faces.push_back(fnew8); ftet3.push_back(faces.size()-1); } else { ftet3.push_back(pos1); } if(!faceIn(fnew9, &pos1)){ faces.push_back(fnew9); ftet3.push_back(faces.size()-1); } else { ftet3.push_back(pos1); } if(!faceIn(fnew7, &pos1)){ faces.push_back(fnew7); ftet3.push_back(faces.size()-1); } else { ftet3.push_back(pos1); } if(!faceIn(fnew4, &pos1)) { faces.push_back(fnew4); ftet3.push_back(faces.size()-1); } else { ftet3.push_back(pos1); } /* push in vectors */ f2t.push_back(ftet3); f2t.push_back(ftet); f2t.push_back(ftet2); // update f2tsize f2tsize = (int)f2t.size(); tetfaces.push_back(ftet3); tetfaces.push_back(ftet); tetfaces.push_back(ftet2); } } } } } } } /* check if point p is already in vector points */ bool Convex3D::duplicateP(Point3D p) { for(size_t dup = 0; dup < points.size(); dup++) { if(points[dup].x == p.x && points[dup].y == p.y && points[dup].z == p.z) { return true; } } return false; } /* build voronoi diagramm 3d */ void Convex3D::buildVoronoi3D(Stream> rStream) { // get all points from input cuboids rStream.open(); Rectangle<3>* next = rStream.request(); while(next != 0){ Point3D p = getCentre(next); // check for duplicates if(!duplicateP(p)) { points.push_back(getCentre(next)); } // free memory delete next; next = rStream.request(); } rStream.close(); if(points.size() < 2) { const string errmsg = "Expected at least two points"; return; } Convex3D* conv3d = new Convex3D(); std::vector tetravec; // create delaunay diagram with points createDelaunay(points, &tetravec); std::vector> facesPoints; std::vector> lines; std::vector> temp; std::vector> tempF; std::vector circumcenters; /* create voronoi diagram from delaunay diagram find all lines including point p from points */ for(int t=0; t < (int)points.size(); t++) { int p_index; for(size_t id=0; id < vertices.size(); id++) { if(comparePoints3D(vertices[id], points[t])) { p_index = id; break; } } lines.clear(); for(int z=0; z<(int)v2t.size(); z++) { std::vector fin = v2t[z]; if(fin[0] == p_index) { if(!insidevec(fin[0], fin[1], lines)) { lines.push_back(std::make_tuple(fin[0], fin[1])); } if(!insidevec(fin[0], fin[2], lines)) { lines.push_back(std::make_tuple(fin[0], fin[2])); } if(!insidevec(fin[0], fin[3], lines)) { lines.push_back(std::make_tuple(fin[0], fin[3])); } } else if(fin[1] == p_index) { if(!insidevec(fin[1], fin[0], lines)) { lines.push_back(std::make_tuple(fin[1], fin[0])); } if(!insidevec(fin[1], fin[2], lines)) { lines.push_back(std::make_tuple(fin[1], fin[2])); } if(!insidevec(fin[1], fin[3], lines)) { lines.push_back(std::make_tuple(fin[1], fin[3])); } } else if(fin[2] == p_index) { if(!insidevec(fin[2], fin[0], lines)) { lines.push_back(std::make_tuple(fin[2], fin[0])); } if(!insidevec(fin[2], fin[1], lines)) { lines.push_back(std::make_tuple(fin[2], fin[1])); } if(!insidevec(fin[2], fin[3], lines)) { lines.push_back(std::make_tuple(fin[2], fin[3])); } } else if(fin[3] == p_index) { if(!insidevec(fin[3], fin[0], lines)) { lines.push_back(std::make_tuple(fin[3], fin[0])); } if(!insidevec(fin[3], fin[1], lines)) { lines.push_back(std::make_tuple(fin[3], fin[1])); } if(!insidevec(fin[3], fin[2], lines)) { lines.push_back(std::make_tuple(fin[3], fin[2])); } } } // find tetrahedrons to lines for(int n=0; n < (int)lines.size(); n++) { std::tuple tup = lines.at(n); int p1 = std::get<0>(tup); int p2 = std::get<1>(tup); for(int b=0; b < (int)v2t.size(); b++) { if(sameline(p1, p2, v2t[b])) { temp.push_back(v2t[b]); tempF.push_back(f2t[b]); } } // sort tetrahedrons of temp // face to face std::vector> tempSorted; std::vector faces = tempF[temp.size()-1]; tempSorted.push_back(temp[temp.size()-1]); int x = temp.size()-1; while(temp.size() > 0) { bool foundface = false; faces = tempF[x]; temp.erase(temp.begin()+x); tempF.erase(tempF.begin()+x); for(size_t st=0; st < faces.size(); st++) { int face = faces[st]; for(int ai=0; ai < (int)tempF.size(); ai++) { auto it = std::find(std::begin(tempF[ai]), std::end(tempF[ai]), face); if(it != std::end(tempF[ai])) { tempSorted.push_back(temp[ai]); foundface = true; x = ai; break; } } if(foundface) { break; } } } /* all tetrahedrons in vector which share line point\_tup[n] get circumcenter which builds vertex of face of polyhedron */ for(int m=0; m< (int)tempSorted.size(); m++) { Point3D vertex = getCircumcenter(vertices[tempSorted[m][0]], vertices[tempSorted[m][1]], vertices[tempSorted[m][2]], vertices[tempSorted[m][3]]); if(isfinite(vertex.x) && isfinite(vertex.y) && isfinite(vertex.z)) { circumcenters.push_back(vertex); } } facesPoints.push_back(circumcenters); tempSorted.clear(); circumcenters.clear(); } // create polyhedron Polyhedron polyhedron = Polyhedron(); std::vector face; polyhedron.setPolyId(t+1); for(int s=0; s< (int)facesPoints.size(); s++) { face.clear(); for(int g=0; g<(int)facesPoints.at(s).size(); g++) { face.push_back(facesPoints.at(s).at(g)); } if(!face.empty()) { polyhedron.faces.push_back(face); } } // save polyhedron in vector polyhedronvec.push_back(polyhedron); facesPoints.clear(); } conv3d->setPolyhedronVector(polyhedronvec); delete conv3d; } /* 8.2.1 cellNumVM */ int cellNum3DVM( Word* args, Word& result, int message, Word& local, Supplier s ) { Convex3D *convex3d = static_cast(args[0].addr); Rectangle<3> *search_window_ptr = static_cast*>( args[1].addr ); /* mode == 1 => precise allocation; mode == 2 => use Bboxes of convex3d cells In case the user did not specify the mode of allocation, use Bboxes */ int mode = ((CcInt*)args[2].addr)->GetIntval(); std::set cell_ids; int bbox = 2; int precise = 1; result = qp->ResultStorage(s); collection::IntSet* res = (collection::IntSet*) result.addr; if(search_window_ptr == nullptr || convex3d == nullptr) { return 0; } if(mode > bbox || mode < precise) { mode = bbox; } cellNum3D(convex3d, search_window_ptr, mode, &cell_ids); res->setTo(cell_ids); return 0; } /* 8.2.2 smallestCommonCellnumVM */ int smallestCommonCellnum3DVM( Word* args, Word& result, int message, Word& local, Supplier s ) { Convex3D *convex3d = static_cast(args[0].addr); Rectangle<3> *search_window_ptr = static_cast*>( args[1].addr ); Rectangle<3> *search_window_ptr_2 = static_cast*>( args[2].addr ); CcInt* cellno_ptr = static_cast(args[3].addr); int cellno = cellno_ptr->GetIntval(); if(search_window_ptr == nullptr || search_window_ptr_2 == nullptr || convex3d == nullptr) { return -1; } result = qp->ResultStorage( s ); CcBool *res = (CcBool*) result.addr; bool boolval = false; std::set intsetRect1; cellNum3D(convex3d, search_window_ptr, 1, &intsetRect1); std::set intsetRect2; cellNum3D(convex3d, search_window_ptr_2, 1, &intsetRect2); std::vector v(sizeof(intsetRect1)+ sizeof(intsetRect2)); std::vector::iterator it; it=std::set_intersection (intsetRect1.begin(), intsetRect1.end(), intsetRect2.begin(), intsetRect2.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; } /* 8.2.3 getcellvoronoi3DVM */ int getcellvoronoi3DVM(Word* args, Word& result, int message, Word& local, Supplier s) { Convex3D *convex3d = static_cast(args[0].addr); CcInt* cellno_ptr = static_cast(args[1].addr); int cellno = cellno_ptr->GetIntval(); result = qp->ResultStorage( s ); Rectangle<3> *res = (Rectangle<3>*) result.addr; std::vector polyvec = convex3d->getPolyhedronVector(); for(size_t i = 0; i < polyvec.size(); i++) { if(polyvec[i].getPolyId() == cellno) { double min[3], max[3]; Rectangle<3> bbox = createBBox3D(&polyvec[i]); min[0] = bbox.getMinX(); min[1] = bbox.getMinY(); min[2] = bbox.getMinZ(); max[0] = bbox.getMaxX(); max[1] = bbox.getMaxY(); max[2] = bbox.getMaxZ(); res->Set(true, min, max); return 0; } } return -1; } /* Valuemapping function for create 3D-Tree */ int voronoi3dVM( Word* args, Word& result, int message, Word& local, Supplier s ) { Stream> input_rect_ptr(args[0]); result = qp->ResultStorage(s); ((Convex3D*)result.addr)->Set( input_rect_ptr); return 0; } /* 8.3 Specifications */ /* createconvexSpec */ const string createconvexSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( stream(points) x bool -> convex " "_ createconvex " "Creates a convex polygon in form of a point sequence " "starting from the left point in clockwise order." "The input point sequence does not have to be ordered in that way. " "Returns the polygon " "if the input point sequence form a convex polygon. " "Otherwise undef is returned either if the point stream " "does not form a convex polygon or " "any other error occurs. With the bool parameter, you can switch on/off " " the convex test. Be sure that your data form convex polygons when " "you switch it to FALSE. With TRUE the test is enabled " " query Kinos feed head [3] projecttransformstream[GeoData] " "createconvex[TRUE] " ") )"; /* voronoiSpec */ const string voronoiSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( ((stream (tuple (..., (ak1 Tk1),...))) x" " ak1 x ak2 x rect x bool" "-> (stream (tuple (..., (ak1 Tk1),..., " "(ak2 Tk2))))) " "_ voronoi [ list ] " "Expands each tuple of the relation with a convex polygon " " representing the voronoi cell that belongs to the " "centerpoint specified " " with point value Tk1 of the attribute ak1. The complete voronoi " " diagramm is set up with " " all points of ak1 from all tuples, in other words with " "all points of the " " ak1 column of the relation. " "The value of ak2 ist the type convex forming a convex polygon " "representing the voronoi region " "that is corresponding to the point value of ak1. " "The rect paramater specifies a rectangle " " forming the bounding box of the voronoi diagram. If the diagram fits " "in the box the rectangle values are used. The sequence of parameters " "for the rectangle values must be (minx, maxx, miny, maxy). " " If the diagram do not fit in the rectangle box, a default box is used " " derived from the expansion of the voronoi diagram." " With the last parameter you can switch on/off the convex polygon test. " " When TRUE is set the contructed polygons are explicit tested " " if they are convex. Choose FALSE, when you are sure about " "that property and " " you want to leave out the test." " query testrel feed voronoi [p, conv, " "[const rect value (-10 9 2 )], TRUE] " ") )"; /* cellNumSpec */ const string cellNumSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( Stream x rect2 x int" "-> intset " "_ cellnum[ list ] " " Returns all cellnumbers of the created voronoi" " diagram which intersect with the given " " rectangle. " " query cellnum((convtest feed voronoi " " [Punkt, Conv, [const rect value (-10 10 -10 10)], " " FALSE] project[Conv] consume) feed " " projecttransformstream[Conv], " " rectangle2(-1.0, 4.0, 0.0, 2.0), 1) " ") )"; const string smallestCommCellnumSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( Stream x rect2 x rect2 x int" "-> bool " "_ sccvoronoi [ list ] " " Returns true if int equals " " the smallest common cellnumber " " of two rectangles in a voronoi diagram. First " " the voronoi diagram is created as in voronoi(). " " query sccvoronoi((convtest feed voronoi " " [Punkt, Conv, [const rect value (-10 10 -10 10)], FALSE] " " project[Conv] consume) feed projecttransformstream[Conv]," " rectangle2(-1.0, 4.0, 0.0, 2.0), " " rectangle2(5.0, 7.0, -0.5, 0.5), 5) " ") )"; const string getcellvoronoiSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( Stream x int " "-> rectangle<2> " "_ getcellvoro [ ] " "Returns the bbox of a cell to " " the given cellid " " query getcellvoro((convtest feed voronoi " " [Punkt, Conv, [const rect value (-10 10 -10 10)], FALSE] " " project[Conv] consume) feed projecttransformstream[Conv]," " 2 " ") )"; const string voronoi3dSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( stream(rect3) x rect3" "-> (stream (convex3d) " "_ voronoi3d [] " " It calculates the centre of the cuboids " " and builds the voronoi diagram to this set of points. " " Returns a list of cell ids with the number of faces " " belonging to this cell ids." " " " query [const rect3 value(-1 2 -3 6 0 2)] feed voronoi3d [ " "[const rect3 value (-10 10 9 20 2 10)]] " ") )"; const string cellNum3DSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( ((stream (rect3) x rect3" "-> intset " "_ cellnum3d[ list ] " " Returns all cellnumbers of the created voronoi" " diagram which intersect with the given " " cuboid. " " query cellnum3d([const rect3 value(-1 2 -3 6 0 2)]" " feed voronoi3d " " [const rect value (-10 10 -10 10 -10 10)], " " rectangle3(-1.0, 4.0, 0.0, 2.0, 1.0, 2.0)) " ") )"; const string smallestCommCellnum3DSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( ((stream(rect3) x rect3 x rect3 x int" "-> bool " "_ sccvoronoi3d [ list ] " " Returns true if int equals " " the smallest common cellnumber " " of two cuboids in a voronoi diagram. First " " the voronoi diagram is created as in voronoi(). " " query ssc_voronoi3d([const rect3 value(-1 2 -3 6 0 2)]" " feed voronoi3d " " [const rect value (-10 10 -10 10 -10 10)], " " rectangle3(-1.0, 4.0, 0.0, 2.0, 1.0, 2.0), " " rectangle3(-1.0, 2.0, 1.0, 2.0, 1.0, 2.0), 5) " ") )"; const string getcellvoronoi3DSpec = "( ( \"Signature\" \"Syntax\" \"Meaning\" \"Example\" ) " "( Stream x int " "-> rectangle<3> " "_ getcellvoro3d [ ] " "Returns the bbox of a cell to " " the given cellid " " query getcellvoro3d((convtest feed voronoi " " [Punkt, Conv, [const rect value (-10 10 -10 10)], FALSE] " " project[Conv] consume) feed projecttransformstream[Conv]," " 2 " ") )"; /* 10 Registration an initialization */ /* 10.1 Registration of Types */ TypeConstructor Conv3DTC( // name of the type in SECONDO Convex3D:: BasicType(), // property function describing signature Convex3D::PropertyConvex3D, // Out and In functions Convex3D::OutConvex3D, Convex3D::InConvex3D, // SaveToList, RestoreFromList functions 0,0, // object creation and deletion Convex3D::CreateConvex3D, Convex3D::DeleteConvex3D, // object open, save 0, 0, // object close and clone Convex3D::Close, Convex3D::CloneConvex3D, // cast function 0, // sizeof function Convex3D::SizeOfConvex3D, // kind checking function Convex3D::KindCheckConvex3D ); TypeConstructor ConvexTC( Convex::BasicType(), Convex::Property, Convex::Out, Convex::In, 0,0, Convex::Create, Convex::Delete, Convex::Open, Convex::Save, Convex::Close, Convex::Clone, Convex::Cast, Convex::Size, Convex::TypeCheck ); /* 10.2 Operator instances */ Operator createconvex ( "createconvex", createconvexSpec, createconvexVM, Operator::SimpleSelect, createconvextypemap ); Operator voronoi ( "voronoi", voronoiSpec, voronoiVM, Operator::SimpleSelect, voronoitypemap ); Operator cellnum ("cellnum", cellNumSpec, cellNumVM, Operator::SimpleSelect, cellnumvoronoitypemap ); Operator sccvoronoi ("sccvoronoi", smallestCommCellnumSpec, smallestCommonCellnumVM, Operator::SimpleSelect, sccvoronoitypemap ); Operator getcellvoronoi ( "getcellvoronoi", getcellvoronoiSpec, getcellvoronoiVM, Operator::SimpleSelect, getcellvoronoitypemap); Operator voronoi3d ( "voronoi3d", voronoi3dSpec, voronoi3dVM, Operator::SimpleSelect, voronoi3dtypemap ); Operator cellnum3d ("cellnum3d", cellNum3DSpec, cellNum3DVM, Operator::SimpleSelect, cellnumvoronoi3dtypemap ); Operator sccvoronoi3d ("sccvoronoi3d", smallestCommCellnum3DSpec, smallestCommonCellnum3DVM, Operator::SimpleSelect, sccvoronoi3dtypemap ); Operator getcellvoronoi3d ( "getcellvoronoi3d", getcellvoronoi3DSpec, getcellvoronoi3DVM, Operator::SimpleSelect, getcellvoronoi3dtypemap); /* 10.3 Creating the Algebra */ class ConvexAlgebra : public Algebra { public: ConvexAlgebra() : Algebra() /* Registration of Types */ { AddTypeConstructor(&ConvexTC); ConvexTC.AssociateKind(Kind::DATA() ); AddTypeConstructor ( &Conv3DTC ); Conv3DTC.AssociateKind(Kind::SIMPLE() ); /* Registration of operators */ AddOperator( &createconvex); AddOperator( &voronoi); AddOperator( &cellnum); AddOperator( &sccvoronoi); AddOperator( &getcellvoronoi ); AddOperator( &voronoi3d ); AddOperator( &cellnum3d ); AddOperator( &sccvoronoi3d ); AddOperator( &getcellvoronoi3d ); } ~ConvexAlgebra() {}; }; } /* end of namespace */ /* 10.4 Initialization */ extern "C" Algebra* InitializeConvex2Algebra( NestedList* nlRef, QueryProcessor* qpRef ) { nl = nlRef; qp = qpRef; return new convex::ConvexAlgebra; }