Skip to content
Snippets Groups Projects
Commit 14ffb18f authored by Tom Fischer's avatar Tom Fischer
Browse files

[GL] Using OctTree in PointVec.

Substitution of PointVec::makePntsUnique() using an OctTree based impl.
parent 33c6c42c
No related branches found
No related tags found
No related merge requests found
...@@ -33,23 +33,44 @@ PointVec::PointVec (const std::string& name, std::vector<Point*>* points, ...@@ -33,23 +33,44 @@ PointVec::PointVec (const std::string& name, std::vector<Point*>* points,
TemplateVec<Point> (name, points, name_id_map), TemplateVec<Point> (name, points, name_id_map),
_type(type), _type(type),
_aabb(points->begin(), points->end()), _aabb(points->begin(), points->end()),
_rel_eps(rel_eps) _rel_eps(rel_eps*sqrt(MathLib::sqrDist(_aabb.getMinPoint(), _aabb.getMaxPoint()))),
_oct_tree(OctTree<GeoLib::Point, 16>::createOctTree(
_aabb.getMinPoint(), _aabb.getMaxPoint(), _rel_eps))
{ {
assert (_data_vec); assert (_data_vec);
std::size_t const number_of_all_input_pnts (_data_vec->size()); std::size_t const number_of_all_input_pnts(_data_vec->size());
// add all points in the oct tree in order to make them unique
_pnt_id_map.resize(number_of_all_input_pnts);
std::iota(_pnt_id_map.begin(), _pnt_id_map.end(), 0);
GeoLib::Point * ret_pnt(nullptr);
std::size_t cnt(0);
for (std::size_t k(0); k<_data_vec->size(); ++k) {
GeoLib::Point *const pnt((*_data_vec)[k]);
if (! _oct_tree->addPoint(pnt, ret_pnt)) {
_pnt_id_map[pnt->getID()] = ret_pnt->getID();
delete (*_data_vec)[k];
(*_data_vec)[k] = nullptr;
} else {
_pnt_id_map[k] = cnt;
cnt++;
}
}
_rel_eps *= sqrt(MathLib::sqrDist (_aabb.getMinPoint(),_aabb.getMaxPoint())); auto const data_vec_end = std::remove(_data_vec->begin(), _data_vec->end(), nullptr);
makePntsUnique (_data_vec, _pnt_id_map, _rel_eps); _data_vec->erase(data_vec_end, _data_vec->end());
if (number_of_all_input_pnts > _data_vec->size()) if (number_of_all_input_pnts > _data_vec->size())
WARN("PointVec::PointVec(): there are %d double points.", WARN("PointVec::PointVec(): there are %d double points.",
number_of_all_input_pnts - _data_vec->size()); number_of_all_input_pnts - _data_vec->size());
correctNameIDMapping(); correctNameIDMapping();
// create the inverse mapping // create the inverse mapping
_id_to_name_map.resize(_data_vec->size()); _id_to_name_map.resize(_data_vec->size());
// fetch the names from the name id map // fetch the names from the name id map
for (auto p : *_name_id_map) { for (auto p : *_name_id_map) {
if (p.second >= _id_to_name_map.size())
continue;
_id_to_name_map[p.second] = p.first; _id_to_name_map[p.second] = p.first;
} }
} }
...@@ -57,14 +78,14 @@ PointVec::PointVec (const std::string& name, std::vector<Point*>* points, ...@@ -57,14 +78,14 @@ PointVec::PointVec (const std::string& name, std::vector<Point*>* points,
PointVec::~PointVec () PointVec::~PointVec ()
{} {}
std::size_t PointVec::push_back (Point* pnt) std::size_t PointVec::push_back(Point* pnt)
{ {
_pnt_id_map.push_back(uniqueInsert(pnt)); _pnt_id_map.push_back(uniqueInsert(pnt));
_id_to_name_map.push_back(""); _id_to_name_map.push_back("");
return _pnt_id_map[_pnt_id_map.size() - 1]; return _pnt_id_map[_pnt_id_map.size() - 1];
} }
void PointVec::push_back (Point* pnt, std::string const*const name) void PointVec::push_back(Point* pnt, std::string const*const name)
{ {
if (name == nullptr) { if (name == nullptr) {
_pnt_id_map.push_back (uniqueInsert(pnt)); _pnt_id_map.push_back (uniqueInsert(pnt));
...@@ -85,102 +106,36 @@ void PointVec::push_back (Point* pnt, std::string const*const name) ...@@ -85,102 +106,36 @@ void PointVec::push_back (Point* pnt, std::string const*const name)
_id_to_name_map.push_back(*name); _id_to_name_map.push_back(*name);
} }
std::size_t PointVec::uniqueInsert (Point* pnt) std::size_t PointVec::uniqueInsert(Point* pnt)
{
auto const it = std::find_if(_data_vec->begin(), _data_vec->end(),
[this, &pnt](Point* const p)
{
return MathLib::maxNormDist(p, pnt) <= _rel_eps;
});
if (it != _data_vec->end())
{
delete pnt;
pnt = nullptr;
return static_cast<std::size_t>(std::distance(_data_vec->begin(), it));
}
_data_vec->push_back(pnt);
// update bounding box
_aabb.update (*(_data_vec->back()));
return _data_vec->size()-1;
}
void PointVec::makePntsUnique (std::vector<GeoLib::Point*>* pnt_vec,
std::vector<std::size_t> &pnt_id_map, double eps)
{ {
std::size_t const n_pnts_in_file(pnt_vec->size()); GeoLib::Point * ret_pnt(nullptr);
std::vector<std::size_t> perm(n_pnts_in_file); if (_oct_tree->addPoint(pnt, ret_pnt)) {
pnt_id_map.resize(n_pnts_in_file); _data_vec->push_back(pnt);
std::iota(perm.begin(), perm.end(), 0); return _data_vec->size()-1;
std::iota(pnt_id_map.begin(), pnt_id_map.end(), 0);
// sort the points
BaseLib::Quicksort<GeoLib::Point*>(*pnt_vec, 0, n_pnts_in_file, perm);
// unfortunately quicksort is not stable -
// sort identical points by id - to make sorting stable
// determine intervals with identical points to resort for stability of sorting
std::vector<std::size_t> identical_pnts_interval;
bool identical(false);
for (std::size_t k = 0; k < n_pnts_in_file - 1; k++)
{
if (MathLib::maxNormDist((*pnt_vec)[k + 1], (*pnt_vec)[k]) <= eps)
{
// points are identical, sort by id
if (!identical)
identical_pnts_interval.push_back(k);
identical = true;
} else {
if (identical)
identical_pnts_interval.push_back(k + 1);
identical = false;
}
} }
if (identical)
identical_pnts_interval.push_back(n_pnts_in_file);
for (std::size_t i(0); i < identical_pnts_interval.size() / 2; i++) {
// bubble sort by id
std::size_t beg(identical_pnts_interval[2 * i]);
std::size_t end(identical_pnts_interval[2 * i + 1]);
for (std::size_t j(beg); j < end; j++)
for (std::size_t k(beg); k < end - 1; k++)
if (perm[k] > perm[k + 1])
std::swap(perm[k], perm[k + 1]);
}
// check if there are identical points
for (std::size_t k = 0; k < n_pnts_in_file - 1; k++)
if (MathLib::maxNormDist((*pnt_vec)[k + 1], (*pnt_vec)[k]) <= eps)
pnt_id_map[perm[k + 1]] = pnt_id_map[perm[k]];
// reverse permutation
BaseLib::Quicksort<std::size_t, GeoLib::Point*>(perm, 0, n_pnts_in_file, *pnt_vec);
// remove the second, third, ... occurrence from vector if (ret_pnt == nullptr) { // pnt is outside of OctTree object
for (std::size_t k(0); k < n_pnts_in_file; k++) { // update the axis aligned bounding box
if (pnt_id_map[k] < k) { _aabb.update(*pnt);
delete (*pnt_vec)[k]; // recreate the (enlarged) OctTree
(*pnt_vec)[k] = nullptr; _oct_tree.reset(GeoLib::OctTree<GeoLib::Point, 16>::createOctTree(
_aabb.getMinPoint(), _aabb.getMaxPoint(), _rel_eps));
// add all points that are already in the _data_vec
for (std::size_t k(0); k<_data_vec->size(); ++k) {
GeoLib::Point *const p((*_data_vec)[k]);
_oct_tree->addPoint(p, ret_pnt);
} }
// add the new point
ret_pnt = nullptr;
_oct_tree->addPoint(pnt, ret_pnt);
pnt->setID(_data_vec->size());
_data_vec->push_back(pnt);
return _data_vec->size()-1;
} else {
delete pnt;
return ret_pnt->getID();
} }
auto const pnt_vec_end = std::remove(pnt_vec->begin(), pnt_vec->end(), nullptr);
pnt_vec->erase(pnt_vec_end, pnt_vec->end());
// renumber id-mapping
std::size_t id(0);
for (std::size_t k(0); k < n_pnts_in_file; k++) {
if (pnt_id_map[k] == k) { // point not removed, if necessary: id change
pnt_id_map[k] = id;
id++;
} else {
pnt_id_map[k] = pnt_id_map[pnt_id_map[k]];
}
}
} }
void PointVec::correctNameIDMapping() void PointVec::correctNameIDMapping()
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "Station.h" #include "Station.h"
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -25,6 +26,7 @@ ...@@ -25,6 +26,7 @@
#define POINTVEC_H_ #define POINTVEC_H_
#include "TemplateVec.h" #include "TemplateVec.h"
#include "OctTree.h"
namespace GeoLib namespace GeoLib
{ {
...@@ -103,16 +105,6 @@ public: ...@@ -103,16 +105,6 @@ public:
std::string const& getItemNameByID(std::size_t id) const; std::string const& getItemNameByID(std::size_t id) const;
private: private:
/**
* Removes points out of the given point set that have the (nearly) same coordinates, i.e.
* the distance of two points is smaller than eps measured in the maximum norm.
* @param pnt_vec the given set of points stored in a vector
* @param pnt_id_map the id mapping
* @param eps if the distance (measured in maximum norm) between points \f$p_i\f$ and \f$p_j\f$
* is smaller than eps the points \f$p_i\f$ and \f$p_j\f$ are considered as equal.
*/
void makePntsUnique (std::vector<GeoLib::Point*>* pnt_vec, std::vector<std::size_t> &pnt_id_map, double eps = std::numeric_limits<double>::epsilon());
/** /**
* After the point set is modified (for example by makePntsUnique()) the mapping has to be corrected. * After the point set is modified (for example by makePntsUnique()) the mapping has to be corrected.
*/ */
...@@ -146,6 +138,7 @@ private: ...@@ -146,6 +138,7 @@ private:
AABB<GeoLib::Point> _aabb; AABB<GeoLib::Point> _aabb;
double _rel_eps; double _rel_eps;
std::unique_ptr<GeoLib::OctTree<GeoLib::Point, 16>> _oct_tree;
}; };
} // end namespace } // end namespace
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment