diff --git a/GeoLib/AABB.h b/GeoLib/AABB.h index 13291b36e5ef87c5cbee7453994abfee699d13d6..403364e7a0bc4abf81e3d058a4d8626346d73713 100644 --- a/GeoLib/AABB.h +++ b/GeoLib/AABB.h @@ -50,192 +50,192 @@ namespace GeoLib class AABB { public: - /** - * construction of object, initialization the axis aligned bounding box - * @tparam PNT_TYPE a point type supporting accessing the coordinates via - * operator[] - * */ - template <typename PNT_TYPE> - AABB(std::vector<PNT_TYPE*> const& pnts, std::vector<std::size_t> const& ids) - { - assert(! ids.empty()); - init(pnts[ids[0]]); - for (std::size_t i=1; i<ids.size(); ++i) { - updateWithoutEnlarge(*(pnts[ids[i]])); - } - enlarge(); - } - - /** - * copy constructor. - * @param src an axis aligned bounding box - * */ - AABB(AABB const& src) : - _min_pnt(src._min_pnt), _max_pnt(src._max_pnt) - {} - - /** - * Construction of object using input iterators. In contrast to give a vector - * this approach is more generic. You can use every (stl) container and - * C arrays as input for constructing the object. - * @attention{The constructor requires that std::distance(first, last) > 0.} - * @param first the input iterator to the initial position in the sequence - * @param last the input iterator to the final position in a container, i.e. [first, last). - * @attention{The iterator last must be reachable from first.} - */ - template <typename InputIterator> - AABB(InputIterator first, InputIterator last) - { - if (std::distance(first,last) <= 0) - { - ERR("AABB::AABB(InputIterator first, InputIterator last): first > last"); - std::abort(); - } - init(*first); - InputIterator it(first); - while (it != last) { - updateWithoutEnlarge(*it); - it++; - } - enlarge(); - } - - /// Checks if the bounding box has to be updated. - /// @return true if AABB is updated. - template <typename PNT_TYPE> - bool update(PNT_TYPE const & p) - { - // First component of the pair signals if the minimum point is changed - // Second component signals not only if the max point is changed. - // Furthermore it is signaled what coordinate (0,1,2) is changed. - std::pair<bool,std::bitset<3>> updated(0,0); - for (std::size_t k(0); k<3; k++) { - // if the minimum point is updated pair.first==true - if (p[k] < _min_pnt[k]) { - _min_pnt[k] = p[k]; - updated.first = true; - } - // if the kth coordinate of the maximum point is updated - // pair.second[k]==true - if (p[k] >= _max_pnt[k]) { - _max_pnt[k] = p[k]; - updated.second[k] = true; - } - } - - if (updated.second.any()) { - enlarge(updated.second); - return true; - } else if (updated.first) { - return true; - } - return false; - } - - /** - * check if point is in the axis aligned bounding box - */ - template <typename T> - bool containsPoint(T const & pnt) const - { - if (pnt[0] < _min_pnt[0] || _max_pnt[0] <= pnt[0]) return false; - if (pnt[1] < _min_pnt[1] || _max_pnt[1] <= pnt[1]) return false; - if (pnt[2] < _min_pnt[2] || _max_pnt[2] <= pnt[2]) return false; - return true; - } - - /** - * returns a point that coordinates are minimal for each dimension - * for the given point set - * @return a point - */ - MathLib::Point3d const& getMinPoint() const { return _min_pnt; } - - /** - * returns a point that coordinates are maximal for each dimension - * within the given point set - * @return a point - */ - MathLib::Point3d const& getMaxPoint() const { return _max_pnt; } - - /** - * Method checks if the given AABB object is contained within the - * AABB represented by this object. - * @param other_aabb the AABB to test with - * @return true if the other AABB is contained in the AABB - * represented by this object - */ - bool containsAABB(AABB const& other_aabb) const - { - return containsPoint(other_aabb.getMinPoint()) && containsPoint(other_aabb.getMaxPoint()); - } + /** + * construction of object, initialization the axis aligned bounding box + * @tparam PNT_TYPE a point type supporting accessing the coordinates via + * operator[] + * */ + template <typename PNT_TYPE> + AABB(std::vector<PNT_TYPE*> const& pnts, std::vector<std::size_t> const& ids) + { + assert(! ids.empty()); + init(pnts[ids[0]]); + for (std::size_t i=1; i<ids.size(); ++i) { + updateWithoutEnlarge(*(pnts[ids[i]])); + } + enlarge(); + } + + /** + * copy constructor. + * @param src an axis aligned bounding box + * */ + AABB(AABB const& src) : + _min_pnt(src._min_pnt), _max_pnt(src._max_pnt) + {} + + /** + * Construction of object using input iterators. In contrast to give a vector + * this approach is more generic. You can use every (stl) container and + * C arrays as input for constructing the object. + * @attention{The constructor requires that std::distance(first, last) > 0.} + * @param first the input iterator to the initial position in the sequence + * @param last the input iterator to the final position in a container, i.e. [first, last). + * @attention{The iterator last must be reachable from first.} + */ + template <typename InputIterator> + AABB(InputIterator first, InputIterator last) + { + if (std::distance(first,last) <= 0) + { + ERR("AABB::AABB(InputIterator first, InputIterator last): first > last"); + std::abort(); + } + init(*first); + InputIterator it(first); + while (it != last) { + updateWithoutEnlarge(*it); + it++; + } + enlarge(); + } + + /// Checks if the bounding box has to be updated. + /// @return true if AABB is updated. + template <typename PNT_TYPE> + bool update(PNT_TYPE const & p) + { + // First component of the pair signals if the minimum point is changed + // Second component signals not only if the max point is changed. + // Furthermore it is signaled what coordinate (0,1,2) is changed. + std::pair<bool,std::bitset<3>> updated(0,0); + for (std::size_t k(0); k<3; k++) { + // if the minimum point is updated pair.first==true + if (p[k] < _min_pnt[k]) { + _min_pnt[k] = p[k]; + updated.first = true; + } + // if the kth coordinate of the maximum point is updated + // pair.second[k]==true + if (p[k] >= _max_pnt[k]) { + _max_pnt[k] = p[k]; + updated.second[k] = true; + } + } + + if (updated.second.any()) { + enlarge(updated.second); + return true; + } else if (updated.first) { + return true; + } + return false; + } + + /** + * check if point is in the axis aligned bounding box + */ + template <typename T> + bool containsPoint(T const & pnt) const + { + if (pnt[0] < _min_pnt[0] || _max_pnt[0] <= pnt[0]) return false; + if (pnt[1] < _min_pnt[1] || _max_pnt[1] <= pnt[1]) return false; + if (pnt[2] < _min_pnt[2] || _max_pnt[2] <= pnt[2]) return false; + return true; + } + + /** + * returns a point that coordinates are minimal for each dimension + * for the given point set + * @return a point + */ + MathLib::Point3d const& getMinPoint() const { return _min_pnt; } + + /** + * returns a point that coordinates are maximal for each dimension + * within the given point set + * @return a point + */ + MathLib::Point3d const& getMaxPoint() const { return _max_pnt; } + + /** + * Method checks if the given AABB object is contained within the + * AABB represented by this object. + * @param other_aabb the AABB to test with + * @return true if the other AABB is contained in the AABB + * represented by this object + */ + bool containsAABB(AABB const& other_aabb) const + { + return containsPoint(other_aabb.getMinPoint()) && containsPoint(other_aabb.getMaxPoint()); + } protected: - MathLib::Point3d _min_pnt = MathLib::Point3d{std::array<double,3>{{ - std::numeric_limits<double>::max(), - std::numeric_limits<double>::max(), - std::numeric_limits<double>::max()}}}; - MathLib::Point3d _max_pnt = MathLib::Point3d{std::array<double,3>{{ - std::numeric_limits<double>::lowest(), - std::numeric_limits<double>::lowest(), - std::numeric_limits<double>::lowest()}}}; + MathLib::Point3d _min_pnt = MathLib::Point3d{std::array<double,3>{{ + std::numeric_limits<double>::max(), + std::numeric_limits<double>::max(), + std::numeric_limits<double>::max()}}}; + MathLib::Point3d _max_pnt = MathLib::Point3d{std::array<double,3>{{ + std::numeric_limits<double>::lowest(), + std::numeric_limits<double>::lowest(), + std::numeric_limits<double>::lowest()}}}; private: - /// Enlarge the bounding box the smallest possible amount (modifying the - /// unit in the last place). Only the coordinates of the maximum point are - /// changed such that the half-open property will be preserved. - void enlarge(std::bitset<3> to_update = 7) - { - for (std::size_t k=0; k<3; ++k) { - if (to_update[k]) { - _max_pnt[k] = std::nextafter(_max_pnt[k], - std::numeric_limits<double>::max()); - } - } - } - - template <typename PNT_TYPE> - void init(PNT_TYPE const & pnt) - { - _min_pnt[0] = _max_pnt[0] = pnt[0]; - _min_pnt[1] = _max_pnt[1] = pnt[1]; - _min_pnt[2] = _max_pnt[2] = pnt[2]; - } - - template <typename PNT_TYPE> - void init(PNT_TYPE * const & pnt) - { - init(*pnt); - } - - /// Private method that is used internally to update the min and max point - /// of the bounding box using point \f$p\f$ without enlarging the bounding - /// box. Using this method the bounding box of the initial point set is - /// enlarged only once. - /// @param p point that will possibly change the bounding box points - template <typename PNT_TYPE> - void updateWithoutEnlarge(PNT_TYPE const & p) - { - for (std::size_t k(0); k<3; k++) { - if (p[k] < _min_pnt[k]) { - _min_pnt[k] = p[k]; - } - if (p[k] >= _max_pnt[k]) { - _max_pnt[k] = p[k]; - } - } - } - - template <typename PNT_TYPE> - void updateWithoutEnlarge(PNT_TYPE * const & pnt) - { - updateWithoutEnlarge(*pnt); - } - - template <typename PNT_TYPE> - void update(PNT_TYPE const * pnt) - { - update(*pnt); - } + /// Enlarge the bounding box the smallest possible amount (modifying the + /// unit in the last place). Only the coordinates of the maximum point are + /// changed such that the half-open property will be preserved. + void enlarge(std::bitset<3> to_update = 7) + { + for (std::size_t k=0; k<3; ++k) { + if (to_update[k]) { + _max_pnt[k] = std::nextafter(_max_pnt[k], + std::numeric_limits<double>::max()); + } + } + } + + template <typename PNT_TYPE> + void init(PNT_TYPE const & pnt) + { + _min_pnt[0] = _max_pnt[0] = pnt[0]; + _min_pnt[1] = _max_pnt[1] = pnt[1]; + _min_pnt[2] = _max_pnt[2] = pnt[2]; + } + + template <typename PNT_TYPE> + void init(PNT_TYPE * const & pnt) + { + init(*pnt); + } + + /// Private method that is used internally to update the min and max point + /// of the bounding box using point \f$p\f$ without enlarging the bounding + /// box. Using this method the bounding box of the initial point set is + /// enlarged only once. + /// @param p point that will possibly change the bounding box points + template <typename PNT_TYPE> + void updateWithoutEnlarge(PNT_TYPE const & p) + { + for (std::size_t k(0); k<3; k++) { + if (p[k] < _min_pnt[k]) { + _min_pnt[k] = p[k]; + } + if (p[k] >= _max_pnt[k]) { + _max_pnt[k] = p[k]; + } + } + } + + template <typename PNT_TYPE> + void updateWithoutEnlarge(PNT_TYPE * const & pnt) + { + updateWithoutEnlarge(*pnt); + } + + template <typename PNT_TYPE> + void update(PNT_TYPE const * pnt) + { + update(*pnt); + } }; } // end namespace diff --git a/GeoLib/AnalyticalGeometry-impl.h b/GeoLib/AnalyticalGeometry-impl.h index bd1b0a3c5826e70261ab54ea4212f6ac273c18b6..a0e159bbef67fc97de4eea77e006c5f7b1a0c8db 100644 --- a/GeoLib/AnalyticalGeometry-impl.h +++ b/GeoLib/AnalyticalGeometry-impl.h @@ -212,9 +212,9 @@ MathLib::DenseMatrix<double> rotatePointsToXY(InputIterator1 p_pnts_begin, template <typename P> void rotatePoints(MathLib::DenseMatrix<double> const& rot_mat, - std::vector<P*> const& pnts) + std::vector<P*> const& pnts) { - rotatePoints(rot_mat, pnts.begin(), pnts.end()); + rotatePoints(rot_mat, pnts.begin(), pnts.end()); } } // end namespace GeoLib diff --git a/GeoLib/AnalyticalGeometry.cpp b/GeoLib/AnalyticalGeometry.cpp index d930894d390133e35835e84adc86e337061c72ae..59f32375023bea373de55a137ddc5142b0dd7dab 100644 --- a/GeoLib/AnalyticalGeometry.cpp +++ b/GeoLib/AnalyticalGeometry.cpp @@ -30,11 +30,11 @@ extern double orient2d(double *, double *, double *); namespace ExactPredicates { double getOrientation2d(MathLib::Point3d const& a, - MathLib::Point3d const& b, MathLib::Point3d const& c) + MathLib::Point3d const& b, MathLib::Point3d const& c) { - return orient2d(const_cast<double*>(a.getCoords()), - const_cast<double*>(b.getCoords()), - const_cast<double*>(c.getCoords())); + return orient2d(const_cast<double*>(a.getCoords()), + const_cast<double*>(b.getCoords()), + const_cast<double*>(c.getCoords())); } } @@ -43,169 +43,169 @@ namespace GeoLib Orientation getOrientation(const double& p0_x, const double& p0_y, const double& p1_x, const double& p1_y, const double& p2_x, const double& p2_y) { - double h1((p1_x - p0_x) * (p2_y - p0_y)); - double h2((p2_x - p0_x) * (p1_y - p0_y)); + double h1((p1_x - p0_x) * (p2_y - p0_y)); + double h2((p2_x - p0_x) * (p1_y - p0_y)); - double tol(std::numeric_limits<double>::epsilon()); - if (fabs(h1 - h2) <= tol * std::max(fabs(h1), fabs(h2))) - return COLLINEAR; - if (h1 - h2 > 0.0) - return CCW; + double tol(std::numeric_limits<double>::epsilon()); + if (fabs(h1 - h2) <= tol * std::max(fabs(h1), fabs(h2))) + return COLLINEAR; + if (h1 - h2 > 0.0) + return CCW; - return CW; + return CW; } Orientation getOrientation(const GeoLib::Point* p0, const GeoLib::Point* p1, const GeoLib::Point* p2) { - return getOrientation((*p0)[0], (*p0)[1], (*p1)[0], (*p1)[1], (*p2)[0], (*p2)[1]); + return getOrientation((*p0)[0], (*p0)[1], (*p1)[0], (*p1)[1], (*p2)[0], (*p2)[1]); } bool parallel(MathLib::Vector3 v, MathLib::Vector3 w) { - const double eps(std::numeric_limits<double>::epsilon()); - - // check degenerated cases - if (v.getLength() < eps) - return false; - - if (w.getLength() < eps) - return false; - - v.normalize(); - w.normalize(); - - bool parallel(true); - if (std::abs(v[0]-w[0]) > eps) - parallel = false; - if (std::abs(v[1]-w[1]) > eps) - parallel = false; - if (std::abs(v[2]-w[2]) > eps) - parallel = false; - - if (! parallel) { - parallel = true; - // change sense of direction of v_normalised - v *= -1.0; - // check again - if (std::abs(v[0]-w[0]) > eps) - parallel = false; - if (std::abs(v[1]-w[1]) > eps) - parallel = false; - if (std::abs(v[2]-w[2]) > eps) - parallel = false; - } - - return parallel; + const double eps(std::numeric_limits<double>::epsilon()); + + // check degenerated cases + if (v.getLength() < eps) + return false; + + if (w.getLength() < eps) + return false; + + v.normalize(); + w.normalize(); + + bool parallel(true); + if (std::abs(v[0]-w[0]) > eps) + parallel = false; + if (std::abs(v[1]-w[1]) > eps) + parallel = false; + if (std::abs(v[2]-w[2]) > eps) + parallel = false; + + if (! parallel) { + parallel = true; + // change sense of direction of v_normalised + v *= -1.0; + // check again + if (std::abs(v[0]-w[0]) > eps) + parallel = false; + if (std::abs(v[1]-w[1]) > eps) + parallel = false; + if (std::abs(v[2]-w[2]) > eps) + parallel = false; + } + + return parallel; } bool lineSegmentIntersect(GeoLib::LineSegment const& s0, GeoLib::LineSegment const& s1, GeoLib::Point& s) { - GeoLib::Point const& a{s0.getBeginPoint()}; - GeoLib::Point const& b{s0.getEndPoint()}; - GeoLib::Point const& c{s1.getBeginPoint()}; - GeoLib::Point const& d{s1.getEndPoint()}; - - if (!isCoplanar(a, b, c, d)) - return false; - - // handle special cases here to avoid computing intersection numerical - if (MathLib::sqrDist(a, c) < std::numeric_limits<double>::epsilon() || - MathLib::sqrDist(a, d) < std::numeric_limits<double>::epsilon()) { - s = a; - return true; - } - if (MathLib::sqrDist(b, c) < std::numeric_limits<double>::epsilon() || - MathLib::sqrDist(b, d) < std::numeric_limits<double>::epsilon()) { - s = b; - return true; - } - - MathLib::Vector3 const v(a, b); - MathLib::Vector3 const w(c, d); - MathLib::Vector3 const qp(a, c); - MathLib::Vector3 const pq(c, a); - - auto isLineSegmentIntersectingAB = [&v](MathLib::Vector3 const& ap, - std::size_t i) - { - // check if p is located at v=(a,b): (ap = t*v, t in [0,1]) - if (0.0 <= ap[i] / v[i] && ap[i] / v[i] <= 1.0) { - return true; - } - return false; - }; - - if (parallel(v,w)) { // original line segments (a,b) and (c,d) are parallel - if (parallel(pq,v)) { // line segment (a,b) and (a,c) are also parallel - // Here it is already checked that the line segments (a,b) and (c,d) - // are parallel. At this point it is also known that the line - // segment (a,c) is also parallel to (a,b). In that case it is - // possible to express c as c(t) = a + t * (b-a) (analog for the - // point d). Since the evaluation of all three coordinate equations - // (x,y,z) have to lead to the same solution for the parameter t it - // is sufficient to evaluate t only once. - - // Search id of coordinate with largest absolute value which is will - // be used in the subsequent computations. This prevents division by - // zero in case the line segments are parallel to one of the - // coordinate axis. - std::size_t i_max(std::abs(v[0]) <= std::abs(v[1]) ? 1 : 0); - i_max = std::abs(v[i_max]) <= std::abs(v[2]) ? 2 : i_max; - if (isLineSegmentIntersectingAB(qp, i_max)) { - s = c; - return true; - } - MathLib::Vector3 const ad(a, d); - if (isLineSegmentIntersectingAB(ad, i_max)) { - s = d; - return true; - } - return false; - } - return false; - } - - // general case - const double sqr_len_v(v.getSqrLength()); - const double sqr_len_w(w.getSqrLength()); - - MathLib::DenseMatrix<double> mat(2,2); - mat(0,0) = sqr_len_v; - mat(0,1) = -1.0 * MathLib::scalarProduct(v,w); - mat(1,1) = sqr_len_w; - mat(1,0) = mat(0,1); - - double rhs[2] = {MathLib::scalarProduct(v,qp), MathLib::scalarProduct(w,pq)}; - - MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> lu; - lu.solve(mat, rhs, true); - - // no theory for the following tolerances, determined by testing - // lower tolerance: little bit smaller than zero - const double l(-1.0*std::numeric_limits<float>::epsilon()); - // upper tolerance a little bit greater than one - const double u(1.0+std::numeric_limits<float>::epsilon()); - if (rhs[0] < l || u < rhs[0] || rhs[1] < l || u < rhs[1]) { - return false; - } - - // compute points along line segments with minimal distance - GeoLib::Point const p0(a[0]+rhs[0]*v[0], a[1]+rhs[0]*v[1], a[2]+rhs[0]*v[2]); - GeoLib::Point const p1(c[0]+rhs[1]*w[0], c[1]+rhs[1]*w[1], c[2]+rhs[1]*w[2]); - - double const min_dist(sqrt(MathLib::sqrDist(p0, p1))); - double const min_seg_len(std::min(sqrt(sqr_len_v), sqrt(sqr_len_w))); - if (min_dist < min_seg_len * 1e-6) { - s[0] = 0.5 * (p0[0] + p1[0]); - s[1] = 0.5 * (p0[1] + p1[1]); - s[2] = 0.5 * (p0[2] + p1[2]); - return true; - } - - return false; + GeoLib::Point const& a{s0.getBeginPoint()}; + GeoLib::Point const& b{s0.getEndPoint()}; + GeoLib::Point const& c{s1.getBeginPoint()}; + GeoLib::Point const& d{s1.getEndPoint()}; + + if (!isCoplanar(a, b, c, d)) + return false; + + // handle special cases here to avoid computing intersection numerical + if (MathLib::sqrDist(a, c) < std::numeric_limits<double>::epsilon() || + MathLib::sqrDist(a, d) < std::numeric_limits<double>::epsilon()) { + s = a; + return true; + } + if (MathLib::sqrDist(b, c) < std::numeric_limits<double>::epsilon() || + MathLib::sqrDist(b, d) < std::numeric_limits<double>::epsilon()) { + s = b; + return true; + } + + MathLib::Vector3 const v(a, b); + MathLib::Vector3 const w(c, d); + MathLib::Vector3 const qp(a, c); + MathLib::Vector3 const pq(c, a); + + auto isLineSegmentIntersectingAB = [&v](MathLib::Vector3 const& ap, + std::size_t i) + { + // check if p is located at v=(a,b): (ap = t*v, t in [0,1]) + if (0.0 <= ap[i] / v[i] && ap[i] / v[i] <= 1.0) { + return true; + } + return false; + }; + + if (parallel(v,w)) { // original line segments (a,b) and (c,d) are parallel + if (parallel(pq,v)) { // line segment (a,b) and (a,c) are also parallel + // Here it is already checked that the line segments (a,b) and (c,d) + // are parallel. At this point it is also known that the line + // segment (a,c) is also parallel to (a,b). In that case it is + // possible to express c as c(t) = a + t * (b-a) (analog for the + // point d). Since the evaluation of all three coordinate equations + // (x,y,z) have to lead to the same solution for the parameter t it + // is sufficient to evaluate t only once. + + // Search id of coordinate with largest absolute value which is will + // be used in the subsequent computations. This prevents division by + // zero in case the line segments are parallel to one of the + // coordinate axis. + std::size_t i_max(std::abs(v[0]) <= std::abs(v[1]) ? 1 : 0); + i_max = std::abs(v[i_max]) <= std::abs(v[2]) ? 2 : i_max; + if (isLineSegmentIntersectingAB(qp, i_max)) { + s = c; + return true; + } + MathLib::Vector3 const ad(a, d); + if (isLineSegmentIntersectingAB(ad, i_max)) { + s = d; + return true; + } + return false; + } + return false; + } + + // general case + const double sqr_len_v(v.getSqrLength()); + const double sqr_len_w(w.getSqrLength()); + + MathLib::DenseMatrix<double> mat(2,2); + mat(0,0) = sqr_len_v; + mat(0,1) = -1.0 * MathLib::scalarProduct(v,w); + mat(1,1) = sqr_len_w; + mat(1,0) = mat(0,1); + + double rhs[2] = {MathLib::scalarProduct(v,qp), MathLib::scalarProduct(w,pq)}; + + MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> lu; + lu.solve(mat, rhs, true); + + // no theory for the following tolerances, determined by testing + // lower tolerance: little bit smaller than zero + const double l(-1.0*std::numeric_limits<float>::epsilon()); + // upper tolerance a little bit greater than one + const double u(1.0+std::numeric_limits<float>::epsilon()); + if (rhs[0] < l || u < rhs[0] || rhs[1] < l || u < rhs[1]) { + return false; + } + + // compute points along line segments with minimal distance + GeoLib::Point const p0(a[0]+rhs[0]*v[0], a[1]+rhs[0]*v[1], a[2]+rhs[0]*v[2]); + GeoLib::Point const p1(c[0]+rhs[1]*w[0], c[1]+rhs[1]*w[1], c[2]+rhs[1]*w[2]); + + double const min_dist(sqrt(MathLib::sqrDist(p0, p1))); + double const min_seg_len(std::min(sqrt(sqr_len_v), sqrt(sqr_len_w))); + if (min_dist < min_seg_len * 1e-6) { + s[0] = 0.5 * (p0[0] + p1[0]); + s[1] = 0.5 * (p0[1] + p1[1]); + s[2] = 0.5 * (p0[2] + p1[2]); + return true; + } + + return false; } bool lineSegmentsIntersect(const GeoLib::Polyline* ply, @@ -213,24 +213,24 @@ bool lineSegmentsIntersect(const GeoLib::Polyline* ply, GeoLib::Polyline::SegmentIterator &seg_it1, GeoLib::Point& intersection_pnt) { - std::size_t const n_segs(ply->getNumberOfSegments()); - // Neighbouring segments always intersects at a common vertex. The algorithm - // checks for intersections of non-neighbouring segments. - for (seg_it0 = ply->begin(); seg_it0 != ply->end() - 2; ++seg_it0) - { - seg_it1 = seg_it0+2; - std::size_t const seg_num_0 = seg_it0.getSegmentNumber(); - for ( ; seg_it1 != ply->end(); ++seg_it1) { - // Do not check first and last segment, because they are - // neighboured. - if (!(seg_num_0 == 0 && seg_it1.getSegmentNumber() == n_segs - 1)) { - if (lineSegmentIntersect(*seg_it0, *seg_it1, intersection_pnt)) { - return true; - } - } - } - } - return false; + std::size_t const n_segs(ply->getNumberOfSegments()); + // Neighbouring segments always intersects at a common vertex. The algorithm + // checks for intersections of non-neighbouring segments. + for (seg_it0 = ply->begin(); seg_it0 != ply->end() - 2; ++seg_it0) + { + seg_it1 = seg_it0+2; + std::size_t const seg_num_0 = seg_it0.getSegmentNumber(); + for ( ; seg_it1 != ply->end(); ++seg_it1) { + // Do not check first and last segment, because they are + // neighboured. + if (!(seg_num_0 == 0 && seg_it1.getSegmentNumber() == n_segs - 1)) { + if (lineSegmentIntersect(*seg_it0, *seg_it1, intersection_pnt)) { + return true; + } + } + } + } + return false; } bool isPointInTriangle(MathLib::Point3d const& p, @@ -241,16 +241,16 @@ bool isPointInTriangle(MathLib::Point3d const& p, double eps_pnt_out_of_tri, GeoLib::TriangleTest algorithm) { - switch (algorithm) - { - case GeoLib::GAUSS: - return gaussPointInTriangle(p, a, b, c, eps_pnt_out_of_plane, eps_pnt_out_of_tri); - case GeoLib::BARYCENTRIC: - return barycentricPointInTriangle(p, a, b, c, eps_pnt_out_of_plane, eps_pnt_out_of_tri); - default: - ERR ("Selected algorithm for point in triangle testing not found, falling back on default."); - } - return gaussPointInTriangle(p, a, b, c, eps_pnt_out_of_plane, eps_pnt_out_of_tri); + switch (algorithm) + { + case GeoLib::GAUSS: + return gaussPointInTriangle(p, a, b, c, eps_pnt_out_of_plane, eps_pnt_out_of_tri); + case GeoLib::BARYCENTRIC: + return barycentricPointInTriangle(p, a, b, c, eps_pnt_out_of_plane, eps_pnt_out_of_tri); + default: + ERR ("Selected algorithm for point in triangle testing not found, falling back on default."); + } + return gaussPointInTriangle(p, a, b, c, eps_pnt_out_of_plane, eps_pnt_out_of_tri); } bool gaussPointInTriangle(MathLib::Point3d const& q, @@ -260,37 +260,37 @@ bool gaussPointInTriangle(MathLib::Point3d const& q, double eps_pnt_out_of_plane, double eps_pnt_out_of_tri) { - MathLib::Vector3 const v(a, b); - MathLib::Vector3 const w(a, c); - - MathLib::DenseMatrix<double> mat (2,2); - mat(0,0) = v.getSqrLength(); - mat(0,1) = v[0]*w[0] + v[1]*w[1] + v[2]*w[2]; - mat(1,0) = mat(0,1); - mat(1,1) = w.getSqrLength(); - double y[2] = { - v[0] * (q[0] - a[0]) + v[1] * (q[1] - a[1]) + v[2] * (q[2] - a[2]), - w[0] * (q[0] - a[0]) + w[1] * (q[1] - a[1]) + w[2] * (q[2] - a[2]) - }; - - MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> gauss; - gauss.solve(mat, y); - - const double lower (eps_pnt_out_of_tri); - const double upper (1 + lower); - - if (-lower <= y[0] && y[0] <= upper && -lower <= y[1] && y[1] <= upper && y[0] + y[1] <= - upper) { - MathLib::Point3d const q_projected(std::array<double,3>{{ - a[0] + y[0] * v[0] + y[1] * w[0], - a[1] + y[0] * v[1] + y[1] * w[1], - a[2] + y[0] * v[2] + y[1] * w[2] - }}); - if (MathLib::sqrDist(q, q_projected) <= eps_pnt_out_of_plane) - return true; - } - - return false; + MathLib::Vector3 const v(a, b); + MathLib::Vector3 const w(a, c); + + MathLib::DenseMatrix<double> mat (2,2); + mat(0,0) = v.getSqrLength(); + mat(0,1) = v[0]*w[0] + v[1]*w[1] + v[2]*w[2]; + mat(1,0) = mat(0,1); + mat(1,1) = w.getSqrLength(); + double y[2] = { + v[0] * (q[0] - a[0]) + v[1] * (q[1] - a[1]) + v[2] * (q[2] - a[2]), + w[0] * (q[0] - a[0]) + w[1] * (q[1] - a[1]) + w[2] * (q[2] - a[2]) + }; + + MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> gauss; + gauss.solve(mat, y); + + const double lower (eps_pnt_out_of_tri); + const double upper (1 + lower); + + if (-lower <= y[0] && y[0] <= upper && -lower <= y[1] && y[1] <= upper && y[0] + y[1] <= + upper) { + MathLib::Point3d const q_projected(std::array<double,3>{{ + a[0] + y[0] * v[0] + y[1] * w[0], + a[1] + y[0] * v[1] + y[1] * w[1], + a[2] + y[0] * v[2] + y[1] * w[2] + }}); + if (MathLib::sqrDist(q, q_projected) <= eps_pnt_out_of_plane) + return true; + } + + return false; } bool barycentricPointInTriangle(MathLib::Point3d const& p, @@ -300,29 +300,29 @@ bool barycentricPointInTriangle(MathLib::Point3d const& p, double eps_pnt_out_of_plane, double eps_pnt_out_of_tri) { - if (std::abs(orientation3d(p, a, b, c)) > eps_pnt_out_of_plane) - return false; - - MathLib::Vector3 const pa (p,a); - MathLib::Vector3 const pb (p,b); - MathLib::Vector3 const pc (p,c); - double const area_x_2 (calcTriangleArea(a,b,c) * 2); - - double const alpha ((MathLib::crossProduct(pb,pc).getLength()) / area_x_2); - if (alpha < -eps_pnt_out_of_tri || alpha > 1+eps_pnt_out_of_tri) - return false; - double const beta ((MathLib::crossProduct(pc,pa).getLength()) / area_x_2); - if (beta < -eps_pnt_out_of_tri || beta > 1+eps_pnt_out_of_tri) - return false; - double const gamma (1 - alpha - beta); - if (gamma < -eps_pnt_out_of_tri || gamma > 1+eps_pnt_out_of_tri) - return false; - return true; + if (std::abs(orientation3d(p, a, b, c)) > eps_pnt_out_of_plane) + return false; + + MathLib::Vector3 const pa (p,a); + MathLib::Vector3 const pb (p,b); + MathLib::Vector3 const pc (p,c); + double const area_x_2 (calcTriangleArea(a,b,c) * 2); + + double const alpha ((MathLib::crossProduct(pb,pc).getLength()) / area_x_2); + if (alpha < -eps_pnt_out_of_tri || alpha > 1+eps_pnt_out_of_tri) + return false; + double const beta ((MathLib::crossProduct(pc,pa).getLength()) / area_x_2); + if (beta < -eps_pnt_out_of_tri || beta > 1+eps_pnt_out_of_tri) + return false; + double const gamma (1 - alpha - beta); + if (gamma < -eps_pnt_out_of_tri || gamma > 1+eps_pnt_out_of_tri) + return false; + return true; } bool isPointInTetrahedron(MathLib::Point3d const& p, - MathLib::Point3d const& a, MathLib::Point3d const& b, - MathLib::Point3d const& c, MathLib::Point3d const& d, double eps) + MathLib::Point3d const& a, MathLib::Point3d const& b, + MathLib::Point3d const& c, MathLib::Point3d const& d, double eps) { double const d0 (orientation3d(d,a,b,c)); // if tetrahedron is not coplanar @@ -353,74 +353,74 @@ bool isPointInTetrahedron(MathLib::Point3d const& p, double calcTriangleArea(MathLib::Point3d const& a, MathLib::Point3d const& b, MathLib::Point3d const& c) { - MathLib::Vector3 const u(a,c); - MathLib::Vector3 const v(a,b); - MathLib::Vector3 const w(MathLib::crossProduct(u, v)); - return 0.5 * w.getLength(); + MathLib::Vector3 const u(a,c); + MathLib::Vector3 const v(a,b); + MathLib::Vector3 const w(MathLib::crossProduct(u, v)); + return 0.5 * w.getLength(); } double calcTetrahedronVolume(MathLib::Point3d const& x1, - MathLib::Point3d const& x2, - MathLib::Point3d const& x3, - MathLib::Point3d const& x4) + MathLib::Point3d const& x2, + MathLib::Point3d const& x3, + MathLib::Point3d const& x4) { - const MathLib::Vector3 ab(x1, x2); - const MathLib::Vector3 ac(x1, x3); - const MathLib::Vector3 ad(x1, x4); - return std::abs(GeoLib::scalarTriple(ac, ad, ab)) / 6.0; + const MathLib::Vector3 ab(x1, x2); + const MathLib::Vector3 ac(x1, x3); + const MathLib::Vector3 ad(x1, x4); + return std::abs(GeoLib::scalarTriple(ac, ad, ab)) / 6.0; } void computeRotationMatrixToXZ(MathLib::Vector3 const& plane_normal, MathLib::DenseMatrix<double> & rot_mat) { - // *** some frequently used terms *** - // n_1^2 + n_2^2 - const double h0(plane_normal[0] * plane_normal[0] + plane_normal[1] * plane_normal[1]); - // 1 / sqrt (n_1^2 + n_2^2) - const double h1(1.0 / sqrt(h0)); - // 1 / sqrt (n_1^2 + n_2^2 + n_3^2) - const double h2(1.0 / sqrt(h0 + plane_normal[2] * plane_normal[2])); - - // calc rotation matrix - rot_mat(0, 0) = plane_normal[1] * h1; - rot_mat(0, 1) = -plane_normal[0] * h1; - rot_mat(0, 2) = 0.0; - rot_mat(1, 0) = plane_normal[0] * h2; - rot_mat(1, 1) = plane_normal[1] * h2; - rot_mat(1, 2) = plane_normal[2] * h2; - rot_mat(2, 0) = plane_normal[0] * plane_normal[2] * h1 * h2; - rot_mat(2, 1) = plane_normal[1] * plane_normal[2] * h1 * h2; - rot_mat(2, 2) = -sqrt(h0) * h2; + // *** some frequently used terms *** + // n_1^2 + n_2^2 + const double h0(plane_normal[0] * plane_normal[0] + plane_normal[1] * plane_normal[1]); + // 1 / sqrt (n_1^2 + n_2^2) + const double h1(1.0 / sqrt(h0)); + // 1 / sqrt (n_1^2 + n_2^2 + n_3^2) + const double h2(1.0 / sqrt(h0 + plane_normal[2] * plane_normal[2])); + + // calc rotation matrix + rot_mat(0, 0) = plane_normal[1] * h1; + rot_mat(0, 1) = -plane_normal[0] * h1; + rot_mat(0, 2) = 0.0; + rot_mat(1, 0) = plane_normal[0] * h2; + rot_mat(1, 1) = plane_normal[1] * h2; + rot_mat(1, 2) = plane_normal[2] * h2; + rot_mat(2, 0) = plane_normal[0] * plane_normal[2] * h1 * h2; + rot_mat(2, 1) = plane_normal[1] * plane_normal[2] * h1 * h2; + rot_mat(2, 2) = -sqrt(h0) * h2; } void rotatePoints(MathLib::DenseMatrix<double> const& rot_mat, std::vector<GeoLib::Point*> &pnts) { - rotatePoints(rot_mat, pnts.begin(), pnts.end()); + rotatePoints(rot_mat, pnts.begin(), pnts.end()); } MathLib::DenseMatrix<double> rotatePointsToXY(std::vector<GeoLib::Point*>& pnts) { - return rotatePointsToXY(pnts.begin(), pnts.end(), pnts.begin(), pnts.end()); + return rotatePointsToXY(pnts.begin(), pnts.end(), pnts.begin(), pnts.end()); } void rotatePointsToXZ(std::vector<GeoLib::Point*> &pnts) { - assert(pnts.size()>2); - // calculate supporting plane - MathLib::Vector3 plane_normal; - double d; - // compute the plane normal - GeoLib::getNewellPlane(pnts, plane_normal, d); - - const double tol (std::numeric_limits<double>::epsilon()); - if (std::abs(plane_normal[0]) > tol || std::abs(plane_normal[1]) > tol) { - // rotate copied points into x-z-plane - MathLib::DenseMatrix<double> rot_mat(3, 3); - computeRotationMatrixToXZ(plane_normal, rot_mat); - rotatePoints(rot_mat, pnts); - } - - for (std::size_t k(0); k<pnts.size(); k++) - (*(pnts[k]))[1] = 0.0; // should be -= d but there are numerical errors + assert(pnts.size()>2); + // calculate supporting plane + MathLib::Vector3 plane_normal; + double d; + // compute the plane normal + GeoLib::getNewellPlane(pnts, plane_normal, d); + + const double tol (std::numeric_limits<double>::epsilon()); + if (std::abs(plane_normal[0]) > tol || std::abs(plane_normal[1]) > tol) { + // rotate copied points into x-z-plane + MathLib::DenseMatrix<double> rot_mat(3, 3); + computeRotationMatrixToXZ(plane_normal, rot_mat); + rotatePoints(rot_mat, pnts); + } + + for (std::size_t k(0); k<pnts.size(); k++) + (*(pnts[k]))[1] = 0.0; // should be -= d but there are numerical errors } std::unique_ptr<GeoLib::Point> triangleLineIntersection( @@ -428,32 +428,32 @@ std::unique_ptr<GeoLib::Point> triangleLineIntersection( MathLib::Point3d const& c, MathLib::Point3d const& p, MathLib::Point3d const& q) { - const MathLib::Vector3 pq(p, q); - const MathLib::Vector3 pa(p, a); - const MathLib::Vector3 pb(p, b); - const MathLib::Vector3 pc(p, c); - - double u (scalarTriple(pq, pc, pb)); - if (u<0) return nullptr; - double v (scalarTriple(pq, pa, pc)); - if (v<0) return nullptr; - double w (scalarTriple(pq, pb, pa)); - if (w<0) return nullptr; - - const double denom (1.0/(u+v+w)); - u*=denom; - v*=denom; - w*=denom; - return std::unique_ptr<GeoLib::Point>{ - new GeoLib::Point(u * a[0] + v * b[0] + w * c[0], - u * a[1] + v * b[1] + w * c[1], - u * a[2] + v * b[2] + w * c[2])}; + const MathLib::Vector3 pq(p, q); + const MathLib::Vector3 pa(p, a); + const MathLib::Vector3 pb(p, b); + const MathLib::Vector3 pc(p, c); + + double u (scalarTriple(pq, pc, pb)); + if (u<0) return nullptr; + double v (scalarTriple(pq, pa, pc)); + if (v<0) return nullptr; + double w (scalarTriple(pq, pb, pa)); + if (w<0) return nullptr; + + const double denom (1.0/(u+v+w)); + u*=denom; + v*=denom; + w*=denom; + return std::unique_ptr<GeoLib::Point>{ + new GeoLib::Point(u * a[0] + v * b[0] + w * c[0], + u * a[1] + v * b[1] + w * c[1], + u * a[2] + v * b[2] + w * c[2])}; } double scalarTriple(MathLib::Vector3 const& u, MathLib::Vector3 const& v, MathLib::Vector3 const& w) { - MathLib::Vector3 const cross(MathLib::crossProduct(u, v)); - return MathLib::scalarProduct(cross,w); + MathLib::Vector3 const cross(MathLib::crossProduct(u, v)); + return MathLib::scalarProduct(cross,w); } double orientation3d(MathLib::Point3d const& p, @@ -468,177 +468,177 @@ double orientation3d(MathLib::Point3d const& p, } bool dividedByPlane(const MathLib::Point3d& a, const MathLib::Point3d& b, - const MathLib::Point3d& c, const MathLib::Point3d& d) + const MathLib::Point3d& c, const MathLib::Point3d& d) { - for (unsigned x=0; x<3; ++x) - { - const unsigned y=(x+1)%3; - const double abc = (b[x] - a[x])*(c[y] - a[y]) - (b[y] - a[y])*(c[x] - a[x]); - const double abd = (b[x] - a[x])*(d[y] - a[y]) - (b[y] - a[y])*(d[x] - a[x]); - - if ((abc>0 && abd<0) || (abc<0 && abd>0)) - return true; - } - return false; + for (unsigned x=0; x<3; ++x) + { + const unsigned y=(x+1)%3; + const double abc = (b[x] - a[x])*(c[y] - a[y]) - (b[y] - a[y])*(c[x] - a[x]); + const double abd = (b[x] - a[x])*(d[y] - a[y]) - (b[y] - a[y])*(d[x] - a[x]); + + if ((abc>0 && abd<0) || (abc<0 && abd>0)) + return true; + } + return false; } bool isCoplanar(const MathLib::Point3d& a, const MathLib::Point3d& b, - const MathLib::Point3d& c, const MathLib::Point3d& d) + const MathLib::Point3d& c, const MathLib::Point3d& d) { - const MathLib::Vector3 ab(a,b); - const MathLib::Vector3 ac(a,c); - const MathLib::Vector3 ad(a,d); - - if (ab.getSqrLength() < pow(std::numeric_limits<double>::epsilon(),2) || - ac.getSqrLength() < pow(std::numeric_limits<double>::epsilon(),2) || - ad.getSqrLength() < pow(std::numeric_limits<double>::epsilon(),2)) { - return true; - } - - // In exact arithmetic <ac*ad^T, ab> should be zero - // if all four points are coplanar. - const double sqr_scalar_triple(pow(MathLib::scalarProduct(MathLib::crossProduct(ac,ad), ab),2)); - // Due to evaluating the above numerically some cancellation or rounding - // can occur. For this reason a normalisation factor is introduced. - const double normalisation_factor = - (ab.getSqrLength() * ac.getSqrLength() * ad.getSqrLength()); - - // tolerance 1e-11 is choosen such that - // a = (0,0,0), b=(1,0,0), c=(0,1,0) and d=(1,1,1e-6) are considered as coplanar - // a = (0,0,0), b=(1,0,0), c=(0,1,0) and d=(1,1,1e-5) are considered as not coplanar - return (sqr_scalar_triple/normalisation_factor < 1e-11); + const MathLib::Vector3 ab(a,b); + const MathLib::Vector3 ac(a,c); + const MathLib::Vector3 ad(a,d); + + if (ab.getSqrLength() < pow(std::numeric_limits<double>::epsilon(),2) || + ac.getSqrLength() < pow(std::numeric_limits<double>::epsilon(),2) || + ad.getSqrLength() < pow(std::numeric_limits<double>::epsilon(),2)) { + return true; + } + + // In exact arithmetic <ac*ad^T, ab> should be zero + // if all four points are coplanar. + const double sqr_scalar_triple(pow(MathLib::scalarProduct(MathLib::crossProduct(ac,ad), ab),2)); + // Due to evaluating the above numerically some cancellation or rounding + // can occur. For this reason a normalisation factor is introduced. + const double normalisation_factor = + (ab.getSqrLength() * ac.getSqrLength() * ad.getSqrLength()); + + // tolerance 1e-11 is choosen such that + // a = (0,0,0), b=(1,0,0), c=(0,1,0) and d=(1,1,1e-6) are considered as coplanar + // a = (0,0,0), b=(1,0,0), c=(0,1,0) and d=(1,1,1e-5) are considered as not coplanar + return (sqr_scalar_triple/normalisation_factor < 1e-11); } void computeAndInsertAllIntersectionPoints(GeoLib::PointVec &pnt_vec, - std::vector<GeoLib::Polyline*> & plys) + std::vector<GeoLib::Polyline*> & plys) { - auto computeSegmentIntersections = [&pnt_vec](GeoLib::Polyline& poly0, - GeoLib::Polyline& poly1) - { - for (auto seg0_it(poly0.begin()); seg0_it != poly0.end(); ++seg0_it) - { - for (auto seg1_it(poly1.begin()); seg1_it != poly1.end(); ++seg1_it) - { - GeoLib::Point s(0.0, 0.0, 0.0, pnt_vec.size()); - if (lineSegmentIntersect(*seg0_it, *seg1_it, s)) - { - std::size_t const id( - pnt_vec.push_back(new GeoLib::Point(s))); - poly0.insertPoint(seg0_it.getSegmentNumber() + 1, id); - poly1.insertPoint(seg1_it.getSegmentNumber() + 1, id); - } - } - } - }; - - for (auto it0(plys.begin()); it0 != plys.end(); ++it0) { - auto it1(it0); - ++it1; - for (; it1 != plys.end(); ++it1) { - computeSegmentIntersections(*(*it0), *(*it1)); - } - } + auto computeSegmentIntersections = [&pnt_vec](GeoLib::Polyline& poly0, + GeoLib::Polyline& poly1) + { + for (auto seg0_it(poly0.begin()); seg0_it != poly0.end(); ++seg0_it) + { + for (auto seg1_it(poly1.begin()); seg1_it != poly1.end(); ++seg1_it) + { + GeoLib::Point s(0.0, 0.0, 0.0, pnt_vec.size()); + if (lineSegmentIntersect(*seg0_it, *seg1_it, s)) + { + std::size_t const id( + pnt_vec.push_back(new GeoLib::Point(s))); + poly0.insertPoint(seg0_it.getSegmentNumber() + 1, id); + poly1.insertPoint(seg1_it.getSegmentNumber() + 1, id); + } + } + } + }; + + for (auto it0(plys.begin()); it0 != plys.end(); ++it0) { + auto it1(it0); + ++it1; + for (; it1 != plys.end(); ++it1) { + computeSegmentIntersections(*(*it0), *(*it1)); + } + } } GeoLib::Polygon rotatePolygonToXY(GeoLib::Polygon const& polygon_in, - MathLib::Vector3 & plane_normal) + MathLib::Vector3 & plane_normal) { - // 1 copy all points - std::vector<GeoLib::Point*> *polygon_pnts(new std::vector<GeoLib::Point*>); - for (std::size_t k(0); k < polygon_in.getNumberOfPoints(); k++) - polygon_pnts->push_back (new GeoLib::Point (*(polygon_in.getPoint(k)))); - - // 2 rotate points - double d_polygon (0.0); - GeoLib::getNewellPlane (*polygon_pnts, plane_normal, d_polygon); - MathLib::DenseMatrix<double> rot_mat(3,3); - GeoLib::computeRotationMatrixToXY(plane_normal, rot_mat); - GeoLib::rotatePoints(rot_mat, *polygon_pnts); - - // 3 set z coord to zero - std::for_each(polygon_pnts->begin(), polygon_pnts->end(), - [] (GeoLib::Point* p) { (*p)[2] = 0.0; } - ); - - // 4 create new polygon - GeoLib::Polyline rot_polyline(*polygon_pnts); - for (std::size_t k(0); k < polygon_in.getNumberOfPoints(); k++) - rot_polyline.addPoint(k); - rot_polyline.addPoint(0); - return GeoLib::Polygon(rot_polyline); + // 1 copy all points + std::vector<GeoLib::Point*> *polygon_pnts(new std::vector<GeoLib::Point*>); + for (std::size_t k(0); k < polygon_in.getNumberOfPoints(); k++) + polygon_pnts->push_back (new GeoLib::Point (*(polygon_in.getPoint(k)))); + + // 2 rotate points + double d_polygon (0.0); + GeoLib::getNewellPlane (*polygon_pnts, plane_normal, d_polygon); + MathLib::DenseMatrix<double> rot_mat(3,3); + GeoLib::computeRotationMatrixToXY(plane_normal, rot_mat); + GeoLib::rotatePoints(rot_mat, *polygon_pnts); + + // 3 set z coord to zero + std::for_each(polygon_pnts->begin(), polygon_pnts->end(), + [] (GeoLib::Point* p) { (*p)[2] = 0.0; } + ); + + // 4 create new polygon + GeoLib::Polyline rot_polyline(*polygon_pnts); + for (std::size_t k(0); k < polygon_in.getNumberOfPoints(); k++) + rot_polyline.addPoint(k); + rot_polyline.addPoint(0); + return GeoLib::Polygon(rot_polyline); } std::vector<MathLib::Point3d> lineSegmentIntersect2d(MathLib::Point3d const& a, MathLib::Point3d const& b, - MathLib::Point3d const& c, MathLib::Point3d const& d) + MathLib::Point3d const& c, MathLib::Point3d const& d) { - double const orient_abc(ExactPredicates::getOrientation2d(a, b, c)); - double const orient_abd(ExactPredicates::getOrientation2d(a, b, d)); - - // check if the segment (cd) lies on the left or on the right of (ab) - if ((orient_abc > 0 && orient_abd > 0) || (orient_abc < 0 && orient_abd < 0)) { - return std::vector<MathLib::Point3d>(); - } - - // check: (cd) and (ab) are on the same line - if (orient_abc == 0.0 && orient_abd == 0.0) { - double const eps(std::numeric_limits<double>::epsilon()); - if (MathLib::sqrDist(a,c) < eps && MathLib::sqrDist(b,d) < eps) - return {{ a, b }}; - if (MathLib::sqrDist(a,d) < eps && MathLib::sqrDist(b,c) < eps) - return {{ a, b }}; - ERR("This case of collinear points is not handled yet. Aborting."); - std::abort(); - } - - auto isCollinearPointOntoLineSegment = [](MathLib::Point3d const& a, - MathLib::Point3d const& b, MathLib::Point3d const& c) - { - double const t((c[0]-a[0])/(b[0]-a[0])); - if (0.0 <= t && t <= 1.0) - return true; - return false; - }; - - if (orient_abc == 0.0) { - if (isCollinearPointOntoLineSegment(a,b,c)) - return {{c}}; - return std::vector<MathLib::Point3d>(); - } - - if (orient_abd == 0.0) { - if (isCollinearPointOntoLineSegment(a,b,d)) - return {{d}}; - return std::vector<MathLib::Point3d>(); - } - - // check if the segment (ab) lies on the left or on the right of (cd) - double const orient_cda(ExactPredicates::getOrientation2d(c, d, a)); - double const orient_cdb(ExactPredicates::getOrientation2d(c, d, b)); - if ((orient_cda > 0 && orient_cdb > 0) || (orient_cda < 0 && orient_cdb < 0)) { - return std::vector<MathLib::Point3d>(); - } - - // at this point it is sure that there is an intersection and the system of - // linear equations will be invertible - // solve the two linear equations (b-a, c-d) (t, s)^T = (c-a) simultaneously - MathLib::DenseMatrix<double, std::size_t> mat(2,2); - mat(0,0) = b[0]-a[0]; - mat(0,1) = c[0]-d[0]; - mat(1,0) = b[1]-a[1]; - mat(1,1) = c[1]-d[1]; - std::vector<double> rhs = {{c[0]-a[0], c[1]-a[1]}}; - - MathLib::GaussAlgorithm< - MathLib::DenseMatrix<double, std::size_t>, std::vector<double>> solver; - solver.solve(mat, rhs); - if (0 <= rhs[1] && rhs[1] <= 1.0) { - return { MathLib::Point3d{std::array<double,3>{{ - c[0]+rhs[1]*(d[0]-c[0]), c[1]+rhs[1]*(d[1]-c[1]), - c[2]+rhs[1]*(d[2]-c[2])}} } }; - } else { - return std::vector<MathLib::Point3d>(); // parameter s not in the valid range - } + double const orient_abc(ExactPredicates::getOrientation2d(a, b, c)); + double const orient_abd(ExactPredicates::getOrientation2d(a, b, d)); + + // check if the segment (cd) lies on the left or on the right of (ab) + if ((orient_abc > 0 && orient_abd > 0) || (orient_abc < 0 && orient_abd < 0)) { + return std::vector<MathLib::Point3d>(); + } + + // check: (cd) and (ab) are on the same line + if (orient_abc == 0.0 && orient_abd == 0.0) { + double const eps(std::numeric_limits<double>::epsilon()); + if (MathLib::sqrDist(a,c) < eps && MathLib::sqrDist(b,d) < eps) + return {{ a, b }}; + if (MathLib::sqrDist(a,d) < eps && MathLib::sqrDist(b,c) < eps) + return {{ a, b }}; + ERR("This case of collinear points is not handled yet. Aborting."); + std::abort(); + } + + auto isCollinearPointOntoLineSegment = [](MathLib::Point3d const& a, + MathLib::Point3d const& b, MathLib::Point3d const& c) + { + double const t((c[0]-a[0])/(b[0]-a[0])); + if (0.0 <= t && t <= 1.0) + return true; + return false; + }; + + if (orient_abc == 0.0) { + if (isCollinearPointOntoLineSegment(a,b,c)) + return {{c}}; + return std::vector<MathLib::Point3d>(); + } + + if (orient_abd == 0.0) { + if (isCollinearPointOntoLineSegment(a,b,d)) + return {{d}}; + return std::vector<MathLib::Point3d>(); + } + + // check if the segment (ab) lies on the left or on the right of (cd) + double const orient_cda(ExactPredicates::getOrientation2d(c, d, a)); + double const orient_cdb(ExactPredicates::getOrientation2d(c, d, b)); + if ((orient_cda > 0 && orient_cdb > 0) || (orient_cda < 0 && orient_cdb < 0)) { + return std::vector<MathLib::Point3d>(); + } + + // at this point it is sure that there is an intersection and the system of + // linear equations will be invertible + // solve the two linear equations (b-a, c-d) (t, s)^T = (c-a) simultaneously + MathLib::DenseMatrix<double, std::size_t> mat(2,2); + mat(0,0) = b[0]-a[0]; + mat(0,1) = c[0]-d[0]; + mat(1,0) = b[1]-a[1]; + mat(1,1) = c[1]-d[1]; + std::vector<double> rhs = {{c[0]-a[0], c[1]-a[1]}}; + + MathLib::GaussAlgorithm< + MathLib::DenseMatrix<double, std::size_t>, std::vector<double>> solver; + solver.solve(mat, rhs); + if (0 <= rhs[1] && rhs[1] <= 1.0) { + return { MathLib::Point3d{std::array<double,3>{{ + c[0]+rhs[1]*(d[0]-c[0]), c[1]+rhs[1]*(d[1]-c[1]), + c[2]+rhs[1]*(d[2]-c[2])}} } }; + } else { + return std::vector<MathLib::Point3d>(); // parameter s not in the valid range + } } } // end namespace GeoLib diff --git a/GeoLib/AnalyticalGeometry.h b/GeoLib/AnalyticalGeometry.h index f4345e9f64c36cebdabac86a75a5680cbf0658cb..ae7af19a7d98ad4adfd7bda8649d2853c6664f05 100644 --- a/GeoLib/AnalyticalGeometry.h +++ b/GeoLib/AnalyticalGeometry.h @@ -143,7 +143,7 @@ void rotatePoints( */ template <typename P> void rotatePoints(MathLib::DenseMatrix<double> const& rot_mat, - std::vector<P*> const& pnts); + std::vector<P*> const& pnts); /** * rotate points to X-Y plane @@ -189,9 +189,9 @@ double calcTriangleArea(MathLib::Point3d const& a, MathLib::Point3d const& b, * The formula is V=1/6*|a(b x c)| with a=x1->x2, b=x1->x3 and c=x1->x4. */ double calcTetrahedronVolume(MathLib::Point3d const& x1, - MathLib::Point3d const& x2, - MathLib::Point3d const& x3, - MathLib::Point3d const& x4); + MathLib::Point3d const& x2, + MathLib::Point3d const& x3, + MathLib::Point3d const& x4); /** * Tests if the given point p is within the triangle, defined by its edge nodes a, b and c. @@ -316,7 +316,7 @@ bool lineSegmentIntersect(GeoLib::LineSegment const& s0, /// segments are interfering. std::vector<MathLib::Point3d> lineSegmentIntersect2d(MathLib::Point3d const& a, MathLib::Point3d const& b, - MathLib::Point3d const& c, MathLib::Point3d const& d); + MathLib::Point3d const& c, MathLib::Point3d const& d); /** * Calculates the intersection points of a line PQ and a triangle ABC. @@ -382,7 +382,7 @@ void computeAndInsertAllIntersectionPoints(GeoLib::PointVec &pnt_vec, * @return a rotated polygon */ GeoLib::Polygon rotatePolygonToXY(GeoLib::Polygon const& polygon_in, - MathLib::Vector3 & plane_normal); + MathLib::Vector3 & plane_normal); } // end namespace GeoLib diff --git a/GeoLib/CMakeLists.txt b/GeoLib/CMakeLists.txt index 71b100412cad9da2632371c128b83d2aeb7dc218..ce9bfc4975c081dda7836eec31d9c242544ab6a1 100644 --- a/GeoLib/CMakeLists.txt +++ b/GeoLib/CMakeLists.txt @@ -11,26 +11,26 @@ GET_SOURCE_FILES(SOURCES_IO_BOOST_XML IO/XmlIO/Boost) set(SOURCES ${SOURCES} ${SOURCES_IO_BASE_XML} ${SOURCES_IO_BOOST_XML}) if(QT4_FOUND) - GET_SOURCE_FILES(SOURCES_IO_QT_XML IO/XmlIO/Qt) - set(SOURCES ${SOURCES} ${SOURCES_IO_QT_XML}) + GET_SOURCE_FILES(SOURCES_IO_QT_XML IO/XmlIO/Qt) + set(SOURCES ${SOURCES} ${SOURCES_IO_QT_XML}) endif() # Create the library add_library(GeoLib STATIC ${SOURCES} - ${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/tetgen/predicates.cxx + ${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/tetgen/predicates.cxx ) target_link_libraries(GeoLib - MathLib + MathLib ) if(QT4_FOUND) - target_link_libraries(GeoLib Qt4::QtXml Qt4::QtXmlPatterns) - if(WIN32 AND CMAKE_CROSSCOMPILING AND OPENSSL_FOUND) - target_link_libraries(GeoLib Qt4::QtNetwork ${OPENSSL_LIBRARIES} ws2_32) - endif() + target_link_libraries(GeoLib Qt4::QtXml Qt4::QtXmlPatterns) + if(WIN32 AND CMAKE_CROSSCOMPILING AND OPENSSL_FOUND) + target_link_libraries(GeoLib Qt4::QtNetwork ${OPENSSL_LIBRARIES} ws2_32) + endif() endif() if(TARGET Boost) - add_dependencies(GeoLib Boost) + add_dependencies(GeoLib Boost) endif() diff --git a/GeoLib/ClosestPair.h b/GeoLib/ClosestPair.h index 489aa54ccdba7c352f9c2e9dc7b46e013606443e..fdf304ee14535f9934f280ca33716bb0afb79339 100644 --- a/GeoLib/ClosestPair.h +++ b/GeoLib/ClosestPair.h @@ -26,14 +26,14 @@ namespace GeoLib { class ClosestPair { public: - ClosestPair (std::vector<GeoLib::Point*> const & pnts, std::size_t id0, std::size_t id1) : - _pnts (pnts), _id0 (id0), _id1 (id1) - {} + ClosestPair (std::vector<GeoLib::Point*> const & pnts, std::size_t id0, std::size_t id1) : + _pnts (pnts), _id0 (id0), _id1 (id1) + {} protected: - std::vector<GeoLib::Point*> const & _pnts; - std::size_t _id0; - std::size_t _id1; + std::vector<GeoLib::Point*> const & _pnts; + std::size_t _id0; + std::size_t _id1; }; } // end namespace GeoLib diff --git a/GeoLib/EarClippingTriangulation.cpp b/GeoLib/EarClippingTriangulation.cpp index 464e0b75f344d88ccf20e19ded46c1924d696220..523a684fa378f9d378fc9ccd9e901b5124907b43 100644 --- a/GeoLib/EarClippingTriangulation.cpp +++ b/GeoLib/EarClippingTriangulation.cpp @@ -23,271 +23,271 @@ namespace GeoLib { EarClippingTriangulation::EarClippingTriangulation(const GeoLib::Polygon* polygon, - std::list<GeoLib::Triangle> &triangles, bool rot) + std::list<GeoLib::Triangle> &triangles, bool rot) { - copyPolygonPoints (polygon); + copyPolygonPoints (polygon); - if (rot) { - rotatePointsToXY (_pnts); - ensureCWOrientation (); - } + if (rot) { + rotatePointsToXY (_pnts); + ensureCWOrientation (); + } - initVertexList (); - initLists (); - clipEars (); + initVertexList (); + initLists (); + clipEars (); - std::vector<GeoLib::Point*> const& ref_pnts_vec (polygon->getPointsVec()); - std::list<GeoLib::Triangle>::const_iterator it (_triangles.begin()); - if (_original_orient == GeoLib::CW) { - while (it != _triangles.end()) { - const std::size_t i0 (polygon->getPointID ((*it)[0])); - const std::size_t i1 (polygon->getPointID ((*it)[1])); - const std::size_t i2 (polygon->getPointID ((*it)[2])); - triangles.push_back (GeoLib::Triangle (ref_pnts_vec, i0, i1, i2)); - ++it; - } - } else { - std::size_t n_pnts (_pnts.size() - 1); - while (it != _triangles.end()) { - const std::size_t i0 (polygon->getPointID (n_pnts - (*it)[0])); - const std::size_t i1 (polygon->getPointID (n_pnts - (*it)[1])); - const std::size_t i2 (polygon->getPointID (n_pnts - (*it)[2])); - triangles.push_back (GeoLib::Triangle (ref_pnts_vec, i0, i1, i2)); - ++it; - } - } + std::vector<GeoLib::Point*> const& ref_pnts_vec (polygon->getPointsVec()); + std::list<GeoLib::Triangle>::const_iterator it (_triangles.begin()); + if (_original_orient == GeoLib::CW) { + while (it != _triangles.end()) { + const std::size_t i0 (polygon->getPointID ((*it)[0])); + const std::size_t i1 (polygon->getPointID ((*it)[1])); + const std::size_t i2 (polygon->getPointID ((*it)[2])); + triangles.push_back (GeoLib::Triangle (ref_pnts_vec, i0, i1, i2)); + ++it; + } + } else { + std::size_t n_pnts (_pnts.size() - 1); + while (it != _triangles.end()) { + const std::size_t i0 (polygon->getPointID (n_pnts - (*it)[0])); + const std::size_t i1 (polygon->getPointID (n_pnts - (*it)[1])); + const std::size_t i2 (polygon->getPointID (n_pnts - (*it)[2])); + triangles.push_back (GeoLib::Triangle (ref_pnts_vec, i0, i1, i2)); + ++it; + } + } } EarClippingTriangulation::~EarClippingTriangulation() { - const std::size_t n_pnts (_pnts.size()); - for (std::size_t k(0); k<n_pnts; k++) { - delete _pnts[k]; - } + const std::size_t n_pnts (_pnts.size()); + for (std::size_t k(0); k<n_pnts; k++) { + delete _pnts[k]; + } } void EarClippingTriangulation::copyPolygonPoints (const GeoLib::Polygon* polygon) { - // copy points - last point is identical to the first - std::size_t n_pnts (polygon->getNumberOfPoints() - 1); - for (std::size_t k(0); k < n_pnts; k++) { - _pnts.push_back (new GeoLib::Point (*(polygon->getPoint(k)))); - } + // copy points - last point is identical to the first + std::size_t n_pnts (polygon->getNumberOfPoints() - 1); + for (std::size_t k(0); k < n_pnts; k++) { + _pnts.push_back (new GeoLib::Point (*(polygon->getPoint(k)))); + } } void EarClippingTriangulation::ensureCWOrientation () { - std::size_t n_pnts (_pnts.size()); - // get the left most upper point - std::size_t min_x_max_y_idx (0); // for orientation check - for (std::size_t k(0); k<n_pnts; k++) { - if ((*(_pnts[k]))[0] <= (*(_pnts[min_x_max_y_idx]))[0]) { - if ((*(_pnts[k]))[0] < (*(_pnts[min_x_max_y_idx]))[0]) { - min_x_max_y_idx = k; - } else { - if ((*(_pnts[k]))[1] > (*(_pnts[min_x_max_y_idx]))[1]) { - min_x_max_y_idx = k; - } - } - } - } - // determine orientation - if (0 < min_x_max_y_idx && min_x_max_y_idx < n_pnts-1) { - _original_orient = GeoLib::getOrientation ( - _pnts[min_x_max_y_idx-1], _pnts[min_x_max_y_idx], _pnts[min_x_max_y_idx+1]); - } else { - if (0 == min_x_max_y_idx) { - _original_orient = GeoLib::getOrientation (_pnts[n_pnts-1], _pnts[0], _pnts[1]); - } else { - _original_orient = GeoLib::getOrientation (_pnts[n_pnts-2], _pnts[n_pnts-1], _pnts[0]); - } - } - if (_original_orient == GeoLib::CCW) { - // switch orientation - for (std::size_t k(0); k<n_pnts/2; k++) { - std::swap (_pnts[k], _pnts[n_pnts-1-k]); - } - } + std::size_t n_pnts (_pnts.size()); + // get the left most upper point + std::size_t min_x_max_y_idx (0); // for orientation check + for (std::size_t k(0); k<n_pnts; k++) { + if ((*(_pnts[k]))[0] <= (*(_pnts[min_x_max_y_idx]))[0]) { + if ((*(_pnts[k]))[0] < (*(_pnts[min_x_max_y_idx]))[0]) { + min_x_max_y_idx = k; + } else { + if ((*(_pnts[k]))[1] > (*(_pnts[min_x_max_y_idx]))[1]) { + min_x_max_y_idx = k; + } + } + } + } + // determine orientation + if (0 < min_x_max_y_idx && min_x_max_y_idx < n_pnts-1) { + _original_orient = GeoLib::getOrientation ( + _pnts[min_x_max_y_idx-1], _pnts[min_x_max_y_idx], _pnts[min_x_max_y_idx+1]); + } else { + if (0 == min_x_max_y_idx) { + _original_orient = GeoLib::getOrientation (_pnts[n_pnts-1], _pnts[0], _pnts[1]); + } else { + _original_orient = GeoLib::getOrientation (_pnts[n_pnts-2], _pnts[n_pnts-1], _pnts[0]); + } + } + if (_original_orient == GeoLib::CCW) { + // switch orientation + for (std::size_t k(0); k<n_pnts/2; k++) { + std::swap (_pnts[k], _pnts[n_pnts-1-k]); + } + } } bool EarClippingTriangulation::isEar(std::size_t v0, std::size_t v1, std::size_t v2) const { - for (std::list<std::size_t>::const_iterator it (_vertex_list.begin ()); - it != _vertex_list.end(); ++it) { - if (*it != v0 && *it != v1 && *it != v2) { - if (isPointInTriangle (*_pnts[*it], *_pnts[v0], *_pnts[v1], *_pnts[v2])) { - return false; - } - } - } - return true; + for (std::list<std::size_t>::const_iterator it (_vertex_list.begin ()); + it != _vertex_list.end(); ++it) { + if (*it != v0 && *it != v1 && *it != v2) { + if (isPointInTriangle (*_pnts[*it], *_pnts[v0], *_pnts[v1], *_pnts[v2])) { + return false; + } + } + } + return true; } void EarClippingTriangulation::initVertexList () { - std::size_t n_pnts (_pnts.size()); - for (std::size_t k(0); k<n_pnts; k++) - _vertex_list.push_back (k); + std::size_t n_pnts (_pnts.size()); + for (std::size_t k(0); k<n_pnts; k++) + _vertex_list.push_back (k); } void EarClippingTriangulation::initLists () { - // go through points checking ccw, cw or collinear order and identifying ears - std::list<std::size_t>::iterator it (_vertex_list.begin()), prev(_vertex_list.end()), next; - --prev; - next = it; - ++next; - GeoLib::Orientation orientation; - bool first_run(true); // saves special handling of the last case with identical code - while (_vertex_list.size() >= 3 && first_run) { - if (next == _vertex_list.end()) { - first_run = false; - next = _vertex_list.begin(); - } - orientation = getOrientation (_pnts[*prev], _pnts[*it], _pnts[*next]); - if (orientation == GeoLib::COLLINEAR) { - WARN("EarClippingTriangulation::initLists(): collinear points (%f, %f, %f), (%f, %f, %f), (%f, %f, %f)", - (*_pnts[*prev])[0], (*_pnts[*prev])[1], (*_pnts[*prev])[2], - (*_pnts[*it])[0], (*_pnts[*it])[1], (*_pnts[*it])[2], - (*_pnts[*next])[0], (*_pnts[*next])[1], (*_pnts[*next])[2]); - it = _vertex_list.erase (it); - ++next; - } else { - if (orientation == GeoLib::CW) { - _convex_vertex_list.push_back (*it); - if (isEar (*prev, *it, *next)) - _ear_list.push_back (*it); - } - prev = it; - it = next; - ++next; - } - } + // go through points checking ccw, cw or collinear order and identifying ears + std::list<std::size_t>::iterator it (_vertex_list.begin()), prev(_vertex_list.end()), next; + --prev; + next = it; + ++next; + GeoLib::Orientation orientation; + bool first_run(true); // saves special handling of the last case with identical code + while (_vertex_list.size() >= 3 && first_run) { + if (next == _vertex_list.end()) { + first_run = false; + next = _vertex_list.begin(); + } + orientation = getOrientation (_pnts[*prev], _pnts[*it], _pnts[*next]); + if (orientation == GeoLib::COLLINEAR) { + WARN("EarClippingTriangulation::initLists(): collinear points (%f, %f, %f), (%f, %f, %f), (%f, %f, %f)", + (*_pnts[*prev])[0], (*_pnts[*prev])[1], (*_pnts[*prev])[2], + (*_pnts[*it])[0], (*_pnts[*it])[1], (*_pnts[*it])[2], + (*_pnts[*next])[0], (*_pnts[*next])[1], (*_pnts[*next])[2]); + it = _vertex_list.erase (it); + ++next; + } else { + if (orientation == GeoLib::CW) { + _convex_vertex_list.push_back (*it); + if (isEar (*prev, *it, *next)) + _ear_list.push_back (*it); + } + prev = it; + it = next; + ++next; + } + } } void EarClippingTriangulation::clipEars() { - std::list<std::size_t>::iterator it, prev, next; - // *** clip an ear - while (_vertex_list.size() > 3) { - // pop ear from list - std::size_t ear = _ear_list.front(); - _ear_list.pop_front(); - // remove ear tip from _convex_vertex_list - _convex_vertex_list.remove(ear); + std::list<std::size_t>::iterator it, prev, next; + // *** clip an ear + while (_vertex_list.size() > 3) { + // pop ear from list + std::size_t ear = _ear_list.front(); + _ear_list.pop_front(); + // remove ear tip from _convex_vertex_list + _convex_vertex_list.remove(ear); - // remove ear from vertex_list, apply changes to _ear_list, _convex_vertex_list - bool nfound(true); - it = _vertex_list.begin(); - prev = _vertex_list.end(); - --prev; - while (nfound && it != _vertex_list.end()) { - if (*it == ear) { - nfound = false; - it = _vertex_list.erase(it); // remove ear tip - next = it; - if (next == _vertex_list.end()) { - next = _vertex_list.begin(); - prev = _vertex_list.end(); - --prev; - } - // add triangle - _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *next, ear)); + // remove ear from vertex_list, apply changes to _ear_list, _convex_vertex_list + bool nfound(true); + it = _vertex_list.begin(); + prev = _vertex_list.end(); + --prev; + while (nfound && it != _vertex_list.end()) { + if (*it == ear) { + nfound = false; + it = _vertex_list.erase(it); // remove ear tip + next = it; + if (next == _vertex_list.end()) { + next = _vertex_list.begin(); + prev = _vertex_list.end(); + --prev; + } + // add triangle + _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *next, ear)); - // check the orientation of prevprev, prev, next - std::list<std::size_t>::iterator prevprev; - if (prev == _vertex_list.begin()) { - prevprev = _vertex_list.end(); - } else { - prevprev = prev; - } - --prevprev; + // check the orientation of prevprev, prev, next + std::list<std::size_t>::iterator prevprev; + if (prev == _vertex_list.begin()) { + prevprev = _vertex_list.end(); + } else { + prevprev = prev; + } + --prevprev; - // apply changes to _convex_vertex_list and _ear_list looking "backward" - GeoLib::Orientation orientation = GeoLib::getOrientation(_pnts[*prevprev], _pnts[*prev], - _pnts[*next]); - if (orientation == GeoLib::CW) { - BaseLib::uniquePushBack(_convex_vertex_list, *prev); - // prev is convex - if (isEar(*prevprev, *prev, *next)) { - // prev is an ear tip - BaseLib::uniquePushBack(_ear_list, *prev); - } else { - // if necessary remove prev - _ear_list.remove(*prev); - } - } else { - // prev is not convex => reflex or collinear - _convex_vertex_list.remove(*prev); - _ear_list.remove(*prev); - if (orientation == GeoLib::COLLINEAR) { - prev = _vertex_list.erase(prev); - if (prev == _vertex_list.begin()) { - prev = _vertex_list.end(); - --prev; - } else { - --prev; - } - } - } + // apply changes to _convex_vertex_list and _ear_list looking "backward" + GeoLib::Orientation orientation = GeoLib::getOrientation(_pnts[*prevprev], _pnts[*prev], + _pnts[*next]); + if (orientation == GeoLib::CW) { + BaseLib::uniquePushBack(_convex_vertex_list, *prev); + // prev is convex + if (isEar(*prevprev, *prev, *next)) { + // prev is an ear tip + BaseLib::uniquePushBack(_ear_list, *prev); + } else { + // if necessary remove prev + _ear_list.remove(*prev); + } + } else { + // prev is not convex => reflex or collinear + _convex_vertex_list.remove(*prev); + _ear_list.remove(*prev); + if (orientation == GeoLib::COLLINEAR) { + prev = _vertex_list.erase(prev); + if (prev == _vertex_list.begin()) { + prev = _vertex_list.end(); + --prev; + } else { + --prev; + } + } + } - // check the orientation of prev, next, nextnext - std::list<std::size_t>::iterator nextnext, - help_it(_vertex_list.end()); - --help_it; - if (next == help_it) { - nextnext = _vertex_list.begin(); - } else { - nextnext = next; - ++nextnext; - } + // check the orientation of prev, next, nextnext + std::list<std::size_t>::iterator nextnext, + help_it(_vertex_list.end()); + --help_it; + if (next == help_it) { + nextnext = _vertex_list.begin(); + } else { + nextnext = next; + ++nextnext; + } - // apply changes to _convex_vertex_list and _ear_list looking "forward" - orientation = getOrientation(_pnts[*prev], _pnts[*next], - _pnts[*nextnext]); - if (orientation == GeoLib::CW) { - BaseLib::uniquePushBack(_convex_vertex_list, *next); - // next is convex - if (isEar(*prev, *next, *nextnext)) { - // next is an ear tip - BaseLib::uniquePushBack(_ear_list, *next); - } else { - // if necessary remove *next - _ear_list.remove(*next); - } - } else { - // next is not convex => reflex or collinear - _convex_vertex_list.remove(*next); - _ear_list.remove(*next); - if (orientation == GeoLib::COLLINEAR) { - next = _vertex_list.erase(next); - if (next == _vertex_list.end()) - next = _vertex_list.begin(); - } - } - } else { - prev = it; - ++it; - } - } + // apply changes to _convex_vertex_list and _ear_list looking "forward" + orientation = getOrientation(_pnts[*prev], _pnts[*next], + _pnts[*nextnext]); + if (orientation == GeoLib::CW) { + BaseLib::uniquePushBack(_convex_vertex_list, *next); + // next is convex + if (isEar(*prev, *next, *nextnext)) { + // next is an ear tip + BaseLib::uniquePushBack(_ear_list, *next); + } else { + // if necessary remove *next + _ear_list.remove(*next); + } + } else { + // next is not convex => reflex or collinear + _convex_vertex_list.remove(*next); + _ear_list.remove(*next); + if (orientation == GeoLib::COLLINEAR) { + next = _vertex_list.erase(next); + if (next == _vertex_list.end()) + next = _vertex_list.begin(); + } + } + } else { + prev = it; + ++it; + } + } - } + } - // add last triangle - next = _vertex_list.begin(); - prev = next; - ++next; - if (next == _vertex_list.end()) - return; - it = next; - ++next; - if (next == _vertex_list.end()) - return; + // add last triangle + next = _vertex_list.begin(); + prev = next; + ++next; + if (next == _vertex_list.end()) + return; + it = next; + ++next; + if (next == _vertex_list.end()) + return; - if (getOrientation(_pnts[*prev], _pnts[*it], _pnts[*next]) == GeoLib::CCW) - _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *it, *next)); - else - _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *next, *it)); + if (getOrientation(_pnts[*prev], _pnts[*it], _pnts[*next]) == GeoLib::CCW) + _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *it, *next)); + else + _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *next, *it)); } } // end namespace GeoLib diff --git a/GeoLib/EarClippingTriangulation.h b/GeoLib/EarClippingTriangulation.h index 493b56d315c7bd42192bdbcbbcd7da8a74143749..0afed2f3b18b2a13113ddfc8270a3760493736c1 100644 --- a/GeoLib/EarClippingTriangulation.h +++ b/GeoLib/EarClippingTriangulation.h @@ -29,37 +29,37 @@ class Triangle; class EarClippingTriangulation { public: - EarClippingTriangulation(const GeoLib::Polygon* ply, - std::list<GeoLib::Triangle> &triangles, - bool rot = true); - virtual ~EarClippingTriangulation(); + EarClippingTriangulation(const GeoLib::Polygon* ply, + std::list<GeoLib::Triangle> &triangles, + bool rot = true); + virtual ~EarClippingTriangulation(); private: - /** - * copies the points of the polygon to the vector _pnts - */ - inline void copyPolygonPoints (const GeoLib::Polygon* polygon); - inline void ensureCWOrientation (); + /** + * copies the points of the polygon to the vector _pnts + */ + inline void copyPolygonPoints (const GeoLib::Polygon* polygon); + inline void ensureCWOrientation (); - inline bool isEar(std::size_t v0, std::size_t v1, std::size_t v2) const; + inline bool isEar(std::size_t v0, std::size_t v1, std::size_t v2) const; - inline void initVertexList (); - inline void initLists (); - inline void clipEars (); + inline void initVertexList (); + inline void initLists (); + inline void clipEars (); - /** - * a copy of the polygon points - */ - std::vector<GeoLib::Point*> _pnts; - std::list<std::size_t> _vertex_list; - std::list<std::size_t> _convex_vertex_list; - std::list<std::size_t> _ear_list; + /** + * a copy of the polygon points + */ + std::vector<GeoLib::Point*> _pnts; + std::list<std::size_t> _vertex_list; + std::list<std::size_t> _convex_vertex_list; + std::list<std::size_t> _ear_list; - /** - * triangles of the triangulation (maybe in the wrong orientation) - */ - std::list<GeoLib::Triangle> _triangles; + /** + * triangles of the triangulation (maybe in the wrong orientation) + */ + std::list<GeoLib::Triangle> _triangles; - GeoLib::Orientation _original_orient; + GeoLib::Orientation _original_orient; }; } // end namespace GeoLib diff --git a/GeoLib/GEOObjects.cpp b/GeoLib/GEOObjects.cpp index 2bb2520d3a29ff8f3ab2b497e779996b24257b96..65a74a8f7e444edfd0a4f56b5e6960e81d563d66 100644 --- a/GeoLib/GEOObjects.cpp +++ b/GeoLib/GEOObjects.cpp @@ -30,15 +30,15 @@ GEOObjects::GEOObjects() GEOObjects::~GEOObjects() { - // delete surfaces - for (std::size_t k(0); k < _sfc_vecs.size(); k++) - delete _sfc_vecs[k]; - // delete polylines - for (std::size_t k(0); k < _ply_vecs.size(); k++) - delete _ply_vecs[k]; - // delete points - for (std::size_t k(0); k < _pnt_vecs.size(); k++) - delete _pnt_vecs[k]; + // delete surfaces + for (std::size_t k(0); k < _sfc_vecs.size(); k++) + delete _sfc_vecs[k]; + // delete polylines + for (std::size_t k(0); k < _ply_vecs.size(); k++) + delete _ply_vecs[k]; + // delete points + for (std::size_t k(0); k < _pnt_vecs.size(); k++) + delete _pnt_vecs[k]; } void GEOObjects::addPointVec( @@ -47,553 +47,553 @@ void GEOObjects::addPointVec( std::map<std::string, std::size_t>* pnt_id_name_map, double eps) { - isUniquePointVecName(name); - if (!points || points->empty()) { - DBUG("GEOObjects::addPointVec(): Failed to create PointVec, because " - "there aren't any points in the given vector."); - return; - } - _pnt_vecs.push_back(new PointVec(name, std::move(points), pnt_id_name_map, PointVec::PointType::POINT, eps)); - _callbacks->addPointVec(name); + isUniquePointVecName(name); + if (!points || points->empty()) { + DBUG("GEOObjects::addPointVec(): Failed to create PointVec, because " + "there aren't any points in the given vector."); + return; + } + _pnt_vecs.push_back(new PointVec(name, std::move(points), pnt_id_name_map, PointVec::PointType::POINT, eps)); + _callbacks->addPointVec(name); } const std::vector<Point*>* GEOObjects::getPointVec(const std::string &name) const { - std::size_t const idx = this->exists(name); - if (idx != std::numeric_limits<std::size_t>::max()) - return _pnt_vecs[idx]->getVector(); + std::size_t const idx = this->exists(name); + if (idx != std::numeric_limits<std::size_t>::max()) + return _pnt_vecs[idx]->getVector(); - DBUG("GEOObjects::getPointVec() - No entry found with name \"%s\".", name.c_str()); - return nullptr; + DBUG("GEOObjects::getPointVec() - No entry found with name \"%s\".", name.c_str()); + return nullptr; } const PointVec* GEOObjects::getPointVecObj(const std::string &name) const { - std::size_t const idx = this->exists(name); - if (idx != std::numeric_limits<std::size_t>::max()) - return _pnt_vecs[idx]; + std::size_t const idx = this->exists(name); + if (idx != std::numeric_limits<std::size_t>::max()) + return _pnt_vecs[idx]; - DBUG("GEOObjects::getPointVecObj() - No entry found with name \"%s\".", name.c_str()); - return nullptr; + DBUG("GEOObjects::getPointVecObj() - No entry found with name \"%s\".", name.c_str()); + return nullptr; } bool GEOObjects::removePointVec(std::string const& name) { - if (isPntVecUsed (name)) - { - DBUG("GEOObjects::removePointVec() - There are still Polylines or Surfaces depending on these points."); - return false; - } - - for (std::vector<PointVec*>::iterator it(_pnt_vecs.begin()); - it != _pnt_vecs.end(); ++it) - if ((*it)->getName().compare(name) == 0) - { - _callbacks->removePointVec(name); - delete *it; - _pnt_vecs.erase(it); - return true; - } - DBUG("GEOObjects::removePointVec() - No entry found with name \"%s\".", name.c_str()); - return false; + if (isPntVecUsed (name)) + { + DBUG("GEOObjects::removePointVec() - There are still Polylines or Surfaces depending on these points."); + return false; + } + + for (std::vector<PointVec*>::iterator it(_pnt_vecs.begin()); + it != _pnt_vecs.end(); ++it) + if ((*it)->getName().compare(name) == 0) + { + _callbacks->removePointVec(name); + delete *it; + _pnt_vecs.erase(it); + return true; + } + DBUG("GEOObjects::removePointVec() - No entry found with name \"%s\".", name.c_str()); + return false; } void GEOObjects::addStationVec(std::unique_ptr<std::vector<Point*>> stations, std::string& name) { - isUniquePointVecName(name); - _pnt_vecs.push_back(new PointVec(name, std::move(stations), nullptr, PointVec::PointType::STATION)); - _callbacks->addStationVec(name); + isUniquePointVecName(name); + _pnt_vecs.push_back(new PointVec(name, std::move(stations), nullptr, PointVec::PointType::STATION)); + _callbacks->addStationVec(name); } const std::vector<GeoLib::Point*>* GEOObjects::getStationVec( const std::string& name) const { - for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); - it != _pnt_vecs.end(); ++it) { - if ((*it)->getName().compare(name) == 0 && (*it)->getType() == PointVec::PointType::STATION) { - return (*it)->getVector(); - } - } - DBUG("GEOObjects::getStationVec() - No entry found with name \"%s\".", name.c_str()); - return nullptr; + for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); + it != _pnt_vecs.end(); ++it) { + if ((*it)->getName().compare(name) == 0 && (*it)->getType() == PointVec::PointType::STATION) { + return (*it)->getVector(); + } + } + DBUG("GEOObjects::getStationVec() - No entry found with name \"%s\".", name.c_str()); + return nullptr; } void GEOObjects::addPolylineVec(std::unique_ptr<std::vector<Polyline*>> lines, const std::string& name, std::map<std::string, std::size_t>* ply_names) { - assert(lines); - for (std::vector<Polyline*>::iterator it (lines->begin()); - it != lines->end(); ) - { - if ((*it)->getNumberOfPoints() < 2) - { - std::vector<Polyline*>::iterator it_erase (it); - it = lines->erase (it_erase); - } - else - ++it; - } - - if (lines->empty()) - return; - - _ply_vecs.push_back(new PolylineVec(name, std::move(lines), ply_names)); - _callbacks->addPolylineVec(name); + assert(lines); + for (std::vector<Polyline*>::iterator it (lines->begin()); + it != lines->end(); ) + { + if ((*it)->getNumberOfPoints() < 2) + { + std::vector<Polyline*>::iterator it_erase (it); + it = lines->erase (it_erase); + } + else + ++it; + } + + if (lines->empty()) + return; + + _ply_vecs.push_back(new PolylineVec(name, std::move(lines), ply_names)); + _callbacks->addPolylineVec(name); } bool GEOObjects::appendPolylineVec(const std::vector<Polyline*>& polylines, const std::string& name) { - // search vector - std::size_t idx (0); - bool nfound (true); - for (idx = 0; idx < _ply_vecs.size() && nfound; idx++) - if ( (_ply_vecs[idx]->getName()).compare (name) == 0 ) - nfound = false; - - if (!nfound) - { - idx--; - std::size_t n_plys (polylines.size()); - // append lines - for (std::size_t k(0); k < n_plys; k++) - _ply_vecs[idx]->push_back (polylines[k]); - _callbacks->appendPolylineVec(name); - return true; - } - else - return false; + // search vector + std::size_t idx (0); + bool nfound (true); + for (idx = 0; idx < _ply_vecs.size() && nfound; idx++) + if ( (_ply_vecs[idx]->getName()).compare (name) == 0 ) + nfound = false; + + if (!nfound) + { + idx--; + std::size_t n_plys (polylines.size()); + // append lines + for (std::size_t k(0); k < n_plys; k++) + _ply_vecs[idx]->push_back (polylines[k]); + _callbacks->appendPolylineVec(name); + return true; + } + else + return false; } const std::vector<Polyline*>* GEOObjects::getPolylineVec(const std::string &name) const { - std::size_t size (_ply_vecs.size()); - for (std::size_t i = 0; i < size; i++) - if (_ply_vecs[i]->getName().compare(name) == 0) - return _ply_vecs[i]->getVector(); + std::size_t size (_ply_vecs.size()); + for (std::size_t i = 0; i < size; i++) + if (_ply_vecs[i]->getName().compare(name) == 0) + return _ply_vecs[i]->getVector(); - DBUG("GEOObjects::getPolylineVec() - No entry found with name \"%s\".", name.c_str()); - return nullptr; + DBUG("GEOObjects::getPolylineVec() - No entry found with name \"%s\".", name.c_str()); + return nullptr; } const PolylineVec* GEOObjects::getPolylineVecObj(const std::string &name) const { - std::size_t size (_ply_vecs.size()); - for (std::size_t i = 0; i < size; i++) - if (_ply_vecs[i]->getName().compare(name) == 0) - return _ply_vecs[i]; + std::size_t size (_ply_vecs.size()); + for (std::size_t i = 0; i < size; i++) + if (_ply_vecs[i]->getName().compare(name) == 0) + return _ply_vecs[i]; - DBUG("GEOObjects::getPolylineVecObj() - No entry found with name \"%s\".", name.c_str()); - return nullptr; + DBUG("GEOObjects::getPolylineVecObj() - No entry found with name \"%s\".", name.c_str()); + return nullptr; } bool GEOObjects::removePolylineVec(std::string const& name) { - _callbacks->removePolylineVec(name); - for (std::vector<PolylineVec*>::iterator it = _ply_vecs.begin(); - it != _ply_vecs.end(); ++it) - if ((*it)->getName().compare(name) == 0) - { - delete *it; - _ply_vecs.erase(it); - return true; - } - - DBUG("GEOObjects::removePolylineVec() - No entry found with name \"%s\".", name.c_str()); - return false; + _callbacks->removePolylineVec(name); + for (std::vector<PolylineVec*>::iterator it = _ply_vecs.begin(); + it != _ply_vecs.end(); ++it) + if ((*it)->getName().compare(name) == 0) + { + delete *it; + _ply_vecs.erase(it); + return true; + } + + DBUG("GEOObjects::removePolylineVec() - No entry found with name \"%s\".", name.c_str()); + return false; } void GEOObjects::addSurfaceVec(std::unique_ptr<std::vector<Surface*>> sfc, const std::string& name, std::map<std::string, std::size_t>* sfc_names) { - _sfc_vecs.push_back(new SurfaceVec(name, std::move(sfc), sfc_names)); - if (!sfc || !sfc->empty()) _callbacks->addSurfaceVec(name); + _sfc_vecs.push_back(new SurfaceVec(name, std::move(sfc), sfc_names)); + if (!sfc || !sfc->empty()) _callbacks->addSurfaceVec(name); } bool GEOObjects::appendSurfaceVec(const std::vector<Surface*>& surfaces, const std::string& name) { - // search vector - std::size_t idx (0); - bool nfound (true); - for (idx = 0; idx < _sfc_vecs.size() && nfound; idx++) - if ( (_sfc_vecs[idx]->getName()).compare (name) == 0 ) - nfound = false; - - if (!nfound) - { - idx--; - std::size_t n_sfcs (surfaces.size()); - // append surfaces - for (std::size_t k(0); k < n_sfcs; k++) - _sfc_vecs[idx]->push_back (surfaces[k]); - _callbacks->appendSurfaceVec(name); - return true; - } - else - { - // the copy is needed because addSurfaceVec is passing it to SurfaceVec - // ctor, which needs write access to the surface vector. - auto sfc = std::unique_ptr<std::vector<GeoLib::Surface*>>{ - new std::vector<GeoLib::Surface*>}; - for (std::size_t i = 0; i < surfaces.size(); i++) - sfc->push_back(surfaces[i]); - addSurfaceVec(std::move(sfc), name); - return false; - } + // search vector + std::size_t idx (0); + bool nfound (true); + for (idx = 0; idx < _sfc_vecs.size() && nfound; idx++) + if ( (_sfc_vecs[idx]->getName()).compare (name) == 0 ) + nfound = false; + + if (!nfound) + { + idx--; + std::size_t n_sfcs (surfaces.size()); + // append surfaces + for (std::size_t k(0); k < n_sfcs; k++) + _sfc_vecs[idx]->push_back (surfaces[k]); + _callbacks->appendSurfaceVec(name); + return true; + } + else + { + // the copy is needed because addSurfaceVec is passing it to SurfaceVec + // ctor, which needs write access to the surface vector. + auto sfc = std::unique_ptr<std::vector<GeoLib::Surface*>>{ + new std::vector<GeoLib::Surface*>}; + for (std::size_t i = 0; i < surfaces.size(); i++) + sfc->push_back(surfaces[i]); + addSurfaceVec(std::move(sfc), name); + return false; + } } const std::vector<Surface*>* GEOObjects::getSurfaceVec(const std::string &name) const { - std::size_t size (_sfc_vecs.size()); - for (std::size_t i = 0; i < size; i++) - if (_sfc_vecs[i]->getName().compare(name) == 0) - return _sfc_vecs[i]->getVector(); - DBUG("GEOObjects::getSurfaceVec() - No entry found with name \"%s\".", name.c_str()); - return nullptr; + std::size_t size (_sfc_vecs.size()); + for (std::size_t i = 0; i < size; i++) + if (_sfc_vecs[i]->getName().compare(name) == 0) + return _sfc_vecs[i]->getVector(); + DBUG("GEOObjects::getSurfaceVec() - No entry found with name \"%s\".", name.c_str()); + return nullptr; } bool GEOObjects::removeSurfaceVec(const std::string &name) { - _callbacks->removeSurfaceVec(name); - for (std::vector<SurfaceVec*>::iterator it (_sfc_vecs.begin()); - it != _sfc_vecs.end(); ++it) - if ((*it)->getName().compare (name) == 0) - { - delete *it; - _sfc_vecs.erase (it); - return true; - } - - DBUG("GEOObjects::removeSurfaceVec() - No entry found with name \"%s\".", name.c_str()); - return false; + _callbacks->removeSurfaceVec(name); + for (std::vector<SurfaceVec*>::iterator it (_sfc_vecs.begin()); + it != _sfc_vecs.end(); ++it) + if ((*it)->getName().compare (name) == 0) + { + delete *it; + _sfc_vecs.erase (it); + return true; + } + + DBUG("GEOObjects::removeSurfaceVec() - No entry found with name \"%s\".", name.c_str()); + return false; } const SurfaceVec* GEOObjects::getSurfaceVecObj(const std::string &name) const { - std::size_t size (_sfc_vecs.size()); - for (std::size_t i = 0; i < size; i++) - if (_sfc_vecs[i]->getName().compare(name) == 0) - return _sfc_vecs[i]; - DBUG("GEOObjects::getSurfaceVecObj() - No entry found with name \"%s\".", name.c_str()); - return nullptr; + std::size_t size (_sfc_vecs.size()); + for (std::size_t i = 0; i < size; i++) + if (_sfc_vecs[i]->getName().compare(name) == 0) + return _sfc_vecs[i]; + DBUG("GEOObjects::getSurfaceVecObj() - No entry found with name \"%s\".", name.c_str()); + return nullptr; } bool GEOObjects::isUniquePointVecName(std::string &name) { - int count = 0; - bool isUnique = false; - std::string cpName; - - while (!isUnique) - { - isUnique = true; - cpName = name; - - count++; - // If the original name already exists we start to add numbers to name for - // as long as it takes to make the name unique. - if (count > 1) - cpName = cpName + "-" + std::to_string(count); - - for (std::size_t i = 0; i < _pnt_vecs.size(); i++) - if ( cpName.compare(_pnt_vecs[i]->getName()) == 0 ) - isUnique = false; - } - - // At this point cpName is a unique name and isUnique is true. - // If cpName is not the original name, "name" is changed and isUnique is set to false, - // indicating that a vector with the original name already exists. - if (count > 1) - { - isUnique = false; - name = cpName; - } - return isUnique; + int count = 0; + bool isUnique = false; + std::string cpName; + + while (!isUnique) + { + isUnique = true; + cpName = name; + + count++; + // If the original name already exists we start to add numbers to name for + // as long as it takes to make the name unique. + if (count > 1) + cpName = cpName + "-" + std::to_string(count); + + for (std::size_t i = 0; i < _pnt_vecs.size(); i++) + if ( cpName.compare(_pnt_vecs[i]->getName()) == 0 ) + isUnique = false; + } + + // At this point cpName is a unique name and isUnique is true. + // If cpName is not the original name, "name" is changed and isUnique is set to false, + // indicating that a vector with the original name already exists. + if (count > 1) + { + isUnique = false; + name = cpName; + } + return isUnique; } bool GEOObjects::isPntVecUsed (const std::string &name) const { - // search dependent data structures (Polyline) - for (std::vector<PolylineVec*>::const_iterator it ( _ply_vecs.begin()); it != _ply_vecs.end(); - ++it) - { - if (((*it)->getName()).compare(name) == 0) - return true; - } - for (std::vector<SurfaceVec*>::const_iterator it ( _sfc_vecs.begin()); it != _sfc_vecs.end(); - ++it) - { - if (((*it)->getName()).compare(name) == 0) - return true; - } - - return false; + // search dependent data structures (Polyline) + for (std::vector<PolylineVec*>::const_iterator it ( _ply_vecs.begin()); it != _ply_vecs.end(); + ++it) + { + if (((*it)->getName()).compare(name) == 0) + return true; + } + for (std::vector<SurfaceVec*>::const_iterator it ( _sfc_vecs.begin()); it != _sfc_vecs.end(); + ++it) + { + if (((*it)->getName()).compare(name) == 0) + return true; + } + + return false; } void GEOObjects::getStationVectorNames(std::vector<std::string>& names) const { - for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); it != _pnt_vecs.end(); - ++it) - if ((*it)->getType() == PointVec::PointType::STATION) - names.push_back((*it)->getName()); + for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); it != _pnt_vecs.end(); + ++it) + if ((*it)->getType() == PointVec::PointType::STATION) + names.push_back((*it)->getName()); } void GEOObjects::getGeometryNames (std::vector<std::string>& names) const { - names.clear (); - for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); it != _pnt_vecs.end(); - ++it) - if ((*it)->getType() == PointVec::PointType::POINT) - names.push_back((*it)->getName()); + names.clear (); + for (std::vector<PointVec*>::const_iterator it(_pnt_vecs.begin()); it != _pnt_vecs.end(); + ++it) + if ((*it)->getType() == PointVec::PointType::POINT) + names.push_back((*it)->getName()); } const std::string GEOObjects::getElementNameByID(const std::string &geometry_name, GeoLib::GEOTYPE type, std::size_t id) const { - std::string name(""); - switch (type) - { - case GeoLib::GEOTYPE::POINT: - this->getPointVecObj(geometry_name)->getNameOfElementByID(id, name); - break; - case GeoLib::GEOTYPE::POLYLINE: - this->getPolylineVecObj(geometry_name)->getNameOfElementByID(id, name); - break; - case GeoLib::GEOTYPE::SURFACE: - this->getSurfaceVecObj(geometry_name)->getNameOfElementByID(id, name); - } - return name; + std::string name(""); + switch (type) + { + case GeoLib::GEOTYPE::POINT: + this->getPointVecObj(geometry_name)->getNameOfElementByID(id, name); + break; + case GeoLib::GEOTYPE::POLYLINE: + this->getPolylineVecObj(geometry_name)->getNameOfElementByID(id, name); + break; + case GeoLib::GEOTYPE::SURFACE: + this->getSurfaceVecObj(geometry_name)->getNameOfElementByID(id, name); + } + return name; } int GEOObjects::mergeGeometries (std::vector<std::string> const & geo_names, std::string &merged_geo_name) { - const std::size_t n_geo_names(geo_names.size()); + const std::size_t n_geo_names(geo_names.size()); - if (n_geo_names < 2) - return 2; + if (n_geo_names < 2) + return 2; - std::vector<std::size_t> pnt_offsets(n_geo_names, 0); + std::vector<std::size_t> pnt_offsets(n_geo_names, 0); - if (! mergePoints(geo_names, merged_geo_name, pnt_offsets)) - return 1; + if (! mergePoints(geo_names, merged_geo_name, pnt_offsets)) + return 1; - mergePolylines(geo_names, merged_geo_name, pnt_offsets); + mergePolylines(geo_names, merged_geo_name, pnt_offsets); - mergeSurfaces(geo_names, merged_geo_name, pnt_offsets); + mergeSurfaces(geo_names, merged_geo_name, pnt_offsets); - return 0; + return 0; } bool GEOObjects::mergePoints(std::vector<std::string> const & geo_names, - std::string & merged_geo_name, std::vector<std::size_t> &pnt_offsets) + std::string & merged_geo_name, std::vector<std::size_t> &pnt_offsets) { - const std::size_t n_geo_names(geo_names.size()); - - auto merged_points = std::unique_ptr<std::vector<GeoLib::Point*>>( - new std::vector<GeoLib::Point*>); - std::map<std::string, std::size_t>* merged_pnt_names(new std::map<std::string, std::size_t>); - - for (std::size_t j(0); j < n_geo_names; ++j) { - GeoLib::PointVec const*const pnt_vec(this->getPointVecObj(geo_names[j])); - if (pnt_vec == nullptr) - continue; - const std::vector<GeoLib::Point*>* pnts(pnt_vec->getVector()); - if (pnts == nullptr) { - return false; - } - - // do not consider stations - if (dynamic_cast<GeoLib::Station*>((*pnts)[0])) { - continue; - } - - std::size_t const n_pnts(pnts->size()); - for (std::size_t k(0); k < n_pnts; ++k) { - merged_points->push_back( - new GeoLib::Point(*(*pnts)[k], pnt_offsets[j]+k)); - std::string const& item_name(pnt_vec->getItemNameByID(k)); - if (! item_name.empty()) { - merged_pnt_names->insert( - std::make_pair(item_name, pnt_offsets[j] + k)); - } - } - if (n_geo_names - 1 > j) { - pnt_offsets[j + 1] = n_pnts + pnt_offsets[j]; - } - } - - addPointVec (std::move(merged_points), merged_geo_name, merged_pnt_names, 1e-6); - return true; + const std::size_t n_geo_names(geo_names.size()); + + auto merged_points = std::unique_ptr<std::vector<GeoLib::Point*>>( + new std::vector<GeoLib::Point*>); + std::map<std::string, std::size_t>* merged_pnt_names(new std::map<std::string, std::size_t>); + + for (std::size_t j(0); j < n_geo_names; ++j) { + GeoLib::PointVec const*const pnt_vec(this->getPointVecObj(geo_names[j])); + if (pnt_vec == nullptr) + continue; + const std::vector<GeoLib::Point*>* pnts(pnt_vec->getVector()); + if (pnts == nullptr) { + return false; + } + + // do not consider stations + if (dynamic_cast<GeoLib::Station*>((*pnts)[0])) { + continue; + } + + std::size_t const n_pnts(pnts->size()); + for (std::size_t k(0); k < n_pnts; ++k) { + merged_points->push_back( + new GeoLib::Point(*(*pnts)[k], pnt_offsets[j]+k)); + std::string const& item_name(pnt_vec->getItemNameByID(k)); + if (! item_name.empty()) { + merged_pnt_names->insert( + std::make_pair(item_name, pnt_offsets[j] + k)); + } + } + if (n_geo_names - 1 > j) { + pnt_offsets[j + 1] = n_pnts + pnt_offsets[j]; + } + } + + addPointVec (std::move(merged_points), merged_geo_name, merged_pnt_names, 1e-6); + return true; } void GEOObjects::mergePolylines(std::vector<std::string> const & geo_names, - std::string & merged_geo_name, std::vector<std::size_t> const& pnt_offsets) + std::string & merged_geo_name, std::vector<std::size_t> const& pnt_offsets) { - const std::size_t n_geo_names(geo_names.size()); - std::vector<std::size_t> ply_offsets(n_geo_names, 0); - - auto merged_polylines = std::unique_ptr<std::vector<GeoLib::Polyline*>>( - new std::vector<GeoLib::Polyline*>); - std::map<std::string, std::size_t>* merged_ply_names(new std::map<std::string, std::size_t>); - - std::vector<GeoLib::Point*> const* merged_points(this->getPointVecObj(merged_geo_name)->getVector()); - std::vector<std::size_t> const& id_map (this->getPointVecObj(merged_geo_name)->getIDMap ()); - - for (std::size_t j(0); j < n_geo_names; j++) { - const std::vector<GeoLib::Polyline*>* plys (this->getPolylineVec(geo_names[j])); - if (plys) { - std::string tmp_name; - for (std::size_t k(0); k < plys->size(); k++) { - GeoLib::Polyline* kth_ply_new(new GeoLib::Polyline (*merged_points)); - GeoLib::Polyline const* const kth_ply_old ((*plys)[k]); - const std::size_t size_of_kth_ply (kth_ply_old->getNumberOfPoints()); - // copy point ids from old ply to new ply (considering the offset) - for (std::size_t i(0); i < size_of_kth_ply; i++) { - kth_ply_new->addPoint (id_map[pnt_offsets[j] + - kth_ply_old->getPointID(i)]); - } - merged_polylines->push_back (kth_ply_new); - if (this->getPolylineVecObj(geo_names[j])->getNameOfElementByID(k, tmp_name)) { - merged_ply_names->insert(std::pair<std::string, std::size_t>(tmp_name, ply_offsets[j] + k)); - } - } - if (n_geo_names - 1 > j) { - ply_offsets[j + 1] = plys->size() + ply_offsets[j]; - } - } - } - - if (! merged_polylines->empty()) { - this->addPolylineVec (std::move(merged_polylines), merged_geo_name, merged_ply_names); - } else { - delete merged_ply_names; - } + const std::size_t n_geo_names(geo_names.size()); + std::vector<std::size_t> ply_offsets(n_geo_names, 0); + + auto merged_polylines = std::unique_ptr<std::vector<GeoLib::Polyline*>>( + new std::vector<GeoLib::Polyline*>); + std::map<std::string, std::size_t>* merged_ply_names(new std::map<std::string, std::size_t>); + + std::vector<GeoLib::Point*> const* merged_points(this->getPointVecObj(merged_geo_name)->getVector()); + std::vector<std::size_t> const& id_map (this->getPointVecObj(merged_geo_name)->getIDMap ()); + + for (std::size_t j(0); j < n_geo_names; j++) { + const std::vector<GeoLib::Polyline*>* plys (this->getPolylineVec(geo_names[j])); + if (plys) { + std::string tmp_name; + for (std::size_t k(0); k < plys->size(); k++) { + GeoLib::Polyline* kth_ply_new(new GeoLib::Polyline (*merged_points)); + GeoLib::Polyline const* const kth_ply_old ((*plys)[k]); + const std::size_t size_of_kth_ply (kth_ply_old->getNumberOfPoints()); + // copy point ids from old ply to new ply (considering the offset) + for (std::size_t i(0); i < size_of_kth_ply; i++) { + kth_ply_new->addPoint (id_map[pnt_offsets[j] + + kth_ply_old->getPointID(i)]); + } + merged_polylines->push_back (kth_ply_new); + if (this->getPolylineVecObj(geo_names[j])->getNameOfElementByID(k, tmp_name)) { + merged_ply_names->insert(std::pair<std::string, std::size_t>(tmp_name, ply_offsets[j] + k)); + } + } + if (n_geo_names - 1 > j) { + ply_offsets[j + 1] = plys->size() + ply_offsets[j]; + } + } + } + + if (! merged_polylines->empty()) { + this->addPolylineVec (std::move(merged_polylines), merged_geo_name, merged_ply_names); + } else { + delete merged_ply_names; + } } void GEOObjects::mergeSurfaces(std::vector<std::string> const & geo_names, - std::string & merged_geo_name, std::vector<std::size_t> const& pnt_offsets) + std::string & merged_geo_name, std::vector<std::size_t> const& pnt_offsets) { - std::vector<GeoLib::Point*> const* merged_points(this->getPointVecObj(merged_geo_name)->getVector()); - std::vector<std::size_t> const& id_map (this->getPointVecObj(merged_geo_name)->getIDMap ()); - - const std::size_t n_geo_names(geo_names.size()); - std::vector<std::size_t> sfc_offsets(n_geo_names, 0); - auto merged_sfcs = std::unique_ptr<std::vector<GeoLib::Surface*>>( - new std::vector<GeoLib::Surface*>); - std::map<std::string, std::size_t>* merged_sfc_names(new std::map<std::string, std::size_t>); - for (std::size_t j(0); j < n_geo_names; j++) { - const std::vector<GeoLib::Surface*>* sfcs (this->getSurfaceVec(geo_names[j])); - if (sfcs) { - std::string tmp_name; - for (std::size_t k(0); k < sfcs->size(); k++) { - GeoLib::Surface* kth_sfc_new(new GeoLib::Surface (*merged_points)); - GeoLib::Surface const* const kth_sfc_old ((*sfcs)[k]); - const std::size_t size_of_kth_sfc (kth_sfc_old->getNTriangles()); - // clone surface elements using new ids - for (std::size_t i(0); i < size_of_kth_sfc; i++) { - const GeoLib::Triangle* tri ((*kth_sfc_old)[i]); - const std::size_t id0 (id_map[pnt_offsets[j] + (*tri)[0]]); - const std::size_t id1 (id_map[pnt_offsets[j] + (*tri)[1]]); - const std::size_t id2 (id_map[pnt_offsets[j] + (*tri)[2]]); - kth_sfc_new->addTriangle (id0, id1, id2); - } - merged_sfcs->push_back (kth_sfc_new); - - if (this->getSurfaceVecObj(geo_names[j])->getNameOfElementByID(k, tmp_name)) { - merged_sfc_names->insert(std::pair<std::string, std::size_t>(tmp_name, sfc_offsets[j] + k)); - } - } - if (n_geo_names - 1 > j) { - sfc_offsets[j + 1] = sfcs->size() + sfc_offsets[j]; - } - } - } - if (! merged_sfcs->empty()) { - this->addSurfaceVec (std::move(merged_sfcs), merged_geo_name, merged_sfc_names); - } else { - delete merged_sfc_names; - } + std::vector<GeoLib::Point*> const* merged_points(this->getPointVecObj(merged_geo_name)->getVector()); + std::vector<std::size_t> const& id_map (this->getPointVecObj(merged_geo_name)->getIDMap ()); + + const std::size_t n_geo_names(geo_names.size()); + std::vector<std::size_t> sfc_offsets(n_geo_names, 0); + auto merged_sfcs = std::unique_ptr<std::vector<GeoLib::Surface*>>( + new std::vector<GeoLib::Surface*>); + std::map<std::string, std::size_t>* merged_sfc_names(new std::map<std::string, std::size_t>); + for (std::size_t j(0); j < n_geo_names; j++) { + const std::vector<GeoLib::Surface*>* sfcs (this->getSurfaceVec(geo_names[j])); + if (sfcs) { + std::string tmp_name; + for (std::size_t k(0); k < sfcs->size(); k++) { + GeoLib::Surface* kth_sfc_new(new GeoLib::Surface (*merged_points)); + GeoLib::Surface const* const kth_sfc_old ((*sfcs)[k]); + const std::size_t size_of_kth_sfc (kth_sfc_old->getNTriangles()); + // clone surface elements using new ids + for (std::size_t i(0); i < size_of_kth_sfc; i++) { + const GeoLib::Triangle* tri ((*kth_sfc_old)[i]); + const std::size_t id0 (id_map[pnt_offsets[j] + (*tri)[0]]); + const std::size_t id1 (id_map[pnt_offsets[j] + (*tri)[1]]); + const std::size_t id2 (id_map[pnt_offsets[j] + (*tri)[2]]); + kth_sfc_new->addTriangle (id0, id1, id2); + } + merged_sfcs->push_back (kth_sfc_new); + + if (this->getSurfaceVecObj(geo_names[j])->getNameOfElementByID(k, tmp_name)) { + merged_sfc_names->insert(std::pair<std::string, std::size_t>(tmp_name, sfc_offsets[j] + k)); + } + } + if (n_geo_names - 1 > j) { + sfc_offsets[j + 1] = sfcs->size() + sfc_offsets[j]; + } + } + } + if (! merged_sfcs->empty()) { + this->addSurfaceVec (std::move(merged_sfcs), merged_geo_name, merged_sfc_names); + } else { + delete merged_sfc_names; + } } const GeoLib::GeoObject* GEOObjects::getGeoObject(const std::string &geo_name, GeoLib::GEOTYPE type, const std::string &geo_obj_name) const { - GeoLib::GeoObject *geo_obj(nullptr); - switch (type) { - case GeoLib::GEOTYPE::POINT: { - GeoLib::PointVec const* pnt_vec(getPointVecObj(geo_name)); - if (pnt_vec) - geo_obj = const_cast<GeoLib::GeoObject*>( - dynamic_cast<GeoLib::GeoObject const*>( - pnt_vec->getElementByName(geo_obj_name))); - break; - } - case GeoLib::GEOTYPE::POLYLINE: { - GeoLib::PolylineVec const* ply_vec(getPolylineVecObj(geo_name)); - if (ply_vec) - geo_obj = const_cast<GeoLib::GeoObject*>( - dynamic_cast<GeoLib::GeoObject const*>( - ply_vec->getElementByName(geo_obj_name))); - break; - } - case GeoLib::GEOTYPE::SURFACE: { - GeoLib::SurfaceVec const* sfc_vec(getSurfaceVecObj(geo_name)); - if (sfc_vec) - geo_obj = const_cast<GeoLib::GeoObject*>( - dynamic_cast<GeoLib::GeoObject const*>( - sfc_vec->getElementByName(geo_obj_name))); - break; - } - default: - ERR("GEOObjects::getGeoObject(): geometric type not handled.") - return nullptr; - }; - - if (!geo_obj) { - DBUG("GEOObjects::getGeoObject(): Could not find %s \"%s\" in geometry.", - GeoLib::convertGeoTypeToString(type).c_str(), geo_obj_name.c_str()); - } - return geo_obj; + GeoLib::GeoObject *geo_obj(nullptr); + switch (type) { + case GeoLib::GEOTYPE::POINT: { + GeoLib::PointVec const* pnt_vec(getPointVecObj(geo_name)); + if (pnt_vec) + geo_obj = const_cast<GeoLib::GeoObject*>( + dynamic_cast<GeoLib::GeoObject const*>( + pnt_vec->getElementByName(geo_obj_name))); + break; + } + case GeoLib::GEOTYPE::POLYLINE: { + GeoLib::PolylineVec const* ply_vec(getPolylineVecObj(geo_name)); + if (ply_vec) + geo_obj = const_cast<GeoLib::GeoObject*>( + dynamic_cast<GeoLib::GeoObject const*>( + ply_vec->getElementByName(geo_obj_name))); + break; + } + case GeoLib::GEOTYPE::SURFACE: { + GeoLib::SurfaceVec const* sfc_vec(getSurfaceVecObj(geo_name)); + if (sfc_vec) + geo_obj = const_cast<GeoLib::GeoObject*>( + dynamic_cast<GeoLib::GeoObject const*>( + sfc_vec->getElementByName(geo_obj_name))); + break; + } + default: + ERR("GEOObjects::getGeoObject(): geometric type not handled.") + return nullptr; + }; + + if (!geo_obj) { + DBUG("GEOObjects::getGeoObject(): Could not find %s \"%s\" in geometry.", + GeoLib::convertGeoTypeToString(type).c_str(), geo_obj_name.c_str()); + } + return geo_obj; } GeoLib::GeoObject const* GEOObjects::getGeoObject( - const std::string &geo_name, - const std::string &geo_obj_name) const + const std::string &geo_name, + const std::string &geo_obj_name) const { - GeoLib::GeoObject const* geo_obj( - getGeoObject(geo_name, GeoLib::GEOTYPE::POINT, geo_obj_name) - ); + GeoLib::GeoObject const* geo_obj( + getGeoObject(geo_name, GeoLib::GEOTYPE::POINT, geo_obj_name) + ); - if(!geo_obj) - geo_obj = getGeoObject(geo_name, GeoLib::GEOTYPE::POLYLINE, geo_obj_name); + if(!geo_obj) + geo_obj = getGeoObject(geo_name, GeoLib::GEOTYPE::POLYLINE, geo_obj_name); - if(!geo_obj) - geo_obj = getGeoObject(geo_name, GeoLib::GEOTYPE::SURFACE, geo_obj_name); + if(!geo_obj) + geo_obj = getGeoObject(geo_name, GeoLib::GEOTYPE::SURFACE, geo_obj_name); - if (!geo_obj) { - DBUG("GEOObjects::getGeoObject(): Could not find \"%s\" in geometry %s.", - geo_obj_name.c_str(), geo_name.c_str()); - } - return geo_obj; + if (!geo_obj) { + DBUG("GEOObjects::getGeoObject(): Could not find \"%s\" in geometry %s.", + geo_obj_name.c_str(), geo_name.c_str()); + } + return geo_obj; } std::size_t GEOObjects::exists(const std::string &geometry_name) const { - std::size_t const size (_pnt_vecs.size()); - for (std::size_t i = 0; i < size; i++) - if (_pnt_vecs[i]->getName().compare(geometry_name) == 0) - return i; + std::size_t const size (_pnt_vecs.size()); + for (std::size_t i = 0; i < size; i++) + if (_pnt_vecs[i]->getName().compare(geometry_name) == 0) + return i; - // HACK for enabling conversion of files without loading the associated geometry - if (size>0 && _pnt_vecs[0]->getName().compare("conversionTestRun#1")==0) - return 1; + // HACK for enabling conversion of files without loading the associated geometry + if (size>0 && _pnt_vecs[0]->getName().compare("conversionTestRun#1")==0) + return 1; - return std::numeric_limits<std::size_t>::max(); + return std::numeric_limits<std::size_t>::max(); } diff --git a/GeoLib/GEOObjects.h b/GeoLib/GEOObjects.h index 72d50ab8146f205db8d5e99a0556628a981bafb1..d877b7d9dc90c32d9174c4315d8636f22bc25c54 100644 --- a/GeoLib/GEOObjects.h +++ b/GeoLib/GEOObjects.h @@ -63,292 +63,292 @@ namespace GeoLib class GEOObjects final { public: - struct Callbacks - { - virtual void addPointVec(std::string const&){} - virtual void removePointVec(std::string const&){} - virtual void addStationVec(std::string const&){} - virtual void removeStationVec(std::string const&){} - virtual void addPolylineVec(std::string const&){} - virtual void appendPolylineVec(std::string const&){} - virtual void removePolylineVec(std::string const&){} - virtual void addSurfaceVec(std::string const&){} - virtual void appendSurfaceVec(std::string const&){} - virtual void removeSurfaceVec(std::string const&){} - }; + struct Callbacks + { + virtual void addPointVec(std::string const&){} + virtual void removePointVec(std::string const&){} + virtual void addStationVec(std::string const&){} + virtual void removeStationVec(std::string const&){} + virtual void addPolylineVec(std::string const&){} + virtual void appendPolylineVec(std::string const&){} + virtual void removePolylineVec(std::string const&){} + virtual void addSurfaceVec(std::string const&){} + virtual void appendSurfaceVec(std::string const&){} + virtual void removeSurfaceVec(std::string const&){} + }; public: - /** - * Adds a vector of points with the given name to GEOObjects. - * @param points vector of pointers to points - * @param name the project name - * @param pnt_names vector of the names corresponding to the points - * @param eps relative tolerance value for testing of point uniqueness - */ - void addPointVec(std::unique_ptr<std::vector<Point*>> points, - std::string& name, - std::map<std::string, std::size_t>* pnt_names = nullptr, - double eps = sqrt(std::numeric_limits<double>::epsilon())); - - /** - * Returns the point vector with the given name. - */ - const std::vector<Point*>* getPointVec(const std::string &name) const; - - /** - * search and returns the PointVec object with the given name. - * @param name the name of the PointVec object - * @return the PointVec object stored in GEOObjects - */ - const PointVec* getPointVecObj(const std::string &name) const; - - /// Returns a pointer to a PointVec object for the given name. - PointVec* getPointVecObj(const std::string &name) - { - return const_cast<PointVec*>(static_cast<const GEOObjects&>(*this). - getPointVecObj(name)); - } - - /** If there exists no dependencies the point vector with the given - * name from GEOObjects will be removed and the method returns true, - * else the return value is false. - */ - bool removePointVec(const std::string &name); - - /// Adds a vector of stations with the given name and colour to GEOObjects. - void addStationVec( - std::unique_ptr<std::vector<Point *>> stations, std::string &name); - - /// Returns the station vector with the given name. - const std::vector<GeoLib::Point*>* getStationVec( - const std::string& name) const; - - /// Removes the station vector with the given name from GEOObjects - bool removeStationVec(const std::string &name) - { - _callbacks->removeStationVec(name); - return removePointVec(name); - } - - /** - * Adds a vector of polylines with the given name to GEOObjects. - * @param lines The lines vector. - * @param name The geometry to which the given Polyline objects should be added. - * @param ply_names map of names and ids that are corresponding to the polylines - */ - void addPolylineVec(std::unique_ptr<std::vector<Polyline*>> lines, - const std::string &name, - std::map<std::string,std::size_t>* ply_names = nullptr); - - /** copies the pointers to the polylines in the vector to the PolylineVec with provided name. - * the pointers are managed by the GEOObjects, i.e. GEOObjects will delete the Polylines at the - * end of its scope - * \param polylines the vector with polylines - * \param name the name of the internal PolylineVec - * \return true if the polylines are appended, false if the PolylineVec with the - * corresponding name does not exist - * */ - bool appendPolylineVec(const std::vector<Polyline*> &polylines, - const std::string &name); - - /** - * Returns the polyline vector with the given name. - * */ - const std::vector<Polyline*>* getPolylineVec(const std::string &name) const; - - /** - * Returns a pointer to a PolylineVec object for the given name as a const. - * @param name the name of the vector of polylines - * @return PolylineVec object - */ - const PolylineVec* getPolylineVecObj(const std::string &name) const; - - /// Returns a pointer to a PolylineVec object for the given name. - PolylineVec* getPolylineVecObj(const std::string &name) - { - return const_cast<PolylineVec*>(static_cast<const GEOObjects&>(*this). - getPolylineVecObj(name)); - } - - /** - * If no Surfaces depends on the vector of Polylines with the given - * name it will be removed and the method returns true, - * else the return value is false. - */ - bool removePolylineVec(const std::string &name); - - /** Adds a vector of surfaces with the given name to GEOObjects. */ - void addSurfaceVec(std::unique_ptr<std::vector<Surface*>> surfaces, - const std::string &name, - std::map<std::string, std::size_t>* sfc_names = nullptr); - - /** - * Copies the surfaces in the vector to the SurfaceVec with the given name. - * \param surfaces the vector with surfaces - * \param name the name of the internal PolylineVec - * \return true if the surfaces are appended, false if the SurfaceVec with the - * corresponding name does not exist and the surfaces are added. - * */ - bool appendSurfaceVec(const std::vector<Surface*> &surfaces, - const std::string &name); - - /// Returns the surface vector with the given name as a const. - const std::vector<Surface*>* getSurfaceVec(const std::string &name) const; - - /// Returns the surface vector with the given name. - SurfaceVec* getSurfaceVecObj(const std::string &name) - { - return const_cast<SurfaceVec*>(static_cast<const GEOObjects&>(*this). - getSurfaceVecObj(name)); - } - - /** removes the vector of Surfaces with the given name */ - bool removeSurfaceVec(const std::string &name); - /** - * Returns a pointer to a SurfaceVec object for the given name. The class - * SurfaceVec stores the relation between surfaces and the names of the surfaces. - * @param name the name of the vector of surfaces (the project name) - * @return SurfaceVec object - */ - const SurfaceVec* getSurfaceVecObj(const std::string &name) const; - - /// Returns the names of all geometry vectors. - void getGeometryNames (std::vector<std::string>& names) const; - - const std::string getElementNameByID(const std::string &geometry_name, GeoLib::GEOTYPE type, std::size_t id) const; - - /// Returns the names of all station vectors. - void getStationVectorNames(std::vector<std::string>& names) const; - - /** - * Determines if the given name is unique among all the names in point vectors and creates a - * new name if this is not the case. The new name is then simply "name + x", where x>1 is - * the smallest number that creates a unique name (i.e. "name-2", "name-3", etc.) - * \param name Original name of the list, this name might be changed within this method if necessary. - * \return true if the name was unique, false if a new name has been generated - */ - bool isUniquePointVecName(std::string &name); - - /** - * Method mergeGeometries merges the geometries that are given by the names in the vector. - * Stations points are not included in the resulting merged geometry. - * @param names the names of the geometries that are to be merged - * @param merged_geo_name the name of the resulting geometry - * @return 0 if success, 1 if no point-list is found for at least one of the geometries and 2 if the mergelist only contains less than two geometry - */ - int mergeGeometries(std::vector<std::string> const & names, std::string &merged_geo_name); - - /// Returns the geo object for a geometric item of the given name and type for the associated geometry. - const GeoLib::GeoObject* getGeoObject(const std::string &geo_name, - GeoLib::GEOTYPE type, - const std::string &geo_obj_name) const; - - /// Return named (by the tuple geo_name and geo_obj_name) geo object. - // It is required that a tuple is a unique key for a geometric object! - // If there is another geo object with same name one of them is returned. - // In theory different types of geometric objects can have the same name. - // For instance it is possible that a point object and a polyline object - // share the same name. If there exists several objects sharing the same - // name the first object found will be returned. - // @param geo_name name of geometry - // @param geo_obj_name name of the geo object - GeoLib::GeoObject const* getGeoObject(const std::string &geo_name, - const std::string &geo_obj_name) const; - - /** constructor */ - GEOObjects(); - /** destructor */ - ~GEOObjects(); - - /// Returns std::numeric_limits<std::size_t>::max() if no geometry of the - /// given name exists or the index of the geometry in _pnt_vecs otherwise - std::size_t exists(const std::string &geometry_name) const; - - /// Checks if the point vector with the given name is referenced in a polyline- or surface vector. - bool isPntVecUsed (const std::string &name) const; - - /** - * vector manages pointers to PointVec objects - */ - std::vector<PointVec*> _pnt_vecs; - - /** vector manages pointers to PolylineVec objects */ - std::vector<PolylineVec*> _ply_vecs; - /** vector manages pointers to SurfaceVec objects */ - std::vector<SurfaceVec*> _sfc_vecs; - - std::unique_ptr<Callbacks> _callbacks{new Callbacks}; - - std::function<void(std::string const&)> addPolylineVecCallback = - [](std::string const&) - { - }; - - std::function<void(std::string const&)> appendPolylineVecCallback = - [](std::string const&) - { - }; - - std::function<void(std::string const&)> removePolylineVecCallback = - [](std::string const&) - { - }; - - std::function<void(std::string const&)> addSurfaceVecCallback = - [](std::string const&) - { - }; - - std::function<void(std::string const&)> appendSurfaceVecCallback = - [](std::string const&) - { - }; - - std::function<void(std::string const&)> removeSurfaceVecCallback = - [](std::string const&) - { - }; + /** + * Adds a vector of points with the given name to GEOObjects. + * @param points vector of pointers to points + * @param name the project name + * @param pnt_names vector of the names corresponding to the points + * @param eps relative tolerance value for testing of point uniqueness + */ + void addPointVec(std::unique_ptr<std::vector<Point*>> points, + std::string& name, + std::map<std::string, std::size_t>* pnt_names = nullptr, + double eps = sqrt(std::numeric_limits<double>::epsilon())); + + /** + * Returns the point vector with the given name. + */ + const std::vector<Point*>* getPointVec(const std::string &name) const; + + /** + * search and returns the PointVec object with the given name. + * @param name the name of the PointVec object + * @return the PointVec object stored in GEOObjects + */ + const PointVec* getPointVecObj(const std::string &name) const; + + /// Returns a pointer to a PointVec object for the given name. + PointVec* getPointVecObj(const std::string &name) + { + return const_cast<PointVec*>(static_cast<const GEOObjects&>(*this). + getPointVecObj(name)); + } + + /** If there exists no dependencies the point vector with the given + * name from GEOObjects will be removed and the method returns true, + * else the return value is false. + */ + bool removePointVec(const std::string &name); + + /// Adds a vector of stations with the given name and colour to GEOObjects. + void addStationVec( + std::unique_ptr<std::vector<Point *>> stations, std::string &name); + + /// Returns the station vector with the given name. + const std::vector<GeoLib::Point*>* getStationVec( + const std::string& name) const; + + /// Removes the station vector with the given name from GEOObjects + bool removeStationVec(const std::string &name) + { + _callbacks->removeStationVec(name); + return removePointVec(name); + } + + /** + * Adds a vector of polylines with the given name to GEOObjects. + * @param lines The lines vector. + * @param name The geometry to which the given Polyline objects should be added. + * @param ply_names map of names and ids that are corresponding to the polylines + */ + void addPolylineVec(std::unique_ptr<std::vector<Polyline*>> lines, + const std::string &name, + std::map<std::string,std::size_t>* ply_names = nullptr); + + /** copies the pointers to the polylines in the vector to the PolylineVec with provided name. + * the pointers are managed by the GEOObjects, i.e. GEOObjects will delete the Polylines at the + * end of its scope + * \param polylines the vector with polylines + * \param name the name of the internal PolylineVec + * \return true if the polylines are appended, false if the PolylineVec with the + * corresponding name does not exist + * */ + bool appendPolylineVec(const std::vector<Polyline*> &polylines, + const std::string &name); + + /** + * Returns the polyline vector with the given name. + * */ + const std::vector<Polyline*>* getPolylineVec(const std::string &name) const; + + /** + * Returns a pointer to a PolylineVec object for the given name as a const. + * @param name the name of the vector of polylines + * @return PolylineVec object + */ + const PolylineVec* getPolylineVecObj(const std::string &name) const; + + /// Returns a pointer to a PolylineVec object for the given name. + PolylineVec* getPolylineVecObj(const std::string &name) + { + return const_cast<PolylineVec*>(static_cast<const GEOObjects&>(*this). + getPolylineVecObj(name)); + } + + /** + * If no Surfaces depends on the vector of Polylines with the given + * name it will be removed and the method returns true, + * else the return value is false. + */ + bool removePolylineVec(const std::string &name); + + /** Adds a vector of surfaces with the given name to GEOObjects. */ + void addSurfaceVec(std::unique_ptr<std::vector<Surface*>> surfaces, + const std::string &name, + std::map<std::string, std::size_t>* sfc_names = nullptr); + + /** + * Copies the surfaces in the vector to the SurfaceVec with the given name. + * \param surfaces the vector with surfaces + * \param name the name of the internal PolylineVec + * \return true if the surfaces are appended, false if the SurfaceVec with the + * corresponding name does not exist and the surfaces are added. + * */ + bool appendSurfaceVec(const std::vector<Surface*> &surfaces, + const std::string &name); + + /// Returns the surface vector with the given name as a const. + const std::vector<Surface*>* getSurfaceVec(const std::string &name) const; + + /// Returns the surface vector with the given name. + SurfaceVec* getSurfaceVecObj(const std::string &name) + { + return const_cast<SurfaceVec*>(static_cast<const GEOObjects&>(*this). + getSurfaceVecObj(name)); + } + + /** removes the vector of Surfaces with the given name */ + bool removeSurfaceVec(const std::string &name); + /** + * Returns a pointer to a SurfaceVec object for the given name. The class + * SurfaceVec stores the relation between surfaces and the names of the surfaces. + * @param name the name of the vector of surfaces (the project name) + * @return SurfaceVec object + */ + const SurfaceVec* getSurfaceVecObj(const std::string &name) const; + + /// Returns the names of all geometry vectors. + void getGeometryNames (std::vector<std::string>& names) const; + + const std::string getElementNameByID(const std::string &geometry_name, GeoLib::GEOTYPE type, std::size_t id) const; + + /// Returns the names of all station vectors. + void getStationVectorNames(std::vector<std::string>& names) const; + + /** + * Determines if the given name is unique among all the names in point vectors and creates a + * new name if this is not the case. The new name is then simply "name + x", where x>1 is + * the smallest number that creates a unique name (i.e. "name-2", "name-3", etc.) + * \param name Original name of the list, this name might be changed within this method if necessary. + * \return true if the name was unique, false if a new name has been generated + */ + bool isUniquePointVecName(std::string &name); + + /** + * Method mergeGeometries merges the geometries that are given by the names in the vector. + * Stations points are not included in the resulting merged geometry. + * @param names the names of the geometries that are to be merged + * @param merged_geo_name the name of the resulting geometry + * @return 0 if success, 1 if no point-list is found for at least one of the geometries and 2 if the mergelist only contains less than two geometry + */ + int mergeGeometries(std::vector<std::string> const & names, std::string &merged_geo_name); + + /// Returns the geo object for a geometric item of the given name and type for the associated geometry. + const GeoLib::GeoObject* getGeoObject(const std::string &geo_name, + GeoLib::GEOTYPE type, + const std::string &geo_obj_name) const; + + /// Return named (by the tuple geo_name and geo_obj_name) geo object. + // It is required that a tuple is a unique key for a geometric object! + // If there is another geo object with same name one of them is returned. + // In theory different types of geometric objects can have the same name. + // For instance it is possible that a point object and a polyline object + // share the same name. If there exists several objects sharing the same + // name the first object found will be returned. + // @param geo_name name of geometry + // @param geo_obj_name name of the geo object + GeoLib::GeoObject const* getGeoObject(const std::string &geo_name, + const std::string &geo_obj_name) const; + + /** constructor */ + GEOObjects(); + /** destructor */ + ~GEOObjects(); + + /// Returns std::numeric_limits<std::size_t>::max() if no geometry of the + /// given name exists or the index of the geometry in _pnt_vecs otherwise + std::size_t exists(const std::string &geometry_name) const; + + /// Checks if the point vector with the given name is referenced in a polyline- or surface vector. + bool isPntVecUsed (const std::string &name) const; + + /** + * vector manages pointers to PointVec objects + */ + std::vector<PointVec*> _pnt_vecs; + + /** vector manages pointers to PolylineVec objects */ + std::vector<PolylineVec*> _ply_vecs; + /** vector manages pointers to SurfaceVec objects */ + std::vector<SurfaceVec*> _sfc_vecs; + + std::unique_ptr<Callbacks> _callbacks{new Callbacks}; + + std::function<void(std::string const&)> addPolylineVecCallback = + [](std::string const&) + { + }; + + std::function<void(std::string const&)> appendPolylineVecCallback = + [](std::string const&) + { + }; + + std::function<void(std::string const&)> removePolylineVecCallback = + [](std::string const&) + { + }; + + std::function<void(std::string const&)> addSurfaceVecCallback = + [](std::string const&) + { + }; + + std::function<void(std::string const&)> appendSurfaceVecCallback = + [](std::string const&) + { + }; + + std::function<void(std::string const&)> removeSurfaceVecCallback = + [](std::string const&) + { + }; private: - /** - * Method merges points from different geometries into one geometry. This - * is a helper method for GEOObjects::mergeGeometries(). - * @param geo_names The vector of names of the geometries to merge. - * @param merged_geo_name The (new) name of the geometry resulting from - * merging. - * @param pnt_offsets offsets in the merged vector storing the points - * @return true, if merging the points succeeded, else false - */ - bool mergePoints(std::vector<std::string> const & geo_names, std::string & merged_geo_name, - std::vector<std::size_t> &pnt_offsets); - - /** - * Method merges GeoLib::Polylines from different geometries into one - * geometry. There isn't a check if the polyline is unique within the - * given data sets. If there are two polylines with the same name, the - * second occurrence will lost their name. This is a helper for - * GEOObjects::mergeGeometries() and should be used only after - * GEOObjects::mergePoints() is executed. - * @param geo_names The vector of names of the geometries to merge. - * @param merged_geo_name The (new) name of the geometry resulting from - * merging. - * @param pnt_offsets offsets in the merged vector storing the points. - */ - void mergePolylines(std::vector<std::string> const & geo_names, std::string & merged_geo_name, - std::vector<std::size_t> const& pnt_offsets); - - /** - * Method merges GeoLib::Surfaces from different geometries into one - * geometry. There isn't a check if the GeoLib::Surface is unique within - * the given data sets. This is a helper for GEOObjects::mergeGeometries() - * and should be used only after GEOObjects::mergePoints() is executed. - * @param geo_names The vector of names of the geometries to merge. - * @param merged_geo_name The (new) name of the geometry resulting from - * merging. - * @param pnt_offsets offsets in the merged vector storing the points. - */ - void mergeSurfaces(std::vector<std::string> const & geo_names, - std::string & merged_geo_name, std::vector<std::size_t> const& pnt_offsets); + /** + * Method merges points from different geometries into one geometry. This + * is a helper method for GEOObjects::mergeGeometries(). + * @param geo_names The vector of names of the geometries to merge. + * @param merged_geo_name The (new) name of the geometry resulting from + * merging. + * @param pnt_offsets offsets in the merged vector storing the points + * @return true, if merging the points succeeded, else false + */ + bool mergePoints(std::vector<std::string> const & geo_names, std::string & merged_geo_name, + std::vector<std::size_t> &pnt_offsets); + + /** + * Method merges GeoLib::Polylines from different geometries into one + * geometry. There isn't a check if the polyline is unique within the + * given data sets. If there are two polylines with the same name, the + * second occurrence will lost their name. This is a helper for + * GEOObjects::mergeGeometries() and should be used only after + * GEOObjects::mergePoints() is executed. + * @param geo_names The vector of names of the geometries to merge. + * @param merged_geo_name The (new) name of the geometry resulting from + * merging. + * @param pnt_offsets offsets in the merged vector storing the points. + */ + void mergePolylines(std::vector<std::string> const & geo_names, std::string & merged_geo_name, + std::vector<std::size_t> const& pnt_offsets); + + /** + * Method merges GeoLib::Surfaces from different geometries into one + * geometry. There isn't a check if the GeoLib::Surface is unique within + * the given data sets. This is a helper for GEOObjects::mergeGeometries() + * and should be used only after GEOObjects::mergePoints() is executed. + * @param geo_names The vector of names of the geometries to merge. + * @param merged_geo_name The (new) name of the geometry resulting from + * merging. + * @param pnt_offsets offsets in the merged vector storing the points. + */ + void mergeSurfaces(std::vector<std::string> const & geo_names, + std::string & merged_geo_name, std::vector<std::size_t> const& pnt_offsets); }; } // end namespace diff --git a/GeoLib/GeoObject.h b/GeoLib/GeoObject.h index a923d983a703f01b1b5fad77a2cf76b2645843ef..eef286c10520e5059e0de229444218eb38b0a71a 100644 --- a/GeoLib/GeoObject.h +++ b/GeoLib/GeoObject.h @@ -23,12 +23,12 @@ namespace GeoLib class GeoObject { public: - GeoObject() = default; - GeoObject(GeoObject const&) = default; - GeoObject& operator=(GeoObject const&) = default; - virtual ~GeoObject() = default; - /// return a geometry type - virtual GEOTYPE getGeoType() const = 0; + GeoObject() = default; + GeoObject(GeoObject const&) = default; + GeoObject& operator=(GeoObject const&) = default; + virtual ~GeoObject() = default; + /// return a geometry type + virtual GEOTYPE getGeoType() const = 0; }; } // end namespace GeoLib diff --git a/GeoLib/Grid.h b/GeoLib/Grid.h index 96dbd51c8f073662080cea369b76ef20d89fe6f6..65e380a9c9549a2dd56d2a32c1b1301b5171c23b 100644 --- a/GeoLib/Grid.h +++ b/GeoLib/Grid.h @@ -35,339 +35,339 @@ template <typename POINT> class Grid : public GeoLib::AABB { public: - /** - * @brief The constructor of the grid object takes a vector of points or nodes. Furthermore the - * user can specify the *average* maximum number of points per grid cell. - * - * The number of grid cells are computed with the following formula - * \f$\frac{n_{points}}{n_{cells}} \le n_{max\_per\_cell}\f$ - * - * In order to limit the memory wasting the maximum number of points per grid cell - * (in the average) should be a power of two (since std::vector objects resize itself - * with this step size). - * - * @param first, last the range of elements to examine - * @param items_per_cell (input) max number per grid cell in the average (default 512) - * - */ - template <typename InputIterator> - Grid(InputIterator first, InputIterator last, std::size_t items_per_cell = 512); - - /** - * This is the destructor of the class. It deletes the internal data structures *not* - * including the pointers to the points. - */ - virtual ~Grid() - { - delete [] _grid_cell_nodes_map; - } - - /** - * The method calculates the grid cell the given point is belonging to, i.e., - * the (internal) coordinates of the grid cell are computed. The method searches the actual - * grid cell and all its neighbors for the POINT object which has the smallest - * distance. A pointer to this object is returned. - * - * If there is not such a point, i.e., all the searched grid cells do not contain any - * POINT object a nullptr is returned. - * - * @param pnt search point - * @return a pointer to the point with the smallest distance within the grid cells that are - * outlined above or nullptr - */ - template <typename P> POINT* getNearestPoint(P const& pnt) const; - - template <typename P> std::vector<std::size_t> getPointsInEpsilonEnvironment( - P const& pnt, double eps) const; - - /** - * Method fetches the vectors of all grid cells intersecting the axis aligned cuboid - * defined by two points. The first point with minimal coordinates in all directions. - * The second point with maximal coordinates in all directions. - * - * @param center (input) the center point of the axis aligned cube - * @param half_len (input) half of the edge length of the axis aligned cube - * @return vector of vectors of points within grid cells that intersects - * the axis aligned cube - */ - template <typename P> - std::vector<std::vector<POINT*> const*> - getPntVecsOfGridCellsIntersectingCube(P const& center, double half_len) const; - - void getPntVecsOfGridCellsIntersectingCuboid( - MathLib::Point3d const& min_pnt, - MathLib::Point3d const& max_pnt, - std::vector<std::vector<POINT*> const*>& pnts) const; + /** + * @brief The constructor of the grid object takes a vector of points or nodes. Furthermore the + * user can specify the *average* maximum number of points per grid cell. + * + * The number of grid cells are computed with the following formula + * \f$\frac{n_{points}}{n_{cells}} \le n_{max\_per\_cell}\f$ + * + * In order to limit the memory wasting the maximum number of points per grid cell + * (in the average) should be a power of two (since std::vector objects resize itself + * with this step size). + * + * @param first, last the range of elements to examine + * @param items_per_cell (input) max number per grid cell in the average (default 512) + * + */ + template <typename InputIterator> + Grid(InputIterator first, InputIterator last, std::size_t items_per_cell = 512); + + /** + * This is the destructor of the class. It deletes the internal data structures *not* + * including the pointers to the points. + */ + virtual ~Grid() + { + delete [] _grid_cell_nodes_map; + } + + /** + * The method calculates the grid cell the given point is belonging to, i.e., + * the (internal) coordinates of the grid cell are computed. The method searches the actual + * grid cell and all its neighbors for the POINT object which has the smallest + * distance. A pointer to this object is returned. + * + * If there is not such a point, i.e., all the searched grid cells do not contain any + * POINT object a nullptr is returned. + * + * @param pnt search point + * @return a pointer to the point with the smallest distance within the grid cells that are + * outlined above or nullptr + */ + template <typename P> POINT* getNearestPoint(P const& pnt) const; + + template <typename P> std::vector<std::size_t> getPointsInEpsilonEnvironment( + P const& pnt, double eps) const; + + /** + * Method fetches the vectors of all grid cells intersecting the axis aligned cuboid + * defined by two points. The first point with minimal coordinates in all directions. + * The second point with maximal coordinates in all directions. + * + * @param center (input) the center point of the axis aligned cube + * @param half_len (input) half of the edge length of the axis aligned cube + * @return vector of vectors of points within grid cells that intersects + * the axis aligned cube + */ + template <typename P> + std::vector<std::vector<POINT*> const*> + getPntVecsOfGridCellsIntersectingCube(P const& center, double half_len) const; + + void getPntVecsOfGridCellsIntersectingCuboid( + MathLib::Point3d const& min_pnt, + MathLib::Point3d const& max_pnt, + std::vector<std::vector<POINT*> const*>& pnts) const; #ifndef NDEBUG - /** - * Method creates a geometry for every mesh grid box. Additionally it - * creates one geometry containing all the box geometries. - * @param geo_obj - */ - void createGridGeometry(GeoLib::GEOObjects* geo_obj) const; + /** + * Method creates a geometry for every mesh grid box. Additionally it + * creates one geometry containing all the box geometries. + * @param geo_obj + */ + void createGridGeometry(GeoLib::GEOObjects* geo_obj) const; #endif private: - /// Computes the number of grid cells per spatial dimension the objects - /// (points or mesh nodes) will be sorted in. - /// On the one hand the number of grid cells should be small to reduce the - /// management overhead. On the other hand the number should be large such - /// that each grid cell contains only a small number of objects. - /// Under the assumption that the points are distributed equidistant in - /// space the grid cells should be as cubical as possible. - /// At first it is necessary to determine the spatial dimension the grid - /// should have. The dimensions are computed from the spatial extensions - /// Let \f$\max\f$ be the largest spatial extension. The grid will have a - /// spatial dimension if the ratio of the corresponding spatial extension - /// and the maximal extension is \f$\ge 10^{-4}\f$. - /// The second step consists of computing the number of cells per dimension. - void initNumberOfSteps(std::size_t n_per_cell, - std::size_t n_pnts, std::array<double,3> const& extensions); - - /** - * Method calculates the grid cell coordinates for the given point pnt. If - * the point is located outside of the bounding box the coordinates of the - * grid cell on the border that is nearest to given point will be returned. - * @param pnt (input) the coordinates of the point - * @return the coordinates of the grid cell - */ - template <typename T> - std::array<std::size_t,3> getGridCoords(T const& pnt) const; - - /** - * - * point numbering of the grid cell is as follow - * @code - * 7 -------- 6 - * /: /| - * / : / | - * / : / | - * / : / | - * 4 -------- 5 | - * | 3 ....|... 2 - * | . | / - * | . | / - * | . | / - * |. |/ - * 0 -------- 1 - * @endcode - * the face numbering is as follow: - * face nodes - * 0 0,3,2,1 bottom - * 1 0,1,5,4 front - * 2 1,2,6,5 right - * 3 2,3,7,6 back - * 4 3,0,4,7 left - * 5 4,5,6,7 top - * @param pnt (input) coordinates of the point - * @param coordinates of the grid cell - * @return squared distances of the point to the faces of the grid cell - * ordered in the same sequence as above described - */ - template <typename P> - std::array<double, 6> getPointCellBorderDistances( - P const& pnt, std::array<std::size_t,3> const& coordinates) const; - - template <typename P> - bool calcNearestPointInGridCell(P const& pnt, - std::array<std::size_t,3> const& coords, - double &sqr_min_dist, - POINT* &nearest_pnt) const; - - static POINT* copyOrAddress(POINT& p) { return &p; } - static POINT const* copyOrAddress(POINT const& p) { return &p; } - static POINT* copyOrAddress(POINT* p) { return p; } - - std::array<std::size_t,3> _n_steps; - std::array<double, 3> _step_sizes; - std::array<double, 3> _inverse_step_sizes; - /** - * This is an array that stores pointers to POINT objects. - */ - std::vector<POINT*>* _grid_cell_nodes_map; + /// Computes the number of grid cells per spatial dimension the objects + /// (points or mesh nodes) will be sorted in. + /// On the one hand the number of grid cells should be small to reduce the + /// management overhead. On the other hand the number should be large such + /// that each grid cell contains only a small number of objects. + /// Under the assumption that the points are distributed equidistant in + /// space the grid cells should be as cubical as possible. + /// At first it is necessary to determine the spatial dimension the grid + /// should have. The dimensions are computed from the spatial extensions + /// Let \f$\max\f$ be the largest spatial extension. The grid will have a + /// spatial dimension if the ratio of the corresponding spatial extension + /// and the maximal extension is \f$\ge 10^{-4}\f$. + /// The second step consists of computing the number of cells per dimension. + void initNumberOfSteps(std::size_t n_per_cell, + std::size_t n_pnts, std::array<double,3> const& extensions); + + /** + * Method calculates the grid cell coordinates for the given point pnt. If + * the point is located outside of the bounding box the coordinates of the + * grid cell on the border that is nearest to given point will be returned. + * @param pnt (input) the coordinates of the point + * @return the coordinates of the grid cell + */ + template <typename T> + std::array<std::size_t,3> getGridCoords(T const& pnt) const; + + /** + * + * point numbering of the grid cell is as follow + * @code + * 7 -------- 6 + * /: /| + * / : / | + * / : / | + * / : / | + * 4 -------- 5 | + * | 3 ....|... 2 + * | . | / + * | . | / + * | . | / + * |. |/ + * 0 -------- 1 + * @endcode + * the face numbering is as follow: + * face nodes + * 0 0,3,2,1 bottom + * 1 0,1,5,4 front + * 2 1,2,6,5 right + * 3 2,3,7,6 back + * 4 3,0,4,7 left + * 5 4,5,6,7 top + * @param pnt (input) coordinates of the point + * @param coordinates of the grid cell + * @return squared distances of the point to the faces of the grid cell + * ordered in the same sequence as above described + */ + template <typename P> + std::array<double, 6> getPointCellBorderDistances( + P const& pnt, std::array<std::size_t,3> const& coordinates) const; + + template <typename P> + bool calcNearestPointInGridCell(P const& pnt, + std::array<std::size_t,3> const& coords, + double &sqr_min_dist, + POINT* &nearest_pnt) const; + + static POINT* copyOrAddress(POINT& p) { return &p; } + static POINT const* copyOrAddress(POINT const& p) { return &p; } + static POINT* copyOrAddress(POINT* p) { return p; } + + std::array<std::size_t,3> _n_steps; + std::array<double, 3> _step_sizes; + std::array<double, 3> _inverse_step_sizes; + /** + * This is an array that stores pointers to POINT objects. + */ + std::vector<POINT*>* _grid_cell_nodes_map; }; template <typename POINT> template <typename InputIterator> Grid<POINT>::Grid(InputIterator first, InputIterator last, - std::size_t max_num_per_grid_cell) - : GeoLib::AABB(first, last), _n_steps({{1,1,1}}), - _step_sizes({{0.0,0.0,0.0}}), _inverse_step_sizes({{0.0,0.0,0.0}}), - _grid_cell_nodes_map(nullptr) + std::size_t max_num_per_grid_cell) + : GeoLib::AABB(first, last), _n_steps({{1,1,1}}), + _step_sizes({{0.0,0.0,0.0}}), _inverse_step_sizes({{0.0,0.0,0.0}}), + _grid_cell_nodes_map(nullptr) { - auto const n_pnts(std::distance(first,last)); - - std::array<double, 3> delta = {{_max_pnt[0] - _min_pnt[0], - _max_pnt[1] - _min_pnt[1], - _max_pnt[2] - _min_pnt[2]}}; - - assert(n_pnts > 0); - initNumberOfSteps(max_num_per_grid_cell, static_cast<std::size_t>(n_pnts), delta); - - const std::size_t n_plane(_n_steps[0] * _n_steps[1]); - _grid_cell_nodes_map = new std::vector<POINT*>[n_plane * _n_steps[2]]; - - // some frequently used expressions to fill the grid vectors - for (std::size_t k(0); k < 3; k++) { - if (std::abs(delta[k]) < std::numeric_limits<double>::epsilon()) { - delta[k] = std::numeric_limits<double>::epsilon(); - } - _step_sizes[k] = delta[k] / _n_steps[k]; - _inverse_step_sizes[k] = 1.0 / _step_sizes[k]; - } - - // fill the grid vectors - InputIterator it(first); - while (it != last) { - std::array<std::size_t,3> coords(getGridCoords(*copyOrAddress(*it))); - if (coords < _n_steps) { - std::size_t const pos(coords[0]+coords[1]*_n_steps[0]+coords[2]*n_plane); - _grid_cell_nodes_map[pos].push_back(const_cast<POINT*>(copyOrAddress(*it))); - } else { - ERR("Grid constructor: error computing indices [%d, %d, %d], " - "max indices [%d, %d, %d].", coords[0], coords[1], coords[2], - _n_steps[0], _n_steps[1], _n_steps[2]); - } - it++; - } + auto const n_pnts(std::distance(first,last)); + + std::array<double, 3> delta = {{_max_pnt[0] - _min_pnt[0], + _max_pnt[1] - _min_pnt[1], + _max_pnt[2] - _min_pnt[2]}}; + + assert(n_pnts > 0); + initNumberOfSteps(max_num_per_grid_cell, static_cast<std::size_t>(n_pnts), delta); + + const std::size_t n_plane(_n_steps[0] * _n_steps[1]); + _grid_cell_nodes_map = new std::vector<POINT*>[n_plane * _n_steps[2]]; + + // some frequently used expressions to fill the grid vectors + for (std::size_t k(0); k < 3; k++) { + if (std::abs(delta[k]) < std::numeric_limits<double>::epsilon()) { + delta[k] = std::numeric_limits<double>::epsilon(); + } + _step_sizes[k] = delta[k] / _n_steps[k]; + _inverse_step_sizes[k] = 1.0 / _step_sizes[k]; + } + + // fill the grid vectors + InputIterator it(first); + while (it != last) { + std::array<std::size_t,3> coords(getGridCoords(*copyOrAddress(*it))); + if (coords < _n_steps) { + std::size_t const pos(coords[0]+coords[1]*_n_steps[0]+coords[2]*n_plane); + _grid_cell_nodes_map[pos].push_back(const_cast<POINT*>(copyOrAddress(*it))); + } else { + ERR("Grid constructor: error computing indices [%d, %d, %d], " + "max indices [%d, %d, %d].", coords[0], coords[1], coords[2], + _n_steps[0], _n_steps[1], _n_steps[2]); + } + it++; + } } template<typename POINT> template <typename P> std::vector<std::vector<POINT*> const*> Grid<POINT>::getPntVecsOfGridCellsIntersectingCube(P const& center, - double half_len) const + double half_len) const { - std::vector<std::vector<POINT*> const*> pnts; - MathLib::Point3d tmp_pnt{ - {{center[0]-half_len, center[1]-half_len, center[2]-half_len}}}; // min - std::array<std::size_t,3> min_coords(getGridCoords(tmp_pnt)); - - tmp_pnt[0] = center[0] + half_len; - tmp_pnt[1] = center[1] + half_len; - tmp_pnt[2] = center[2] + half_len; - std::array<std::size_t,3> max_coords(getGridCoords(tmp_pnt)); - - std::size_t coords[3], steps0_x_steps1(_n_steps[0] * _n_steps[1]); - for (coords[0] = min_coords[0]; coords[0] < max_coords[0] + 1; coords[0]++) { - for (coords[1] = min_coords[1]; coords[1] < max_coords[1] + 1; coords[1]++) { - const std::size_t coords0_p_coords1_x_steps0(coords[0] + coords[1] * _n_steps[0]); - for (coords[2] = min_coords[2]; coords[2] < max_coords[2] + 1; coords[2]++) { - pnts.push_back(&(_grid_cell_nodes_map[coords0_p_coords1_x_steps0 + coords[2] - * steps0_x_steps1])); - } - } - } - return pnts; + std::vector<std::vector<POINT*> const*> pnts; + MathLib::Point3d tmp_pnt{ + {{center[0]-half_len, center[1]-half_len, center[2]-half_len}}}; // min + std::array<std::size_t,3> min_coords(getGridCoords(tmp_pnt)); + + tmp_pnt[0] = center[0] + half_len; + tmp_pnt[1] = center[1] + half_len; + tmp_pnt[2] = center[2] + half_len; + std::array<std::size_t,3> max_coords(getGridCoords(tmp_pnt)); + + std::size_t coords[3], steps0_x_steps1(_n_steps[0] * _n_steps[1]); + for (coords[0] = min_coords[0]; coords[0] < max_coords[0] + 1; coords[0]++) { + for (coords[1] = min_coords[1]; coords[1] < max_coords[1] + 1; coords[1]++) { + const std::size_t coords0_p_coords1_x_steps0(coords[0] + coords[1] * _n_steps[0]); + for (coords[2] = min_coords[2]; coords[2] < max_coords[2] + 1; coords[2]++) { + pnts.push_back(&(_grid_cell_nodes_map[coords0_p_coords1_x_steps0 + coords[2] + * steps0_x_steps1])); + } + } + } + return pnts; } template<typename POINT> void Grid<POINT>::getPntVecsOfGridCellsIntersectingCuboid( - MathLib::Point3d const& min_pnt, - MathLib::Point3d const& max_pnt, - std::vector<std::vector<POINT*> const*>& pnts) const + MathLib::Point3d const& min_pnt, + MathLib::Point3d const& max_pnt, + std::vector<std::vector<POINT*> const*>& pnts) const { - std::array<std::size_t,3> min_coords(getGridCoords(min_pnt)); - std::array<std::size_t,3> max_coords(getGridCoords(max_pnt)); - - std::size_t coords[3], steps0_x_steps1(_n_steps[0] * _n_steps[1]); - for (coords[0] = min_coords[0]; coords[0] < max_coords[0] + 1; coords[0]++) { - for (coords[1] = min_coords[1]; coords[1] < max_coords[1] + 1; coords[1]++) { - const std::size_t coords0_p_coords1_x_steps0(coords[0] + coords[1] * _n_steps[0]); - for (coords[2] = min_coords[2]; coords[2] < max_coords[2] + 1; coords[2]++) { - pnts.push_back(&(_grid_cell_nodes_map[coords0_p_coords1_x_steps0 + coords[2] - * steps0_x_steps1])); - } - } - } + std::array<std::size_t,3> min_coords(getGridCoords(min_pnt)); + std::array<std::size_t,3> max_coords(getGridCoords(max_pnt)); + + std::size_t coords[3], steps0_x_steps1(_n_steps[0] * _n_steps[1]); + for (coords[0] = min_coords[0]; coords[0] < max_coords[0] + 1; coords[0]++) { + for (coords[1] = min_coords[1]; coords[1] < max_coords[1] + 1; coords[1]++) { + const std::size_t coords0_p_coords1_x_steps0(coords[0] + coords[1] * _n_steps[0]); + for (coords[2] = min_coords[2]; coords[2] < max_coords[2] + 1; coords[2]++) { + pnts.push_back(&(_grid_cell_nodes_map[coords0_p_coords1_x_steps0 + coords[2] + * steps0_x_steps1])); + } + } + } } #ifndef NDEBUG template <typename POINT> void Grid<POINT>::createGridGeometry(GeoLib::GEOObjects* geo_obj) const { - std::vector<std::string> grid_names; - - GeoLib::Point const& llf (getMinPoint()); - GeoLib::Point const& urb (getMaxPoint()); - - const double dx ((urb[0] - llf[0]) / _n_steps[0]); - const double dy ((urb[1] - llf[1]) / _n_steps[1]); - const double dz ((urb[2] - llf[2]) / _n_steps[2]); - - // create grid names and grid boxes as geometry - for (std::size_t i(0); i<_n_steps[0]; i++) { - for (std::size_t j(0); j<_n_steps[1]; j++) { - for (std::size_t k(0); k<_n_steps[2]; k++) { - - std::string name("Grid-"); - name += std::to_string(i); - name += "-"; - name += std::to_string(j); - name += "-"; - name += std::to_string (k); - grid_names.push_back(name); - - { - auto points = std::unique_ptr<std::vector<GeoLib::Point*>>( - new std::vector<GeoLib::Point*>); - points->push_back(new GeoLib::Point(llf[0]+i*dx, llf[1]+j*dy, llf[2]+k*dz)); - points->push_back(new GeoLib::Point(llf[0]+i*dx, llf[1]+(j+1)*dy, llf[2]+k*dz)); - points->push_back(new GeoLib::Point(llf[0]+(i+1)*dx, llf[1]+(j+1)*dy, llf[2]+k*dz)); - points->push_back(new GeoLib::Point(llf[0]+(i+1)*dx, llf[1]+j*dy, llf[2]+k*dz)); - points->push_back(new GeoLib::Point(llf[0]+i*dx, llf[1]+j*dy, llf[2]+(k+1)*dz)); - points->push_back(new GeoLib::Point(llf[0]+i*dx, llf[1]+(j+1)*dy, llf[2]+(k+1)*dz)); - points->push_back(new GeoLib::Point(llf[0]+(i+1)*dx, llf[1]+(j+1)*dy, llf[2]+(k+1)*dz)); - points->push_back(new GeoLib::Point(llf[0]+(i+1)*dx, llf[1]+j*dy, llf[2]+(k+1)*dz)); - geo_obj->addPointVec(std::move(points), grid_names.back(), - nullptr); - } - - auto plys = std::unique_ptr<std::vector<GeoLib::Polyline*>>( - new std::vector<GeoLib::Polyline*>); - auto const& points = *geo_obj->getPointVec(grid_names.back()); - GeoLib::Polyline* ply0 (new GeoLib::Polyline(points)); - - for (std::size_t l(0); l < 4; l++) - ply0->addPoint(l); - ply0->addPoint(0); - plys->push_back(ply0); - - GeoLib::Polyline* ply1 (new GeoLib::Polyline(points)); - for (std::size_t l(4); l < 8; l++) - ply1->addPoint(l); - ply1->addPoint(4); - plys->push_back(ply1); - - GeoLib::Polyline* ply2 (new GeoLib::Polyline(points)); - ply2->addPoint(0); - ply2->addPoint(4); - plys->push_back(ply2); - - GeoLib::Polyline* ply3 (new GeoLib::Polyline(points)); - ply3->addPoint(1); - ply3->addPoint(5); - plys->push_back(ply3); - - GeoLib::Polyline* ply4 (new GeoLib::Polyline(points)); - ply4->addPoint(2); - ply4->addPoint(6); - plys->push_back(ply4); - - GeoLib::Polyline* ply5 (new GeoLib::Polyline(points)); - ply5->addPoint(3); - ply5->addPoint(7); - plys->push_back(ply5); - - geo_obj->addPolylineVec(std::move(plys), grid_names.back(), - nullptr); - } - } - } - std::string merged_geo_name("Grid"); - - geo_obj->mergeGeometries(grid_names, merged_geo_name); + std::vector<std::string> grid_names; + + GeoLib::Point const& llf (getMinPoint()); + GeoLib::Point const& urb (getMaxPoint()); + + const double dx ((urb[0] - llf[0]) / _n_steps[0]); + const double dy ((urb[1] - llf[1]) / _n_steps[1]); + const double dz ((urb[2] - llf[2]) / _n_steps[2]); + + // create grid names and grid boxes as geometry + for (std::size_t i(0); i<_n_steps[0]; i++) { + for (std::size_t j(0); j<_n_steps[1]; j++) { + for (std::size_t k(0); k<_n_steps[2]; k++) { + + std::string name("Grid-"); + name += std::to_string(i); + name += "-"; + name += std::to_string(j); + name += "-"; + name += std::to_string (k); + grid_names.push_back(name); + + { + auto points = std::unique_ptr<std::vector<GeoLib::Point*>>( + new std::vector<GeoLib::Point*>); + points->push_back(new GeoLib::Point(llf[0]+i*dx, llf[1]+j*dy, llf[2]+k*dz)); + points->push_back(new GeoLib::Point(llf[0]+i*dx, llf[1]+(j+1)*dy, llf[2]+k*dz)); + points->push_back(new GeoLib::Point(llf[0]+(i+1)*dx, llf[1]+(j+1)*dy, llf[2]+k*dz)); + points->push_back(new GeoLib::Point(llf[0]+(i+1)*dx, llf[1]+j*dy, llf[2]+k*dz)); + points->push_back(new GeoLib::Point(llf[0]+i*dx, llf[1]+j*dy, llf[2]+(k+1)*dz)); + points->push_back(new GeoLib::Point(llf[0]+i*dx, llf[1]+(j+1)*dy, llf[2]+(k+1)*dz)); + points->push_back(new GeoLib::Point(llf[0]+(i+1)*dx, llf[1]+(j+1)*dy, llf[2]+(k+1)*dz)); + points->push_back(new GeoLib::Point(llf[0]+(i+1)*dx, llf[1]+j*dy, llf[2]+(k+1)*dz)); + geo_obj->addPointVec(std::move(points), grid_names.back(), + nullptr); + } + + auto plys = std::unique_ptr<std::vector<GeoLib::Polyline*>>( + new std::vector<GeoLib::Polyline*>); + auto const& points = *geo_obj->getPointVec(grid_names.back()); + GeoLib::Polyline* ply0 (new GeoLib::Polyline(points)); + + for (std::size_t l(0); l < 4; l++) + ply0->addPoint(l); + ply0->addPoint(0); + plys->push_back(ply0); + + GeoLib::Polyline* ply1 (new GeoLib::Polyline(points)); + for (std::size_t l(4); l < 8; l++) + ply1->addPoint(l); + ply1->addPoint(4); + plys->push_back(ply1); + + GeoLib::Polyline* ply2 (new GeoLib::Polyline(points)); + ply2->addPoint(0); + ply2->addPoint(4); + plys->push_back(ply2); + + GeoLib::Polyline* ply3 (new GeoLib::Polyline(points)); + ply3->addPoint(1); + ply3->addPoint(5); + plys->push_back(ply3); + + GeoLib::Polyline* ply4 (new GeoLib::Polyline(points)); + ply4->addPoint(2); + ply4->addPoint(6); + plys->push_back(ply4); + + GeoLib::Polyline* ply5 (new GeoLib::Polyline(points)); + ply5->addPoint(3); + ply5->addPoint(7); + plys->push_back(ply5); + + geo_obj->addPolylineVec(std::move(plys), grid_names.back(), + nullptr); + } + } + } + std::string merged_geo_name("Grid"); + + geo_obj->mergeGeometries(grid_names, merged_geo_name); } #endif @@ -375,206 +375,206 @@ template <typename POINT> template <typename T> std::array<std::size_t,3> Grid<POINT>::getGridCoords(T const& pnt) const { - std::array<std::size_t,3> coords; - for (std::size_t k(0); k<3; k++) { - if (pnt[k] < _min_pnt[k]) { - coords[k] = 0; - } else { - if (pnt[k] > _max_pnt[k]) { - coords[k] = _n_steps[k]-1; - } else { - coords[k] = static_cast<std::size_t>( - std::floor((pnt[k] - _min_pnt[k])) * - _inverse_step_sizes[k]); - } - } - } - return coords; + std::array<std::size_t,3> coords; + for (std::size_t k(0); k<3; k++) { + if (pnt[k] < _min_pnt[k]) { + coords[k] = 0; + } else { + if (pnt[k] > _max_pnt[k]) { + coords[k] = _n_steps[k]-1; + } else { + coords[k] = static_cast<std::size_t>( + std::floor((pnt[k] - _min_pnt[k])) * + _inverse_step_sizes[k]); + } + } + } + return coords; } template <typename POINT> template <typename P> std::array<double,6> Grid<POINT>::getPointCellBorderDistances(P const& p, - std::array<std::size_t,3> const& coords) const + std::array<std::size_t,3> const& coords) const { - std::array<double,6> dists; - dists[0] = std::abs(p[2]-_min_pnt[2] + coords[2]*_step_sizes[2]); // bottom - dists[5] = std::abs(p[2]-_min_pnt[2] + (coords[2]+1)*_step_sizes[2]); // top + std::array<double,6> dists; + dists[0] = std::abs(p[2]-_min_pnt[2] + coords[2]*_step_sizes[2]); // bottom + dists[5] = std::abs(p[2]-_min_pnt[2] + (coords[2]+1)*_step_sizes[2]); // top - dists[1] = std::abs(p[1]-_min_pnt[1] + coords[1]*_step_sizes[1]); // front - dists[3] = std::abs(p[1]-_min_pnt[1] + (coords[1]+1)*_step_sizes[1]); // back + dists[1] = std::abs(p[1]-_min_pnt[1] + coords[1]*_step_sizes[1]); // front + dists[3] = std::abs(p[1]-_min_pnt[1] + (coords[1]+1)*_step_sizes[1]); // back - dists[4] = std::abs(p[0]-_min_pnt[0] + coords[0]*_step_sizes[0]); // left - dists[2] = std::abs(p[0]-_min_pnt[0] + (coords[0]+1)*_step_sizes[0]); // right - return dists; + dists[4] = std::abs(p[0]-_min_pnt[0] + coords[0]*_step_sizes[0]); // left + dists[2] = std::abs(p[0]-_min_pnt[0] + (coords[0]+1)*_step_sizes[0]); // right + return dists; } template <typename POINT> template <typename P> POINT* Grid<POINT>::getNearestPoint(P const& pnt) const { - std::array<std::size_t,3> coords(getGridCoords(pnt)); - - double sqr_min_dist(MathLib::sqrDist(_min_pnt, _max_pnt)); - POINT* nearest_pnt(nullptr); - - std::array<double,6> dists(getPointCellBorderDistances(pnt, coords)); - - if (calcNearestPointInGridCell(pnt, coords, sqr_min_dist, nearest_pnt)) { - double min_dist(sqrt(sqr_min_dist)); - if (dists[0] >= min_dist && dists[1] >= min_dist - && dists[2] >= min_dist && dists[3] >= min_dist - && dists[4] >= min_dist && dists[5] >= min_dist) { - return nearest_pnt; - } - } else { - // search in all border cells for at least one neighbor - double sqr_min_dist_tmp; - POINT * nearest_pnt_tmp(nullptr); - std::size_t offset(1); - - while (nearest_pnt == nullptr) { - std::array<std::size_t,3> ijk{{ - coords[0]<offset ? 0 : coords[0]-offset, - coords[1]<offset ? 0 : coords[1]-offset, - coords[2]<offset ? 0 : coords[2]-offset}}; - for (; ijk[0]<coords[0]+offset; ijk[0]++) { - for (; ijk[1] < coords[1] + offset; ijk[1]++) { - for (; ijk[2] < coords[2] + offset; ijk[2]++) { - // do not check the origin grid cell twice - if (ijk[0] == coords[0] - && ijk[1] == coords[1] - && ijk[2] == coords[2]) { - continue; - } - // check if temporary grid cell coordinates are valid - if (ijk[0] >= _n_steps[0] - || ijk[1] >= _n_steps[1] - || ijk[2] >= _n_steps[2]) { - continue; - } - - if (calcNearestPointInGridCell(pnt, ijk, - sqr_min_dist_tmp, nearest_pnt_tmp)) { - if (sqr_min_dist_tmp < sqr_min_dist) { - sqr_min_dist = sqr_min_dist_tmp; - nearest_pnt = nearest_pnt_tmp; - } - } - } // end k - } // end j - } // end i - offset++; - } // end while - } // end else - - double len(sqrt(MathLib::sqrDist(pnt, *nearest_pnt))); - // search all other grid cells within the cube with the edge nodes - std::vector<std::vector<POINT*> const*> vecs_of_pnts( - getPntVecsOfGridCellsIntersectingCube(pnt, len)); - - const std::size_t n_vecs(vecs_of_pnts.size()); - for (std::size_t j(0); j<n_vecs; j++) { - std::vector<POINT*> const& pnts(*(vecs_of_pnts[j])); - const std::size_t n_pnts(pnts.size()); - for (std::size_t k(0); k<n_pnts; k++) { - const double sqr_dist(MathLib::sqrDist(pnt, *pnts[k])); - if (sqr_dist < sqr_min_dist) { - sqr_min_dist = sqr_dist; - nearest_pnt = pnts[k]; - } - } - } - - return nearest_pnt; + std::array<std::size_t,3> coords(getGridCoords(pnt)); + + double sqr_min_dist(MathLib::sqrDist(_min_pnt, _max_pnt)); + POINT* nearest_pnt(nullptr); + + std::array<double,6> dists(getPointCellBorderDistances(pnt, coords)); + + if (calcNearestPointInGridCell(pnt, coords, sqr_min_dist, nearest_pnt)) { + double min_dist(sqrt(sqr_min_dist)); + if (dists[0] >= min_dist && dists[1] >= min_dist + && dists[2] >= min_dist && dists[3] >= min_dist + && dists[4] >= min_dist && dists[5] >= min_dist) { + return nearest_pnt; + } + } else { + // search in all border cells for at least one neighbor + double sqr_min_dist_tmp; + POINT * nearest_pnt_tmp(nullptr); + std::size_t offset(1); + + while (nearest_pnt == nullptr) { + std::array<std::size_t,3> ijk{{ + coords[0]<offset ? 0 : coords[0]-offset, + coords[1]<offset ? 0 : coords[1]-offset, + coords[2]<offset ? 0 : coords[2]-offset}}; + for (; ijk[0]<coords[0]+offset; ijk[0]++) { + for (; ijk[1] < coords[1] + offset; ijk[1]++) { + for (; ijk[2] < coords[2] + offset; ijk[2]++) { + // do not check the origin grid cell twice + if (ijk[0] == coords[0] + && ijk[1] == coords[1] + && ijk[2] == coords[2]) { + continue; + } + // check if temporary grid cell coordinates are valid + if (ijk[0] >= _n_steps[0] + || ijk[1] >= _n_steps[1] + || ijk[2] >= _n_steps[2]) { + continue; + } + + if (calcNearestPointInGridCell(pnt, ijk, + sqr_min_dist_tmp, nearest_pnt_tmp)) { + if (sqr_min_dist_tmp < sqr_min_dist) { + sqr_min_dist = sqr_min_dist_tmp; + nearest_pnt = nearest_pnt_tmp; + } + } + } // end k + } // end j + } // end i + offset++; + } // end while + } // end else + + double len(sqrt(MathLib::sqrDist(pnt, *nearest_pnt))); + // search all other grid cells within the cube with the edge nodes + std::vector<std::vector<POINT*> const*> vecs_of_pnts( + getPntVecsOfGridCellsIntersectingCube(pnt, len)); + + const std::size_t n_vecs(vecs_of_pnts.size()); + for (std::size_t j(0); j<n_vecs; j++) { + std::vector<POINT*> const& pnts(*(vecs_of_pnts[j])); + const std::size_t n_pnts(pnts.size()); + for (std::size_t k(0); k<n_pnts; k++) { + const double sqr_dist(MathLib::sqrDist(pnt, *pnts[k])); + if (sqr_dist < sqr_min_dist) { + sqr_min_dist = sqr_dist; + nearest_pnt = pnts[k]; + } + } + } + + return nearest_pnt; } template <typename POINT> void Grid<POINT>::initNumberOfSteps(std::size_t n_per_cell, - std::size_t n_pnts, std::array<double,3> const& extensions) + std::size_t n_pnts, std::array<double,3> const& extensions) { - double const max_extension( - *std::max_element(extensions.cbegin(), extensions.cend())); - - std::bitset<3> dim; // all bits set to zero - for (std::size_t k(0); k<3; ++k) { - // set dimension if the ratio kth-extension/max_extension >= 1e-4 - if (extensions[k] >= 1e-4 * max_extension) { - dim[k] = true; - } - } - - // structured grid: n_cells = _n_steps[0] * _n_steps[1] * _n_steps[2] - // *** condition: n_pnts / n_cells < n_per_cell - // => n_pnts / n_per_cell < n_cells - // _n_steps[1] = _n_steps[0] * extensions[1]/extensions[0], - // _n_steps[2] = _n_steps[0] * extensions[2]/extensions[0], - // => n_cells = _n_steps[0]^3 * extensions[1]/extensions[0] * - // extensions[2]/extensions[0], - // => _n_steps[0] = cbrt(n_cells * extensions[0]^2 / - // (extensions[1]*extensions[2])) - auto sc_ceil = [](double v) { - return static_cast<std::size_t>(ceil(v)); - }; - - switch (dim.count()) { - case 3: // 3d case - _n_steps[0] = - sc_ceil(std::cbrt(n_pnts * (extensions[0] / extensions[1]) * - (extensions[0] / extensions[2]) / n_per_cell)); - _n_steps[1] = sc_ceil(_n_steps[0] * - std::min(extensions[1] / extensions[0], 100.0)); - _n_steps[2] = sc_ceil(_n_steps[0] * - std::min(extensions[2] / extensions[0], 100.0)); - break; - case 2: // 2d cases - if (dim[0] && dim[1]) { // xy - _n_steps[0] = sc_ceil(std::sqrt(n_pnts * extensions[0] / - (n_per_cell * extensions[1]))); - _n_steps[1] = sc_ceil( - _n_steps[0] * std::min(extensions[1] / extensions[0], 100.0)); - } else if (dim[0] && dim[2]) { // xz - _n_steps[0] = sc_ceil(std::sqrt(n_pnts * extensions[0] / - (n_per_cell * extensions[2]))); - _n_steps[2] = sc_ceil( - _n_steps[0] * std::min(extensions[2] / extensions[0], 100.0)); - } else if (dim[1] && dim[2]) { // yz - _n_steps[1] = sc_ceil(std::sqrt(n_pnts * extensions[1] / - (n_per_cell * extensions[2]))); - _n_steps[2] = sc_ceil(std::min(extensions[2]/extensions[1],100.0)); - } - break; - case 1: // 1d cases - for (std::size_t k(0); k<3; ++k) { - if (dim[k]) { - _n_steps[k] = sc_ceil(static_cast<double>(n_pnts)/n_per_cell); - } - } - } + double const max_extension( + *std::max_element(extensions.cbegin(), extensions.cend())); + + std::bitset<3> dim; // all bits set to zero + for (std::size_t k(0); k<3; ++k) { + // set dimension if the ratio kth-extension/max_extension >= 1e-4 + if (extensions[k] >= 1e-4 * max_extension) { + dim[k] = true; + } + } + + // structured grid: n_cells = _n_steps[0] * _n_steps[1] * _n_steps[2] + // *** condition: n_pnts / n_cells < n_per_cell + // => n_pnts / n_per_cell < n_cells + // _n_steps[1] = _n_steps[0] * extensions[1]/extensions[0], + // _n_steps[2] = _n_steps[0] * extensions[2]/extensions[0], + // => n_cells = _n_steps[0]^3 * extensions[1]/extensions[0] * + // extensions[2]/extensions[0], + // => _n_steps[0] = cbrt(n_cells * extensions[0]^2 / + // (extensions[1]*extensions[2])) + auto sc_ceil = [](double v) { + return static_cast<std::size_t>(ceil(v)); + }; + + switch (dim.count()) { + case 3: // 3d case + _n_steps[0] = + sc_ceil(std::cbrt(n_pnts * (extensions[0] / extensions[1]) * + (extensions[0] / extensions[2]) / n_per_cell)); + _n_steps[1] = sc_ceil(_n_steps[0] * + std::min(extensions[1] / extensions[0], 100.0)); + _n_steps[2] = sc_ceil(_n_steps[0] * + std::min(extensions[2] / extensions[0], 100.0)); + break; + case 2: // 2d cases + if (dim[0] && dim[1]) { // xy + _n_steps[0] = sc_ceil(std::sqrt(n_pnts * extensions[0] / + (n_per_cell * extensions[1]))); + _n_steps[1] = sc_ceil( + _n_steps[0] * std::min(extensions[1] / extensions[0], 100.0)); + } else if (dim[0] && dim[2]) { // xz + _n_steps[0] = sc_ceil(std::sqrt(n_pnts * extensions[0] / + (n_per_cell * extensions[2]))); + _n_steps[2] = sc_ceil( + _n_steps[0] * std::min(extensions[2] / extensions[0], 100.0)); + } else if (dim[1] && dim[2]) { // yz + _n_steps[1] = sc_ceil(std::sqrt(n_pnts * extensions[1] / + (n_per_cell * extensions[2]))); + _n_steps[2] = sc_ceil(std::min(extensions[2]/extensions[1],100.0)); + } + break; + case 1: // 1d cases + for (std::size_t k(0); k<3; ++k) { + if (dim[k]) { + _n_steps[k] = sc_ceil(static_cast<double>(n_pnts)/n_per_cell); + } + } + } } template <typename POINT> template <typename P> bool Grid<POINT>::calcNearestPointInGridCell(P const& pnt, - std::array<std::size_t,3> const& coords, - double &sqr_min_dist, - POINT* &nearest_pnt) const + std::array<std::size_t,3> const& coords, + double &sqr_min_dist, + POINT* &nearest_pnt) const { - const std::size_t grid_idx (coords[0]+coords[1]*_n_steps[0]+coords[2]*_n_steps[0]*_n_steps[1]); - std::vector<typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type> const& pnts(_grid_cell_nodes_map[grid_idx]); - if (pnts.empty()) return false; - - const std::size_t n_pnts(pnts.size()); - sqr_min_dist = MathLib::sqrDist(*pnts[0], pnt); - nearest_pnt = pnts[0]; - for (std::size_t i(1); i < n_pnts; i++) { - const double sqr_dist(MathLib::sqrDist(*pnts[i], pnt)); - if (sqr_dist < sqr_min_dist) { - sqr_min_dist = sqr_dist; - nearest_pnt = pnts[i]; - } - } - return true; + const std::size_t grid_idx (coords[0]+coords[1]*_n_steps[0]+coords[2]*_n_steps[0]*_n_steps[1]); + std::vector<typename std::add_pointer<typename std::remove_pointer<POINT>::type>::type> const& pnts(_grid_cell_nodes_map[grid_idx]); + if (pnts.empty()) return false; + + const std::size_t n_pnts(pnts.size()); + sqr_min_dist = MathLib::sqrDist(*pnts[0], pnt); + nearest_pnt = pnts[0]; + for (std::size_t i(1); i < n_pnts; i++) { + const double sqr_dist(MathLib::sqrDist(*pnts[i], pnt)); + if (sqr_dist < sqr_min_dist) { + sqr_min_dist = sqr_dist; + nearest_pnt = pnts[i]; + } + } + return true; } template <typename POINT> @@ -582,21 +582,21 @@ template <typename P> std::vector<std::size_t> Grid<POINT>::getPointsInEpsilonEnvironment(P const& pnt, double eps) const { - std::vector<std::vector<POINT*> const*> vec_pnts( - getPntVecsOfGridCellsIntersectingCube(pnt, eps)); + std::vector<std::vector<POINT*> const*> vec_pnts( + getPntVecsOfGridCellsIntersectingCube(pnt, eps)); - double const sqr_eps(eps*eps); + double const sqr_eps(eps*eps); - std::vector<std::size_t> pnts; - for (auto vec : vec_pnts) { - for (auto const p : *vec) { - if (MathLib::sqrDist(*p, pnt) < sqr_eps) { - pnts.push_back(p->getID()); - } - } - } + std::vector<std::size_t> pnts; + for (auto vec : vec_pnts) { + for (auto const p : *vec) { + if (MathLib::sqrDist(*p, pnt) < sqr_eps) { + pnts.push_back(p->getID()); + } + } + } - return pnts; + return pnts; } } // end namespace GeoLib diff --git a/GeoLib/IO/AsciiRasterInterface.cpp b/GeoLib/IO/AsciiRasterInterface.cpp index 523c6863c7aff8da813bb9be3f03bd2d576027bf..59f9e27eda3bf4dcd40e46a9689be07c799c51fd 100644 --- a/GeoLib/IO/AsciiRasterInterface.cpp +++ b/GeoLib/IO/AsciiRasterInterface.cpp @@ -28,171 +28,171 @@ namespace IO GeoLib::Raster* AsciiRasterInterface::readRaster(std::string const& fname) { - std::string ext (BaseLib::getFileExtension(fname)); - std::transform(ext.begin(), ext.end(), ext.begin(), tolower); - if (ext.compare("asc") == 0) - return getRasterFromASCFile(fname); - if (ext.compare("grd") == 0) - return getRasterFromSurferFile(fname); - return nullptr; + std::string ext (BaseLib::getFileExtension(fname)); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); + if (ext.compare("asc") == 0) + return getRasterFromASCFile(fname); + if (ext.compare("grd") == 0) + return getRasterFromSurferFile(fname); + return nullptr; } GeoLib::Raster* AsciiRasterInterface::getRasterFromASCFile(std::string const& fname) { - std::ifstream in(fname.c_str()); - - if (!in.is_open()) { - WARN("Raster::getRasterFromASCFile(): Could not open file %s.", fname.c_str()); - return nullptr; - } - - // header information - GeoLib::RasterHeader header; - if (readASCHeader(in, header)) { - double* values = new double[header.n_cols*header.n_rows]; - std::string s; - // read the data into the double-array - for (std::size_t j(0); j < header.n_rows; ++j) { - const std::size_t idx ((header.n_rows - j - 1) * header.n_cols); - for (std::size_t i(0); i < header.n_cols; ++i) { - in >> s; - values[idx+i] = strtod(BaseLib::replaceString(",", ".", s).c_str(),0); - - } - } - in.close(); - GeoLib::Raster *raster(new GeoLib::Raster(header, values, values+header.n_cols*header.n_rows)); - delete [] values; - return raster; - } else { - WARN("Raster::getRasterFromASCFile(): Could not read header of file %s", fname.c_str()); - return nullptr; - } + std::ifstream in(fname.c_str()); + + if (!in.is_open()) { + WARN("Raster::getRasterFromASCFile(): Could not open file %s.", fname.c_str()); + return nullptr; + } + + // header information + GeoLib::RasterHeader header; + if (readASCHeader(in, header)) { + double* values = new double[header.n_cols*header.n_rows]; + std::string s; + // read the data into the double-array + for (std::size_t j(0); j < header.n_rows; ++j) { + const std::size_t idx ((header.n_rows - j - 1) * header.n_cols); + for (std::size_t i(0); i < header.n_cols; ++i) { + in >> s; + values[idx+i] = strtod(BaseLib::replaceString(",", ".", s).c_str(),0); + + } + } + in.close(); + GeoLib::Raster *raster(new GeoLib::Raster(header, values, values+header.n_cols*header.n_rows)); + delete [] values; + return raster; + } else { + WARN("Raster::getRasterFromASCFile(): Could not read header of file %s", fname.c_str()); + return nullptr; + } } bool AsciiRasterInterface::readASCHeader(std::ifstream &in, GeoLib::RasterHeader &header) { - std::string tag, value; - - in >> tag; - if (tag.compare("ncols") == 0) { - in >> value; - header.n_cols = atoi(value.c_str()); - } else return false; - - in >> tag; - if (tag.compare("nrows") == 0) { - in >> value; - header.n_rows = atoi(value.c_str()); - } else return false; - - in >> tag; - if (tag.compare("xllcorner") == 0 || tag.compare("xllcenter") == 0) { - in >> value; - header.origin[0] = strtod(BaseLib::replaceString(",", ".", value).c_str(), 0); - } else return false; - - in >> tag; - if (tag.compare("yllcorner") == 0 || tag.compare("yllcenter") == 0) { - in >> value; - header.origin[1] = strtod(BaseLib::replaceString(",", ".", value).c_str(), 0); - } else return false; - header.origin[2] = 0; - - in >> tag; - if (tag.compare("cellsize") == 0) { - in >> value; - header.cell_size = strtod(BaseLib::replaceString(",", ".", value).c_str(), 0); - } else return false; - - in >> tag; - if (tag.compare("NODATA_value") == 0 || tag.compare("nodata_value") == 0) { - in >> value; - header.no_data = strtod(BaseLib::replaceString(",", ".", value).c_str(), 0); - } else return false; - - return true; + std::string tag, value; + + in >> tag; + if (tag.compare("ncols") == 0) { + in >> value; + header.n_cols = atoi(value.c_str()); + } else return false; + + in >> tag; + if (tag.compare("nrows") == 0) { + in >> value; + header.n_rows = atoi(value.c_str()); + } else return false; + + in >> tag; + if (tag.compare("xllcorner") == 0 || tag.compare("xllcenter") == 0) { + in >> value; + header.origin[0] = strtod(BaseLib::replaceString(",", ".", value).c_str(), 0); + } else return false; + + in >> tag; + if (tag.compare("yllcorner") == 0 || tag.compare("yllcenter") == 0) { + in >> value; + header.origin[1] = strtod(BaseLib::replaceString(",", ".", value).c_str(), 0); + } else return false; + header.origin[2] = 0; + + in >> tag; + if (tag.compare("cellsize") == 0) { + in >> value; + header.cell_size = strtod(BaseLib::replaceString(",", ".", value).c_str(), 0); + } else return false; + + in >> tag; + if (tag.compare("NODATA_value") == 0 || tag.compare("nodata_value") == 0) { + in >> value; + header.no_data = strtod(BaseLib::replaceString(",", ".", value).c_str(), 0); + } else return false; + + return true; } GeoLib::Raster* AsciiRasterInterface::getRasterFromSurferFile(std::string const& fname) { - std::ifstream in(fname.c_str()); - - if (!in.is_open()) { - ERR("Raster::getRasterFromSurferFile() - Could not open file %s", fname.c_str()); - return nullptr; - } - - // header information - GeoLib::RasterHeader header; - double min(0.0), max(0.0); - - if (readSurferHeader(in, header, min, max)) - { - const double no_data_val (min-1); - double* values = new double[header.n_cols*header.n_rows]; - std::string s; - // read the data into the double-array - for (std::size_t j(0); j < header.n_rows; ++j) - { - const std::size_t idx (j * header.n_cols); - for (std::size_t i(0); i < header.n_cols; ++i) - { - in >> s; - const double val (strtod(BaseLib::replaceString(",", ".", s).c_str(),0)); - values[idx+i] = (val > max || val < min) ? no_data_val : val; - } - } - in.close(); - GeoLib::Raster *raster(new GeoLib::Raster(header, values, values+header.n_cols*header.n_rows)); - delete [] values; - return raster; - } else { - ERR("Raster::getRasterFromASCFile() - could not read header of file %s", fname.c_str()); - return nullptr; - } + std::ifstream in(fname.c_str()); + + if (!in.is_open()) { + ERR("Raster::getRasterFromSurferFile() - Could not open file %s", fname.c_str()); + return nullptr; + } + + // header information + GeoLib::RasterHeader header; + double min(0.0), max(0.0); + + if (readSurferHeader(in, header, min, max)) + { + const double no_data_val (min-1); + double* values = new double[header.n_cols*header.n_rows]; + std::string s; + // read the data into the double-array + for (std::size_t j(0); j < header.n_rows; ++j) + { + const std::size_t idx (j * header.n_cols); + for (std::size_t i(0); i < header.n_cols; ++i) + { + in >> s; + const double val (strtod(BaseLib::replaceString(",", ".", s).c_str(),0)); + values[idx+i] = (val > max || val < min) ? no_data_val : val; + } + } + in.close(); + GeoLib::Raster *raster(new GeoLib::Raster(header, values, values+header.n_cols*header.n_rows)); + delete [] values; + return raster; + } else { + ERR("Raster::getRasterFromASCFile() - could not read header of file %s", fname.c_str()); + return nullptr; + } } bool AsciiRasterInterface::readSurferHeader( - std::ifstream &in, GeoLib::RasterHeader &header, double &min, double &max) + std::ifstream &in, GeoLib::RasterHeader &header, double &min, double &max) { - std::string tag; - - in >> tag; - - if (tag.compare("DSAA") != 0) - { - ERR("Error in readSurferHeader() - No Surfer file."); - return false; - } - else - { - in >> header.n_cols >> header.n_rows; - in >> min >> max; - header.origin[0] = min; - header.cell_size = (max-min)/static_cast<double>(header.n_cols); - - in >> min >> max; - header.origin[1] = min; - header.origin[2] = 0; - - if (ceil((max-min)/static_cast<double>(header.n_rows)) == ceil(header.cell_size)) - header.cell_size = ceil(header.cell_size); - else - { - ERR("Error in readSurferHeader() - Anisotropic cellsize detected."); - return 0; - } - header.no_data = min-1; - in >> min >> max; - } - - return true; + std::string tag; + + in >> tag; + + if (tag.compare("DSAA") != 0) + { + ERR("Error in readSurferHeader() - No Surfer file."); + return false; + } + else + { + in >> header.n_cols >> header.n_rows; + in >> min >> max; + header.origin[0] = min; + header.cell_size = (max-min)/static_cast<double>(header.n_cols); + + in >> min >> max; + header.origin[1] = min; + header.origin[2] = 0; + + if (ceil((max-min)/static_cast<double>(header.n_rows)) == ceil(header.cell_size)) + header.cell_size = ceil(header.cell_size); + else + { + ERR("Error in readSurferHeader() - Anisotropic cellsize detected."); + return 0; + } + header.no_data = min-1; + in >> min >> max; + } + + return true; } void AsciiRasterInterface::writeRasterAsASC(GeoLib::Raster const& raster, std::string const& file_name) { - GeoLib::RasterHeader header (raster.getHeader()); + GeoLib::RasterHeader header (raster.getHeader()); MathLib::Point3d const& origin (header.origin); unsigned const nCols (header.n_cols); unsigned const nRows (header.n_rows); @@ -223,25 +223,25 @@ void AsciiRasterInterface::writeRasterAsASC(GeoLib::Raster const& raster, std::s /// Checks if all raster files actually exist static bool allRastersExist(std::vector<std::string> const& raster_paths) { - for (auto raster = raster_paths.begin(); raster != raster_paths.end(); - ++raster) - { - std::ifstream file_stream(*raster, std::ifstream::in); - if (!file_stream.good()) return false; - file_stream.close(); - } - return true; + for (auto raster = raster_paths.begin(); raster != raster_paths.end(); + ++raster) + { + std::ifstream file_stream(*raster, std::ifstream::in); + if (!file_stream.good()) return false; + file_stream.close(); + } + return true; } boost::optional<std::vector<GeoLib::Raster const*>> readRasters( std::vector<std::string> const& raster_paths) { - if (!allRastersExist(raster_paths)) return boost::none; + if (!allRastersExist(raster_paths)) return boost::none; - std::vector<GeoLib::Raster const*> rasters; - rasters.reserve(raster_paths.size()); - for (auto const& path : raster_paths) - rasters.push_back(GeoLib::IO::AsciiRasterInterface::readRaster(path)); + std::vector<GeoLib::Raster const*> rasters; + rasters.reserve(raster_paths.size()); + for (auto const& path : raster_paths) + rasters.push_back(GeoLib::IO::AsciiRasterInterface::readRaster(path)); return boost::make_optional(rasters); } } // end namespace IO diff --git a/GeoLib/IO/Legacy/OGSIOVer4.cpp b/GeoLib/IO/Legacy/OGSIOVer4.cpp index bcdbbfb69d246ce0e0e3d69c85101fb84705767d..2d2d501c82f4765d76815dc36df151de5031cc15 100644 --- a/GeoLib/IO/Legacy/OGSIOVer4.cpp +++ b/GeoLib/IO/Legacy/OGSIOVer4.cpp @@ -53,59 +53,59 @@ namespace Legacy { std::string readPoints(std::istream &in, std::vector<GeoLib::Point*>* pnt_vec, bool &zero_based_indexing, std::map<std::string,std::size_t>* pnt_id_name_map) { - std::string line; - std::size_t cnt(0); - - getline(in, line); - // geometric key words start with the hash # - // while not found a new key word do ... - while (line.find("#") == std::string::npos && !in.eof() && !in.fail()) - { - // read id and point coordinates - std::stringstream inss(line); - std::size_t id; - double x, y, z; - inss >> id >> x >> y >> z; - if (!inss.fail ()) - { - if (cnt == 0) - { - if (id == 0) - zero_based_indexing = true; - else - zero_based_indexing = false; - } - pnt_vec->push_back(new GeoLib::Point(x, y, z, id)); - - // read mesh density - if (line.find("$MD") != std::string::npos) - { - double mesh_density; - std::size_t pos1(line.find_first_of("M")); - inss.str(line.substr(pos1 + 2, std::string::npos)); - inss >> mesh_density; - } - - // read name of point - std::size_t pos (line.find("$NAME")); - if (pos != std::string::npos) //OK - { - std::size_t end_pos ((line.substr (pos + 6)).find(" ")); - if (end_pos != std::string::npos) - (*pnt_id_name_map)[line.substr (pos + 6, end_pos)] = id; - else - (*pnt_id_name_map)[line.substr (pos + 6)] = id; - } - - std::size_t id_pos (line.find("$ID")); - if (id_pos != std::string::npos) - WARN("readPoints(): found tag $ID - please use tag $NAME for reading point names in point %d.", cnt); - cnt++; - } - getline(in, line); - } - - return line; + std::string line; + std::size_t cnt(0); + + getline(in, line); + // geometric key words start with the hash # + // while not found a new key word do ... + while (line.find("#") == std::string::npos && !in.eof() && !in.fail()) + { + // read id and point coordinates + std::stringstream inss(line); + std::size_t id; + double x, y, z; + inss >> id >> x >> y >> z; + if (!inss.fail ()) + { + if (cnt == 0) + { + if (id == 0) + zero_based_indexing = true; + else + zero_based_indexing = false; + } + pnt_vec->push_back(new GeoLib::Point(x, y, z, id)); + + // read mesh density + if (line.find("$MD") != std::string::npos) + { + double mesh_density; + std::size_t pos1(line.find_first_of("M")); + inss.str(line.substr(pos1 + 2, std::string::npos)); + inss >> mesh_density; + } + + // read name of point + std::size_t pos (line.find("$NAME")); + if (pos != std::string::npos) //OK + { + std::size_t end_pos ((line.substr (pos + 6)).find(" ")); + if (end_pos != std::string::npos) + (*pnt_id_name_map)[line.substr (pos + 6, end_pos)] = id; + else + (*pnt_id_name_map)[line.substr (pos + 6)] = id; + } + + std::size_t id_pos (line.find("$ID")); + if (id_pos != std::string::npos) + WARN("readPoints(): found tag $ID - please use tag $NAME for reading point names in point %d.", cnt); + cnt++; + } + getline(in, line); + } + + return line; } /** reads points from a vector */ @@ -115,22 +115,22 @@ void readPolylinePointVector(const std::string &fname, const std::string &path, std::vector<std::string> &errors) { - // open file - std::ifstream in((path + fname).c_str()); - if (!in) { - WARN("readPolylinePointVector(): error opening stream from %s", fname.c_str()); - errors.push_back ("[readPolylinePointVector] error opening stream from " + fname); - return; - } - - double x, y, z; - while (in) - { - in >> x >> y >> z; - std::size_t pnt_id(pnt_vec.size()); - pnt_vec.push_back(new GeoLib::Point(x, y, z)); - ply->addPoint(pnt_id); - } + // open file + std::ifstream in((path + fname).c_str()); + if (!in) { + WARN("readPolylinePointVector(): error opening stream from %s", fname.c_str()); + errors.push_back ("[readPolylinePointVector] error opening stream from " + fname); + return; + } + + double x, y, z; + while (in) + { + in >> x >> y >> z; + std::size_t pnt_id(pnt_vec.size()); + pnt_vec.push_back(new GeoLib::Point(x, y, z)); + ply->addPoint(pnt_id); + } } /************************************************************************** @@ -154,78 +154,78 @@ std::string readPolyline(std::istream &in, const std::string &path, std::vector<std::string> &errors) { - std::string line, name_of_ply; - GeoLib::Polyline* ply(new GeoLib::Polyline(pnt_vec)); - std::size_t type = 2; // need an initial value - - // Schleife ueber alle Phasen bzw. Komponenten - do { - in >> line; - if (line.find("$ID") != std::string::npos) // subkeyword found CC - in >> line; // read value - // id = strtol(line_string.data(), NULL, 0); - //.................................................................... - if (line.find("$NAME") != std::string::npos) // subkeyword found - { - in >> line; - name_of_ply = line.substr(0); // read value - } - //.................................................................... - if (line.find("$TYPE") != std::string::npos) // subkeyword found - { - in >> line; // read value - type = static_cast<std::size_t> (strtol(line.c_str(), NULL, 0)); - } - //.................................................................... - if (line.find("$EPSILON") != std::string::npos) // subkeyword found - in >> line; // read value - //.................................................................... - if (line.find("$MAT_GROUP") != std::string::npos) // subkeyword found - in >> line; // read value - //.................................................................... - if (line.find("$POINTS") != std::string::npos) // subkeyword found - { // read the point ids - in >> line; - if (type != 100) - while (!in.eof() && !in.fail() && line.size() != 0 - && (line.find("#") == std::string::npos) - && (line.find("$") == std::string::npos)) - { - std::size_t pnt_id(BaseLib::str2number<std::size_t> (line)); - if (!zero_based_indexing) - pnt_id--; // one based indexing - std::size_t ply_size (ply->getNumberOfPoints()); - if (ply_size > 0) - { - if (ply->getPointID (ply_size - 1) != pnt_id_map[pnt_id]) - ply->addPoint(pnt_id_map[pnt_id]); - } - else - ply->addPoint(pnt_id_map[pnt_id]); - in >> line; - } - else { - WARN("readPolyline(): polyline is an arc *** reading not implemented"); - errors.push_back ("[readPolyline] reading polyline as an arc is not implemented"); - } - // empty line or the keyword or subkeyword or end of file - } - //.................................................................... - if (line.find("$POINT_VECTOR") != std::string::npos) // subkeyword found - { - in >> line; // read file name - line = path + line; - readPolylinePointVector(line, pnt_vec, ply, path, errors); - } // subkeyword found - } while (line.find("#") == std::string::npos && line.size() != 0 && in); - - if (type != 100) - { - ply_vec_names.insert (std::pair<std::string,std::size_t>(name_of_ply, ply_vec->size())); - ply_vec->push_back(ply); - } - - return line; + std::string line, name_of_ply; + GeoLib::Polyline* ply(new GeoLib::Polyline(pnt_vec)); + std::size_t type = 2; // need an initial value + + // Schleife ueber alle Phasen bzw. Komponenten + do { + in >> line; + if (line.find("$ID") != std::string::npos) // subkeyword found CC + in >> line; // read value + // id = strtol(line_string.data(), NULL, 0); + //.................................................................... + if (line.find("$NAME") != std::string::npos) // subkeyword found + { + in >> line; + name_of_ply = line.substr(0); // read value + } + //.................................................................... + if (line.find("$TYPE") != std::string::npos) // subkeyword found + { + in >> line; // read value + type = static_cast<std::size_t> (strtol(line.c_str(), NULL, 0)); + } + //.................................................................... + if (line.find("$EPSILON") != std::string::npos) // subkeyword found + in >> line; // read value + //.................................................................... + if (line.find("$MAT_GROUP") != std::string::npos) // subkeyword found + in >> line; // read value + //.................................................................... + if (line.find("$POINTS") != std::string::npos) // subkeyword found + { // read the point ids + in >> line; + if (type != 100) + while (!in.eof() && !in.fail() && line.size() != 0 + && (line.find("#") == std::string::npos) + && (line.find("$") == std::string::npos)) + { + std::size_t pnt_id(BaseLib::str2number<std::size_t> (line)); + if (!zero_based_indexing) + pnt_id--; // one based indexing + std::size_t ply_size (ply->getNumberOfPoints()); + if (ply_size > 0) + { + if (ply->getPointID (ply_size - 1) != pnt_id_map[pnt_id]) + ply->addPoint(pnt_id_map[pnt_id]); + } + else + ply->addPoint(pnt_id_map[pnt_id]); + in >> line; + } + else { + WARN("readPolyline(): polyline is an arc *** reading not implemented"); + errors.push_back ("[readPolyline] reading polyline as an arc is not implemented"); + } + // empty line or the keyword or subkeyword or end of file + } + //.................................................................... + if (line.find("$POINT_VECTOR") != std::string::npos) // subkeyword found + { + in >> line; // read file name + line = path + line; + readPolylinePointVector(line, pnt_vec, ply, path, errors); + } // subkeyword found + } while (line.find("#") == std::string::npos && line.size() != 0 && in); + + if (type != 100) + { + ply_vec_names.insert (std::pair<std::string,std::size_t>(name_of_ply, ply_vec->size())); + ply_vec->push_back(ply); + } + + return line; } /************************************************************************** @@ -247,17 +247,17 @@ std::string readPolylines(std::istream &in, std::vector<GeoLib::Polyline*>* ply_ bool zero_based_indexing, const std::vector<std::size_t>& pnt_id_map, const std::string &path, std::vector<std::string>& errors) { - if (!in) { - WARN("readPolylines(): input stream error."); - return std::string(""); - } - std::string tag("#POLYLINE"); + if (!in) { + WARN("readPolylines(): input stream error."); + return std::string(""); + } + std::string tag("#POLYLINE"); - while (!in.eof() && !in.fail() && tag.find("#POLYLINE") != std::string::npos) - tag = readPolyline(in, ply_vec, ply_vec_names, pnt_vec, - zero_based_indexing, pnt_id_map, path, errors); + while (!in.eof() && !in.fail() && tag.find("#POLYLINE") != std::string::npos) + tag = readPolyline(in, ply_vec, ply_vec_names, pnt_vec, + zero_based_indexing, pnt_id_map, path, errors); - return tag; + return tag; } /************************************************************************** @@ -279,85 +279,85 @@ std::string readSurface(std::istream &in, GeoLib::PointVec &pnt_vec, std::string const& path, std::vector<std::string>& errors) { - std::string line; - GeoLib::Surface* sfc(NULL); - - int type (-1); - std::string name; - std::size_t ply_id (0); // std::numeric_limits<std::size_t>::max()); - - do { - in >> line; - if (line.find("$ID") != std::string::npos) // subkeyword found CC - in >> line; // read value - // id = strtol(line_string.data(), NULL, 0); - //.................................................................... - if (line.find("$NAME") != std::string::npos) // subkeyword found - { - in >> line; // read value - name = line.substr(0); - } - //.................................................................... - if (line.find("$TYPE") != std::string::npos) // subkeyword found - { - in >> line; // read value - type = strtol(line.c_str(), NULL, 0); - } - //.................................................................... - if (line.find("$EPSILON") != std::string::npos) // subkeyword found - in >> line; // read value - //.................................................................... - if (line.find("$TIN") != std::string::npos) // subkeyword found - { - in >> line; // read value (file name) - line = path + line; - sfc = GeoLib::IO::TINInterface::readTIN(line, pnt_vec, &errors); - } - //.................................................................... - if (line.find("$MAT_GROUP") != std::string::npos) // subkeyword found - in >> line; // read value - //.................................................................... - if (line.find("$POLYLINES") != std::string::npos) // subkeyword found - { // read the name of the polyline(s) - in >> line; - while (!in.eof() && !in.fail() && line.size() != 0 - && (line.find("#") == std::string::npos) - && (line.find("$") == std::string::npos)) - { - // we did read the name of a polyline -> search the id for polyline - std::map<std::string,std::size_t>::const_iterator it (ply_vec_names.find ( - line)); - if (it != ply_vec_names.end()) - ply_id = it->second; - else - ply_id = ply_vec.size(); - - if (ply_id == ply_vec.size()) { - WARN("readSurface(): polyline for surface not found!"); - errors.push_back("[readSurface] polyline for surface not found!"); - } else { - if (type == 3) { - WARN("readSurface(): surface type 3: flat surface with any normal direction - reading not implemented."); - errors.push_back("[readSurface] surface type 3: flat surface with any normal direction - reading not implemented"); - } - if (type == 2) { - WARN("readSurface(): vertical surface (type 2) - reading not implemented"); - errors.push_back("[readSurface] vertical surface (type 2) - reading not implemented"); - } - } - in >> line; - } - // empty line or a keyword is found - } - } while (line.find("#") == std::string::npos && line.size() != 0 && in); - - if (!name.empty()) - sfc_names.insert(std::pair<std::string,std::size_t>(name,sfc_vec.size())); - - if (sfc) - // surface create by TIN - sfc_vec.push_back (sfc); - else + std::string line; + GeoLib::Surface* sfc(NULL); + + int type (-1); + std::string name; + std::size_t ply_id (0); // std::numeric_limits<std::size_t>::max()); + + do { + in >> line; + if (line.find("$ID") != std::string::npos) // subkeyword found CC + in >> line; // read value + // id = strtol(line_string.data(), NULL, 0); + //.................................................................... + if (line.find("$NAME") != std::string::npos) // subkeyword found + { + in >> line; // read value + name = line.substr(0); + } + //.................................................................... + if (line.find("$TYPE") != std::string::npos) // subkeyword found + { + in >> line; // read value + type = strtol(line.c_str(), NULL, 0); + } + //.................................................................... + if (line.find("$EPSILON") != std::string::npos) // subkeyword found + in >> line; // read value + //.................................................................... + if (line.find("$TIN") != std::string::npos) // subkeyword found + { + in >> line; // read value (file name) + line = path + line; + sfc = GeoLib::IO::TINInterface::readTIN(line, pnt_vec, &errors); + } + //.................................................................... + if (line.find("$MAT_GROUP") != std::string::npos) // subkeyword found + in >> line; // read value + //.................................................................... + if (line.find("$POLYLINES") != std::string::npos) // subkeyword found + { // read the name of the polyline(s) + in >> line; + while (!in.eof() && !in.fail() && line.size() != 0 + && (line.find("#") == std::string::npos) + && (line.find("$") == std::string::npos)) + { + // we did read the name of a polyline -> search the id for polyline + std::map<std::string,std::size_t>::const_iterator it (ply_vec_names.find ( + line)); + if (it != ply_vec_names.end()) + ply_id = it->second; + else + ply_id = ply_vec.size(); + + if (ply_id == ply_vec.size()) { + WARN("readSurface(): polyline for surface not found!"); + errors.push_back("[readSurface] polyline for surface not found!"); + } else { + if (type == 3) { + WARN("readSurface(): surface type 3: flat surface with any normal direction - reading not implemented."); + errors.push_back("[readSurface] surface type 3: flat surface with any normal direction - reading not implemented"); + } + if (type == 2) { + WARN("readSurface(): vertical surface (type 2) - reading not implemented"); + errors.push_back("[readSurface] vertical surface (type 2) - reading not implemented"); + } + } + in >> line; + } + // empty line or a keyword is found + } + } while (line.find("#") == std::string::npos && line.size() != 0 && in); + + if (!name.empty()) + sfc_names.insert(std::pair<std::string,std::size_t>(name,sfc_vec.size())); + + if (sfc) + // surface create by TIN + sfc_vec.push_back (sfc); + else { // surface created by polygon if (ply_id != std::numeric_limits<std::size_t>::max() && ply_id != ply_vec.size()) @@ -373,7 +373,7 @@ std::string readSurface(std::istream &in, } } - return line; + return line; } /************************************************************************** @@ -392,43 +392,43 @@ std::string readSurfaces(std::istream &in, GeoLib::PointVec & pnt_vec, const std::string &path, std::vector<std::string>& errors) { - if (!in.good()) - { - WARN("readSurfaces(): input stream error."); - return std::string(""); - } - std::string tag("#SURFACE"); - - std::vector<GeoLib::Polygon*> polygon_vec; - - while (!in.eof() && !in.fail() && tag.find("#SURFACE") != std::string::npos) - { - std::size_t n_polygons (polygon_vec.size()); - tag = readSurface(in, - polygon_vec, - sfc_vec, - sfc_names, - ply_vec, - ply_vec_names, - pnt_vec, - path, - errors); - if (n_polygons < polygon_vec.size()) - { - // subdivide polygon in simple polygons - GeoLib::Surface* sfc(GeoLib::Surface::createSurface( - *(dynamic_cast<GeoLib::Polyline*> (polygon_vec - [ - polygon_vec - . - size() - 1])))); - sfc_vec.push_back(sfc); - } - } - for (std::size_t k(0); k < polygon_vec.size(); k++) - delete polygon_vec[k]; - - return tag; + if (!in.good()) + { + WARN("readSurfaces(): input stream error."); + return std::string(""); + } + std::string tag("#SURFACE"); + + std::vector<GeoLib::Polygon*> polygon_vec; + + while (!in.eof() && !in.fail() && tag.find("#SURFACE") != std::string::npos) + { + std::size_t n_polygons (polygon_vec.size()); + tag = readSurface(in, + polygon_vec, + sfc_vec, + sfc_names, + ply_vec, + ply_vec_names, + pnt_vec, + path, + errors); + if (n_polygons < polygon_vec.size()) + { + // subdivide polygon in simple polygons + GeoLib::Surface* sfc(GeoLib::Surface::createSurface( + *(dynamic_cast<GeoLib::Polyline*> (polygon_vec + [ + polygon_vec + . + size() - 1])))); + sfc_vec.push_back(sfc); + } + } + for (std::size_t k(0); k < polygon_vec.size(); k++) + delete polygon_vec[k]; + + return tag; } bool readGLIFileV4(const std::string& fname, @@ -436,258 +436,258 @@ bool readGLIFileV4(const std::string& fname, std::string& unique_name, std::vector<std::string>& errors) { - INFO("GeoLib::readGLIFile(): open stream from file %s.", fname.c_str()); - std::ifstream in(fname.c_str()); - if (!in) { - WARN("GeoLib::readGLIFile(): could not open file %s.", fname.c_str()); - errors.push_back("[readGLIFileV4] error opening stream from " + fname); - return false; - } - INFO("GeoLib::readGLIFile(): \t done."); - - std::string tag; - while (tag.find("#POINTS") == std::string::npos && !in.eof()) - getline (in, tag); - - // read names of points into vector of strings - std::map<std::string,std::size_t>* pnt_id_names_map (new std::map<std::string,std::size_t>); - bool zero_based_idx(true); - auto pnt_vec = std::unique_ptr<std::vector<GeoLib::Point*>>( - new std::vector<GeoLib::Point*>); - INFO("GeoLib::readGLIFile(): read points from stream."); - tag = readPoints(in, pnt_vec.get(), zero_based_idx, pnt_id_names_map); - INFO("GeoLib::readGLIFile(): \t ok, %d points read.", pnt_vec->size()); - - unique_name = BaseLib::extractBaseName(fname); - if (!pnt_vec->empty()) - geo.addPointVec(std::move(pnt_vec), unique_name, pnt_id_names_map, 1e-6); - - // extract path for reading external files - const std::string path = BaseLib::extractPath(fname); - - // read names of plys into temporary string-vec - std::map<std::string,std::size_t>* ply_names (new std::map<std::string,std::size_t>); - auto ply_vec = std::unique_ptr<std::vector<GeoLib::Polyline*>>( - new std::vector<GeoLib::Polyline*>); - GeoLib::PointVec & point_vec( - *const_cast<GeoLib::PointVec*>(geo.getPointVecObj(unique_name))); - std::vector<GeoLib::Point*>* geo_pnt_vec(const_cast<std::vector<GeoLib::Point*>*>( - point_vec.getVector())); - if (tag.find("#POLYLINE") != std::string::npos && in) - { - INFO("GeoLib::readGLIFile(): read polylines from stream."); - tag = readPolylines(in, ply_vec.get(), *ply_names, *geo_pnt_vec, - zero_based_idx, - geo.getPointVecObj(unique_name)->getIDMap(), path, errors); - INFO("GeoLib::readGLIFile(): \t ok, %d polylines read.", ply_vec->size()); - } - else - INFO("GeoLib::readGLIFile(): tag #POLYLINE not found."); - - auto sfc_vec = std::unique_ptr<std::vector<GeoLib::Surface*>>( - new std::vector<GeoLib::Surface*>); - std::map<std::string,std::size_t>* sfc_names (new std::map<std::string,std::size_t>); - if (tag.find("#SURFACE") != std::string::npos && in) - { - INFO("GeoLib::readGLIFile(): read surfaces from stream."); - tag = readSurfaces(in, - *sfc_vec, - *sfc_names, - *ply_vec, - *ply_names, - point_vec, - path, - errors); - INFO("GeoLib::readGLIFile(): \tok, %d surfaces read.", sfc_vec->size()); - } - else - INFO("GeoLib::readGLIFile(): tag #SURFACE not found."); - - in.close(); - - if (!ply_vec->empty()) - geo.addPolylineVec(std::move(ply_vec), unique_name, ply_names); // KR: insert into GEOObjects if not empty - else { - delete ply_names; - } - - if (!sfc_vec->empty()) - geo.addSurfaceVec(std::move(sfc_vec), unique_name, sfc_names); // KR: insert into GEOObjects if not empty - else { - delete sfc_names; - } - - if (errors.empty()) - return true; - else - return false; + INFO("GeoLib::readGLIFile(): open stream from file %s.", fname.c_str()); + std::ifstream in(fname.c_str()); + if (!in) { + WARN("GeoLib::readGLIFile(): could not open file %s.", fname.c_str()); + errors.push_back("[readGLIFileV4] error opening stream from " + fname); + return false; + } + INFO("GeoLib::readGLIFile(): \t done."); + + std::string tag; + while (tag.find("#POINTS") == std::string::npos && !in.eof()) + getline (in, tag); + + // read names of points into vector of strings + std::map<std::string,std::size_t>* pnt_id_names_map (new std::map<std::string,std::size_t>); + bool zero_based_idx(true); + auto pnt_vec = std::unique_ptr<std::vector<GeoLib::Point*>>( + new std::vector<GeoLib::Point*>); + INFO("GeoLib::readGLIFile(): read points from stream."); + tag = readPoints(in, pnt_vec.get(), zero_based_idx, pnt_id_names_map); + INFO("GeoLib::readGLIFile(): \t ok, %d points read.", pnt_vec->size()); + + unique_name = BaseLib::extractBaseName(fname); + if (!pnt_vec->empty()) + geo.addPointVec(std::move(pnt_vec), unique_name, pnt_id_names_map, 1e-6); + + // extract path for reading external files + const std::string path = BaseLib::extractPath(fname); + + // read names of plys into temporary string-vec + std::map<std::string,std::size_t>* ply_names (new std::map<std::string,std::size_t>); + auto ply_vec = std::unique_ptr<std::vector<GeoLib::Polyline*>>( + new std::vector<GeoLib::Polyline*>); + GeoLib::PointVec & point_vec( + *const_cast<GeoLib::PointVec*>(geo.getPointVecObj(unique_name))); + std::vector<GeoLib::Point*>* geo_pnt_vec(const_cast<std::vector<GeoLib::Point*>*>( + point_vec.getVector())); + if (tag.find("#POLYLINE") != std::string::npos && in) + { + INFO("GeoLib::readGLIFile(): read polylines from stream."); + tag = readPolylines(in, ply_vec.get(), *ply_names, *geo_pnt_vec, + zero_based_idx, + geo.getPointVecObj(unique_name)->getIDMap(), path, errors); + INFO("GeoLib::readGLIFile(): \t ok, %d polylines read.", ply_vec->size()); + } + else + INFO("GeoLib::readGLIFile(): tag #POLYLINE not found."); + + auto sfc_vec = std::unique_ptr<std::vector<GeoLib::Surface*>>( + new std::vector<GeoLib::Surface*>); + std::map<std::string,std::size_t>* sfc_names (new std::map<std::string,std::size_t>); + if (tag.find("#SURFACE") != std::string::npos && in) + { + INFO("GeoLib::readGLIFile(): read surfaces from stream."); + tag = readSurfaces(in, + *sfc_vec, + *sfc_names, + *ply_vec, + *ply_names, + point_vec, + path, + errors); + INFO("GeoLib::readGLIFile(): \tok, %d surfaces read.", sfc_vec->size()); + } + else + INFO("GeoLib::readGLIFile(): tag #SURFACE not found."); + + in.close(); + + if (!ply_vec->empty()) + geo.addPolylineVec(std::move(ply_vec), unique_name, ply_names); // KR: insert into GEOObjects if not empty + else { + delete ply_names; + } + + if (!sfc_vec->empty()) + geo.addSurfaceVec(std::move(sfc_vec), unique_name, sfc_names); // KR: insert into GEOObjects if not empty + else { + delete sfc_names; + } + + if (errors.empty()) + return true; + else + return false; } std::size_t writeTINSurfaces(std::ofstream &os, GeoLib::SurfaceVec const* sfcs_vec, std::size_t sfc_count, std::string const& path) { - const std::vector<GeoLib::Surface*>* sfcs (sfcs_vec->getVector()); - for (std::size_t k(0); k < sfcs->size(); k++) - { - os << "#SURFACE" << "\n"; - std::string sfc_name; - if (sfcs_vec->getNameOfElementByID (sfc_count, sfc_name)) { - os << "\t$NAME " << "\n" << "\t\t" << sfc_name << "\n"; - } else { - os << "\t$NAME " << "\n" << "\t\t" << sfc_count << "\n"; - sfc_name = std::to_string (sfc_count); - } - sfc_name += ".tin"; - os << "\t$TIN" << "\n"; - os << "\t\t" << sfc_name << "\n"; - // create tin file - sfc_name = path + sfc_name; - GeoLib::IO::TINInterface::writeSurfaceAsTIN(*(*sfcs)[k], sfc_name.c_str()); - sfc_count++; - } - return sfc_count; + const std::vector<GeoLib::Surface*>* sfcs (sfcs_vec->getVector()); + for (std::size_t k(0); k < sfcs->size(); k++) + { + os << "#SURFACE" << "\n"; + std::string sfc_name; + if (sfcs_vec->getNameOfElementByID (sfc_count, sfc_name)) { + os << "\t$NAME " << "\n" << "\t\t" << sfc_name << "\n"; + } else { + os << "\t$NAME " << "\n" << "\t\t" << sfc_count << "\n"; + sfc_name = std::to_string (sfc_count); + } + sfc_name += ".tin"; + os << "\t$TIN" << "\n"; + os << "\t\t" << sfc_name << "\n"; + // create tin file + sfc_name = path + sfc_name; + GeoLib::IO::TINInterface::writeSurfaceAsTIN(*(*sfcs)[k], sfc_name.c_str()); + sfc_count++; + } + return sfc_count; } void writeGLIFileV4 (const std::string& fname, const std::string& geo_name, const GeoLib::GEOObjects& geo) { - GeoLib::PointVec const* const pnt_vec(geo.getPointVecObj(geo_name)); - std::vector<GeoLib::Point*> const* const pnts (pnt_vec->getVector()); - std::ofstream os (fname.c_str()); - if (pnts) { - const std::size_t n_pnts(pnts->size()); - INFO("GeoLib::writeGLIFileV4(): writing %d points to file %s.", n_pnts, fname.c_str()); - os << "#POINTS" << "\n"; - os.precision(std::numeric_limits<double>::digits10); - for (std::size_t k(0); k < n_pnts; k++) { - os << k << " " << *((*pnts)[k]); - std::string const& pnt_name(pnt_vec->getItemNameByID(k)); - if (!pnt_name.empty()) { - os << " $NAME " << pnt_name; - } - os << "\n"; - } - } - - const GeoLib::PolylineVec* plys_vec (geo.getPolylineVecObj (geo_name)); - if (plys_vec) - { - const std::vector<GeoLib::Polyline*>* plys (plys_vec->getVector()); - INFO("GeoLib::writeGLIFileV4(): %d polylines to file %s.", - plys->size (), fname.c_str()); - for (std::size_t k(0); k < plys->size(); k++) - { - os << "#POLYLINE" << "\n"; - std::string polyline_name; - plys_vec->getNameOfElement((*plys)[k], polyline_name); - os << " $NAME " << "\n" << " " << polyline_name << "\n"; - os << " $POINTS" << "\n"; - for (std::size_t j(0); j < (*plys)[k]->getNumberOfPoints(); j++) - os << " " << ((*plys)[k])->getPointID(j) << "\n"; - } - } - - // writing surfaces as TIN files - const GeoLib::SurfaceVec* sfcs_vec (geo.getSurfaceVecObj (geo_name)); - if (sfcs_vec) - writeTINSurfaces(os, sfcs_vec, 0, BaseLib::extractPath(fname)); - - os << "#STOP" << "\n"; - os.close (); + GeoLib::PointVec const* const pnt_vec(geo.getPointVecObj(geo_name)); + std::vector<GeoLib::Point*> const* const pnts (pnt_vec->getVector()); + std::ofstream os (fname.c_str()); + if (pnts) { + const std::size_t n_pnts(pnts->size()); + INFO("GeoLib::writeGLIFileV4(): writing %d points to file %s.", n_pnts, fname.c_str()); + os << "#POINTS" << "\n"; + os.precision(std::numeric_limits<double>::digits10); + for (std::size_t k(0); k < n_pnts; k++) { + os << k << " " << *((*pnts)[k]); + std::string const& pnt_name(pnt_vec->getItemNameByID(k)); + if (!pnt_name.empty()) { + os << " $NAME " << pnt_name; + } + os << "\n"; + } + } + + const GeoLib::PolylineVec* plys_vec (geo.getPolylineVecObj (geo_name)); + if (plys_vec) + { + const std::vector<GeoLib::Polyline*>* plys (plys_vec->getVector()); + INFO("GeoLib::writeGLIFileV4(): %d polylines to file %s.", + plys->size (), fname.c_str()); + for (std::size_t k(0); k < plys->size(); k++) + { + os << "#POLYLINE" << "\n"; + std::string polyline_name; + plys_vec->getNameOfElement((*plys)[k], polyline_name); + os << " $NAME " << "\n" << " " << polyline_name << "\n"; + os << " $POINTS" << "\n"; + for (std::size_t j(0); j < (*plys)[k]->getNumberOfPoints(); j++) + os << " " << ((*plys)[k])->getPointID(j) << "\n"; + } + } + + // writing surfaces as TIN files + const GeoLib::SurfaceVec* sfcs_vec (geo.getSurfaceVecObj (geo_name)); + if (sfcs_vec) + writeTINSurfaces(os, sfcs_vec, 0, BaseLib::extractPath(fname)); + + os << "#STOP" << "\n"; + os.close (); } void writeAllDataToGLIFileV4 (const std::string& fname, const GeoLib::GEOObjects& geo) { - std::vector<std::string> geo_names; - geo.getGeometryNames (geo_names); - - // extract path for reading external files - const std::string path = BaseLib::extractPath(fname); - - std::ofstream os (fname.c_str()); - - std::size_t pnts_offset (0); - std::vector<std::size_t> pnts_id_offset; - pnts_id_offset.push_back (0); - - // writing all points - os << "#POINTS" << "\n"; - for (std::size_t j(0); j < geo_names.size(); j++) - { - os.precision(std::numeric_limits<double>::digits10); - GeoLib::PointVec const* const pnt_vec(geo.getPointVecObj(geo_names[j])); - std::vector<GeoLib::Point*> const* const pnts (pnt_vec->getVector()); - if (pnts) { - std::string pnt_name; - const std::size_t n_pnts(pnts->size()); - for (std::size_t k(0); k < n_pnts; k++) { - os << pnts_offset + k << " " << *((*pnts)[k]); - std::string const& pnt_name(pnt_vec->getItemNameByID(k)); - if (! pnt_name.empty()) { - os << "$NAME " << pnt_name; - } - os << "\n"; - } - pnts_offset += pnts->size(); - pnts_id_offset.push_back (pnts_offset); - } - } - - INFO("GeoLib::writeAllDataToGLIFileV4(): wrote %d points.", pnts_offset); - - // writing all stations - std::vector<std::string> stn_names; - geo.getStationVectorNames (stn_names); - for (std::size_t j(0); j < stn_names.size(); j++) - { - os.precision(std::numeric_limits<double>::digits10); - const std::vector<GeoLib::Point*>* pnts (geo.getStationVec(stn_names[j])); - if (pnts) - { - for (std::size_t k(0); k < pnts->size(); k++) - os << k + pnts_offset << " " << *((*pnts)[k]) << " $NAME " << - static_cast<GeoLib::Station*>((*pnts)[k])->getName() << "\n"; - pnts_offset += pnts->size(); - pnts_id_offset.push_back (pnts_offset); - } - } - - std::size_t plys_cnt (0); - - // writing all polylines - for (std::size_t j(0); j < geo_names.size(); j++) - { - const GeoLib::PolylineVec* plys_vec (geo.getPolylineVecObj (geo_names[j])); - if (plys_vec) { - const std::vector<GeoLib::Polyline*>* plys (plys_vec->getVector()); - for (std::size_t k(0); k < plys->size(); k++) { - os << "#POLYLINE" << "\n"; - std::string ply_name; - os << " $NAME\n"; - if (plys_vec->getNameOfElementByID (plys_cnt, ply_name)) - os << " " << ply_name << "\n"; - else - os << " " << geo_names[j] << "-" << plys_cnt << "\n"; - os << " $POINTS" << "\n"; - for (std::size_t l(0); l < (*plys)[k]->getNumberOfPoints(); l++) - os << " " << pnts_id_offset[j] + - ((*plys)[k])->getPointID(l) << "\n"; - plys_cnt++; - } - } - } - - // writing surfaces as TIN files - std::size_t sfcs_cnt (0); - for (std::size_t j(0); j < geo_names.size(); j++) - { - const GeoLib::SurfaceVec* sfcs_vec (geo.getSurfaceVecObj (geo_names[j])); - if (sfcs_vec) - sfcs_cnt += writeTINSurfaces(os, sfcs_vec, sfcs_cnt, path); - } - - os << "#STOP" << "\n"; - os.close (); + std::vector<std::string> geo_names; + geo.getGeometryNames (geo_names); + + // extract path for reading external files + const std::string path = BaseLib::extractPath(fname); + + std::ofstream os (fname.c_str()); + + std::size_t pnts_offset (0); + std::vector<std::size_t> pnts_id_offset; + pnts_id_offset.push_back (0); + + // writing all points + os << "#POINTS" << "\n"; + for (std::size_t j(0); j < geo_names.size(); j++) + { + os.precision(std::numeric_limits<double>::digits10); + GeoLib::PointVec const* const pnt_vec(geo.getPointVecObj(geo_names[j])); + std::vector<GeoLib::Point*> const* const pnts (pnt_vec->getVector()); + if (pnts) { + std::string pnt_name; + const std::size_t n_pnts(pnts->size()); + for (std::size_t k(0); k < n_pnts; k++) { + os << pnts_offset + k << " " << *((*pnts)[k]); + std::string const& pnt_name(pnt_vec->getItemNameByID(k)); + if (! pnt_name.empty()) { + os << "$NAME " << pnt_name; + } + os << "\n"; + } + pnts_offset += pnts->size(); + pnts_id_offset.push_back (pnts_offset); + } + } + + INFO("GeoLib::writeAllDataToGLIFileV4(): wrote %d points.", pnts_offset); + + // writing all stations + std::vector<std::string> stn_names; + geo.getStationVectorNames (stn_names); + for (std::size_t j(0); j < stn_names.size(); j++) + { + os.precision(std::numeric_limits<double>::digits10); + const std::vector<GeoLib::Point*>* pnts (geo.getStationVec(stn_names[j])); + if (pnts) + { + for (std::size_t k(0); k < pnts->size(); k++) + os << k + pnts_offset << " " << *((*pnts)[k]) << " $NAME " << + static_cast<GeoLib::Station*>((*pnts)[k])->getName() << "\n"; + pnts_offset += pnts->size(); + pnts_id_offset.push_back (pnts_offset); + } + } + + std::size_t plys_cnt (0); + + // writing all polylines + for (std::size_t j(0); j < geo_names.size(); j++) + { + const GeoLib::PolylineVec* plys_vec (geo.getPolylineVecObj (geo_names[j])); + if (plys_vec) { + const std::vector<GeoLib::Polyline*>* plys (plys_vec->getVector()); + for (std::size_t k(0); k < plys->size(); k++) { + os << "#POLYLINE" << "\n"; + std::string ply_name; + os << " $NAME\n"; + if (plys_vec->getNameOfElementByID (plys_cnt, ply_name)) + os << " " << ply_name << "\n"; + else + os << " " << geo_names[j] << "-" << plys_cnt << "\n"; + os << " $POINTS" << "\n"; + for (std::size_t l(0); l < (*plys)[k]->getNumberOfPoints(); l++) + os << " " << pnts_id_offset[j] + + ((*plys)[k])->getPointID(l) << "\n"; + plys_cnt++; + } + } + } + + // writing surfaces as TIN files + std::size_t sfcs_cnt (0); + for (std::size_t j(0); j < geo_names.size(); j++) + { + const GeoLib::SurfaceVec* sfcs_vec (geo.getSurfaceVecObj (geo_names[j])); + if (sfcs_vec) + sfcs_cnt += writeTINSurfaces(os, sfcs_vec, sfcs_cnt, path); + } + + os << "#STOP" << "\n"; + os.close (); } } diff --git a/GeoLib/IO/TINInterface.cpp b/GeoLib/IO/TINInterface.cpp index e47f94d296445574fdfff3af480905222389965e..3ab445b9e17ff43ba028cbbb7f54e673ad3b07a2 100644 --- a/GeoLib/IO/TINInterface.cpp +++ b/GeoLib/IO/TINInterface.cpp @@ -26,120 +26,120 @@ namespace IO { GeoLib::Surface* TINInterface::readTIN(std::string const& fname, - GeoLib::PointVec &pnt_vec, - std::vector<std::string>* errors) + GeoLib::PointVec &pnt_vec, + std::vector<std::string>* errors) { - // open file - std::ifstream in(fname.c_str()); - if (!in) { - WARN("readTIN(): could not open stream from %s.", fname.c_str()); - if (errors) - errors->push_back ("readTINFile error opening stream from " + fname); - return nullptr; - } + // open file + std::ifstream in(fname.c_str()); + if (!in) { + WARN("readTIN(): could not open stream from %s.", fname.c_str()); + if (errors) + errors->push_back ("readTINFile error opening stream from " + fname); + return nullptr; + } - GeoLib::Surface* sfc = new GeoLib::Surface(*(pnt_vec.getVector())); - std::size_t id; - MathLib::Point3d p0, p1, p2; - std::string line; - while (std::getline(in, line).good()) - { - // allow empty lines - if (line.empty()) - continue; + GeoLib::Surface* sfc = new GeoLib::Surface(*(pnt_vec.getVector())); + std::size_t id; + MathLib::Point3d p0, p1, p2; + std::string line; + while (std::getline(in, line).good()) + { + // allow empty lines + if (line.empty()) + continue; - // parse line - std::stringstream input(line); - // read id - if (!(input >> id)) { - in.close(); - delete sfc; - return nullptr; - } - // read first point - if (!(input >> p0[0] >> p0[1] >> p0[2])) { - ERR("Could not read coords of 1st point of triangle %d.", id); - if (errors) - errors->push_back (std::string("readTIN error: ") + - std::string("Could not read coords of 1st point in triangle ") + - std::to_string(id)); - in.close(); - delete sfc; - return nullptr; - } - // read second point - if (!(input >> p1[0] >> p1[1] >> p1[2])) { - ERR("Could not read coords of 2nd point of triangle %d.", id); - if (errors) - errors->push_back (std::string("readTIN error: ") + - std::string("Could not read coords of 2nd point in triangle ") + - std::to_string(id)); - in.close(); - delete sfc; - return nullptr; - } - // read third point - if (!(input >> p2[0] >> p2[1] >> p2[2])) { - ERR("Could not read coords of 3rd point of triangle %d.", id); - if (errors) - errors->push_back (std::string("readTIN error: ") + - std::string("Could not read coords of 3rd point in triangle ") + - std::to_string(id)); - in.close(); - delete sfc; - return nullptr; - } + // parse line + std::stringstream input(line); + // read id + if (!(input >> id)) { + in.close(); + delete sfc; + return nullptr; + } + // read first point + if (!(input >> p0[0] >> p0[1] >> p0[2])) { + ERR("Could not read coords of 1st point of triangle %d.", id); + if (errors) + errors->push_back (std::string("readTIN error: ") + + std::string("Could not read coords of 1st point in triangle ") + + std::to_string(id)); + in.close(); + delete sfc; + return nullptr; + } + // read second point + if (!(input >> p1[0] >> p1[1] >> p1[2])) { + ERR("Could not read coords of 2nd point of triangle %d.", id); + if (errors) + errors->push_back (std::string("readTIN error: ") + + std::string("Could not read coords of 2nd point in triangle ") + + std::to_string(id)); + in.close(); + delete sfc; + return nullptr; + } + // read third point + if (!(input >> p2[0] >> p2[1] >> p2[2])) { + ERR("Could not read coords of 3rd point of triangle %d.", id); + if (errors) + errors->push_back (std::string("readTIN error: ") + + std::string("Could not read coords of 3rd point in triangle ") + + std::to_string(id)); + in.close(); + delete sfc; + return nullptr; + } - // check area of triangle - double const d_eps(std::numeric_limits<double>::epsilon()); - if (GeoLib::calcTriangleArea(p0, p1, p2) < d_eps) { - ERR("readTIN: Triangle %d has zero area.", id); - if (errors) - errors->push_back (std::string("readTIN: Triangle ") - + std::to_string(id) + std::string(" has zero area.")); - delete sfc; - return nullptr; - } + // check area of triangle + double const d_eps(std::numeric_limits<double>::epsilon()); + if (GeoLib::calcTriangleArea(p0, p1, p2) < d_eps) { + ERR("readTIN: Triangle %d has zero area.", id); + if (errors) + errors->push_back (std::string("readTIN: Triangle ") + + std::to_string(id) + std::string(" has zero area.")); + delete sfc; + return nullptr; + } - // determine size pnt_vec to insert the correct ids - std::size_t const s(pnt_vec.getVector()->size()); + // determine size pnt_vec to insert the correct ids + std::size_t const s(pnt_vec.getVector()->size()); - std::size_t const pnt_pos_0(pnt_vec.push_back(new GeoLib::Point(p0, s))); - std::size_t const pnt_pos_1(pnt_vec.push_back(new GeoLib::Point(p1, s+1))); - std::size_t const pnt_pos_2(pnt_vec.push_back(new GeoLib::Point(p2, s+2))); - // create new Triangle - if (pnt_pos_0 != std::numeric_limits<std::size_t>::max() && - pnt_pos_1 != std::numeric_limits<std::size_t>::max() && - pnt_pos_1 != std::numeric_limits<std::size_t>::max()) { - sfc->addTriangle(pnt_pos_0, pnt_pos_1, pnt_pos_2); - } - } + std::size_t const pnt_pos_0(pnt_vec.push_back(new GeoLib::Point(p0, s))); + std::size_t const pnt_pos_1(pnt_vec.push_back(new GeoLib::Point(p1, s+1))); + std::size_t const pnt_pos_2(pnt_vec.push_back(new GeoLib::Point(p2, s+2))); + // create new Triangle + if (pnt_pos_0 != std::numeric_limits<std::size_t>::max() && + pnt_pos_1 != std::numeric_limits<std::size_t>::max() && + pnt_pos_1 != std::numeric_limits<std::size_t>::max()) { + sfc->addTriangle(pnt_pos_0, pnt_pos_1, pnt_pos_2); + } + } - if (sfc->getNTriangles() == 0) { - WARN("readTIN(): No triangle found.", fname.c_str()); - if (errors) - errors->push_back ("readTIN error because of no triangle found"); - delete sfc; - return nullptr; - } + if (sfc->getNTriangles() == 0) { + WARN("readTIN(): No triangle found.", fname.c_str()); + if (errors) + errors->push_back ("readTIN error because of no triangle found"); + delete sfc; + return nullptr; + } - return sfc; + return sfc; } void TINInterface::writeSurfaceAsTIN(GeoLib::Surface const& surface, std::string const& file_name) { - std::ofstream os (file_name.c_str()); - if (!os) { - WARN("writeSurfaceAsTIN(): could not open stream to %s.", file_name.c_str()); - return; - } - os.precision(std::numeric_limits<double>::digits10); - const std::size_t n_tris (surface.getNTriangles()); - for (std::size_t l(0); l < n_tris; l++) { - GeoLib::Triangle const& tri (*(surface[l])); - os << l << " " << *(tri.getPoint(0)) << " " << *(tri.getPoint(1)) << " " << *(tri.getPoint(2)) << "\n"; - } - os.close(); + std::ofstream os (file_name.c_str()); + if (!os) { + WARN("writeSurfaceAsTIN(): could not open stream to %s.", file_name.c_str()); + return; + } + os.precision(std::numeric_limits<double>::digits10); + const std::size_t n_tris (surface.getNTriangles()); + for (std::size_t l(0); l < n_tris; l++) { + GeoLib::Triangle const& tri (*(surface[l])); + os << l << " " << *(tri.getPoint(0)) << " " << *(tri.getPoint(1)) << " " << *(tri.getPoint(2)) << "\n"; + } + os.close(); } } // end namespace IO } // end namespace GeoLib diff --git a/GeoLib/IO/TINInterface.h b/GeoLib/IO/TINInterface.h index a64d9740e6677aeb343fd2150e753a7f148a19a5..a4de2273f8dc33737323c1c15a8803ddbffbd489 100644 --- a/GeoLib/IO/TINInterface.h +++ b/GeoLib/IO/TINInterface.h @@ -28,23 +28,23 @@ namespace IO class TINInterface { public: - /** - * Reads TIN file - * @param fname TIN file name - * @param pnt_vec a point vector to which triangle vertexes are added - * @param errors a vector of error messages - * @return a pointer to a GeoLib::Surface object created from TIN data. nullptr is returned if it fails to read the file. - */ - static GeoLib::Surface* readTIN(std::string const& fname, - GeoLib::PointVec &pnt_vec, - std::vector<std::string>* errors = nullptr); - - /** - * Writes surface data into TIN file - * @param surface surface object - * @param file_name TIN file name - */ - static void writeSurfaceAsTIN(GeoLib::Surface const& surface, std::string const& file_name); + /** + * Reads TIN file + * @param fname TIN file name + * @param pnt_vec a point vector to which triangle vertexes are added + * @param errors a vector of error messages + * @return a pointer to a GeoLib::Surface object created from TIN data. nullptr is returned if it fails to read the file. + */ + static GeoLib::Surface* readTIN(std::string const& fname, + GeoLib::PointVec &pnt_vec, + std::vector<std::string>* errors = nullptr); + + /** + * Writes surface data into TIN file + * @param surface surface object + * @param file_name TIN file name + */ + static void writeSurfaceAsTIN(GeoLib::Surface const& surface, std::string const& file_name); }; } // end namespace IO diff --git a/GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.cpp b/GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.cpp index 8e6c4edf08426784b21f77bab1113d8b63a26cce..1797a2e1046f32a709db0e61ff8c9f6ba42eca41 100644 --- a/GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.cpp +++ b/GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.cpp @@ -32,100 +32,100 @@ namespace IO { BoostXmlGmlInterface::BoostXmlGmlInterface(GeoLib::GEOObjects& geo_objs) : - _geo_objects(geo_objs) + _geo_objects(geo_objs) {} bool BoostXmlGmlInterface::readFile(const std::string &fname) { - //! \todo Reading geometries is always strict. - auto doc = BaseLib::makeConfigTree(fname, true, "OpenGeoSysGLI"); - - // ignore attributes related to XML schema - doc->ignoreConfAttribute("xmlns:xsi"); - doc->ignoreConfAttribute("xsi:noNamespaceSchemaLocation"); - doc->ignoreConfAttribute("xmlns:ogs"); - - auto points = std::unique_ptr<std::vector<GeoLib::Point*>>( - new std::vector<GeoLib::Point*>); - auto polylines = std::unique_ptr<std::vector<GeoLib::Polyline*>>( - new std::vector<GeoLib::Polyline*>); - auto surfaces = std::unique_ptr<std::vector<GeoLib::Surface*>>( - new std::vector<GeoLib::Surface*>); - - using MapNameId = std::map<std::string, std::size_t>; - std::unique_ptr<MapNameId> pnt_names{new MapNameId}; - std::unique_ptr<MapNameId> ply_names{new MapNameId}; - std::unique_ptr<MapNameId> sfc_names{new MapNameId}; - - auto geo_name = doc->getConfParam<std::string>("name"); - if (geo_name.empty()) - { - ERR("BoostXmlGmlInterface::readFile(): <name> tag is empty."); - std::abort(); - } - - for (auto st : doc->getConfSubtreeList("points")) - { - readPoints(st, *points, *pnt_names); - _geo_objects.addPointVec(std::move(points), geo_name, pnt_names.release()); - } - - for (auto st : doc->getConfSubtreeList("polylines")) - { - readPolylines(st, - *polylines, - *_geo_objects.getPointVec(geo_name), - _geo_objects.getPointVecObj(geo_name)->getIDMap(), - *ply_names); - } - - for (auto st : doc->getConfSubtreeList("surfaces")) - { - readSurfaces(st, - *surfaces, - *_geo_objects.getPointVec(geo_name), - _geo_objects.getPointVecObj(geo_name)->getIDMap(), - *sfc_names); - } - - if (!polylines->empty()) { - _geo_objects.addPolylineVec(std::move(polylines), geo_name, ply_names.release()); - } - - if (!surfaces->empty()) { - _geo_objects.addSurfaceVec(std::move(surfaces), geo_name, sfc_names.release()); - } - - return true; + //! \todo Reading geometries is always strict. + auto doc = BaseLib::makeConfigTree(fname, true, "OpenGeoSysGLI"); + + // ignore attributes related to XML schema + doc->ignoreConfAttribute("xmlns:xsi"); + doc->ignoreConfAttribute("xsi:noNamespaceSchemaLocation"); + doc->ignoreConfAttribute("xmlns:ogs"); + + auto points = std::unique_ptr<std::vector<GeoLib::Point*>>( + new std::vector<GeoLib::Point*>); + auto polylines = std::unique_ptr<std::vector<GeoLib::Polyline*>>( + new std::vector<GeoLib::Polyline*>); + auto surfaces = std::unique_ptr<std::vector<GeoLib::Surface*>>( + new std::vector<GeoLib::Surface*>); + + using MapNameId = std::map<std::string, std::size_t>; + std::unique_ptr<MapNameId> pnt_names{new MapNameId}; + std::unique_ptr<MapNameId> ply_names{new MapNameId}; + std::unique_ptr<MapNameId> sfc_names{new MapNameId}; + + auto geo_name = doc->getConfParam<std::string>("name"); + if (geo_name.empty()) + { + ERR("BoostXmlGmlInterface::readFile(): <name> tag is empty."); + std::abort(); + } + + for (auto st : doc->getConfSubtreeList("points")) + { + readPoints(st, *points, *pnt_names); + _geo_objects.addPointVec(std::move(points), geo_name, pnt_names.release()); + } + + for (auto st : doc->getConfSubtreeList("polylines")) + { + readPolylines(st, + *polylines, + *_geo_objects.getPointVec(geo_name), + _geo_objects.getPointVecObj(geo_name)->getIDMap(), + *ply_names); + } + + for (auto st : doc->getConfSubtreeList("surfaces")) + { + readSurfaces(st, + *surfaces, + *_geo_objects.getPointVec(geo_name), + _geo_objects.getPointVecObj(geo_name)->getIDMap(), + *sfc_names); + } + + if (!polylines->empty()) { + _geo_objects.addPolylineVec(std::move(polylines), geo_name, ply_names.release()); + } + + if (!surfaces->empty()) { + _geo_objects.addSurfaceVec(std::move(surfaces), geo_name, sfc_names.release()); + } + + return true; } void BoostXmlGmlInterface::readPoints(BaseLib::ConfigTree const& pointsRoot, - std::vector<GeoLib::Point*>& points, - std::map<std::string, std::size_t>& pnt_names ) + std::vector<GeoLib::Point*>& points, + std::map<std::string, std::size_t>& pnt_names ) { - for (auto const pt : pointsRoot.getConfParamList("point")) - { - auto const p_id = pt.getConfAttribute<std::size_t>("id"); - auto const p_x = pt.getConfAttribute<double>("x"); - auto const p_y = pt.getConfAttribute<double>("y"); - auto const p_z = pt.getConfAttribute<double>("z"); - - auto const p_size = points.size(); - BaseLib::insertIfKeyUniqueElseError(_idx_map, p_id, p_size, - "The point id is not unique."); - points.push_back(new GeoLib::Point(p_x, p_y, p_z, p_id)); - - if (auto const p_name = pt.getConfAttributeOptional<std::string>("name")) - { - if (p_name->empty()) { - ERR("Empty point name found in geometry file."); - std::abort(); - } - - BaseLib::insertIfKeyUniqueElseError(pnt_names, *p_name, p_size, - "The point name is not unique."); - } - } + for (auto const pt : pointsRoot.getConfParamList("point")) + { + auto const p_id = pt.getConfAttribute<std::size_t>("id"); + auto const p_x = pt.getConfAttribute<double>("x"); + auto const p_y = pt.getConfAttribute<double>("y"); + auto const p_z = pt.getConfAttribute<double>("z"); + + auto const p_size = points.size(); + BaseLib::insertIfKeyUniqueElseError(_idx_map, p_id, p_size, + "The point id is not unique."); + points.push_back(new GeoLib::Point(p_x, p_y, p_z, p_id)); + + if (auto const p_name = pt.getConfAttributeOptional<std::string>("name")) + { + if (p_name->empty()) { + ERR("Empty point name found in geometry file."); + std::abort(); + } + + BaseLib::insertIfKeyUniqueElseError(pnt_names, *p_name, p_size, + "The point name is not unique."); + } + } } void BoostXmlGmlInterface::readPolylines( @@ -135,35 +135,35 @@ void BoostXmlGmlInterface::readPolylines( std::vector<std::size_t> const& pnt_id_map, std::map<std::string, std::size_t>& ply_names) { - for (auto const pl : polylinesRoot.getConfSubtreeList("polyline")) - { - auto const id = pl.getConfAttribute<std::size_t>("id"); - // The id is not used but must be present in the GML file. - // That's why pl.ignore...() cannot be used. - (void) id; - - polylines.push_back(new GeoLib::Polyline(points)); - - if (auto const p_name = pl.getConfAttributeOptional<std::string>("name")) - { - if (p_name->empty()) { - ERR("Empty polyline name found in geometry file."); - std::abort(); - } - - BaseLib::insertIfKeyUniqueElseError(ply_names, *p_name, polylines.size()-1, - "The polyline name is not unique."); - - for (auto const pt : pl.getConfParamList<std::size_t>("pnt")) { - polylines.back()->addPoint(pnt_id_map[_idx_map[pt]]); - } - } - else - { - // polyline has no name, ignore it. - pl.ignoreConfParamAll("pnt"); - } - } + for (auto const pl : polylinesRoot.getConfSubtreeList("polyline")) + { + auto const id = pl.getConfAttribute<std::size_t>("id"); + // The id is not used but must be present in the GML file. + // That's why pl.ignore...() cannot be used. + (void) id; + + polylines.push_back(new GeoLib::Polyline(points)); + + if (auto const p_name = pl.getConfAttributeOptional<std::string>("name")) + { + if (p_name->empty()) { + ERR("Empty polyline name found in geometry file."); + std::abort(); + } + + BaseLib::insertIfKeyUniqueElseError(ply_names, *p_name, polylines.size()-1, + "The polyline name is not unique."); + + for (auto const pt : pl.getConfParamList<std::size_t>("pnt")) { + polylines.back()->addPoint(pnt_id_map[_idx_map[pt]]); + } + } + else + { + // polyline has no name, ignore it. + pl.ignoreConfParamAll("pnt"); + } + } } void BoostXmlGmlInterface::readSurfaces( @@ -173,171 +173,171 @@ void BoostXmlGmlInterface::readSurfaces( const std::vector<std::size_t>& pnt_id_map, std::map<std::string, std::size_t>& sfc_names) { - for (auto const& sfc : surfacesRoot.getConfSubtreeList("surface")) - { - auto const id = sfc.getConfAttribute<std::size_t>("id"); - // The id is not used but must be present in the GML file. - // That's why sfc.ignore...() cannot be used. - (void) id; - surfaces.push_back(new GeoLib::Surface(points)); - - if (auto const s_name = sfc.getConfAttributeOptional<std::string>("name")) - { - if (s_name->empty()) { - ERR("Empty surface name found in geometry file."); - std::abort(); - } - - BaseLib::insertIfKeyUniqueElseError(sfc_names, *s_name, surfaces.size()-1, - "The surface name is not unique."); - - for (auto const& element : sfc.getConfParamList("element")) { - auto const p1_attr = element.getConfAttribute<std::size_t>("p1"); - auto const p2_attr = element.getConfAttribute<std::size_t>("p2"); - auto const p3_attr = element.getConfAttribute<std::size_t>("p3"); - - auto const p1 = pnt_id_map[_idx_map[p1_attr]]; - auto const p2 = pnt_id_map[_idx_map[p2_attr]]; - auto const p3 = pnt_id_map[_idx_map[p3_attr]]; - surfaces.back()->addTriangle(p1,p2,p3); - } - } - else - { - // surface has no name, ignore it. - sfc.ignoreConfParamAll("element"); - } - } + for (auto const& sfc : surfacesRoot.getConfSubtreeList("surface")) + { + auto const id = sfc.getConfAttribute<std::size_t>("id"); + // The id is not used but must be present in the GML file. + // That's why sfc.ignore...() cannot be used. + (void) id; + surfaces.push_back(new GeoLib::Surface(points)); + + if (auto const s_name = sfc.getConfAttributeOptional<std::string>("name")) + { + if (s_name->empty()) { + ERR("Empty surface name found in geometry file."); + std::abort(); + } + + BaseLib::insertIfKeyUniqueElseError(sfc_names, *s_name, surfaces.size()-1, + "The surface name is not unique."); + + for (auto const& element : sfc.getConfParamList("element")) { + auto const p1_attr = element.getConfAttribute<std::size_t>("p1"); + auto const p2_attr = element.getConfAttribute<std::size_t>("p2"); + auto const p3_attr = element.getConfAttribute<std::size_t>("p3"); + + auto const p1 = pnt_id_map[_idx_map[p1_attr]]; + auto const p2 = pnt_id_map[_idx_map[p2_attr]]; + auto const p3 = pnt_id_map[_idx_map[p3_attr]]; + surfaces.back()->addTriangle(p1,p2,p3); + } + } + else + { + // surface has no name, ignore it. + sfc.ignoreConfParamAll("element"); + } + } } bool BoostXmlGmlInterface::write() { - if (this->_exportName.empty()) { - ERR("BoostXmlGmlInterface::write(): No geometry specified."); - return false; - } - - GeoLib::PointVec const*const pnt_vec(_geo_objects.getPointVecObj(_exportName)); - if (! pnt_vec) { - ERR("BoostXmlGmlInterface::write(): No PointVec within the geometry \"%s\".", - _exportName.c_str()); - return false; - } - - std::vector<GeoLib::Point*> const*const pnts(pnt_vec->getVector()); - if (! pnts) { - ERR("BoostXmlGmlInterface::write(): No vector of points within the geometry \"%s\".", - _exportName.c_str()); - return false; - } - if (pnts->empty()) { - ERR("BoostXmlGmlInterface::write(): No points within the geometry \"%s\".", - _exportName.c_str()); - return false; - } - - // create a property tree for writing it to file - boost::property_tree::ptree pt; - - // put header in property tree - pt.put("<xmlattr>.xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); - pt.put("<xmlattr>.xsi:noNamespaceSchemaLocation", - "http://www.opengeosys.org/images/xsd/OpenGeoSysGLI.xsd"); - pt.put("<xmlattr>.xmlns:ogs", "http://www.opengeosys.net"); - auto& geometry_set = pt.add("OpenGeoSysGLI", ""); - - geometry_set.add("name", _exportName); - auto& pnts_tag = geometry_set.add("points", ""); - for (std::size_t k(0); k<pnts->size(); k++) { - auto& pnt_tag = pnts_tag.add("point", ""); - pnt_tag.put("<xmlattr>.id", k); - pnt_tag.put("<xmlattr>.x", (*((*pnts)[k]))[0]); - pnt_tag.put("<xmlattr>.y", (*((*pnts)[k]))[1]); - pnt_tag.put("<xmlattr>.z", (*((*pnts)[k]))[2]); - std::string const& point_name(pnt_vec->getItemNameByID(k)); - if (!point_name.empty()) - pnt_tag.put("<xmlattr>.name", point_name); - } - - addPolylinesToPropertyTree(geometry_set); - addSurfacesToPropertyTree(geometry_set); - - boost::property_tree::xml_writer_settings<std::string> settings('\t', 1); - write_xml(_out, pt, settings); - return true; + if (this->_exportName.empty()) { + ERR("BoostXmlGmlInterface::write(): No geometry specified."); + return false; + } + + GeoLib::PointVec const*const pnt_vec(_geo_objects.getPointVecObj(_exportName)); + if (! pnt_vec) { + ERR("BoostXmlGmlInterface::write(): No PointVec within the geometry \"%s\".", + _exportName.c_str()); + return false; + } + + std::vector<GeoLib::Point*> const*const pnts(pnt_vec->getVector()); + if (! pnts) { + ERR("BoostXmlGmlInterface::write(): No vector of points within the geometry \"%s\".", + _exportName.c_str()); + return false; + } + if (pnts->empty()) { + ERR("BoostXmlGmlInterface::write(): No points within the geometry \"%s\".", + _exportName.c_str()); + return false; + } + + // create a property tree for writing it to file + boost::property_tree::ptree pt; + + // put header in property tree + pt.put("<xmlattr>.xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); + pt.put("<xmlattr>.xsi:noNamespaceSchemaLocation", + "http://www.opengeosys.org/images/xsd/OpenGeoSysGLI.xsd"); + pt.put("<xmlattr>.xmlns:ogs", "http://www.opengeosys.net"); + auto& geometry_set = pt.add("OpenGeoSysGLI", ""); + + geometry_set.add("name", _exportName); + auto& pnts_tag = geometry_set.add("points", ""); + for (std::size_t k(0); k<pnts->size(); k++) { + auto& pnt_tag = pnts_tag.add("point", ""); + pnt_tag.put("<xmlattr>.id", k); + pnt_tag.put("<xmlattr>.x", (*((*pnts)[k]))[0]); + pnt_tag.put("<xmlattr>.y", (*((*pnts)[k]))[1]); + pnt_tag.put("<xmlattr>.z", (*((*pnts)[k]))[2]); + std::string const& point_name(pnt_vec->getItemNameByID(k)); + if (!point_name.empty()) + pnt_tag.put("<xmlattr>.name", point_name); + } + + addPolylinesToPropertyTree(geometry_set); + addSurfacesToPropertyTree(geometry_set); + + boost::property_tree::xml_writer_settings<std::string> settings('\t', 1); + write_xml(_out, pt, settings); + return true; } void BoostXmlGmlInterface::addSurfacesToPropertyTree( - boost::property_tree::ptree & geometry_set) + boost::property_tree::ptree & geometry_set) { - GeoLib::SurfaceVec const*const sfc_vec(_geo_objects.getSurfaceVecObj(_exportName)); - if (!sfc_vec) { - INFO("BoostXmlGmlInterface::addSurfacesToPropertyTree(): " - "No surfaces within the geometry \"%s\".", _exportName.c_str()); - return; - } - - std::vector<GeoLib::Surface*> const*const surfaces(sfc_vec->getVector()); - if (!surfaces || surfaces->empty()) - { - INFO( - "BoostXmlGmlInterface::addSurfacesToPropertyTree(): " - "No surfaces within the geometry \"%s\".", - _exportName.c_str()); - return; - } - - auto& surfaces_tag = geometry_set.add("surfaces", ""); - for (std::size_t i=0; i<surfaces->size(); ++i) { - GeoLib::Surface const*const surface((*surfaces)[i]); - std::string sfc_name(""); - sfc_vec->getNameOfElement(surface, sfc_name); - auto& surface_tag = surfaces_tag.add("surface", ""); - surface_tag.put("<xmlattr>.id", i); - if (!sfc_name.empty()) - surface_tag.put("<xmlattr>.name", sfc_name); - for (std::size_t j=0; j<surface->getNTriangles(); ++j) { - auto& element_tag = surface_tag.add("element", ""); - element_tag.put("<xmlattr>.p1", (*(*surface)[j])[0]); - element_tag.put("<xmlattr>.p2", (*(*surface)[j])[1]); - element_tag.put("<xmlattr>.p3", (*(*surface)[j])[2]); - } - } + GeoLib::SurfaceVec const*const sfc_vec(_geo_objects.getSurfaceVecObj(_exportName)); + if (!sfc_vec) { + INFO("BoostXmlGmlInterface::addSurfacesToPropertyTree(): " + "No surfaces within the geometry \"%s\".", _exportName.c_str()); + return; + } + + std::vector<GeoLib::Surface*> const*const surfaces(sfc_vec->getVector()); + if (!surfaces || surfaces->empty()) + { + INFO( + "BoostXmlGmlInterface::addSurfacesToPropertyTree(): " + "No surfaces within the geometry \"%s\".", + _exportName.c_str()); + return; + } + + auto& surfaces_tag = geometry_set.add("surfaces", ""); + for (std::size_t i=0; i<surfaces->size(); ++i) { + GeoLib::Surface const*const surface((*surfaces)[i]); + std::string sfc_name(""); + sfc_vec->getNameOfElement(surface, sfc_name); + auto& surface_tag = surfaces_tag.add("surface", ""); + surface_tag.put("<xmlattr>.id", i); + if (!sfc_name.empty()) + surface_tag.put("<xmlattr>.name", sfc_name); + for (std::size_t j=0; j<surface->getNTriangles(); ++j) { + auto& element_tag = surface_tag.add("element", ""); + element_tag.put("<xmlattr>.p1", (*(*surface)[j])[0]); + element_tag.put("<xmlattr>.p2", (*(*surface)[j])[1]); + element_tag.put("<xmlattr>.p3", (*(*surface)[j])[2]); + } + } } void BoostXmlGmlInterface::addPolylinesToPropertyTree( - boost::property_tree::ptree & geometry_set) + boost::property_tree::ptree & geometry_set) { - GeoLib::PolylineVec const*const vec(_geo_objects.getPolylineVecObj(_exportName)); - if (!vec) { - INFO("BoostXmlGmlInterface::addPolylinesToPropertyTree(): " - "No polylines within the geometry \"%s\".", _exportName.c_str()); - return; - } - - std::vector<GeoLib::Polyline*> const*const polylines(vec->getVector()); - if (!polylines || polylines->empty()) - { - INFO( - "BoostXmlGmlInterface::addPolylinesToPropertyTree(): " - "No polylines within the geometry \"%s\".", - _exportName.c_str()); - return; - } - - auto& polylines_tag = geometry_set.add("polylines", ""); - for (std::size_t i=0; i<polylines->size(); ++i) { - GeoLib::Polyline const*const polyline((*polylines)[i]); - std::string ply_name(""); - vec->getNameOfElement(polyline, ply_name); - auto& polyline_tag = polylines_tag.add("polyline", ""); - polyline_tag.put("<xmlattr>.id", i); - if (!ply_name.empty()) - polyline_tag.put("<xmlattr>.name", ply_name); - for (std::size_t j=0; j<polyline->getNumberOfPoints(); ++j) { - polyline_tag.add("pnt", polyline->getPointID(j)); - } - } + GeoLib::PolylineVec const*const vec(_geo_objects.getPolylineVecObj(_exportName)); + if (!vec) { + INFO("BoostXmlGmlInterface::addPolylinesToPropertyTree(): " + "No polylines within the geometry \"%s\".", _exportName.c_str()); + return; + } + + std::vector<GeoLib::Polyline*> const*const polylines(vec->getVector()); + if (!polylines || polylines->empty()) + { + INFO( + "BoostXmlGmlInterface::addPolylinesToPropertyTree(): " + "No polylines within the geometry \"%s\".", + _exportName.c_str()); + return; + } + + auto& polylines_tag = geometry_set.add("polylines", ""); + for (std::size_t i=0; i<polylines->size(); ++i) { + GeoLib::Polyline const*const polyline((*polylines)[i]); + std::string ply_name(""); + vec->getNameOfElement(polyline, ply_name); + auto& polyline_tag = polylines_tag.add("polyline", ""); + polyline_tag.put("<xmlattr>.id", i); + if (!ply_name.empty()) + polyline_tag.put("<xmlattr>.name", ply_name); + for (std::size_t j=0; j<polyline->getNumberOfPoints(); ++j) { + polyline_tag.add("pnt", polyline->getPointID(j)); + } + } } } // end namespace IO diff --git a/GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.h b/GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.h index a7633c13307eb0af6292ccbbd3dff1ace981ab93..3a172abaf147535ef1beba7ea1c10a8197a3246c 100644 --- a/GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.h +++ b/GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.h @@ -36,41 +36,41 @@ namespace IO class BoostXmlGmlInterface : public BaseLib::IO::XMLInterface { public: - BoostXmlGmlInterface(GeoLib::GEOObjects& geo_objs); - virtual ~BoostXmlGmlInterface() {} + BoostXmlGmlInterface(GeoLib::GEOObjects& geo_objs); + virtual ~BoostXmlGmlInterface() {} - /// Reads an xml-file containing OGS geometry - bool readFile(const std::string &fname); + /// Reads an xml-file containing OGS geometry + bool readFile(const std::string &fname); protected: - /// Required method for writing geometry. This is not implemented here, use the Qt class for writing. - bool write(); + /// Required method for writing geometry. This is not implemented here, use the Qt class for writing. + bool write(); private: - /// Reads GeoLib::Point-objects from an xml-file - void readPoints ( BaseLib::ConfigTree const& pointsRoot, - std::vector<GeoLib::Point*>& points, - std::map<std::string, std::size_t>& pnt_names); - - /// Reads GeoLib::Polyline-objects from an xml-file - void readPolylines ( BaseLib::ConfigTree const& polylinesRoot, - std::vector<GeoLib::Polyline*>& polylines, - std::vector<GeoLib::Point*> const& points, - const std::vector<std::size_t>& pnt_id_map, - std::map<std::string, std::size_t>& ply_names); - - /// Reads GeoLib::Surface-objects from an xml-file - void readSurfaces ( BaseLib::ConfigTree const& surfacesRoot, - std::vector<GeoLib::Surface*>& surfaces, - std::vector<GeoLib::Point*> const& points, - const std::vector<std::size_t>& pnt_id_map, - std::map<std::string, std::size_t>& sfc_names); - - void addSurfacesToPropertyTree(BaseLib::ConfigTree::PTree & pt); - void addPolylinesToPropertyTree(BaseLib::ConfigTree::PTree & geometry_set); - - std::map<std::size_t, std::size_t> _idx_map; - GeoLib::GEOObjects &_geo_objects; + /// Reads GeoLib::Point-objects from an xml-file + void readPoints ( BaseLib::ConfigTree const& pointsRoot, + std::vector<GeoLib::Point*>& points, + std::map<std::string, std::size_t>& pnt_names); + + /// Reads GeoLib::Polyline-objects from an xml-file + void readPolylines ( BaseLib::ConfigTree const& polylinesRoot, + std::vector<GeoLib::Polyline*>& polylines, + std::vector<GeoLib::Point*> const& points, + const std::vector<std::size_t>& pnt_id_map, + std::map<std::string, std::size_t>& ply_names); + + /// Reads GeoLib::Surface-objects from an xml-file + void readSurfaces ( BaseLib::ConfigTree const& surfacesRoot, + std::vector<GeoLib::Surface*>& surfaces, + std::vector<GeoLib::Point*> const& points, + const std::vector<std::size_t>& pnt_id_map, + std::map<std::string, std::size_t>& sfc_names); + + void addSurfacesToPropertyTree(BaseLib::ConfigTree::PTree & pt); + void addPolylinesToPropertyTree(BaseLib::ConfigTree::PTree & geometry_set); + + std::map<std::size_t, std::size_t> _idx_map; + GeoLib::GEOObjects &_geo_objects; }; } // end namespace IO diff --git a/GeoLib/IO/XmlIO/Qt/XmlGmlInterface.cpp b/GeoLib/IO/XmlIO/Qt/XmlGmlInterface.cpp index 36e488caef86addc9fd0204e02a62dc0a8fa3224..3c34a129161674996cd5103243907068417f7daa 100644 --- a/GeoLib/IO/XmlIO/Qt/XmlGmlInterface.cpp +++ b/GeoLib/IO/XmlIO/Qt/XmlGmlInterface.cpp @@ -28,107 +28,107 @@ namespace GeoLib namespace IO { XmlGmlInterface::XmlGmlInterface(GeoLib::GEOObjects& geo_objs) : - XMLInterface(), XMLQtInterface(BaseLib::FileFinder().getPath("OpenGeoSysGLI.xsd")), _geo_objs(geo_objs) + XMLInterface(), XMLQtInterface(BaseLib::FileFinder().getPath("OpenGeoSysGLI.xsd")), _geo_objs(geo_objs) { } int XmlGmlInterface::readFile(const QString &fileName) { - if(XMLQtInterface::readFile(fileName) == 0) - return 0; - - QDomDocument doc("OGS-GLI-DOM"); - doc.setContent(_fileData); - QDomElement docElement = doc.documentElement(); //OpenGeoSysGLI - if (docElement.nodeName().compare("OpenGeoSysGLI")) - { - ERR("XmlGmlInterface::readFile() - Unexpected XML root."); - return 0; - } - - std::string gliName("[NN]"); - - auto points = std::unique_ptr<std::vector<GeoLib::Point*>>( - new std::vector<GeoLib::Point*>); - auto polylines = std::unique_ptr<std::vector<GeoLib::Polyline*>>( - new std::vector<GeoLib::Polyline*>); - auto surfaces = std::unique_ptr<std::vector<GeoLib::Surface*>>( - new std::vector<GeoLib::Surface*>); - - std::map<std::string, std::size_t>* pnt_names = new std::map<std::string, std::size_t>; - std::map<std::string, std::size_t>* ply_names = new std::map<std::string, std::size_t>; - std::map<std::string, std::size_t>* sfc_names = new std::map<std::string, std::size_t>; - - QDomNodeList geoTypes = docElement.childNodes(); - for (int i = 0; i < geoTypes.count(); i++) - { - const QDomNode type_node(geoTypes.at(i)); - const QString nodeName = type_node.nodeName(); - if (nodeName.compare("name") == 0) - if (type_node.toElement().text().isEmpty()) - { - ERR("XmlGmlInterface::readFile(): <name>-tag is empty.") - deleteGeometry(std::move(points), std::move(polylines), - std::move(surfaces), pnt_names, ply_names, - sfc_names); - return 0; - } - else - gliName = type_node.toElement().text().toStdString(); - else if (nodeName.compare("points") == 0) - { - readPoints(type_node, points.get(), pnt_names); - _geo_objs.addPointVec(std::move(points), gliName, pnt_names); - } - else if (nodeName.compare("polylines") == 0) - readPolylines( - type_node, polylines.get(), *_geo_objs.getPointVec(gliName), - _geo_objs.getPointVecObj(gliName)->getIDMap(), ply_names); - else if (nodeName.compare("surfaces") == 0) - readSurfaces( - type_node, surfaces.get(), *_geo_objs.getPointVec(gliName), - _geo_objs.getPointVecObj(gliName)->getIDMap(), sfc_names); - } - - if (polylines->empty()) - deletePolylines(std::move(polylines), ply_names); - else - _geo_objs.addPolylineVec(std::move(polylines), gliName, ply_names); - - if (surfaces->empty()) - deleteSurfaces(std::move(surfaces), sfc_names); - else - _geo_objs.addSurfaceVec(std::move(surfaces), gliName, sfc_names); - return 1; + if(XMLQtInterface::readFile(fileName) == 0) + return 0; + + QDomDocument doc("OGS-GLI-DOM"); + doc.setContent(_fileData); + QDomElement docElement = doc.documentElement(); //OpenGeoSysGLI + if (docElement.nodeName().compare("OpenGeoSysGLI")) + { + ERR("XmlGmlInterface::readFile() - Unexpected XML root."); + return 0; + } + + std::string gliName("[NN]"); + + auto points = std::unique_ptr<std::vector<GeoLib::Point*>>( + new std::vector<GeoLib::Point*>); + auto polylines = std::unique_ptr<std::vector<GeoLib::Polyline*>>( + new std::vector<GeoLib::Polyline*>); + auto surfaces = std::unique_ptr<std::vector<GeoLib::Surface*>>( + new std::vector<GeoLib::Surface*>); + + std::map<std::string, std::size_t>* pnt_names = new std::map<std::string, std::size_t>; + std::map<std::string, std::size_t>* ply_names = new std::map<std::string, std::size_t>; + std::map<std::string, std::size_t>* sfc_names = new std::map<std::string, std::size_t>; + + QDomNodeList geoTypes = docElement.childNodes(); + for (int i = 0; i < geoTypes.count(); i++) + { + const QDomNode type_node(geoTypes.at(i)); + const QString nodeName = type_node.nodeName(); + if (nodeName.compare("name") == 0) + if (type_node.toElement().text().isEmpty()) + { + ERR("XmlGmlInterface::readFile(): <name>-tag is empty.") + deleteGeometry(std::move(points), std::move(polylines), + std::move(surfaces), pnt_names, ply_names, + sfc_names); + return 0; + } + else + gliName = type_node.toElement().text().toStdString(); + else if (nodeName.compare("points") == 0) + { + readPoints(type_node, points.get(), pnt_names); + _geo_objs.addPointVec(std::move(points), gliName, pnt_names); + } + else if (nodeName.compare("polylines") == 0) + readPolylines( + type_node, polylines.get(), *_geo_objs.getPointVec(gliName), + _geo_objs.getPointVecObj(gliName)->getIDMap(), ply_names); + else if (nodeName.compare("surfaces") == 0) + readSurfaces( + type_node, surfaces.get(), *_geo_objs.getPointVec(gliName), + _geo_objs.getPointVecObj(gliName)->getIDMap(), sfc_names); + } + + if (polylines->empty()) + deletePolylines(std::move(polylines), ply_names); + else + _geo_objs.addPolylineVec(std::move(polylines), gliName, ply_names); + + if (surfaces->empty()) + deleteSurfaces(std::move(surfaces), sfc_names); + else + _geo_objs.addSurfaceVec(std::move(surfaces), gliName, sfc_names); + return 1; } void XmlGmlInterface::readPoints(const QDomNode &pointsRoot, std::vector<GeoLib::Point*>* points, std::map<std::string, std::size_t>* &pnt_names ) { - char* pEnd; - QDomElement point = pointsRoot.firstChildElement(); - while (!point.isNull()) - { - _idx_map.insert (std::pair<std::size_t, std::size_t>( - strtol((point.attribute("id")).toStdString().c_str(), &pEnd, 10), points->size())); - GeoLib::Point* p = new GeoLib::Point(point.attribute("x").toDouble(), - point.attribute("y").toDouble(), - point.attribute("z").toDouble(), - point.attribute("id").toInt()); - if (point.hasAttribute("name")) - pnt_names->insert( std::pair<std::string, std::size_t>( - point.attribute("name").toStdString(), points->size()) ); - - points->push_back(p); - point = point.nextSiblingElement(); - } - - // if names-map is empty, set it to NULL because it is not needed - if (pnt_names->empty()) - { - delete pnt_names; - pnt_names = nullptr; - } + char* pEnd; + QDomElement point = pointsRoot.firstChildElement(); + while (!point.isNull()) + { + _idx_map.insert (std::pair<std::size_t, std::size_t>( + strtol((point.attribute("id")).toStdString().c_str(), &pEnd, 10), points->size())); + GeoLib::Point* p = new GeoLib::Point(point.attribute("x").toDouble(), + point.attribute("y").toDouble(), + point.attribute("z").toDouble(), + point.attribute("id").toInt()); + if (point.hasAttribute("name")) + pnt_names->insert( std::pair<std::string, std::size_t>( + point.attribute("name").toStdString(), points->size()) ); + + points->push_back(p); + point = point.nextSiblingElement(); + } + + // if names-map is empty, set it to NULL because it is not needed + if (pnt_names->empty()) + { + delete pnt_names; + pnt_names = nullptr; + } } void XmlGmlInterface::readPolylines(const QDomNode &polylinesRoot, @@ -137,44 +137,44 @@ void XmlGmlInterface::readPolylines(const QDomNode &polylinesRoot, const std::vector<std::size_t> &pnt_id_map, std::map<std::string, std::size_t>* &ply_names) { - std::size_t idx(0); - QDomElement polyline = polylinesRoot.firstChildElement(); - while (!polyline.isNull()) - { - idx = polylines->size(); - polylines->push_back(new GeoLib::Polyline(points)); - - if (polyline.hasAttribute("name")) { - std::string const ply_name( - polyline.attribute("name").toStdString() - ); - std::map<std::string, std::size_t>::const_iterator it( - ply_names->find(ply_name) - ); - if (it == ply_names->end()) { - ply_names->insert(std::pair<std::string, std::size_t>(ply_name, idx)); - } else { - WARN("Polyline \"%s\" exists already. The polyline will be " - "inserted without a name.", ply_name.c_str()); - } - } - - QDomElement point = polyline.firstChildElement(); - while (!point.isNull()) - { - (*polylines)[idx]->addPoint(pnt_id_map[_idx_map[point.text().toInt()]]); - point = point.nextSiblingElement(); - } - - polyline = polyline.nextSiblingElement(); - } - - // if names-map is empty, set it to NULL because it is not needed - if (ply_names->empty()) - { - delete ply_names; - ply_names = nullptr; - } + std::size_t idx(0); + QDomElement polyline = polylinesRoot.firstChildElement(); + while (!polyline.isNull()) + { + idx = polylines->size(); + polylines->push_back(new GeoLib::Polyline(points)); + + if (polyline.hasAttribute("name")) { + std::string const ply_name( + polyline.attribute("name").toStdString() + ); + std::map<std::string, std::size_t>::const_iterator it( + ply_names->find(ply_name) + ); + if (it == ply_names->end()) { + ply_names->insert(std::pair<std::string, std::size_t>(ply_name, idx)); + } else { + WARN("Polyline \"%s\" exists already. The polyline will be " + "inserted without a name.", ply_name.c_str()); + } + } + + QDomElement point = polyline.firstChildElement(); + while (!point.isNull()) + { + (*polylines)[idx]->addPoint(pnt_id_map[_idx_map[point.text().toInt()]]); + point = point.nextSiblingElement(); + } + + polyline = polyline.nextSiblingElement(); + } + + // if names-map is empty, set it to NULL because it is not needed + if (ply_names->empty()) + { + delete ply_names; + ply_names = nullptr; + } } void XmlGmlInterface::readSurfaces(const QDomNode &surfacesRoot, @@ -183,34 +183,34 @@ void XmlGmlInterface::readSurfaces(const QDomNode &surfacesRoot, const std::vector<std::size_t> &pnt_id_map, std::map<std::string,std::size_t>* &sfc_names) { - QDomElement surface = surfacesRoot.firstChildElement(); - while (!surface.isNull()) - { - surfaces->push_back(new GeoLib::Surface(points)); - - if (surface.hasAttribute("name")) - sfc_names->insert( std::pair<std::string, std::size_t>( surface.attribute("name").toStdString(), - surfaces->size()-1) ); - - QDomElement element = surface.firstChildElement(); - while (!element.isNull()) - { - std::size_t p1 = pnt_id_map[_idx_map[element.attribute("p1").toInt()]]; - std::size_t p2 = pnt_id_map[_idx_map[element.attribute("p2").toInt()]]; - std::size_t p3 = pnt_id_map[_idx_map[element.attribute("p3").toInt()]]; - surfaces->back()->addTriangle(p1,p2,p3); - element = element.nextSiblingElement(); - } - - surface = surface.nextSiblingElement(); - } - - // if names-map is empty, set it to NULL because it is not needed - if (sfc_names->empty()) - { - delete sfc_names; - sfc_names = nullptr; - } + QDomElement surface = surfacesRoot.firstChildElement(); + while (!surface.isNull()) + { + surfaces->push_back(new GeoLib::Surface(points)); + + if (surface.hasAttribute("name")) + sfc_names->insert( std::pair<std::string, std::size_t>( surface.attribute("name").toStdString(), + surfaces->size()-1) ); + + QDomElement element = surface.firstChildElement(); + while (!element.isNull()) + { + std::size_t p1 = pnt_id_map[_idx_map[element.attribute("p1").toInt()]]; + std::size_t p2 = pnt_id_map[_idx_map[element.attribute("p2").toInt()]]; + std::size_t p3 = pnt_id_map[_idx_map[element.attribute("p3").toInt()]]; + surfaces->back()->addTriangle(p1,p2,p3); + element = element.nextSiblingElement(); + } + + surface = surface.nextSiblingElement(); + } + + // if names-map is empty, set it to NULL because it is not needed + if (sfc_names->empty()) + { + delete sfc_names; + sfc_names = nullptr; + } } void XmlGmlInterface::deleteGeometry( @@ -221,190 +221,190 @@ void XmlGmlInterface::deleteGeometry( std::map<std::string, std::size_t>* ply_names, std::map<std::string, std::size_t>* sfc_names) const { - for (GeoLib::Point* point : *points) - delete point; - delete pnt_names; - deletePolylines(std::move(polylines), ply_names); - deleteSurfaces(std::move(surfaces), sfc_names); + for (GeoLib::Point* point : *points) + delete point; + delete pnt_names; + deletePolylines(std::move(polylines), ply_names); + deleteSurfaces(std::move(surfaces), sfc_names); } void XmlGmlInterface::deletePolylines( std::unique_ptr<std::vector<GeoLib::Polyline*>> polylines, std::map<std::string, std::size_t>* ply_names) const { - for (GeoLib::Polyline* line : *polylines) - delete line; - delete ply_names; + for (GeoLib::Polyline* line : *polylines) + delete line; + delete ply_names; } void XmlGmlInterface::deleteSurfaces( std::unique_ptr<std::vector<GeoLib::Surface*>> surfaces, std::map<std::string, std::size_t>* sfc_names) const { - for (GeoLib::Surface* line : *surfaces) - delete line; - delete sfc_names; + for (GeoLib::Surface* line : *surfaces) + delete line; + delete sfc_names; } bool XmlGmlInterface::write() { - if (this->_exportName.empty()) - { - ERR("XmlGmlInterface::write(): No geometry specified."); - return false; - } - - std::size_t nPoints = 0, nPolylines = 0, nSurfaces = 0; - - _out << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; // xml definition - //_out << "<?xml-stylesheet type=\"text/xsl\" href=\"OpenGeoSysGLI.xsl\"?>\n\n"; // stylefile definition - - QDomDocument doc("OGS-GML-DOM"); - QDomElement root = doc.createElement("OpenGeoSysGLI"); - root.setAttribute( "xmlns:ogs", "http://www.opengeosys.org" ); - root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); - root.setAttribute( "xsi:noNamespaceSchemaLocation", "http://www.opengeosys.org/images/xsd/OpenGeoSysGLI.xsd" ); - - doc.appendChild(root); - - QDomElement geoNameTag = doc.createElement("name"); - root.appendChild(geoNameTag); - QDomText geoNameText = doc.createTextNode(QString::fromStdString(_exportName)); - geoNameTag.appendChild(geoNameText); - - // POINTS - QDomElement pointsListTag = doc.createElement("points"); - root.appendChild(pointsListTag); - - const GeoLib::PointVec* pnt_vec (_geo_objs.getPointVecObj(_exportName)); - if (pnt_vec) - { - const std::vector<GeoLib::Point*>* points (pnt_vec->getVector()); - - if (!points->empty()) - { - nPoints = points->size(); - for (std::size_t i = 0; i < nPoints; i++) - { - QDomElement pointTag = doc.createElement("point"); - pointTag.setAttribute("id", QString::number(i)); - pointTag.setAttribute("x", QString::number((*(*points)[i])[0], 'f')); - pointTag.setAttribute("y", QString::number((*(*points)[i])[1], 'f')); - pointTag.setAttribute("z", QString::number((*(*points)[i])[2], 'f')); - - std::string const& point_name(pnt_vec->getItemNameByID(i)); - if (!point_name.empty()) - pointTag.setAttribute("name", - QString::fromStdString(point_name)); - - pointsListTag.appendChild(pointTag); - } - } - else - { - ERR("XmlGmlInterface::write(): Point vector empty, abort writing geometry."); - return 0; - } - } - else - { - ERR("XmlGmlInterface::write(): Did not found any point vector, abort writing geometry."); - return 0; - } - - // POLYLINES - const GeoLib::PolylineVec* ply_vec (_geo_objs.getPolylineVecObj(_exportName)); - if (ply_vec) - { - const std::vector<GeoLib::Polyline*>* polylines (ply_vec->getVector()); - - if (polylines) - { - if (!polylines->empty()) - { - QDomElement plyListTag = doc.createElement("polylines"); - root.appendChild(plyListTag); - nPolylines = polylines->size(); - for (std::size_t i = 0; i < nPolylines; i++) - { - QDomElement polylineTag = doc.createElement("polyline"); - polylineTag.setAttribute("id", QString::number(i)); - - std::string ply_name(""); - if (ply_vec->getNameOfElementByID(i, ply_name)) - polylineTag.setAttribute("name", QString::fromStdString(ply_name)); - - plyListTag.appendChild(polylineTag); - - nPoints = (*polylines)[i]->getNumberOfPoints(); - for (std::size_t j = 0; j < nPoints; j++) - { - QDomElement plyPointTag = doc.createElement("pnt"); - polylineTag.appendChild(plyPointTag); - QDomText plyPointText = doc.createTextNode(QString::number(((*polylines)[i])->getPointID(j))); - plyPointTag.appendChild(plyPointText); - } - } - } - else - INFO("XmlGmlInterface::write(): Polyline vector empty, no polylines written to file."); - } - } - else - INFO("XmlGmlInterface::write(): Did not found any polyline vector, no polylines written to file."); - - - // SURFACES - const GeoLib::SurfaceVec* sfc_vec (_geo_objs.getSurfaceVecObj(_exportName)); - if (sfc_vec) - { - const std::vector<GeoLib::Surface*>* surfaces (sfc_vec->getVector()); - - if (surfaces) - { - if (!surfaces->empty()) - { - QDomElement sfcListTag = doc.createElement("surfaces"); - root.appendChild(sfcListTag); - nSurfaces = surfaces->size(); - for (std::size_t i = 0; i < nSurfaces; i++) - { - QDomElement surfaceTag = doc.createElement("surface"); - surfaceTag.setAttribute("id", QString::number(i)); - - std::string sfc_name(""); - if (sfc_vec->getNameOfElementByID(i, sfc_name)) - surfaceTag.setAttribute("name", - QString::fromStdString( - sfc_name)); - - sfcListTag.appendChild(surfaceTag); - - // writing the elements compromising the surface - std::size_t nElements = ((*surfaces)[i])->getNTriangles(); - for (std::size_t j = 0; j < nElements; j++) - { - QDomElement elementTag = doc.createElement("element"); - elementTag.setAttribute("p1", QString::number((*(*(*surfaces)[i])[j])[0])); - elementTag.setAttribute("p2", QString::number((*(*(*surfaces)[i])[j])[1])); - elementTag.setAttribute("p3", QString::number((*(*(*surfaces)[i])[j])[2])); - surfaceTag.appendChild(elementTag); - } - } - } - else - INFO("XmlGmlInterface::write(): Surface vector empty, no surfaces written to file."); - } - } - else - INFO("XmlGmlInterface::write(): Did not found any surface vector, no surfaces written to file."); - - - //insertStyleFileDefinition(filename); - std::string xml = doc.toString().toStdString(); - _out << xml; - - return true; + if (this->_exportName.empty()) + { + ERR("XmlGmlInterface::write(): No geometry specified."); + return false; + } + + std::size_t nPoints = 0, nPolylines = 0, nSurfaces = 0; + + _out << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; // xml definition + //_out << "<?xml-stylesheet type=\"text/xsl\" href=\"OpenGeoSysGLI.xsl\"?>\n\n"; // stylefile definition + + QDomDocument doc("OGS-GML-DOM"); + QDomElement root = doc.createElement("OpenGeoSysGLI"); + root.setAttribute( "xmlns:ogs", "http://www.opengeosys.org" ); + root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); + root.setAttribute( "xsi:noNamespaceSchemaLocation", "http://www.opengeosys.org/images/xsd/OpenGeoSysGLI.xsd" ); + + doc.appendChild(root); + + QDomElement geoNameTag = doc.createElement("name"); + root.appendChild(geoNameTag); + QDomText geoNameText = doc.createTextNode(QString::fromStdString(_exportName)); + geoNameTag.appendChild(geoNameText); + + // POINTS + QDomElement pointsListTag = doc.createElement("points"); + root.appendChild(pointsListTag); + + const GeoLib::PointVec* pnt_vec (_geo_objs.getPointVecObj(_exportName)); + if (pnt_vec) + { + const std::vector<GeoLib::Point*>* points (pnt_vec->getVector()); + + if (!points->empty()) + { + nPoints = points->size(); + for (std::size_t i = 0; i < nPoints; i++) + { + QDomElement pointTag = doc.createElement("point"); + pointTag.setAttribute("id", QString::number(i)); + pointTag.setAttribute("x", QString::number((*(*points)[i])[0], 'f')); + pointTag.setAttribute("y", QString::number((*(*points)[i])[1], 'f')); + pointTag.setAttribute("z", QString::number((*(*points)[i])[2], 'f')); + + std::string const& point_name(pnt_vec->getItemNameByID(i)); + if (!point_name.empty()) + pointTag.setAttribute("name", + QString::fromStdString(point_name)); + + pointsListTag.appendChild(pointTag); + } + } + else + { + ERR("XmlGmlInterface::write(): Point vector empty, abort writing geometry."); + return 0; + } + } + else + { + ERR("XmlGmlInterface::write(): Did not found any point vector, abort writing geometry."); + return 0; + } + + // POLYLINES + const GeoLib::PolylineVec* ply_vec (_geo_objs.getPolylineVecObj(_exportName)); + if (ply_vec) + { + const std::vector<GeoLib::Polyline*>* polylines (ply_vec->getVector()); + + if (polylines) + { + if (!polylines->empty()) + { + QDomElement plyListTag = doc.createElement("polylines"); + root.appendChild(plyListTag); + nPolylines = polylines->size(); + for (std::size_t i = 0; i < nPolylines; i++) + { + QDomElement polylineTag = doc.createElement("polyline"); + polylineTag.setAttribute("id", QString::number(i)); + + std::string ply_name(""); + if (ply_vec->getNameOfElementByID(i, ply_name)) + polylineTag.setAttribute("name", QString::fromStdString(ply_name)); + + plyListTag.appendChild(polylineTag); + + nPoints = (*polylines)[i]->getNumberOfPoints(); + for (std::size_t j = 0; j < nPoints; j++) + { + QDomElement plyPointTag = doc.createElement("pnt"); + polylineTag.appendChild(plyPointTag); + QDomText plyPointText = doc.createTextNode(QString::number(((*polylines)[i])->getPointID(j))); + plyPointTag.appendChild(plyPointText); + } + } + } + else + INFO("XmlGmlInterface::write(): Polyline vector empty, no polylines written to file."); + } + } + else + INFO("XmlGmlInterface::write(): Did not found any polyline vector, no polylines written to file."); + + + // SURFACES + const GeoLib::SurfaceVec* sfc_vec (_geo_objs.getSurfaceVecObj(_exportName)); + if (sfc_vec) + { + const std::vector<GeoLib::Surface*>* surfaces (sfc_vec->getVector()); + + if (surfaces) + { + if (!surfaces->empty()) + { + QDomElement sfcListTag = doc.createElement("surfaces"); + root.appendChild(sfcListTag); + nSurfaces = surfaces->size(); + for (std::size_t i = 0; i < nSurfaces; i++) + { + QDomElement surfaceTag = doc.createElement("surface"); + surfaceTag.setAttribute("id", QString::number(i)); + + std::string sfc_name(""); + if (sfc_vec->getNameOfElementByID(i, sfc_name)) + surfaceTag.setAttribute("name", + QString::fromStdString( + sfc_name)); + + sfcListTag.appendChild(surfaceTag); + + // writing the elements compromising the surface + std::size_t nElements = ((*surfaces)[i])->getNTriangles(); + for (std::size_t j = 0; j < nElements; j++) + { + QDomElement elementTag = doc.createElement("element"); + elementTag.setAttribute("p1", QString::number((*(*(*surfaces)[i])[j])[0])); + elementTag.setAttribute("p2", QString::number((*(*(*surfaces)[i])[j])[1])); + elementTag.setAttribute("p3", QString::number((*(*(*surfaces)[i])[j])[2])); + surfaceTag.appendChild(elementTag); + } + } + } + else + INFO("XmlGmlInterface::write(): Surface vector empty, no surfaces written to file."); + } + } + else + INFO("XmlGmlInterface::write(): Did not found any surface vector, no surfaces written to file."); + + + //insertStyleFileDefinition(filename); + std::string xml = doc.toString().toStdString(); + _out << xml; + + return true; } } diff --git a/GeoLib/IO/XmlIO/Qt/XmlGmlInterface.h b/GeoLib/IO/XmlIO/Qt/XmlGmlInterface.h index 7c695ba277856cdfeb687a9ee344c1b6b8c1690a..fe97f1339d98ef0f08ca96cf81a65716d9f9a5ee 100644 --- a/GeoLib/IO/XmlIO/Qt/XmlGmlInterface.h +++ b/GeoLib/IO/XmlIO/Qt/XmlGmlInterface.h @@ -34,58 +34,58 @@ class XmlGmlInterface : public BaseLib::IO::XMLInterface, public BaseLib::IO::XMLQtInterface { public: - XmlGmlInterface(GeoLib::GEOObjects& geo_objs); + XmlGmlInterface(GeoLib::GEOObjects& geo_objs); - virtual ~XmlGmlInterface() {} + virtual ~XmlGmlInterface() {} - /// Reads an xml-file containing geometric object definitions into the GEOObjects used in the contructor - int readFile(const QString &fileName); + /// Reads an xml-file containing geometric object definitions into the GEOObjects used in the contructor + int readFile(const QString &fileName); - bool readFile(std::string const& fname) { return readFile(QString(fname.c_str())) != 0; } + bool readFile(std::string const& fname) { return readFile(QString(fname.c_str())) != 0; } protected: - bool write(); + bool write(); private: - /// Reads GeoLib::Point-objects from an xml-file - void readPoints ( const QDomNode &pointsRoot, - std::vector<GeoLib::Point*>* points, - std::map<std::string, std::size_t>* &pnt_names ); - - /// Reads GeoLib::Polyline-objects from an xml-file - void readPolylines ( const QDomNode &polylinesRoot, - std::vector<GeoLib::Polyline*>* polylines, - std::vector<GeoLib::Point*> const& points, - const std::vector<std::size_t> &pnt_id_map, - std::map<std::string, std::size_t>* &ply_names ); - - /// Reads GeoLib::Surface-objects from an xml-file - void readSurfaces ( const QDomNode &surfacesRoot, - std::vector<GeoLib::Surface*>* surfaces, - std::vector<GeoLib::Point*> const& points, - const std::vector<std::size_t> &pnt_id_map, - std::map<std::string, std::size_t>* &sfc_names ); - - /// Deletes all geometry data structures - void deleteGeometry( - std::unique_ptr<std::vector<GeoLib::Point*>> points, - std::unique_ptr<std::vector<GeoLib::Polyline*>> polylines, - std::unique_ptr<std::vector<GeoLib::Surface*>> surfaces, - std::map<std::string, std::size_t>* pnt_names, - std::map<std::string, std::size_t>* ply_names, - std::map<std::string, std::size_t>* sfc_names) const; - - /// Cleans up polylines-vector as well as its content if necessary - void deletePolylines( - std::unique_ptr<std::vector<GeoLib::Polyline*>> polylines, - std::map<std::string, std::size_t>* ply_names) const; - - /// Cleans up surfaces-vector as well as its content if necessary - void deleteSurfaces(std::unique_ptr<std::vector<GeoLib::Surface*>> surfaces, - std::map<std::string, std::size_t>* sfc_names) const; - - GeoLib::GEOObjects& _geo_objs; - std::map<std::size_t, std::size_t> _idx_map; + /// Reads GeoLib::Point-objects from an xml-file + void readPoints ( const QDomNode &pointsRoot, + std::vector<GeoLib::Point*>* points, + std::map<std::string, std::size_t>* &pnt_names ); + + /// Reads GeoLib::Polyline-objects from an xml-file + void readPolylines ( const QDomNode &polylinesRoot, + std::vector<GeoLib::Polyline*>* polylines, + std::vector<GeoLib::Point*> const& points, + const std::vector<std::size_t> &pnt_id_map, + std::map<std::string, std::size_t>* &ply_names ); + + /// Reads GeoLib::Surface-objects from an xml-file + void readSurfaces ( const QDomNode &surfacesRoot, + std::vector<GeoLib::Surface*>* surfaces, + std::vector<GeoLib::Point*> const& points, + const std::vector<std::size_t> &pnt_id_map, + std::map<std::string, std::size_t>* &sfc_names ); + + /// Deletes all geometry data structures + void deleteGeometry( + std::unique_ptr<std::vector<GeoLib::Point*>> points, + std::unique_ptr<std::vector<GeoLib::Polyline*>> polylines, + std::unique_ptr<std::vector<GeoLib::Surface*>> surfaces, + std::map<std::string, std::size_t>* pnt_names, + std::map<std::string, std::size_t>* ply_names, + std::map<std::string, std::size_t>* sfc_names) const; + + /// Cleans up polylines-vector as well as its content if necessary + void deletePolylines( + std::unique_ptr<std::vector<GeoLib::Polyline*>> polylines, + std::map<std::string, std::size_t>* ply_names) const; + + /// Cleans up surfaces-vector as well as its content if necessary + void deleteSurfaces(std::unique_ptr<std::vector<GeoLib::Surface*>> surfaces, + std::map<std::string, std::size_t>* sfc_names) const; + + GeoLib::GEOObjects& _geo_objs; + std::map<std::size_t, std::size_t> _idx_map; }; } // end namespace IO diff --git a/GeoLib/IO/XmlIO/Qt/XmlStnInterface.cpp b/GeoLib/IO/XmlIO/Qt/XmlStnInterface.cpp index 4835acc84d6164e24f874b6bfa2f78145e943d20..43d2a7eb33e2455d0be54bbd9a556bfebec9e3e3 100644 --- a/GeoLib/IO/XmlIO/Qt/XmlStnInterface.cpp +++ b/GeoLib/IO/XmlIO/Qt/XmlStnInterface.cpp @@ -33,449 +33,449 @@ namespace GeoLib namespace IO { XmlStnInterface::XmlStnInterface(GeoLib::GEOObjects& geo_objs) : - XMLInterface(), XMLQtInterface(BaseLib::FileFinder().getPath("OpenGeoSysSTN.xsd")), _geo_objs(geo_objs) + XMLInterface(), XMLQtInterface(BaseLib::FileFinder().getPath("OpenGeoSysSTN.xsd")), _geo_objs(geo_objs) { } int XmlStnInterface::readFile(const QString &fileName) { - if(XMLQtInterface::readFile(fileName) == 0) - return 0; - - QDomDocument doc("OGS-STN-DOM"); - doc.setContent(_fileData); - QDomElement docElement = doc.documentElement(); //root element, used for identifying file-type - if (docElement.nodeName().compare("OpenGeoSysSTN")) - { - ERR("XmlStnInterface::readFile(): Unexpected XML root."); - return 0; - } - - QDomNodeList lists = docElement.childNodes(); - for (int i = 0; i < lists.count(); i++) - { - // read all the station lists - QDomNodeList stationList = lists.at(i).childNodes(); - auto stations = std::unique_ptr<std::vector<GeoLib::Point*>>( - new std::vector<GeoLib::Point*>); - std::string stnName("[NN]"); - - for (int j = 0; j < stationList.count(); j++) - { - const QDomNode station_node(stationList.at(j)); - const QString station_type(station_node.nodeName()); - if (station_type.compare("name") == 0) - stnName = station_node.toElement().text().toStdString(); - else if (station_type.compare("stations") == 0) - readStations(station_node, stations.get(), fileName.toStdString()); - else if (station_type.compare("boreholes") == 0) - readStations(station_node, stations.get(), fileName.toStdString()); - } - - if (!stations->empty()) - _geo_objs.addStationVec(std::move(stations), stnName); - } - - return 1; + if(XMLQtInterface::readFile(fileName) == 0) + return 0; + + QDomDocument doc("OGS-STN-DOM"); + doc.setContent(_fileData); + QDomElement docElement = doc.documentElement(); //root element, used for identifying file-type + if (docElement.nodeName().compare("OpenGeoSysSTN")) + { + ERR("XmlStnInterface::readFile(): Unexpected XML root."); + return 0; + } + + QDomNodeList lists = docElement.childNodes(); + for (int i = 0; i < lists.count(); i++) + { + // read all the station lists + QDomNodeList stationList = lists.at(i).childNodes(); + auto stations = std::unique_ptr<std::vector<GeoLib::Point*>>( + new std::vector<GeoLib::Point*>); + std::string stnName("[NN]"); + + for (int j = 0; j < stationList.count(); j++) + { + const QDomNode station_node(stationList.at(j)); + const QString station_type(station_node.nodeName()); + if (station_type.compare("name") == 0) + stnName = station_node.toElement().text().toStdString(); + else if (station_type.compare("stations") == 0) + readStations(station_node, stations.get(), fileName.toStdString()); + else if (station_type.compare("boreholes") == 0) + readStations(station_node, stations.get(), fileName.toStdString()); + } + + if (!stations->empty()) + _geo_objs.addStationVec(std::move(stations), stnName); + } + + return 1; } void XmlStnInterface::readStations( const QDomNode &stationsRoot, std::vector<GeoLib::Point*>* stations, const std::string &station_file_name ) { - QDomElement station = stationsRoot.firstChildElement(); - while (!station.isNull()) - { - if (station.hasAttribute("id") && station.hasAttribute("x") && - station.hasAttribute("y")) - { - std::string stationName("[NN]"); - std::string sensor_data_file_name(""); - std::string boreholeDate("0000-00-00"); - double boreholeDepth(0.0), stationValue(0.0); - - QDomNodeList stationFeatures = station.childNodes(); - for(int i = 0; i < stationFeatures.count(); i++) - { - // check for general station features - const QDomNode feature_node (stationFeatures.at(i)); - const QString feature_name (feature_node.nodeName()); - const QString element_text (feature_node.toElement().text()); - if (feature_name.compare("name") == 0) - stationName = element_text.toStdString(); - if (feature_name.compare("sensordata") == 0) - sensor_data_file_name = element_text.toStdString(); - /* add other station features here */ - - // check for general borehole features - else if (feature_name.compare("value") == 0) - stationValue = element_text.toDouble(); - else if (feature_name.compare("bdepth") == 0) - boreholeDepth = element_text.toDouble(); - else if (feature_name.compare("bdate") == 0) - boreholeDate = element_text.toStdString(); - /* add other borehole features here */ - } - - double zVal = (station.hasAttribute("z")) ? station.attribute("z").toDouble() : 0.0; - - if (station.nodeName().compare("station") == 0) - { - GeoLib::Station* s = new GeoLib::Station(station.attribute("x").toDouble(), - station.attribute("y").toDouble(), - zVal, - stationName); - s->setStationValue(stationValue); - if (!sensor_data_file_name.empty()) - s->addSensorDataFromCSV(BaseLib::copyPathToFileName(sensor_data_file_name, - station_file_name)); - stations->push_back(s); - } - else if (station.nodeName().compare("borehole") == 0) - { - GeoLib::StationBorehole* s = GeoLib::StationBorehole::createStation( - stationName, - station.attribute("x").toDouble(), - station.attribute("y").toDouble(), - zVal, - boreholeDepth, - boreholeDate); - s->setStationValue(stationValue); - /* add stratigraphy to the borehole */ - for(int j = 0; j < stationFeatures.count(); j++) - if (stationFeatures.at(j).nodeName().compare("strat") == 0) - this->readStratigraphy(stationFeatures.at(j), s); - - stations->push_back(s); - } - } - else - WARN("XmlStnInterface::readStations(): Attribute missing in <station> tag."); - station = station.nextSiblingElement(); - } + QDomElement station = stationsRoot.firstChildElement(); + while (!station.isNull()) + { + if (station.hasAttribute("id") && station.hasAttribute("x") && + station.hasAttribute("y")) + { + std::string stationName("[NN]"); + std::string sensor_data_file_name(""); + std::string boreholeDate("0000-00-00"); + double boreholeDepth(0.0), stationValue(0.0); + + QDomNodeList stationFeatures = station.childNodes(); + for(int i = 0; i < stationFeatures.count(); i++) + { + // check for general station features + const QDomNode feature_node (stationFeatures.at(i)); + const QString feature_name (feature_node.nodeName()); + const QString element_text (feature_node.toElement().text()); + if (feature_name.compare("name") == 0) + stationName = element_text.toStdString(); + if (feature_name.compare("sensordata") == 0) + sensor_data_file_name = element_text.toStdString(); + /* add other station features here */ + + // check for general borehole features + else if (feature_name.compare("value") == 0) + stationValue = element_text.toDouble(); + else if (feature_name.compare("bdepth") == 0) + boreholeDepth = element_text.toDouble(); + else if (feature_name.compare("bdate") == 0) + boreholeDate = element_text.toStdString(); + /* add other borehole features here */ + } + + double zVal = (station.hasAttribute("z")) ? station.attribute("z").toDouble() : 0.0; + + if (station.nodeName().compare("station") == 0) + { + GeoLib::Station* s = new GeoLib::Station(station.attribute("x").toDouble(), + station.attribute("y").toDouble(), + zVal, + stationName); + s->setStationValue(stationValue); + if (!sensor_data_file_name.empty()) + s->addSensorDataFromCSV(BaseLib::copyPathToFileName(sensor_data_file_name, + station_file_name)); + stations->push_back(s); + } + else if (station.nodeName().compare("borehole") == 0) + { + GeoLib::StationBorehole* s = GeoLib::StationBorehole::createStation( + stationName, + station.attribute("x").toDouble(), + station.attribute("y").toDouble(), + zVal, + boreholeDepth, + boreholeDate); + s->setStationValue(stationValue); + /* add stratigraphy to the borehole */ + for(int j = 0; j < stationFeatures.count(); j++) + if (stationFeatures.at(j).nodeName().compare("strat") == 0) + this->readStratigraphy(stationFeatures.at(j), s); + + stations->push_back(s); + } + } + else + WARN("XmlStnInterface::readStations(): Attribute missing in <station> tag."); + station = station.nextSiblingElement(); + } } void XmlStnInterface::readStratigraphy( const QDomNode &stratRoot, GeoLib::StationBorehole* borehole ) { - //borehole->addSoilLayer((*borehole)[0], (*borehole)[1], (*borehole)[2], ""); - double depth_check((*borehole)[2]); - QDomElement horizon = stratRoot.firstChildElement(); - while (!horizon.isNull()) - { - if (horizon.hasAttribute("id") && horizon.hasAttribute("x") && - horizon.hasAttribute("y") && horizon.hasAttribute("z")) - { - std::string horizonName("[NN]"); - - QDomNodeList horizonFeatures = horizon.childNodes(); - for(int i = 0; i < horizonFeatures.count(); i++) - if (horizonFeatures.at(i).nodeName().compare("name") == 0) - horizonName = horizonFeatures.at(i).toElement().text().toStdString(); - /* add other horizon features here */ - - double depth (horizon.attribute("z").toDouble()); - if (fabs(depth - depth_check) > std::numeric_limits<double>::epsilon()) // skip soil-layer if its thickness is zero - { - borehole->addSoilLayer(horizon.attribute("x").toDouble(), - horizon.attribute("y").toDouble(), - depth, - horizonName); - depth_check = depth; - } - else - WARN("XmlStnInterface::readStratigraphy(): Skipped layer \"%s\" in borehole \"%s\" because of thickness 0.0.", - horizonName.c_str(), borehole->getName().c_str()); - } - else - WARN("XmlStnInterface::readStratigraphy(): Attribute missing in <horizon> tag."); - horizon = horizon.nextSiblingElement(); - } + //borehole->addSoilLayer((*borehole)[0], (*borehole)[1], (*borehole)[2], ""); + double depth_check((*borehole)[2]); + QDomElement horizon = stratRoot.firstChildElement(); + while (!horizon.isNull()) + { + if (horizon.hasAttribute("id") && horizon.hasAttribute("x") && + horizon.hasAttribute("y") && horizon.hasAttribute("z")) + { + std::string horizonName("[NN]"); + + QDomNodeList horizonFeatures = horizon.childNodes(); + for(int i = 0; i < horizonFeatures.count(); i++) + if (horizonFeatures.at(i).nodeName().compare("name") == 0) + horizonName = horizonFeatures.at(i).toElement().text().toStdString(); + /* add other horizon features here */ + + double depth (horizon.attribute("z").toDouble()); + if (fabs(depth - depth_check) > std::numeric_limits<double>::epsilon()) // skip soil-layer if its thickness is zero + { + borehole->addSoilLayer(horizon.attribute("x").toDouble(), + horizon.attribute("y").toDouble(), + depth, + horizonName); + depth_check = depth; + } + else + WARN("XmlStnInterface::readStratigraphy(): Skipped layer \"%s\" in borehole \"%s\" because of thickness 0.0.", + horizonName.c_str(), borehole->getName().c_str()); + } + else + WARN("XmlStnInterface::readStratigraphy(): Attribute missing in <horizon> tag."); + horizon = horizon.nextSiblingElement(); + } } bool XmlStnInterface::write() { - if (this->_exportName.empty()) - { - ERR("XmlStnInterface::write(): No station list specified."); - return 0; - } - - _out << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; // xml definition - _out << "<?xml-stylesheet type=\"text/xsl\" href=\"OpenGeoSysSTN.xsl\"?>\n\n"; // stylefile definition - - QDomDocument doc("OGS-STN-DOM"); - QDomElement root = doc.createElement("OpenGeoSysSTN"); - root.setAttribute( "xmlns:ogs", "http://www.opengeosys.org" ); - root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); - root.setAttribute( "xsi:noNamespaceSchemaLocation", "http://www.opengeosys.org/images/xsd/OpenGeoSysSTN.xsd" ); - - const std::vector<GeoLib::Point*>* stations (_geo_objs.getStationVec(_exportName)); - bool isBorehole = - (static_cast<GeoLib::Station*>((*stations)[0])->type() == - GeoLib::Station::StationType::BOREHOLE) ? true : false; - - doc.appendChild(root); - QDomElement stationListTag = doc.createElement("stationlist"); - root.appendChild(stationListTag); - - QDomElement listNameTag = doc.createElement("name"); - stationListTag.appendChild(listNameTag); - QDomText stationListNameText = doc.createTextNode(QString::fromStdString(_exportName)); - listNameTag.appendChild(stationListNameText); - QString listType = (isBorehole) ? "boreholes" : "stations"; - QDomElement stationsTag = doc.createElement(listType); - stationListTag.appendChild(stationsTag); - - bool useStationValue(false); - double sValue = static_cast<GeoLib::Station*>((*stations)[0])->getStationValue(); - std::size_t nStations(stations->size()); - for (std::size_t i = 1; i < nStations; i++) - if ((static_cast<GeoLib::Station*>((*stations)[i])->getStationValue() - sValue) < - std::numeric_limits<double>::epsilon()) - { - useStationValue = true; - break; - } - - for (std::size_t i = 0; i < nStations; i++) - { - QString stationType = (isBorehole) ? "borehole" : "station"; - QDomElement stationTag = doc.createElement(stationType); - stationTag.setAttribute( "id", QString::number(i) ); - stationTag.setAttribute( "x", QString::number((*(*stations)[i])[0], 'f') ); - stationTag.setAttribute( "y", QString::number((*(*stations)[i])[1], 'f') ); - stationTag.setAttribute( "z", QString::number((*(*stations)[i])[2], 'f') ); - stationsTag.appendChild(stationTag); - - QDomElement stationNameTag = doc.createElement("name"); - stationTag.appendChild(stationNameTag); - QDomText stationNameText = - doc.createTextNode(QString::fromStdString(static_cast<GeoLib::Station*>((*stations)[i])->getName())); - stationNameTag.appendChild(stationNameText); - - if (useStationValue) - { - QDomElement stationValueTag = doc.createElement("value"); - stationTag.appendChild(stationValueTag); - QDomText stationValueText = - doc.createTextNode(QString::number(static_cast<GeoLib::Station*>((*stations)[i])->getStationValue())); - stationValueTag.appendChild(stationValueText); - } - - if (isBorehole) - writeBoreholeData(doc, stationTag, - static_cast<GeoLib::StationBorehole*>((*stations)[i])); - } - - std::string xml = doc.toString().toStdString(); - _out << xml; - return true; + if (this->_exportName.empty()) + { + ERR("XmlStnInterface::write(): No station list specified."); + return 0; + } + + _out << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; // xml definition + _out << "<?xml-stylesheet type=\"text/xsl\" href=\"OpenGeoSysSTN.xsl\"?>\n\n"; // stylefile definition + + QDomDocument doc("OGS-STN-DOM"); + QDomElement root = doc.createElement("OpenGeoSysSTN"); + root.setAttribute( "xmlns:ogs", "http://www.opengeosys.org" ); + root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); + root.setAttribute( "xsi:noNamespaceSchemaLocation", "http://www.opengeosys.org/images/xsd/OpenGeoSysSTN.xsd" ); + + const std::vector<GeoLib::Point*>* stations (_geo_objs.getStationVec(_exportName)); + bool isBorehole = + (static_cast<GeoLib::Station*>((*stations)[0])->type() == + GeoLib::Station::StationType::BOREHOLE) ? true : false; + + doc.appendChild(root); + QDomElement stationListTag = doc.createElement("stationlist"); + root.appendChild(stationListTag); + + QDomElement listNameTag = doc.createElement("name"); + stationListTag.appendChild(listNameTag); + QDomText stationListNameText = doc.createTextNode(QString::fromStdString(_exportName)); + listNameTag.appendChild(stationListNameText); + QString listType = (isBorehole) ? "boreholes" : "stations"; + QDomElement stationsTag = doc.createElement(listType); + stationListTag.appendChild(stationsTag); + + bool useStationValue(false); + double sValue = static_cast<GeoLib::Station*>((*stations)[0])->getStationValue(); + std::size_t nStations(stations->size()); + for (std::size_t i = 1; i < nStations; i++) + if ((static_cast<GeoLib::Station*>((*stations)[i])->getStationValue() - sValue) < + std::numeric_limits<double>::epsilon()) + { + useStationValue = true; + break; + } + + for (std::size_t i = 0; i < nStations; i++) + { + QString stationType = (isBorehole) ? "borehole" : "station"; + QDomElement stationTag = doc.createElement(stationType); + stationTag.setAttribute( "id", QString::number(i) ); + stationTag.setAttribute( "x", QString::number((*(*stations)[i])[0], 'f') ); + stationTag.setAttribute( "y", QString::number((*(*stations)[i])[1], 'f') ); + stationTag.setAttribute( "z", QString::number((*(*stations)[i])[2], 'f') ); + stationsTag.appendChild(stationTag); + + QDomElement stationNameTag = doc.createElement("name"); + stationTag.appendChild(stationNameTag); + QDomText stationNameText = + doc.createTextNode(QString::fromStdString(static_cast<GeoLib::Station*>((*stations)[i])->getName())); + stationNameTag.appendChild(stationNameText); + + if (useStationValue) + { + QDomElement stationValueTag = doc.createElement("value"); + stationTag.appendChild(stationValueTag); + QDomText stationValueText = + doc.createTextNode(QString::number(static_cast<GeoLib::Station*>((*stations)[i])->getStationValue())); + stationValueTag.appendChild(stationValueText); + } + + if (isBorehole) + writeBoreholeData(doc, stationTag, + static_cast<GeoLib::StationBorehole*>((*stations)[i])); + } + + std::string xml = doc.toString().toStdString(); + _out << xml; + return true; } void XmlStnInterface::writeBoreholeData(QDomDocument &doc, QDomElement &boreholeTag, GeoLib::StationBorehole* borehole) const { - QDomElement stationDepthTag = doc.createElement("bdepth"); - boreholeTag.appendChild(stationDepthTag); - QDomText stationDepthText = doc.createTextNode(QString::number(borehole->getDepth(), 'f')); - stationDepthTag.appendChild(stationDepthText); - if (fabs(borehole->getDate()) > 0) - { - QDomElement stationDateTag = doc.createElement("bdate"); - boreholeTag.appendChild(stationDateTag); - QDomText stationDateText = - doc.createTextNode(QString::fromStdString(BaseLib::date2string(borehole-> - getDate()))); - stationDateTag.appendChild(stationDateText); - } - - std::vector<GeoLib::Point*> profile = borehole->getProfile(); - std::vector<std::string> soilNames = borehole->getSoilNames(); - std::size_t nHorizons(profile.size()); - - if (nHorizons > 1) - { - QDomElement stratTag = doc.createElement("strat"); - boreholeTag.appendChild(stratTag); - - for (std::size_t j = 1; j < nHorizons; j++) /// the first entry in the profile vector is just the position of the borehole - { - QDomElement horizonTag = doc.createElement("horizon"); - horizonTag.setAttribute( "id", QString::number(j) ); - horizonTag.setAttribute( "x", QString::number((*profile[j])[0], 'f') ); - horizonTag.setAttribute( "y", QString::number((*profile[j])[1], 'f') ); - horizonTag.setAttribute( "z", QString::number((*profile[j])[2], 'f') ); - stratTag.appendChild(horizonTag); - QDomElement horizonNameTag = doc.createElement("name"); - horizonTag.appendChild(horizonNameTag); - QDomText horizonNameText = - doc.createTextNode(QString::fromStdString(soilNames[j])); - horizonNameTag.appendChild(horizonNameText); - } - } + QDomElement stationDepthTag = doc.createElement("bdepth"); + boreholeTag.appendChild(stationDepthTag); + QDomText stationDepthText = doc.createTextNode(QString::number(borehole->getDepth(), 'f')); + stationDepthTag.appendChild(stationDepthText); + if (fabs(borehole->getDate()) > 0) + { + QDomElement stationDateTag = doc.createElement("bdate"); + boreholeTag.appendChild(stationDateTag); + QDomText stationDateText = + doc.createTextNode(QString::fromStdString(BaseLib::date2string(borehole-> + getDate()))); + stationDateTag.appendChild(stationDateText); + } + + std::vector<GeoLib::Point*> profile = borehole->getProfile(); + std::vector<std::string> soilNames = borehole->getSoilNames(); + std::size_t nHorizons(profile.size()); + + if (nHorizons > 1) + { + QDomElement stratTag = doc.createElement("strat"); + boreholeTag.appendChild(stratTag); + + for (std::size_t j = 1; j < nHorizons; j++) /// the first entry in the profile vector is just the position of the borehole + { + QDomElement horizonTag = doc.createElement("horizon"); + horizonTag.setAttribute( "id", QString::number(j) ); + horizonTag.setAttribute( "x", QString::number((*profile[j])[0], 'f') ); + horizonTag.setAttribute( "y", QString::number((*profile[j])[1], 'f') ); + horizonTag.setAttribute( "z", QString::number((*profile[j])[2], 'f') ); + stratTag.appendChild(horizonTag); + QDomElement horizonNameTag = doc.createElement("name"); + horizonTag.appendChild(horizonNameTag); + QDomText horizonNameText = + doc.createTextNode(QString::fromStdString(soilNames[j])); + horizonNameTag.appendChild(horizonNameText); + } + } } int XmlStnInterface::rapidReadFile(const std::string &fileName) { - std::ifstream in(fileName.c_str()); - if (in.fail()) - { - ERR("XmlStnInterface::rapidReadFile(): Can't open xml-file %s.", fileName.c_str()); - return 0; - } - - // buffer file - in.seekg(0, std::ios::end); - std::size_t length = in.tellg(); - in.seekg(0, std::ios::beg); - char* buffer = new char[length + 1]; - in.read(buffer, length); - buffer[in.gcount()] = '\0'; - in.close(); - - // build DOM tree - rapidxml::xml_document<> doc; - doc.parse<0>(buffer); - - // parse content - if (std::string(doc.first_node()->name()).compare("OpenGeoSysSTN") != 0) - { - ERR("XmlStnInterface::readFile() - Unexpected XML root."); - return 0; - } - - // iterate over all station lists - for (rapidxml::xml_node<>* station_list = doc.first_node()->first_node(); station_list; - station_list = station_list->next_sibling()) - { - auto stations = std::unique_ptr<std::vector<GeoLib::Point*>>( - new std::vector<GeoLib::Point*>); - std::string stnName("[NN]"); - - stnName = station_list->first_node("name")->value(); - for (rapidxml::xml_node<>* list_item = station_list->first_node(); list_item; - list_item = list_item->next_sibling()) - { - std::string b(list_item->name()); - if (b.compare("stations") == 0) - this->rapidReadStations(list_item, stations.get(), fileName); - if (b.compare("boreholes") == 0) - this->rapidReadStations(list_item, stations.get(), fileName); - } - - if (!stations->empty()) - _geo_objs.addStationVec(std::move(stations), stnName); - } - - doc.clear(); - delete [] buffer; - - return 1; + std::ifstream in(fileName.c_str()); + if (in.fail()) + { + ERR("XmlStnInterface::rapidReadFile(): Can't open xml-file %s.", fileName.c_str()); + return 0; + } + + // buffer file + in.seekg(0, std::ios::end); + std::size_t length = in.tellg(); + in.seekg(0, std::ios::beg); + char* buffer = new char[length + 1]; + in.read(buffer, length); + buffer[in.gcount()] = '\0'; + in.close(); + + // build DOM tree + rapidxml::xml_document<> doc; + doc.parse<0>(buffer); + + // parse content + if (std::string(doc.first_node()->name()).compare("OpenGeoSysSTN") != 0) + { + ERR("XmlStnInterface::readFile() - Unexpected XML root."); + return 0; + } + + // iterate over all station lists + for (rapidxml::xml_node<>* station_list = doc.first_node()->first_node(); station_list; + station_list = station_list->next_sibling()) + { + auto stations = std::unique_ptr<std::vector<GeoLib::Point*>>( + new std::vector<GeoLib::Point*>); + std::string stnName("[NN]"); + + stnName = station_list->first_node("name")->value(); + for (rapidxml::xml_node<>* list_item = station_list->first_node(); list_item; + list_item = list_item->next_sibling()) + { + std::string b(list_item->name()); + if (b.compare("stations") == 0) + this->rapidReadStations(list_item, stations.get(), fileName); + if (b.compare("boreholes") == 0) + this->rapidReadStations(list_item, stations.get(), fileName); + } + + if (!stations->empty()) + _geo_objs.addStationVec(std::move(stations), stnName); + } + + doc.clear(); + delete [] buffer; + + return 1; } void XmlStnInterface::rapidReadStations(const rapidxml::xml_node<>* station_root, std::vector<GeoLib::Point*>* stations, const std::string &file_name) { - for (rapidxml::xml_node<>* station_node = station_root->first_node(); station_node; - station_node = station_node->next_sibling()) - { - if (station_node->first_attribute("id") && station_node->first_attribute("x") && - station_node->first_attribute("y")) - { - double zVal(0.0); - if (station_node->first_attribute("z")) - zVal = strtod(station_node->first_attribute("z")->value(), 0); - - std::string station_name(""), sensor_data_file_name(""), bdate_str("0000-00-00"); - double station_value(0.0), borehole_depth(0.0); - if (station_node->first_node("name")) - station_name = station_node->first_node("name")->value(); - if (station_node->first_node("sensordata")) - sensor_data_file_name = - station_node->first_node("sensordata")->value(); - if (station_node->first_node("value")) - station_value = strtod(station_node->first_node("value")->value(), 0); - /* add other station features here */ - - if (std::string(station_node->name()).compare("station") == 0) - { - GeoLib::Station* s = new GeoLib::Station( - strtod(station_node->first_attribute("x")->value(), 0), - strtod(station_node->first_attribute("y")->value(), 0), - zVal, - station_name); - s->setStationValue(station_value); - if (!sensor_data_file_name.empty()) - s->addSensorDataFromCSV(BaseLib::copyPathToFileName( - sensor_data_file_name, - file_name)); - stations->push_back(s); - } - else if (std::string(station_node->name()).compare("borehole") == 0) - { - if (station_node->first_node("bdepth")) - borehole_depth = strtod(station_node->first_node("bdepth")->value(), 0); - if (station_node->first_node("bdate")) - bdate_str = station_node->first_node("bdate")->value(); - /* add other borehole features here */ - - GeoLib::StationBorehole* s = GeoLib::StationBorehole::createStation( - station_name, - strtod(station_node->first_attribute("x")->value(), 0), - strtod(station_node->first_attribute("y")->value(), 0), - zVal, - borehole_depth, - bdate_str); - s->setStationValue(station_value); - - if (station_node->first_node("strat")) - this->rapidReadStratigraphy(station_node->first_node("strat"), s); - - stations->push_back(s); - } - } - else - WARN("XmlStnInterface::rapidReadStations(): Attribute missing in <station> tag."); - } + for (rapidxml::xml_node<>* station_node = station_root->first_node(); station_node; + station_node = station_node->next_sibling()) + { + if (station_node->first_attribute("id") && station_node->first_attribute("x") && + station_node->first_attribute("y")) + { + double zVal(0.0); + if (station_node->first_attribute("z")) + zVal = strtod(station_node->first_attribute("z")->value(), 0); + + std::string station_name(""), sensor_data_file_name(""), bdate_str("0000-00-00"); + double station_value(0.0), borehole_depth(0.0); + if (station_node->first_node("name")) + station_name = station_node->first_node("name")->value(); + if (station_node->first_node("sensordata")) + sensor_data_file_name = + station_node->first_node("sensordata")->value(); + if (station_node->first_node("value")) + station_value = strtod(station_node->first_node("value")->value(), 0); + /* add other station features here */ + + if (std::string(station_node->name()).compare("station") == 0) + { + GeoLib::Station* s = new GeoLib::Station( + strtod(station_node->first_attribute("x")->value(), 0), + strtod(station_node->first_attribute("y")->value(), 0), + zVal, + station_name); + s->setStationValue(station_value); + if (!sensor_data_file_name.empty()) + s->addSensorDataFromCSV(BaseLib::copyPathToFileName( + sensor_data_file_name, + file_name)); + stations->push_back(s); + } + else if (std::string(station_node->name()).compare("borehole") == 0) + { + if (station_node->first_node("bdepth")) + borehole_depth = strtod(station_node->first_node("bdepth")->value(), 0); + if (station_node->first_node("bdate")) + bdate_str = station_node->first_node("bdate")->value(); + /* add other borehole features here */ + + GeoLib::StationBorehole* s = GeoLib::StationBorehole::createStation( + station_name, + strtod(station_node->first_attribute("x")->value(), 0), + strtod(station_node->first_attribute("y")->value(), 0), + zVal, + borehole_depth, + bdate_str); + s->setStationValue(station_value); + + if (station_node->first_node("strat")) + this->rapidReadStratigraphy(station_node->first_node("strat"), s); + + stations->push_back(s); + } + } + else + WARN("XmlStnInterface::rapidReadStations(): Attribute missing in <station> tag."); + } } void XmlStnInterface::rapidReadStratigraphy( const rapidxml::xml_node<>* strat_root, GeoLib::StationBorehole* borehole ) { - double depth_check((*borehole)[2]); - - for (rapidxml::xml_node<>* horizon_node = strat_root->first_node("horizon"); horizon_node; - horizon_node = horizon_node->next_sibling()) - { - if (horizon_node->first_attribute("id") && horizon_node->first_attribute("x") && - horizon_node->first_attribute("y") && horizon_node->first_attribute("z")) - { - std::string horizon_name("[NN]"); - if (horizon_node->first_node("name")) - horizon_name = horizon_node->first_node("name")->value(); - /* add other horizon features here */ - - double depth (strtod(horizon_node->first_attribute("z")->value(), 0)); - if (fabs(depth - depth_check) > std::numeric_limits<double>::epsilon()) // skip soil-layer if its thickness is zero - { - borehole->addSoilLayer(strtod(horizon_node->first_attribute("x")->value(), 0), - strtod(horizon_node->first_attribute("y")->value(), 0), - depth, - horizon_name); - depth_check = depth; - } - else - WARN( - "XmlStnInterface::rapidReadStratigraphy(): Skipped layer \"%s\" in borehole \"%s\" because of thickness 0.0.", - horizon_name.c_str(), - borehole->getName().c_str()); - } - else - WARN("XmlStnInterface::rapidReadStratigraphy(): Attribute missing in <horizon> tag."); - } + double depth_check((*borehole)[2]); + + for (rapidxml::xml_node<>* horizon_node = strat_root->first_node("horizon"); horizon_node; + horizon_node = horizon_node->next_sibling()) + { + if (horizon_node->first_attribute("id") && horizon_node->first_attribute("x") && + horizon_node->first_attribute("y") && horizon_node->first_attribute("z")) + { + std::string horizon_name("[NN]"); + if (horizon_node->first_node("name")) + horizon_name = horizon_node->first_node("name")->value(); + /* add other horizon features here */ + + double depth (strtod(horizon_node->first_attribute("z")->value(), 0)); + if (fabs(depth - depth_check) > std::numeric_limits<double>::epsilon()) // skip soil-layer if its thickness is zero + { + borehole->addSoilLayer(strtod(horizon_node->first_attribute("x")->value(), 0), + strtod(horizon_node->first_attribute("y")->value(), 0), + depth, + horizon_name); + depth_check = depth; + } + else + WARN( + "XmlStnInterface::rapidReadStratigraphy(): Skipped layer \"%s\" in borehole \"%s\" because of thickness 0.0.", + horizon_name.c_str(), + borehole->getName().c_str()); + } + else + WARN("XmlStnInterface::rapidReadStratigraphy(): Attribute missing in <horizon> tag."); + } } } // end namespace IO diff --git a/GeoLib/IO/XmlIO/Qt/XmlStnInterface.h b/GeoLib/IO/XmlIO/Qt/XmlStnInterface.h index 7bce4df6a95a5c71ed850711eb1bb39b9811872e..229866b9141b4b2de3eb2221bd9f4c12525d7a81 100644 --- a/GeoLib/IO/XmlIO/Qt/XmlStnInterface.h +++ b/GeoLib/IO/XmlIO/Qt/XmlStnInterface.h @@ -37,38 +37,38 @@ class XmlStnInterface : public BaseLib::IO::XMLInterface, public BaseLib::IO::XMLQtInterface { public: - XmlStnInterface(GeoLib::GEOObjects& geo_objs); + XmlStnInterface(GeoLib::GEOObjects& geo_objs); - /// Reads an xml-file containing station object definitions into the GEOObjects used in the contructor (requires Qt) - int readFile(const QString &fileName); + /// Reads an xml-file containing station object definitions into the GEOObjects used in the contructor (requires Qt) + int readFile(const QString &fileName); - bool readFile(std::string const& fname) { return readFile(QString(fname.c_str())) != 0; } + bool readFile(std::string const& fname) { return readFile(QString(fname.c_str())) != 0; } - /// Reads an xml-file using the RapidXML parser integrated in the source code (i.e. this function is usable without Qt) - int rapidReadFile(const std::string &fileName); + /// Reads an xml-file using the RapidXML parser integrated in the source code (i.e. this function is usable without Qt) + int rapidReadFile(const std::string &fileName); protected: - bool write(); + bool write(); private: - /// Reads GeoLib::Station- or StationBorehole-objects from an xml-file - void readStations ( const QDomNode &stationsRoot, std::vector<GeoLib::Point*>* stations, const std::string &station_file_name); + /// Reads GeoLib::Station- or StationBorehole-objects from an xml-file + void readStations ( const QDomNode &stationsRoot, std::vector<GeoLib::Point*>* stations, const std::string &station_file_name); - /// Writes borehole-specific data to a station-xml-file. - void writeBoreholeData(QDomDocument &doc, - QDomElement &boreholeTag, - GeoLib::StationBorehole* borehole) const; + /// Writes borehole-specific data to a station-xml-file. + void writeBoreholeData(QDomDocument &doc, + QDomElement &boreholeTag, + GeoLib::StationBorehole* borehole) const; - /// Reads the stratigraphy of a borehole from an xml-file - void readStratigraphy( const QDomNode &stratRoot, GeoLib::StationBorehole* borehole ); + /// Reads the stratigraphy of a borehole from an xml-file + void readStratigraphy( const QDomNode &stratRoot, GeoLib::StationBorehole* borehole ); - /// Reads GeoLib::Station- or StationBorehole-objects from an xml-file using the RapidXML parser - void rapidReadStations(const rapidxml::xml_node<>* station_root, std::vector<GeoLib::Point*> *stations, const std::string &file_name); + /// Reads GeoLib::Station- or StationBorehole-objects from an xml-file using the RapidXML parser + void rapidReadStations(const rapidxml::xml_node<>* station_root, std::vector<GeoLib::Point*> *stations, const std::string &file_name); - /// Reads the stratigraphy of a borehole from an xml-file using the RapidXML parser - void rapidReadStratigraphy(const rapidxml::xml_node<>* strat_root, GeoLib::StationBorehole* borehole); + /// Reads the stratigraphy of a borehole from an xml-file using the RapidXML parser + void rapidReadStratigraphy(const rapidxml::xml_node<>* strat_root, GeoLib::StationBorehole* borehole); - GeoLib::GEOObjects& _geo_objs; + GeoLib::GEOObjects& _geo_objs; }; } // end namespace IO diff --git a/GeoLib/IO/readGeometryFromFile.cpp b/GeoLib/IO/readGeometryFromFile.cpp index 5cfb82b0c9dbd44d63111022786ca6d10eedde5e..8b4b237eda1eb0b1a3bd26d3ebc417fa4bbcf152 100644 --- a/GeoLib/IO/readGeometryFromFile.cpp +++ b/GeoLib/IO/readGeometryFromFile.cpp @@ -26,14 +26,14 @@ namespace IO void readGeometryFromFile(std::string const& fname, GeoLib::GEOObjects & geo_objs) { - if (BaseLib::getFileExtension(fname).compare("gml") == 0) { - GeoLib::IO::BoostXmlGmlInterface xml(geo_objs); - xml.readFile(fname); - } else { - std::vector<std::string> errors; - std::string geo_name(BaseLib::extractBaseNameWithoutExtension(fname)); - GeoLib::IO::Legacy::readGLIFileV4(fname, geo_objs, geo_name, errors); - } + if (BaseLib::getFileExtension(fname).compare("gml") == 0) { + GeoLib::IO::BoostXmlGmlInterface xml(geo_objs); + xml.readFile(fname); + } else { + std::vector<std::string> errors; + std::string geo_name(BaseLib::extractBaseNameWithoutExtension(fname)); + GeoLib::IO::Legacy::readGLIFileV4(fname, geo_objs, geo_name, errors); + } } } } diff --git a/GeoLib/IO/readGeometryFromFile.h b/GeoLib/IO/readGeometryFromFile.h index fe0156a04676a96f03534d48b3d499a547f9ae6b..2d9fa24d36adea9ce2bd0a189ec5ef9517ce4dce 100644 --- a/GeoLib/IO/readGeometryFromFile.h +++ b/GeoLib/IO/readGeometryFromFile.h @@ -15,15 +15,15 @@ namespace GeoLib { - class GEOObjects; + class GEOObjects; } namespace GeoLib { namespace IO { - void - readGeometryFromFile(std::string const& fname, GeoLib::GEOObjects & geo_objs); + void + readGeometryFromFile(std::string const& fname, GeoLib::GEOObjects & geo_objs); } } diff --git a/GeoLib/IO/writeGeometryToFile.cpp b/GeoLib/IO/writeGeometryToFile.cpp index 518bcea09033dd1865adedf106e31116db441914..8a89fe8360ecc271fc368e5525e7066eaab93469 100644 --- a/GeoLib/IO/writeGeometryToFile.cpp +++ b/GeoLib/IO/writeGeometryToFile.cpp @@ -22,19 +22,19 @@ namespace GeoLib namespace IO { void writeGeometryToFile(std::string const& geo_name, - GeoLib::GEOObjects& geo_objs, std::string const& fname) + GeoLib::GEOObjects& geo_objs, std::string const& fname) { - std::string const extension(BaseLib::getFileExtension(fname)); - if (extension == "gml" || extension == "GML") { - GeoLib::IO::BoostXmlGmlInterface xml(geo_objs); - xml.setNameForExport(geo_name); - xml.writeToFile(fname); - } else if (extension == "gli" || extension == "GLI") { - GeoLib::IO::Legacy::writeGLIFileV4(fname, geo_name, geo_objs); - } else { - ERR("Writing of geometry failed, since it was not possible to determine" - " the required format from file extension."); - } + std::string const extension(BaseLib::getFileExtension(fname)); + if (extension == "gml" || extension == "GML") { + GeoLib::IO::BoostXmlGmlInterface xml(geo_objs); + xml.setNameForExport(geo_name); + xml.writeToFile(fname); + } else if (extension == "gli" || extension == "GLI") { + GeoLib::IO::Legacy::writeGLIFileV4(fname, geo_name, geo_objs); + } else { + ERR("Writing of geometry failed, since it was not possible to determine" + " the required format from file extension."); + } } } } diff --git a/GeoLib/IO/writeGeometryToFile.h b/GeoLib/IO/writeGeometryToFile.h index 19459e57174509f7b017984d15cf91f50707f603..57e8167927bcabd947a60206a2c26cae272ddd81 100644 --- a/GeoLib/IO/writeGeometryToFile.h +++ b/GeoLib/IO/writeGeometryToFile.h @@ -25,7 +25,7 @@ namespace IO /// given in the \c fname parameter is "gml" or "GML" a gml file is written. In /// case the extension is "gli" or "GLI" a gli file is written. void writeGeometryToFile(std::string const& geo_name, - GeoLib::GEOObjects& geo_objs, std::string const& fname); + GeoLib::GEOObjects& geo_objs, std::string const& fname); } } diff --git a/GeoLib/LineSegment.cpp b/GeoLib/LineSegment.cpp index 15cf94231cf86525ff28c99a873e5bc72c3ecf88..5e77328d3014d76ff744e5c69825a06388441df8 100644 --- a/GeoLib/LineSegment.cpp +++ b/GeoLib/LineSegment.cpp @@ -33,50 +33,50 @@ LineSegment::LineSegment(LineSegment&& line_segment) _point_mem_management_by_line_segment( line_segment._point_mem_management_by_line_segment) { - line_segment._a = nullptr; - line_segment._b = nullptr; - line_segment._point_mem_management_by_line_segment = false; + line_segment._a = nullptr; + line_segment._b = nullptr; + line_segment._point_mem_management_by_line_segment = false; } LineSegment::~LineSegment() { - if (_point_mem_management_by_line_segment) { - delete _b; - delete _a; - } + if (_point_mem_management_by_line_segment) { + delete _b; + delete _a; + } } Point const& LineSegment::getBeginPoint() const { - return *_a; + return *_a; } Point & LineSegment::getBeginPoint() { - return *_a; + return *_a; } Point const& LineSegment::getEndPoint() const { - return *_b; + return *_b; } Point & LineSegment::getEndPoint() { - return *_b; + return *_b; } std::ostream& operator<< (std::ostream& os, LineSegment const& s) { - os << "{(" << s.getBeginPoint() << "), (" << s.getEndPoint() << ")}"; - return os; + os << "{(" << s.getBeginPoint() << "), (" << s.getEndPoint() << ")}"; + return os; } std::ostream& operator<<(std::ostream& os, std::pair<GeoLib::LineSegment const&, GeoLib::LineSegment const&> const& seg_pair) { - os << seg_pair.first << " x " << seg_pair.second; - return os; + os << seg_pair.first << " x " << seg_pair.second; + return os; } } diff --git a/GeoLib/LineSegment.h b/GeoLib/LineSegment.h index c69a21b8865b7d933357770afbe5d310824d1a11..8b88e31f7948b0bb454639f883f077a6ec665006 100644 --- a/GeoLib/LineSegment.h +++ b/GeoLib/LineSegment.h @@ -17,31 +17,31 @@ namespace GeoLib class LineSegment final { public: - /// Constructs a line segment given by its begin and end points. - /// @remark The main purpose of class LineSegment is the use within a - /// polyline. For this reason the memory is not managed per default. But the - /// user has the freedom to hand over the responsibility for the mem - /// managment of the points to the object. - LineSegment(GeoLib::Point* const beg, GeoLib::Point* const end, - bool point_mem_management_by_line_segment = false); + /// Constructs a line segment given by its begin and end points. + /// @remark The main purpose of class LineSegment is the use within a + /// polyline. For this reason the memory is not managed per default. But the + /// user has the freedom to hand over the responsibility for the mem + /// managment of the points to the object. + LineSegment(GeoLib::Point* const beg, GeoLib::Point* const end, + bool point_mem_management_by_line_segment = false); - LineSegment(LineSegment&& line_segment); - LineSegment(LineSegment const& line_segment); + LineSegment(LineSegment&& line_segment); + LineSegment(LineSegment const& line_segment); - ~LineSegment(); + ~LineSegment(); - LineSegment& operator= (LineSegment const& rhs) = delete; + LineSegment& operator= (LineSegment const& rhs) = delete; - GeoLib::Point const& getBeginPoint() const; - GeoLib::Point & getBeginPoint(); + GeoLib::Point const& getBeginPoint() const; + GeoLib::Point & getBeginPoint(); - GeoLib::Point const& getEndPoint() const; - GeoLib::Point & getEndPoint(); + GeoLib::Point const& getEndPoint() const; + GeoLib::Point & getEndPoint(); private: - GeoLib::Point* _a = nullptr; - GeoLib::Point* _b = nullptr; - bool _point_mem_management_by_line_segment = false; + GeoLib::Point* _a = nullptr; + GeoLib::Point* _b = nullptr; + bool _point_mem_management_by_line_segment = false; }; std::ostream& operator<< (std::ostream& os, LineSegment const& s); diff --git a/GeoLib/MinimalBoundingSphere.cpp b/GeoLib/MinimalBoundingSphere.cpp index 03725f270e7528bb645221f40f9f4e550a8f9b5a..f8ef9db51ca092ef0a9217e55e2f9d76487e8658 100644 --- a/GeoLib/MinimalBoundingSphere.cpp +++ b/GeoLib/MinimalBoundingSphere.cpp @@ -29,13 +29,13 @@ MinimalBoundingSphere::MinimalBoundingSphere() } MinimalBoundingSphere::MinimalBoundingSphere( - MathLib::Point3d const& p, double radius) + MathLib::Point3d const& p, double radius) : _radius(radius), _center(p) { } MinimalBoundingSphere::MinimalBoundingSphere( - MathLib::Point3d const& p, MathLib::Point3d const& q) + MathLib::Point3d const& p, MathLib::Point3d const& q) : _radius(std::numeric_limits<double>::epsilon()), _center(p) { MathLib::Vector3 const a(p, q); @@ -49,7 +49,7 @@ MinimalBoundingSphere::MinimalBoundingSphere( } MinimalBoundingSphere::MinimalBoundingSphere(MathLib::Point3d const& p, - MathLib::Point3d const& q, MathLib::Point3d const& r) + MathLib::Point3d const& q, MathLib::Point3d const& r) { MathLib::Vector3 const a(p,r); MathLib::Vector3 const b(p,q); @@ -78,9 +78,9 @@ MinimalBoundingSphere::MinimalBoundingSphere(MathLib::Point3d const& p, } MinimalBoundingSphere::MinimalBoundingSphere(MathLib::Point3d const& p, - MathLib::Point3d const& q, - MathLib::Point3d const& r, - MathLib::Point3d const& s) + MathLib::Point3d const& q, + MathLib::Point3d const& r, + MathLib::Point3d const& s) { MathLib::Vector3 const a(p, q); MathLib::Vector3 const b(p, r); @@ -124,21 +124,21 @@ MinimalBoundingSphere::MinimalBoundingSphere(MathLib::Point3d const& p, } MinimalBoundingSphere::MinimalBoundingSphere( - std::vector<MathLib::Point3d*> const& points) + std::vector<MathLib::Point3d*> const& points) : _radius(-1), _center(0,0,0) { - std::vector<MathLib::Point3d*> sphere_points(points); - MinimalBoundingSphere const bounding_sphere = recurseCalculation(sphere_points, 0, sphere_points.size(), 0); - _center = bounding_sphere.getCenter(); - _radius = bounding_sphere.getRadius(); + std::vector<MathLib::Point3d*> sphere_points(points); + MinimalBoundingSphere const bounding_sphere = recurseCalculation(sphere_points, 0, sphere_points.size(), 0); + _center = bounding_sphere.getCenter(); + _radius = bounding_sphere.getRadius(); } MinimalBoundingSphere MinimalBoundingSphere::recurseCalculation( - std::vector<MathLib::Point3d*> sphere_points, - std::size_t start_idx, - std::size_t length, - std::size_t n_boundary_points) + std::vector<MathLib::Point3d*> sphere_points, + std::size_t start_idx, + std::size_t length, + std::size_t n_boundary_points) { MinimalBoundingSphere sphere; switch(n_boundary_points) diff --git a/GeoLib/OctTree-impl.h b/GeoLib/OctTree-impl.h index 44c915874f578e01f11ab4018c6953094ad160ad..c8ef1d16201a63dbfcb41ec23d51f60fca3053a6 100644 --- a/GeoLib/OctTree-impl.h +++ b/GeoLib/OctTree-impl.h @@ -16,261 +16,261 @@ namespace GeoLib { template <typename POINT, std::size_t MAX_POINTS> template <typename T> OctTree<POINT, MAX_POINTS>* OctTree<POINT, MAX_POINTS>::createOctTree(T ll, T ur, - double eps) + double eps) { - // compute an axis aligned cube around the points ll and ur - const double dx(ur[0] - ll[0]); - const double dy(ur[1] - ll[1]); - const double dz(ur[2] - ll[2]); - if (dx >= dy && dx >= dz) { - ll[1] -= (dx-dy)/2.0; - ur[1] += (dx-dy)/2.0; - ll[2] -= (dx-dz)/2.0; - ur[2] += (dx-dz)/2.0; - } else { - if (dy >= dx && dy >= dz) { - ll[0] -= (dy-dx)/2.0; - ur[0] += (dy-dx)/2.0; - ll[2] -= (dy-dz)/2.0; - ur[2] += (dy-dz)/2.0; - } else { - ll[0] -= (dz-dx)/2.0; - ur[0] += (dz-dx)/2.0; - ll[1] -= (dz-dy)/2.0; - ur[1] += (dz-dy)/2.0; - } - } - if (eps == 0.0) - eps = std::numeric_limits<double>::epsilon(); - for (std::size_t k(0); k<3; ++k) { - if (ur[k] - ll[k] > 0.0) { - ur[k] += (ur[k] - ll[k]) * 1e-6; - } else { - ur[k] += eps; - } - } - return new OctTree<POINT, MAX_POINTS>(ll, ur, eps); + // compute an axis aligned cube around the points ll and ur + const double dx(ur[0] - ll[0]); + const double dy(ur[1] - ll[1]); + const double dz(ur[2] - ll[2]); + if (dx >= dy && dx >= dz) { + ll[1] -= (dx-dy)/2.0; + ur[1] += (dx-dy)/2.0; + ll[2] -= (dx-dz)/2.0; + ur[2] += (dx-dz)/2.0; + } else { + if (dy >= dx && dy >= dz) { + ll[0] -= (dy-dx)/2.0; + ur[0] += (dy-dx)/2.0; + ll[2] -= (dy-dz)/2.0; + ur[2] += (dy-dz)/2.0; + } else { + ll[0] -= (dz-dx)/2.0; + ur[0] += (dz-dx)/2.0; + ll[1] -= (dz-dy)/2.0; + ur[1] += (dz-dy)/2.0; + } + } + if (eps == 0.0) + eps = std::numeric_limits<double>::epsilon(); + for (std::size_t k(0); k<3; ++k) { + if (ur[k] - ll[k] > 0.0) { + ur[k] += (ur[k] - ll[k]) * 1e-6; + } else { + ur[k] += eps; + } + } + return new OctTree<POINT, MAX_POINTS>(ll, ur, eps); } template <typename POINT, std::size_t MAX_POINTS> OctTree<POINT, MAX_POINTS>::~OctTree() { - for (auto c : _children) - delete c; + for (auto c : _children) + delete c; } template <typename POINT, std::size_t MAX_POINTS> bool OctTree<POINT, MAX_POINTS>::addPoint(POINT * pnt, POINT *& ret_pnt) { - // first do a range query using a epsilon box around the point pnt - std::vector<POINT*> query_pnts; - MathLib::Point3d min( - std::array<double,3>{{(*pnt)[0]-_eps, (*pnt)[1]-_eps, (*pnt)[2]-_eps}}); - MathLib::Point3d max( - std::array<double,3>{{(*pnt)[0]+_eps, (*pnt)[1]+_eps, (*pnt)[2]+_eps}}); - getPointsInRange(min, max, query_pnts); - if (! query_pnts.empty()) { - // check Euclidean norm - for (auto p : query_pnts) { - if (MathLib::sqrDist(*p, *pnt) <= _eps*_eps) { - ret_pnt = p; - return false; - } - } - } + // first do a range query using a epsilon box around the point pnt + std::vector<POINT*> query_pnts; + MathLib::Point3d min( + std::array<double,3>{{(*pnt)[0]-_eps, (*pnt)[1]-_eps, (*pnt)[2]-_eps}}); + MathLib::Point3d max( + std::array<double,3>{{(*pnt)[0]+_eps, (*pnt)[1]+_eps, (*pnt)[2]+_eps}}); + getPointsInRange(min, max, query_pnts); + if (! query_pnts.empty()) { + // check Euclidean norm + for (auto p : query_pnts) { + if (MathLib::sqrDist(*p, *pnt) <= _eps*_eps) { + ret_pnt = p; + return false; + } + } + } - // the point pnt is not yet in the OctTree - if (isOutside(pnt)) { - ret_pnt = nullptr; - return false; - } + // the point pnt is not yet in the OctTree + if (isOutside(pnt)) { + ret_pnt = nullptr; + return false; + } - // at this place it holds true that the point is within [_ll, _ur] - if (!_is_leaf) { - for (auto c : _children) { - if (c->addPoint_(pnt, ret_pnt)) { - return true; - } else { - if (ret_pnt != nullptr) - return false; - } - } - } + // at this place it holds true that the point is within [_ll, _ur] + if (!_is_leaf) { + for (auto c : _children) { + if (c->addPoint_(pnt, ret_pnt)) { + return true; + } else { + if (ret_pnt != nullptr) + return false; + } + } + } - ret_pnt = pnt; + ret_pnt = pnt; - if (_pnts.size () < MAX_POINTS) { - _pnts.push_back(pnt); - } else { // i.e. _pnts.size () == MAX_POINTS - splitNode(pnt); - _pnts.clear(); - } - return true; + if (_pnts.size () < MAX_POINTS) { + _pnts.push_back(pnt); + } else { // i.e. _pnts.size () == MAX_POINTS + splitNode(pnt); + _pnts.clear(); + } + return true; } template <typename POINT, std::size_t MAX_POINTS> template <typename T> void OctTree<POINT, MAX_POINTS>::getPointsInRange(T const& min, T const& max, - std::vector<POINT*> &pnts) const + std::vector<POINT*> &pnts) const { - if (_ur[0] < min[0] || _ur[1] < min[1] || _ur[2] < min[2]) - return; + if (_ur[0] < min[0] || _ur[1] < min[1] || _ur[2] < min[2]) + return; - if (max[0] < _ll[0] || max[1] < _ll[1] || max[2] < _ll[2]) - return; + if (max[0] < _ll[0] || max[1] < _ll[1] || max[2] < _ll[2]) + return; - if (_is_leaf) { - for (auto p : _pnts) { - if (min[0] <= (*p)[0] && (*p)[0] < max[0] - && min[1] <= (*p)[1] && (*p)[1] < max[1] - && min[2] <= (*p)[2] && (*p)[2] < max[2]) - pnts.push_back(p); - } - } else { - for (std::size_t k(0); k<8; k++) { - _children[k]->getPointsInRange(min, max, pnts); - } - } + if (_is_leaf) { + for (auto p : _pnts) { + if (min[0] <= (*p)[0] && (*p)[0] < max[0] + && min[1] <= (*p)[1] && (*p)[1] < max[1] + && min[2] <= (*p)[2] && (*p)[2] < max[2]) + pnts.push_back(p); + } + } else { + for (std::size_t k(0); k<8; k++) { + _children[k]->getPointsInRange(min, max, pnts); + } + } } template <typename POINT, std::size_t MAX_POINTS> OctTree<POINT, MAX_POINTS>::OctTree( - MathLib::Point3d const& ll, MathLib::Point3d const& ur, double eps) - : _ll(ll), _ur(ur), _is_leaf(true), _eps(eps) + MathLib::Point3d const& ll, MathLib::Point3d const& ur, double eps) + : _ll(ll), _ur(ur), _is_leaf(true), _eps(eps) { - _children.fill(nullptr); + _children.fill(nullptr); } template <typename POINT, std::size_t MAX_POINTS> bool OctTree<POINT, MAX_POINTS>::addPoint_(POINT * pnt, POINT *& ret_pnt) { - if (isOutside(pnt)) { - ret_pnt = nullptr; - return false; - } + if (isOutside(pnt)) { + ret_pnt = nullptr; + return false; + } - // at this place it holds true that the point is within [_ll, _ur] - if (!_is_leaf) { - for (auto c : _children) { - if (c->addPoint_(pnt, ret_pnt)) { - return true; - } else { - if (ret_pnt != nullptr) - return false; - } - } - } + // at this place it holds true that the point is within [_ll, _ur] + if (!_is_leaf) { + for (auto c : _children) { + if (c->addPoint_(pnt, ret_pnt)) { + return true; + } else { + if (ret_pnt != nullptr) + return false; + } + } + } - ret_pnt = pnt; - if (_pnts.size() < MAX_POINTS) { - _pnts.push_back(pnt); - } else { // i.e. _pnts.size () == MAX_POINTS - splitNode(pnt); - _pnts.clear(); - } - return true; + ret_pnt = pnt; + if (_pnts.size() < MAX_POINTS) { + _pnts.push_back(pnt); + } else { // i.e. _pnts.size () == MAX_POINTS + splitNode(pnt); + _pnts.clear(); + } + return true; } template <typename POINT, std::size_t MAX_POINTS> bool OctTree<POINT, MAX_POINTS>::addPointToChild(POINT * pnt) { - if (isOutside(pnt)) - return false; + if (isOutside(pnt)) + return false; - if (_pnts.size() < MAX_POINTS) { - _pnts.push_back(pnt); - } else { // i.e. _pnts.size () == MAX_POINTS - splitNode(pnt); - _pnts.clear(); - } - return true; + if (_pnts.size() < MAX_POINTS) { + _pnts.push_back(pnt); + } else { // i.e. _pnts.size () == MAX_POINTS + splitNode(pnt); + _pnts.clear(); + } + return true; } template <typename POINT, std::size_t MAX_POINTS> void OctTree<POINT, MAX_POINTS>::splitNode(POINT * pnt) { - const double x_mid((_ur[0] + _ll[0]) / 2.0); - const double y_mid((_ur[1] + _ll[1]) / 2.0); - const double z_mid((_ur[2] + _ll[2]) / 2.0); - MathLib::Point3d p0(std::array<double,3>{{x_mid, y_mid, _ll[2]}}); - MathLib::Point3d p1(std::array<double,3>{{_ur[0], _ur[1], z_mid}}); + const double x_mid((_ur[0] + _ll[0]) / 2.0); + const double y_mid((_ur[1] + _ll[1]) / 2.0); + const double z_mid((_ur[2] + _ll[2]) / 2.0); + MathLib::Point3d p0(std::array<double,3>{{x_mid, y_mid, _ll[2]}}); + MathLib::Point3d p1(std::array<double,3>{{_ur[0], _ur[1], z_mid}}); - // create child NEL - _children[static_cast<std::int8_t>(Quadrant::NEL)] - = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); + // create child NEL + _children[static_cast<std::int8_t>(Quadrant::NEL)] + = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); - // create child NWL - p0[0] = _ll[0]; - p1[0] = x_mid; - _children[static_cast<std::int8_t>(Quadrant::NWL)] - = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); + // create child NWL + p0[0] = _ll[0]; + p1[0] = x_mid; + _children[static_cast<std::int8_t>(Quadrant::NWL)] + = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); - // create child SWL - p0[1] = _ll[1]; - p1[1] = y_mid; - _children[static_cast<std::int8_t>(Quadrant::SWL)] - = new OctTree<POINT, MAX_POINTS> (_ll, p1, _eps); + // create child SWL + p0[1] = _ll[1]; + p1[1] = y_mid; + _children[static_cast<std::int8_t>(Quadrant::SWL)] + = new OctTree<POINT, MAX_POINTS> (_ll, p1, _eps); - // create child NEU - _children[static_cast<std::int8_t>(Quadrant::NEU)] - = new OctTree<POINT, MAX_POINTS> (p1, _ur, _eps); + // create child NEU + _children[static_cast<std::int8_t>(Quadrant::NEU)] + = new OctTree<POINT, MAX_POINTS> (p1, _ur, _eps); - // create child SEL - p0[0] = x_mid; - p1[0] = _ur[0]; - _children[static_cast<std::int8_t>(Quadrant::SEL)] - = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); + // create child SEL + p0[0] = x_mid; + p1[0] = _ur[0]; + _children[static_cast<std::int8_t>(Quadrant::SEL)] + = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); - // create child NWU - p0[0] = _ll[0]; - p0[1] = y_mid; - p0[2] = z_mid; - p1[0] = x_mid; - p1[1] = _ur[1]; - p1[2] = _ur[2]; - _children[static_cast<std::int8_t>(Quadrant::NWU)] - = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); + // create child NWU + p0[0] = _ll[0]; + p0[1] = y_mid; + p0[2] = z_mid; + p1[0] = x_mid; + p1[1] = _ur[1]; + p1[2] = _ur[2]; + _children[static_cast<std::int8_t>(Quadrant::NWU)] + = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); - // create child SWU - p0[1] = _ll[1]; - p1[1] = y_mid; - _children[static_cast<std::int8_t>(Quadrant::SWU)] - = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); + // create child SWU + p0[1] = _ll[1]; + p1[1] = y_mid; + _children[static_cast<std::int8_t>(Quadrant::SWU)] + = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); - // create child SEU - p0[0] = x_mid; - p1[0] = _ur[0]; - p1[1] = y_mid; - p1[2] = _ur[2]; - _children[static_cast<std::int8_t>(Quadrant::SEU)] - = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); + // create child SEU + p0[0] = x_mid; + p1[0] = _ur[0]; + p1[1] = y_mid; + p1[2] = _ur[2]; + _children[static_cast<std::int8_t>(Quadrant::SEU)] + = new OctTree<POINT, MAX_POINTS> (p0, p1, _eps); - // add the passed point pnt to the childs at first - for (std::size_t k(0); k < 8; k++) { - if (_children[k]->addPointToChild(pnt)) - break; - } + // add the passed point pnt to the childs at first + for (std::size_t k(0); k < 8; k++) { + if (_children[k]->addPointToChild(pnt)) + break; + } - // distribute points to sub quadtrees - const std::size_t n_pnts(_pnts.size()); - for (std::size_t j(0); j < n_pnts; j++) { - for (auto c : _children) { - if (c->addPointToChild(_pnts[j])) { - break; - } - } - } - _is_leaf = false; + // distribute points to sub quadtrees + const std::size_t n_pnts(_pnts.size()); + for (std::size_t j(0); j < n_pnts; j++) { + for (auto c : _children) { + if (c->addPointToChild(_pnts[j])) { + break; + } + } + } + _is_leaf = false; } template <typename POINT, std::size_t MAX_POINTS> bool OctTree<POINT, MAX_POINTS>::isOutside(POINT * pnt) const { - if ((*pnt)[0] < _ll[0] || (*pnt)[1] < _ll[1] || (*pnt)[2] < _ll[2]) - return true; - if ((*pnt)[0] >= _ur[0] || (*pnt)[1] >= _ur[1] || (*pnt)[2] >= _ur[2]) - return true; - return false; + if ((*pnt)[0] < _ll[0] || (*pnt)[1] < _ll[1] || (*pnt)[2] < _ll[2]) + return true; + if ((*pnt)[0] >= _ur[0] || (*pnt)[1] >= _ur[1] || (*pnt)[2] >= _ur[2]) + return true; + return false; } } // end namespace GeoLib diff --git a/GeoLib/OctTree.h b/GeoLib/OctTree.h index 80b90541c1f198c269e6888ce7229a77b12479d4..7f9121c8ceffcb3ac05d0ae38af7dac759ce41f9 100644 --- a/GeoLib/OctTree.h +++ b/GeoLib/OctTree.h @@ -27,122 +27,122 @@ namespace GeoLib { template <typename POINT, std::size_t MAX_POINTS> class OctTree { public: - /// Create an OctTree object. The arguments ll and ur are used to compute a - /// cube domain the OctTree will living in. - /// @attention This cubic domain can not be resized during the life time of - /// the OctTree. - /// @param ll lower left front point, used for computation of cubic domain - /// @param ur upper right back point, used for computation of cubic domain - /// @param eps the euclidean distance as a threshold to make objects unique - /// [default std::numeric_limits<double>::epsilon()] - /// Adding a new item to an already "filled" OctTree node results in a - /// split of the OctTree node. The smaller this number is the more leaves - /// the OctTree will have, i.e. it needs more memory and more time to walk - /// through the OctTree, but the search inside a leaf is fast. In - /// contrast a big value results into a smaller number of OctTree leaves, - /// the memory requirements for the OctTree may be lower but the search - /// inside a OctTree leaf may be more expensive. The value should be - /// choosen application dependend. [default 8] - template <typename T> - static OctTree<POINT, MAX_POINTS>* createOctTree(T ll, T ur, - double eps = std::numeric_limits<double>::epsilon()); - - /// Destroys the children of this node. @attention Does not destroy the - /// pointers to the managed objects. - virtual ~OctTree(); - - /// This method adds the given point to the OctTree. If necessary, - /// new OctTree nodes will be inserted deploying a split of the - /// corresponding OctTree node. - /// @param pnt the pointer to a point that should be inserted - /// @param ret_pnt the pointer to a point in the OctTree. Three cases can - /// occure: - /// (1) ret_pnt is nullptr: the given point (pnt) is outside of the OctTree - /// domain - /// (2) ret_pnt is equal to pnt: the point is added to the OctTree - /// (3) In case ret_pnt is neither equal to pnt nor equal to nullptr, - /// another item within the eps distance is already in the OctTree and the - /// pointer to this object is returned. - /// @return If the point can be inserted the method returns true, else false. - bool addPoint(POINT * pnt, POINT *& ret_pnt); - - /// range query - returns all points inside the range [min[0], max[0]) x - /// [min[1], max[1]) x [min[2], max[2]) - template <typename T> - void - getPointsInRange(T const& min, T const& max, std::vector<POINT*> &pnts) const; + /// Create an OctTree object. The arguments ll and ur are used to compute a + /// cube domain the OctTree will living in. + /// @attention This cubic domain can not be resized during the life time of + /// the OctTree. + /// @param ll lower left front point, used for computation of cubic domain + /// @param ur upper right back point, used for computation of cubic domain + /// @param eps the euclidean distance as a threshold to make objects unique + /// [default std::numeric_limits<double>::epsilon()] + /// Adding a new item to an already "filled" OctTree node results in a + /// split of the OctTree node. The smaller this number is the more leaves + /// the OctTree will have, i.e. it needs more memory and more time to walk + /// through the OctTree, but the search inside a leaf is fast. In + /// contrast a big value results into a smaller number of OctTree leaves, + /// the memory requirements for the OctTree may be lower but the search + /// inside a OctTree leaf may be more expensive. The value should be + /// choosen application dependend. [default 8] + template <typename T> + static OctTree<POINT, MAX_POINTS>* createOctTree(T ll, T ur, + double eps = std::numeric_limits<double>::epsilon()); + + /// Destroys the children of this node. @attention Does not destroy the + /// pointers to the managed objects. + virtual ~OctTree(); + + /// This method adds the given point to the OctTree. If necessary, + /// new OctTree nodes will be inserted deploying a split of the + /// corresponding OctTree node. + /// @param pnt the pointer to a point that should be inserted + /// @param ret_pnt the pointer to a point in the OctTree. Three cases can + /// occure: + /// (1) ret_pnt is nullptr: the given point (pnt) is outside of the OctTree + /// domain + /// (2) ret_pnt is equal to pnt: the point is added to the OctTree + /// (3) In case ret_pnt is neither equal to pnt nor equal to nullptr, + /// another item within the eps distance is already in the OctTree and the + /// pointer to this object is returned. + /// @return If the point can be inserted the method returns true, else false. + bool addPoint(POINT * pnt, POINT *& ret_pnt); + + /// range query - returns all points inside the range [min[0], max[0]) x + /// [min[1], max[1]) x [min[2], max[2]) + template <typename T> + void + getPointsInRange(T const& min, T const& max, std::vector<POINT*> &pnts) const; #ifndef NDEBUG - MathLib::Point3d const& getLowerLeftCornerPoint() const { return _ll; } - MathLib::Point3d const& getUpperRightCornerPoint() const { return _ur; } - OctTree<POINT, MAX_POINTS> const* getChild(std::size_t i) const - { - return _children[i]; - } - std::vector<POINT*> const& getPointVector() const { return _pnts; } + MathLib::Point3d const& getLowerLeftCornerPoint() const { return _ll; } + MathLib::Point3d const& getUpperRightCornerPoint() const { return _ur; } + OctTree<POINT, MAX_POINTS> const* getChild(std::size_t i) const + { + return _children[i]; + } + std::vector<POINT*> const& getPointVector() const { return _pnts; } #endif private: - /// private constructor - /// @param ll lower left point - /// @param ur upper right point - OctTree(MathLib::Point3d const& ll, MathLib::Point3d const& ur, double eps); - - enum class Quadrant : std::int8_t { - NEL = 0, //!< north east lower - NWL, //!< north west lower - SWL, //!< south west lower - SEL, //!< south east lower - NEU, //!< south west upper - NWU, //!< south west upper - SWU, //!< south west upper - SEU //!< south east upper - }; - - /// This method tries to add the given point to the OctTree. If necessary - /// for adding the point, new nodes will be inserted into the OctTree. - /// @param pnt, ret_pnt see documentation of addPoint() - /// @return If the point can be inserted the method returns true, else false. - bool addPoint_(POINT * pnt, POINT *& ret_pnt); - - /** - * This method adds the given point to the OctTree. If necessary, - * the OctTree will be extended. - * @param pnt the point - * @return If the point can be inserted the method returns true, else false. - */ - bool addPointToChild(POINT* pnt); - - /// Creates the child nodes of this leaf and distribute the points stored - /// in _pnts to the children. - /// @param pnt the pointer to the points that is responsible for the split - void splitNode(POINT * pnt); - - /// checks if the given point pnt is outside of the OctTree node. - /// @param pnt the point that check is performed on - /// @return true if the point is outside of the OctTree node. - bool isOutside(POINT * pnt) const; - - /// children are sorted: - /// _children[0] is north east lower child - /// _children[1] is north west lower child - /// _children[2] is south west lower child - /// _children[3] is south east lower child - /// _children[4] is north east upper child - /// _children[5] is north west upper child - /// _children[6] is south west upper child - /// _children[7] is south east upper child - std::array<OctTree<POINT, MAX_POINTS>*, 8> _children; - /// lower left front face point of the cube - MathLib::Point3d const _ll; - /// upper right back face point of the cube - MathLib::Point3d const _ur; - /// vector of pointers to POINT objects - std::vector<POINT*> _pnts; - /// flag if this OctTree is a leaf - bool _is_leaf; - /// threshold for point uniqueness - double const _eps; + /// private constructor + /// @param ll lower left point + /// @param ur upper right point + OctTree(MathLib::Point3d const& ll, MathLib::Point3d const& ur, double eps); + + enum class Quadrant : std::int8_t { + NEL = 0, //!< north east lower + NWL, //!< north west lower + SWL, //!< south west lower + SEL, //!< south east lower + NEU, //!< south west upper + NWU, //!< south west upper + SWU, //!< south west upper + SEU //!< south east upper + }; + + /// This method tries to add the given point to the OctTree. If necessary + /// for adding the point, new nodes will be inserted into the OctTree. + /// @param pnt, ret_pnt see documentation of addPoint() + /// @return If the point can be inserted the method returns true, else false. + bool addPoint_(POINT * pnt, POINT *& ret_pnt); + + /** + * This method adds the given point to the OctTree. If necessary, + * the OctTree will be extended. + * @param pnt the point + * @return If the point can be inserted the method returns true, else false. + */ + bool addPointToChild(POINT* pnt); + + /// Creates the child nodes of this leaf and distribute the points stored + /// in _pnts to the children. + /// @param pnt the pointer to the points that is responsible for the split + void splitNode(POINT * pnt); + + /// checks if the given point pnt is outside of the OctTree node. + /// @param pnt the point that check is performed on + /// @return true if the point is outside of the OctTree node. + bool isOutside(POINT * pnt) const; + + /// children are sorted: + /// _children[0] is north east lower child + /// _children[1] is north west lower child + /// _children[2] is south west lower child + /// _children[3] is south east lower child + /// _children[4] is north east upper child + /// _children[5] is north west upper child + /// _children[6] is south west upper child + /// _children[7] is south east upper child + std::array<OctTree<POINT, MAX_POINTS>*, 8> _children; + /// lower left front face point of the cube + MathLib::Point3d const _ll; + /// upper right back face point of the cube + MathLib::Point3d const _ur; + /// vector of pointers to POINT objects + std::vector<POINT*> _pnts; + /// flag if this OctTree is a leaf + bool _is_leaf; + /// threshold for point uniqueness + double const _eps; }; } // end namespace GeoLib diff --git a/GeoLib/Point.h b/GeoLib/Point.h index 910a2c0b450941290875bf03813387f9776a4ec4..b93c37fa189088f91d54206744e7aa700e11ccbb 100644 --- a/GeoLib/Point.h +++ b/GeoLib/Point.h @@ -33,32 +33,32 @@ class PointVec; class Point : public MathLib::Point3dWithID, public GeoLib::GeoObject { public: - Point(double x1, double x2, double x3, - std::size_t id = std::numeric_limits<std::size_t>::max()) : - MathLib::Point3dWithID(std::array<double,3>({{x1, x2, x3}}), id), - GeoLib::GeoObject() - {} + Point(double x1, double x2, double x3, + std::size_t id = std::numeric_limits<std::size_t>::max()) : + MathLib::Point3dWithID(std::array<double,3>({{x1, x2, x3}}), id), + GeoLib::GeoObject() + {} - Point() : - MathLib::Point3dWithID(), GeoLib::GeoObject() - {} + Point() : + MathLib::Point3dWithID(), GeoLib::GeoObject() + {} - Point(MathLib::Point3d const& x, std::size_t id) : - MathLib::Point3dWithID(x, id), GeoLib::GeoObject() - {} + Point(MathLib::Point3d const& x, std::size_t id) : + MathLib::Point3dWithID(x, id), GeoLib::GeoObject() + {} - Point(std::array<double,3> const& x, - std::size_t id = std::numeric_limits<std::size_t>::max()) : - MathLib::Point3dWithID(x, id), GeoLib::GeoObject() - {} + Point(std::array<double,3> const& x, + std::size_t id = std::numeric_limits<std::size_t>::max()) : + MathLib::Point3dWithID(x, id), GeoLib::GeoObject() + {} - /// return a geometry type - virtual GEOTYPE getGeoType() const {return GEOTYPE::POINT;} + /// return a geometry type + virtual GEOTYPE getGeoType() const {return GEOTYPE::POINT;} protected: - friend GeoLib::PointVec; - /// Resets the id. - void setID(std::size_t id) { _id = id; } + friend GeoLib::PointVec; + /// Resets the id. + void setID(std::size_t id) { _id = id; } }; extern const Point ORIGIN; diff --git a/GeoLib/PointVec.cpp b/GeoLib/PointVec.cpp index 582ba48269401999ba8d145505315ae195973cf8..22af4c9442a6e141f424e6054c56530dafadc49c 100644 --- a/GeoLib/PointVec.cpp +++ b/GeoLib/PointVec.cpp @@ -34,91 +34,91 @@ PointVec::PointVec(const std::string& name, _oct_tree(OctTree<GeoLib::Point, 16>::createOctTree( _aabb.getMinPoint(), _aabb.getMaxPoint(), _rel_eps)) { - assert(_data_vec); - std::size_t const number_of_all_input_pnts(_data_vec->size()); - - // correct the ids if necessary - for (std::size_t k(0); k < _data_vec->size(); ++k) - { - if ((*_data_vec)[k]->getID() == std::numeric_limits<std::size_t>::max()) - { - (*_data_vec)[k]->setID(k); - } - } - - std::vector<std::size_t> rm_pos; - // 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); - 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)) - { - assert(ret_pnt != nullptr); - _pnt_id_map[pnt->getID()] = ret_pnt->getID(); - rm_pos.push_back(k); - delete (*_data_vec)[k]; - (*_data_vec)[k] = nullptr; - } - else - { - _pnt_id_map[k] = pnt->getID(); - } - } - - auto const data_vec_end = - std::remove(_data_vec->begin(), _data_vec->end(), nullptr); - _data_vec->erase(data_vec_end, _data_vec->end()); - - // decrement the ids according to the number of removed points (==k) before - // the j-th point (positions of removed points are stored in the vector - // rm_pos) - for (std::size_t k(1); k < rm_pos.size(); ++k) - { - // decrement the ids in the interval [rm_pos[k-1]+1, rm_pos[k]) - for (std::size_t j(rm_pos[k - 1] + 1); j < rm_pos[k]; ++j) - { - _pnt_id_map[j] -= k; - } - } - // decrement the ids from rm_pos.back()+1 until the end of _pnt_id_map - if (!rm_pos.empty()) - { - for (std::size_t j(rm_pos.back() + 1); j < _pnt_id_map.size(); ++j) - { - _pnt_id_map[j] -= rm_pos.size(); - } - } - // decrement the ids within the _pnt_id_map at positions of the removed - // points - for (std::size_t k(1); k < rm_pos.size(); ++k) - { - std::size_t cnt(0); - for (cnt = 0; - cnt < rm_pos.size() && _pnt_id_map[rm_pos[k]] > rm_pos[cnt];) - cnt++; - _pnt_id_map[rm_pos[k]] -= cnt; - } - - // set value of the point id to the position of the point within _data_vec - for (std::size_t k(0); k < _data_vec->size(); ++k) - (*_data_vec)[k]->setID(k); - - if (number_of_all_input_pnts > _data_vec->size()) - WARN("PointVec::PointVec(): there are %d double points.", - number_of_all_input_pnts - _data_vec->size()); - - correctNameIDMapping(); - // create the inverse mapping - _id_to_name_map.resize(_data_vec->size()); - // fetch the names from the 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; - } + assert(_data_vec); + std::size_t const number_of_all_input_pnts(_data_vec->size()); + + // correct the ids if necessary + for (std::size_t k(0); k < _data_vec->size(); ++k) + { + if ((*_data_vec)[k]->getID() == std::numeric_limits<std::size_t>::max()) + { + (*_data_vec)[k]->setID(k); + } + } + + std::vector<std::size_t> rm_pos; + // 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); + 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)) + { + assert(ret_pnt != nullptr); + _pnt_id_map[pnt->getID()] = ret_pnt->getID(); + rm_pos.push_back(k); + delete (*_data_vec)[k]; + (*_data_vec)[k] = nullptr; + } + else + { + _pnt_id_map[k] = pnt->getID(); + } + } + + auto const data_vec_end = + std::remove(_data_vec->begin(), _data_vec->end(), nullptr); + _data_vec->erase(data_vec_end, _data_vec->end()); + + // decrement the ids according to the number of removed points (==k) before + // the j-th point (positions of removed points are stored in the vector + // rm_pos) + for (std::size_t k(1); k < rm_pos.size(); ++k) + { + // decrement the ids in the interval [rm_pos[k-1]+1, rm_pos[k]) + for (std::size_t j(rm_pos[k - 1] + 1); j < rm_pos[k]; ++j) + { + _pnt_id_map[j] -= k; + } + } + // decrement the ids from rm_pos.back()+1 until the end of _pnt_id_map + if (!rm_pos.empty()) + { + for (std::size_t j(rm_pos.back() + 1); j < _pnt_id_map.size(); ++j) + { + _pnt_id_map[j] -= rm_pos.size(); + } + } + // decrement the ids within the _pnt_id_map at positions of the removed + // points + for (std::size_t k(1); k < rm_pos.size(); ++k) + { + std::size_t cnt(0); + for (cnt = 0; + cnt < rm_pos.size() && _pnt_id_map[rm_pos[k]] > rm_pos[cnt];) + cnt++; + _pnt_id_map[rm_pos[k]] -= cnt; + } + + // set value of the point id to the position of the point within _data_vec + for (std::size_t k(0); k < _data_vec->size(); ++k) + (*_data_vec)[k]->setID(k); + + if (number_of_all_input_pnts > _data_vec->size()) + WARN("PointVec::PointVec(): there are %d double points.", + number_of_all_input_pnts - _data_vec->size()); + + correctNameIDMapping(); + // create the inverse mapping + _id_to_name_map.resize(_data_vec->size()); + // fetch the names from the 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; + } } PointVec::~PointVec() @@ -127,124 +127,124 @@ PointVec::~PointVec() std::size_t PointVec::push_back(Point* pnt) { - _pnt_id_map.push_back(uniqueInsert(pnt)); - _id_to_name_map.push_back(""); - return _pnt_id_map[_pnt_id_map.size() - 1]; + _pnt_id_map.push_back(uniqueInsert(pnt)); + _id_to_name_map.push_back(""); + return _pnt_id_map[_pnt_id_map.size() - 1]; } void PointVec::push_back(Point* pnt, std::string const* const name) { - if (name == nullptr) - { - _pnt_id_map.push_back(uniqueInsert(pnt)); - _id_to_name_map.push_back(""); - return; - } - - std::map<std::string, std::size_t>::const_iterator it( - _name_id_map->find(*name)); - if (it != _name_id_map->end()) - { - _id_to_name_map.push_back(""); - WARN("PointVec::push_back(): two points share the name %s.", - name->c_str()); - return; - } - - std::size_t id(uniqueInsert(pnt)); - _pnt_id_map.push_back(id); - (*_name_id_map)[*name] = id; - _id_to_name_map.push_back(*name); + if (name == nullptr) + { + _pnt_id_map.push_back(uniqueInsert(pnt)); + _id_to_name_map.push_back(""); + return; + } + + std::map<std::string, std::size_t>::const_iterator it( + _name_id_map->find(*name)); + if (it != _name_id_map->end()) + { + _id_to_name_map.push_back(""); + WARN("PointVec::push_back(): two points share the name %s.", + name->c_str()); + return; + } + + std::size_t id(uniqueInsert(pnt)); + _pnt_id_map.push_back(id); + (*_name_id_map)[*name] = id; + _id_to_name_map.push_back(*name); } std::size_t PointVec::uniqueInsert(Point* pnt) { - GeoLib::Point* ret_pnt(nullptr); - if (_oct_tree->addPoint(pnt, ret_pnt)) - { - // set value of the point id to the position of the point within - // _data_vec - pnt->setID(_data_vec->size()); - _data_vec->push_back(pnt); - return _data_vec->size() - 1; - } - - // pnt is outside of OctTree object - if (ret_pnt == nullptr) - { - // update the axis aligned bounding box - _aabb.update(*pnt); - // recreate the (enlarged) OctTree - _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); - // set value of the point id to the position of the point within - // _data_vec - pnt->setID(_data_vec->size()); - _data_vec->push_back(pnt); - return _data_vec->size() - 1; - } - else - { - delete pnt; - return ret_pnt->getID(); - } + GeoLib::Point* ret_pnt(nullptr); + if (_oct_tree->addPoint(pnt, ret_pnt)) + { + // set value of the point id to the position of the point within + // _data_vec + pnt->setID(_data_vec->size()); + _data_vec->push_back(pnt); + return _data_vec->size() - 1; + } + + // pnt is outside of OctTree object + if (ret_pnt == nullptr) + { + // update the axis aligned bounding box + _aabb.update(*pnt); + // recreate the (enlarged) OctTree + _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); + // set value of the point id to the position of the point within + // _data_vec + pnt->setID(_data_vec->size()); + _data_vec->push_back(pnt); + return _data_vec->size() - 1; + } + else + { + delete pnt; + return ret_pnt->getID(); + } } void PointVec::correctNameIDMapping() { - // create mapping id -> name using the std::vector id_names - std::vector<std::string> id_names(_pnt_id_map.size(), std::string("")); - for (auto it = _name_id_map->begin(); it != _name_id_map->end(); ++it) - { - id_names[it->second] = it->first; - } - - for (auto it = _name_id_map->begin(); it != _name_id_map->end();) - { - // extract the id associated with the name - const std::size_t id(it->second); - - if (_pnt_id_map[id] == id) - { - ++it; - continue; - } - - if (_pnt_id_map[_pnt_id_map[id]] == _pnt_id_map[id]) - { - if (id_names[_pnt_id_map[id]].length() != 0) - { - // point has already a name, erase the second occurrence - it = _name_id_map->erase(it); - } - else - { - // until now the point has not a name assign the second - // occurrence the correct id - it->second = _pnt_id_map[id]; - ++it; - } - } - else - { - it->second = _pnt_id_map[id]; // update id associated to the name - ++it; - } - } + // create mapping id -> name using the std::vector id_names + std::vector<std::string> id_names(_pnt_id_map.size(), std::string("")); + for (auto it = _name_id_map->begin(); it != _name_id_map->end(); ++it) + { + id_names[it->second] = it->first; + } + + for (auto it = _name_id_map->begin(); it != _name_id_map->end();) + { + // extract the id associated with the name + const std::size_t id(it->second); + + if (_pnt_id_map[id] == id) + { + ++it; + continue; + } + + if (_pnt_id_map[_pnt_id_map[id]] == _pnt_id_map[id]) + { + if (id_names[_pnt_id_map[id]].length() != 0) + { + // point has already a name, erase the second occurrence + it = _name_id_map->erase(it); + } + else + { + // until now the point has not a name assign the second + // occurrence the correct id + it->second = _pnt_id_map[id]; + ++it; + } + } + else + { + it->second = _pnt_id_map[id]; // update id associated to the name + ++it; + } + } } std::string const& PointVec::getItemNameByID(std::size_t id) const { - return _id_to_name_map[id]; + return _id_to_name_map[id]; } } // end namespace diff --git a/GeoLib/PointVec.h b/GeoLib/PointVec.h index bd3ae47a2cd274794f61319692e491a5c9811560..31dd0042104e51943b6c3d9405ca706b835c2575 100644 --- a/GeoLib/PointVec.h +++ b/GeoLib/PointVec.h @@ -42,103 +42,103 @@ namespace GeoLib class PointVec : public TemplateVec<Point> { public: - /// Signals if the vector contains object of type Point or Station - enum class PointType - { - POINT = 0, - STATION = 1 - }; - - /** - * Constructor initializes the name of the PointVec object, - * the internal pointer _pnt_vec to the raw points and the internal - * pointer the vector of names of the points - * and sets the type of PointVec. - * @param name the name of the point group - * @param points Pointer to a vector of pointers to GeoLib::Points. - * @attention{PointVec will take the ownership of (the pointer to) - * the vector, i.e. it deletes the vector in the destructor! The class - * takes also the ownership of the GeoLib::Points the pointers within - * the vector points at, i.e. it delete the points!} - * @param name_id_map A std::map that stores the relation name to point. - * @attention{PointVec will take the ownership of the vector, i.e. it - * deletes the names.} - * @param type the type of the point, \sa enum PointType - * @param rel_eps This is a relative error tolerance value for the test of identical points. - * The size of the axis aligned bounding box multiplied with the value of rel_eps gives the - * real tolerance \f$tol\f$. Two points \f$p_0, p_1 \f$ are identical iff - * \f$|p_1 - p_0| \le tol.\f$ - */ - PointVec (const std::string& name, std::unique_ptr<std::vector<Point*>> points, - std::map<std::string, std::size_t>* name_id_map = nullptr, - PointType type = PointVec::PointType::POINT, double rel_eps = std::numeric_limits<double>::epsilon()); - - /** Destructor deletes all Points of this PointVec. */ - virtual ~PointVec (); - - /** - * Method adds a Point to the (internal) standard vector and takes the ownership. - * If the given point is already included in the vector, the point will be destroyed and - * the id of the existing point will be returned. - * @param pnt the pointer to the Point - * @return the id of the point within the internal vector - */ - std::size_t push_back (Point* pnt); - - /** - * push_back adds new elements at the end of the vector _data_vec. - * @param pnt a pointer to the point, PointVec takes ownership of the point - * @param name the name of the point - */ - virtual void push_back (Point* pnt, std::string const*const name); - - /** - * get the type of Point, this can be either POINT or STATION - * - */ - PointType getType() const { return _type; } - - const std::vector<std::size_t>& getIDMap () const { return _pnt_id_map; } - - const GeoLib::AABB& getAABB () const; - - std::string const& getItemNameByID(std::size_t id) const; + /// Signals if the vector contains object of type Point or Station + enum class PointType + { + POINT = 0, + STATION = 1 + }; + + /** + * Constructor initializes the name of the PointVec object, + * the internal pointer _pnt_vec to the raw points and the internal + * pointer the vector of names of the points + * and sets the type of PointVec. + * @param name the name of the point group + * @param points Pointer to a vector of pointers to GeoLib::Points. + * @attention{PointVec will take the ownership of (the pointer to) + * the vector, i.e. it deletes the vector in the destructor! The class + * takes also the ownership of the GeoLib::Points the pointers within + * the vector points at, i.e. it delete the points!} + * @param name_id_map A std::map that stores the relation name to point. + * @attention{PointVec will take the ownership of the vector, i.e. it + * deletes the names.} + * @param type the type of the point, \sa enum PointType + * @param rel_eps This is a relative error tolerance value for the test of identical points. + * The size of the axis aligned bounding box multiplied with the value of rel_eps gives the + * real tolerance \f$tol\f$. Two points \f$p_0, p_1 \f$ are identical iff + * \f$|p_1 - p_0| \le tol.\f$ + */ + PointVec (const std::string& name, std::unique_ptr<std::vector<Point*>> points, + std::map<std::string, std::size_t>* name_id_map = nullptr, + PointType type = PointVec::PointType::POINT, double rel_eps = std::numeric_limits<double>::epsilon()); + + /** Destructor deletes all Points of this PointVec. */ + virtual ~PointVec (); + + /** + * Method adds a Point to the (internal) standard vector and takes the ownership. + * If the given point is already included in the vector, the point will be destroyed and + * the id of the existing point will be returned. + * @param pnt the pointer to the Point + * @return the id of the point within the internal vector + */ + std::size_t push_back (Point* pnt); + + /** + * push_back adds new elements at the end of the vector _data_vec. + * @param pnt a pointer to the point, PointVec takes ownership of the point + * @param name the name of the point + */ + virtual void push_back (Point* pnt, std::string const*const name); + + /** + * get the type of Point, this can be either POINT or STATION + * + */ + PointType getType() const { return _type; } + + const std::vector<std::size_t>& getIDMap () const { return _pnt_id_map; } + + const GeoLib::AABB& getAABB () const; + + std::string const& getItemNameByID(std::size_t id) const; private: - /** - * After the point set is modified (for example by makePntsUnique()) the mapping has to be corrected. - */ - void correctNameIDMapping(); - - /** copy constructor doesn't have an implementation */ - // compiler does not create a (possible unwanted) copy constructor - PointVec (const PointVec &); - /** standard constructor doesn't have an implementation */ - // compiler does not create a (possible unwanted) standard constructor - PointVec (); - - /** assignment operator doesn't have an implementation */ - // this way the compiler does not create a (possible unwanted) assignment operator - PointVec& operator= (const PointVec& rhs); - - std::size_t uniqueInsert (Point* pnt); - - /** the type of the point (\sa enum PointType) */ - PointType _type; - - /** - * permutation of the geometric elements according - * to their lexicographical order - */ - std::vector<std::size_t> _pnt_id_map; - - /// The reverse map to the name to id map, for fast lookup of the name to a - /// given point id. - std::vector<std::string> _id_to_name_map; - - AABB _aabb; - double _rel_eps; - std::unique_ptr<GeoLib::OctTree<GeoLib::Point, 16>> _oct_tree; + /** + * After the point set is modified (for example by makePntsUnique()) the mapping has to be corrected. + */ + void correctNameIDMapping(); + + /** copy constructor doesn't have an implementation */ + // compiler does not create a (possible unwanted) copy constructor + PointVec (const PointVec &); + /** standard constructor doesn't have an implementation */ + // compiler does not create a (possible unwanted) standard constructor + PointVec (); + + /** assignment operator doesn't have an implementation */ + // this way the compiler does not create a (possible unwanted) assignment operator + PointVec& operator= (const PointVec& rhs); + + std::size_t uniqueInsert (Point* pnt); + + /** the type of the point (\sa enum PointType) */ + PointType _type; + + /** + * permutation of the geometric elements according + * to their lexicographical order + */ + std::vector<std::size_t> _pnt_id_map; + + /// The reverse map to the name to id map, for fast lookup of the name to a + /// given point id. + std::vector<std::string> _id_to_name_map; + + AABB _aabb; + double _rel_eps; + std::unique_ptr<GeoLib::OctTree<GeoLib::Point, 16>> _oct_tree; }; } // end namespace diff --git a/GeoLib/Polygon.cpp b/GeoLib/Polygon.cpp index dc7a6c153501898534069644109c908a21941397..0dc41b4d7d931ef771b3e0a34c09e82b32182288 100644 --- a/GeoLib/Polygon.cpp +++ b/GeoLib/Polygon.cpp @@ -24,337 +24,337 @@ namespace GeoLib { Polygon::Polygon(const Polyline &ply, bool init) : - Polyline(ply), _aabb(ply.getPointsVec(), ply._ply_pnt_ids) + Polyline(ply), _aabb(ply.getPointsVec(), ply._ply_pnt_ids) { - if (init) - initialise (); - _simple_polygon_list.push_back(this); + if (init) + initialise (); + _simple_polygon_list.push_back(this); } Polygon::Polygon(Polygon const& other) : Polyline(other), _aabb(other._aabb) { - _simple_polygon_list.push_back(this); - auto sub_polygon_it(other._simple_polygon_list.begin()); - for (sub_polygon_it++; // the first entry is the polygon itself, skip the - // entry - sub_polygon_it != other._simple_polygon_list.end(); - ++sub_polygon_it) - { - _simple_polygon_list.emplace_back(new Polygon(*(*sub_polygon_it))); - } + _simple_polygon_list.push_back(this); + auto sub_polygon_it(other._simple_polygon_list.begin()); + for (sub_polygon_it++; // the first entry is the polygon itself, skip the + // entry + sub_polygon_it != other._simple_polygon_list.end(); + ++sub_polygon_it) + { + _simple_polygon_list.emplace_back(new Polygon(*(*sub_polygon_it))); + } } Polygon::~Polygon() { - // remove polygons from list - for (std::list<Polygon*>::iterator it (_simple_polygon_list.begin()); - it != _simple_polygon_list.end(); ++it) - // the first entry of the list can be a pointer the object itself - if (*it != this) - delete *it; + // remove polygons from list + for (std::list<Polygon*>::iterator it (_simple_polygon_list.begin()); + it != _simple_polygon_list.end(); ++it) + // the first entry of the list can be a pointer the object itself + if (*it != this) + delete *it; } bool Polygon::initialise () { - if (this->isClosed()) { - ensureCWOrientation(); - return true; - } else { - WARN("Polygon::initialise(): base polyline is not closed."); - return false; - } + if (this->isClosed()) { + ensureCWOrientation(); + return true; + } else { + WARN("Polygon::initialise(): base polyline is not closed."); + return false; + } } bool Polygon::isPntInPolygon (GeoLib::Point const & pnt) const { - MathLib::Point3d const& min_aabb_pnt(_aabb.getMinPoint()); - MathLib::Point3d const& max_aabb_pnt(_aabb.getMaxPoint()); - - if (pnt[0] < min_aabb_pnt[0] || max_aabb_pnt[0] < pnt[0] || pnt[1] < min_aabb_pnt[1] || - max_aabb_pnt[1] < pnt[1]) - return false; - - std::size_t n_intersections (0); - GeoLib::Point s; - - if (_simple_polygon_list.size() == 1) { - const std::size_t n_nodes (getNumberOfPoints() - 1); - for (std::size_t k(0); k < n_nodes; k++) { - if (((*(getPoint(k)))[1] <= pnt[1] && pnt[1] <= (*(getPoint(k + 1)))[1]) || - ((*(getPoint(k + 1)))[1] <= pnt[1] && pnt[1] <= (*(getPoint(k)))[1])) { - switch (getEdgeType(k, pnt)) - { - case EdgeType::TOUCHING: - return true; - case EdgeType::CROSSING: - n_intersections++; - break; - case EdgeType::INESSENTIAL: - break; - default: - // do nothing - ; - } - } - } - if (n_intersections % 2 == 1) - return true; - } else { - for (std::list<Polygon*>::const_iterator it( - _simple_polygon_list.begin()++); - it != _simple_polygon_list.end(); - ++it) - { - if ((*it)->isPntInPolygon (pnt)) - return true; - } - return false; - } - return false; + MathLib::Point3d const& min_aabb_pnt(_aabb.getMinPoint()); + MathLib::Point3d const& max_aabb_pnt(_aabb.getMaxPoint()); + + if (pnt[0] < min_aabb_pnt[0] || max_aabb_pnt[0] < pnt[0] || pnt[1] < min_aabb_pnt[1] || + max_aabb_pnt[1] < pnt[1]) + return false; + + std::size_t n_intersections (0); + GeoLib::Point s; + + if (_simple_polygon_list.size() == 1) { + const std::size_t n_nodes (getNumberOfPoints() - 1); + for (std::size_t k(0); k < n_nodes; k++) { + if (((*(getPoint(k)))[1] <= pnt[1] && pnt[1] <= (*(getPoint(k + 1)))[1]) || + ((*(getPoint(k + 1)))[1] <= pnt[1] && pnt[1] <= (*(getPoint(k)))[1])) { + switch (getEdgeType(k, pnt)) + { + case EdgeType::TOUCHING: + return true; + case EdgeType::CROSSING: + n_intersections++; + break; + case EdgeType::INESSENTIAL: + break; + default: + // do nothing + ; + } + } + } + if (n_intersections % 2 == 1) + return true; + } else { + for (std::list<Polygon*>::const_iterator it( + _simple_polygon_list.begin()++); + it != _simple_polygon_list.end(); + ++it) + { + if ((*it)->isPntInPolygon (pnt)) + return true; + } + return false; + } + return false; } bool Polygon::isPntInPolygon(double x, double y, double z) const { - const GeoLib::Point pnt(x,y,z); - return isPntInPolygon (pnt); + const GeoLib::Point pnt(x,y,z); + return isPntInPolygon (pnt); } std::vector<GeoLib::Point> Polygon::getAllIntersectionPoints( - GeoLib::LineSegment const& segment) const + GeoLib::LineSegment const& segment) const { - std::vector<GeoLib::Point> intersections; - GeoLib::Point s; - for (auto seg_it(begin()); seg_it != end(); ++seg_it) - { - if (GeoLib::lineSegmentIntersect(*seg_it, segment, s)) { - intersections.push_back(s); - } - } - - return intersections; + std::vector<GeoLib::Point> intersections; + GeoLib::Point s; + for (auto seg_it(begin()); seg_it != end(); ++seg_it) + { + if (GeoLib::lineSegmentIntersect(*seg_it, segment, s)) { + intersections.push_back(s); + } + } + + return intersections; } bool Polygon::containsSegment(GeoLib::LineSegment const& segment) const { - std::vector<GeoLib::Point> s(getAllIntersectionPoints(segment)); - - GeoLib::Point const& a{segment.getBeginPoint()}; - GeoLib::Point const& b{segment.getEndPoint()}; - // no intersections -> check if at least one point of segment is in polygon - if (s.empty()) { - return (isPntInPolygon(a)); - } - - const double tol(std::numeric_limits<float>::epsilon()); - - // one intersection, intersection in line segment end point - if (s.size() == 1) { - const double sqr_dist_as(MathLib::sqrDist(a,s[0])); - if (sqr_dist_as < tol) { - return (isPntInPolygon(b)); - } - - const double sqr_dist_bs(MathLib::sqrDist(b,s[0])); - if (sqr_dist_bs < tol) { - return (isPntInPolygon(a)); - } - } - - // Sorting the intersection with respect to the distance to the point a. - // This induces a partition of the line segment into sub segments. - std::sort(s.begin(), s.end(), - [&a] (GeoLib::Point const& p0, GeoLib::Point const& p1) { - return MathLib::sqrDist(a, p0) < MathLib::sqrDist(a, p1); - } - ); - - // remove sub segments with almost zero length - for (std::size_t k(0); k<s.size()-1; ) { - if (MathLib::sqrDist(s[k], s[k+1]) < tol) { - s.erase(s.begin()+k+1); - } else { - k++; - } - } - - // Check if all sub segments are within the polygon. - if (!isPntInPolygon(GeoLib::Point(0.5*(a[0]+s[0][0]), 0.5*(a[1]+s[0][1]), 0.5*(a[2]+s[0][2])))) - return false; - const std::size_t n_sub_segs(s.size()-1); - for (std::size_t k(0); k<n_sub_segs; k++) { - if (!isPntInPolygon(GeoLib::Point(0.5*(s[k][0]+s[k+1][0]), 0.5*(s[k][1]+s[k+1][1]), 0.5*(s[k][2]+s[k+1][2])))) - return false; - } - if (!isPntInPolygon(GeoLib::Point(0.5*(s[0][0]+b[0]), 0.5*(s[0][1]+b[1]), 0.5*(s[0][2]+b[2])))) - return false; - return true; + std::vector<GeoLib::Point> s(getAllIntersectionPoints(segment)); + + GeoLib::Point const& a{segment.getBeginPoint()}; + GeoLib::Point const& b{segment.getEndPoint()}; + // no intersections -> check if at least one point of segment is in polygon + if (s.empty()) { + return (isPntInPolygon(a)); + } + + const double tol(std::numeric_limits<float>::epsilon()); + + // one intersection, intersection in line segment end point + if (s.size() == 1) { + const double sqr_dist_as(MathLib::sqrDist(a,s[0])); + if (sqr_dist_as < tol) { + return (isPntInPolygon(b)); + } + + const double sqr_dist_bs(MathLib::sqrDist(b,s[0])); + if (sqr_dist_bs < tol) { + return (isPntInPolygon(a)); + } + } + + // Sorting the intersection with respect to the distance to the point a. + // This induces a partition of the line segment into sub segments. + std::sort(s.begin(), s.end(), + [&a] (GeoLib::Point const& p0, GeoLib::Point const& p1) { + return MathLib::sqrDist(a, p0) < MathLib::sqrDist(a, p1); + } + ); + + // remove sub segments with almost zero length + for (std::size_t k(0); k<s.size()-1; ) { + if (MathLib::sqrDist(s[k], s[k+1]) < tol) { + s.erase(s.begin()+k+1); + } else { + k++; + } + } + + // Check if all sub segments are within the polygon. + if (!isPntInPolygon(GeoLib::Point(0.5*(a[0]+s[0][0]), 0.5*(a[1]+s[0][1]), 0.5*(a[2]+s[0][2])))) + return false; + const std::size_t n_sub_segs(s.size()-1); + for (std::size_t k(0); k<n_sub_segs; k++) { + if (!isPntInPolygon(GeoLib::Point(0.5*(s[k][0]+s[k+1][0]), 0.5*(s[k][1]+s[k+1][1]), 0.5*(s[k][2]+s[k+1][2])))) + return false; + } + if (!isPntInPolygon(GeoLib::Point(0.5*(s[0][0]+b[0]), 0.5*(s[0][1]+b[1]), 0.5*(s[0][2]+b[2])))) + return false; + return true; } bool Polygon::isPolylineInPolygon(const Polyline& ply) const { - for (auto segment : ply) { - if (!containsSegment(segment)) { - return false; - } - } - return true; + for (auto segment : ply) { + if (!containsSegment(segment)) { + return false; + } + } + return true; } bool Polygon::isPartOfPolylineInPolygon(const Polyline& ply) const { - const std::size_t ply_size (ply.getNumberOfPoints()); - // check points - for (std::size_t k(0); k < ply_size; k++) { - if (isPntInPolygon (*(ply.getPoint(k)))) { - return true; - } - } - - GeoLib::Point s; - for (auto polygon_seg : *this) { - for (auto polyline_seg : ply) { - if (GeoLib::lineSegmentIntersect(polyline_seg, polygon_seg, s)) { - return true; - } - } - } - - return false; + const std::size_t ply_size (ply.getNumberOfPoints()); + // check points + for (std::size_t k(0); k < ply_size; k++) { + if (isPntInPolygon (*(ply.getPoint(k)))) { + return true; + } + } + + GeoLib::Point s; + for (auto polygon_seg : *this) { + for (auto polyline_seg : ply) { + if (GeoLib::lineSegmentIntersect(polyline_seg, polygon_seg, s)) { + return true; + } + } + } + + return false; } bool Polygon::getNextIntersectionPointPolygonLine( GeoLib::LineSegment const& seg, GeoLib::Point & intersection, std::size_t& seg_num) const { - if (_simple_polygon_list.size() == 1) { - for (auto seg_it(begin()+seg_num); seg_it != end(); ++seg_it) { - if (GeoLib::lineSegmentIntersect(*seg_it, seg, intersection)) { - seg_num = seg_it.getSegmentNumber(); - return true; - } - } - } else { - for (auto polygon_it(_simple_polygon_list.begin()); - polygon_it != _simple_polygon_list.end(); - ++polygon_it) - { - Polygon const& polygon(*(*polygon_it)); - for (auto seg_it(polygon.begin()); seg_it != polygon.end(); ++seg_it) - { - if (GeoLib::lineSegmentIntersect(*seg_it, seg, intersection)) { - seg_num = seg_it.getSegmentNumber(); - return true; - } - } - } - } - return false; + if (_simple_polygon_list.size() == 1) { + for (auto seg_it(begin()+seg_num); seg_it != end(); ++seg_it) { + if (GeoLib::lineSegmentIntersect(*seg_it, seg, intersection)) { + seg_num = seg_it.getSegmentNumber(); + return true; + } + } + } else { + for (auto polygon_it(_simple_polygon_list.begin()); + polygon_it != _simple_polygon_list.end(); + ++polygon_it) + { + Polygon const& polygon(*(*polygon_it)); + for (auto seg_it(polygon.begin()); seg_it != polygon.end(); ++seg_it) + { + if (GeoLib::lineSegmentIntersect(*seg_it, seg, intersection)) { + seg_num = seg_it.getSegmentNumber(); + return true; + } + } + } + } + return false; } const std::list<Polygon*>& Polygon::getListOfSimplePolygons() { - return _simple_polygon_list; + return _simple_polygon_list; } void Polygon::computeListOfSimplePolygons () { - splitPolygonAtPoint (_simple_polygon_list.begin()); - splitPolygonAtIntersection (_simple_polygon_list.begin()); + splitPolygonAtPoint (_simple_polygon_list.begin()); + splitPolygonAtIntersection (_simple_polygon_list.begin()); - for (std::list<Polygon*>::iterator it (_simple_polygon_list.begin()); - it != _simple_polygon_list.end(); ++it) - (*it)->initialise (); + for (std::list<Polygon*>::iterator it (_simple_polygon_list.begin()); + it != _simple_polygon_list.end(); ++it) + (*it)->initialise (); } EdgeType Polygon::getEdgeType (std::size_t k, GeoLib::Point const & pnt) const { - switch (getLocationOfPoint(k, pnt)) - { - case Location::LEFT: { - const GeoLib::Point & v (*(getPoint(k))); - const GeoLib::Point & w (*(getPoint(k + 1))); - if (v[1] < pnt[1] && pnt[1] <= w[1]) - return EdgeType::CROSSING; - else - return EdgeType::INESSENTIAL; - } - case Location::RIGHT: { - const GeoLib::Point & v (*(getPoint(k))); - const GeoLib::Point & w (*(getPoint(k + 1))); - if (w[1] < pnt[1] && pnt[1] <= v[1]) - return EdgeType::CROSSING; - else - return EdgeType::INESSENTIAL; - } - case Location::BETWEEN: - case Location::SOURCE: - case Location::DESTINATION: - return EdgeType::TOUCHING; - default: - return EdgeType::INESSENTIAL; - } + switch (getLocationOfPoint(k, pnt)) + { + case Location::LEFT: { + const GeoLib::Point & v (*(getPoint(k))); + const GeoLib::Point & w (*(getPoint(k + 1))); + if (v[1] < pnt[1] && pnt[1] <= w[1]) + return EdgeType::CROSSING; + else + return EdgeType::INESSENTIAL; + } + case Location::RIGHT: { + const GeoLib::Point & v (*(getPoint(k))); + const GeoLib::Point & w (*(getPoint(k + 1))); + if (w[1] < pnt[1] && pnt[1] <= v[1]) + return EdgeType::CROSSING; + else + return EdgeType::INESSENTIAL; + } + case Location::BETWEEN: + case Location::SOURCE: + case Location::DESTINATION: + return EdgeType::TOUCHING; + default: + return EdgeType::INESSENTIAL; + } } void Polygon::ensureCWOrientation () { - // *** pre processing: rotate points to xy-plan - // *** copy points to vector - last point is identical to the first - std::size_t n_pnts (this->getNumberOfPoints() - 1); - std::vector<GeoLib::Point*> tmp_polygon_pnts; - for (std::size_t k(0); k < n_pnts; k++) - tmp_polygon_pnts.push_back (new GeoLib::Point (*(this->getPoint(k)))); - - // rotate copied points into x-y-plane - GeoLib::rotatePointsToXY(tmp_polygon_pnts); - - for (std::size_t k(0); k < tmp_polygon_pnts.size(); k++) - (*(tmp_polygon_pnts[k]))[2] = 0.0; // should be -= d but there are numerical errors - - // *** get the left most upper point - std::size_t min_x_max_y_idx (0); // for orientation check - for (std::size_t k(0); k < n_pnts; k++) - if ((*(tmp_polygon_pnts[k]))[0] <= (*(tmp_polygon_pnts[min_x_max_y_idx]))[0]) - { - if ((*(tmp_polygon_pnts[k]))[0] < (*(tmp_polygon_pnts[min_x_max_y_idx]))[0]) - min_x_max_y_idx = k; - else if ((*(tmp_polygon_pnts[k]))[1] > - (*(tmp_polygon_pnts[min_x_max_y_idx]))[1]) - min_x_max_y_idx = k; - - } - // *** determine orientation - GeoLib::Orientation orient; - if (0 < min_x_max_y_idx && min_x_max_y_idx < n_pnts - 2) - orient = GeoLib::getOrientation ( - tmp_polygon_pnts[min_x_max_y_idx - 1], - tmp_polygon_pnts[min_x_max_y_idx], - tmp_polygon_pnts[min_x_max_y_idx + 1]); - else - { - if (0 == min_x_max_y_idx) - orient = GeoLib::getOrientation ( - tmp_polygon_pnts[n_pnts - 1], - tmp_polygon_pnts[0], - tmp_polygon_pnts[1]); - else - orient = GeoLib::getOrientation ( - tmp_polygon_pnts[n_pnts - 2], - tmp_polygon_pnts[n_pnts - 1], - tmp_polygon_pnts[0]); - } - - if (orient == GeoLib::CCW) - { - // switch orientation - std::size_t tmp_n_pnts (n_pnts); - tmp_n_pnts++; // include last point of polygon (which is identical to the first) - for (std::size_t k(0); k < tmp_n_pnts / 2; k++) - std::swap (_ply_pnt_ids[k], _ply_pnt_ids[tmp_n_pnts - 1 - k]); - } - - for (std::size_t k(0); k < n_pnts; k++) - delete tmp_polygon_pnts[k]; + // *** pre processing: rotate points to xy-plan + // *** copy points to vector - last point is identical to the first + std::size_t n_pnts (this->getNumberOfPoints() - 1); + std::vector<GeoLib::Point*> tmp_polygon_pnts; + for (std::size_t k(0); k < n_pnts; k++) + tmp_polygon_pnts.push_back (new GeoLib::Point (*(this->getPoint(k)))); + + // rotate copied points into x-y-plane + GeoLib::rotatePointsToXY(tmp_polygon_pnts); + + for (std::size_t k(0); k < tmp_polygon_pnts.size(); k++) + (*(tmp_polygon_pnts[k]))[2] = 0.0; // should be -= d but there are numerical errors + + // *** get the left most upper point + std::size_t min_x_max_y_idx (0); // for orientation check + for (std::size_t k(0); k < n_pnts; k++) + if ((*(tmp_polygon_pnts[k]))[0] <= (*(tmp_polygon_pnts[min_x_max_y_idx]))[0]) + { + if ((*(tmp_polygon_pnts[k]))[0] < (*(tmp_polygon_pnts[min_x_max_y_idx]))[0]) + min_x_max_y_idx = k; + else if ((*(tmp_polygon_pnts[k]))[1] > + (*(tmp_polygon_pnts[min_x_max_y_idx]))[1]) + min_x_max_y_idx = k; + + } + // *** determine orientation + GeoLib::Orientation orient; + if (0 < min_x_max_y_idx && min_x_max_y_idx < n_pnts - 2) + orient = GeoLib::getOrientation ( + tmp_polygon_pnts[min_x_max_y_idx - 1], + tmp_polygon_pnts[min_x_max_y_idx], + tmp_polygon_pnts[min_x_max_y_idx + 1]); + else + { + if (0 == min_x_max_y_idx) + orient = GeoLib::getOrientation ( + tmp_polygon_pnts[n_pnts - 1], + tmp_polygon_pnts[0], + tmp_polygon_pnts[1]); + else + orient = GeoLib::getOrientation ( + tmp_polygon_pnts[n_pnts - 2], + tmp_polygon_pnts[n_pnts - 1], + tmp_polygon_pnts[0]); + } + + if (orient == GeoLib::CCW) + { + // switch orientation + std::size_t tmp_n_pnts (n_pnts); + tmp_n_pnts++; // include last point of polygon (which is identical to the first) + for (std::size_t k(0); k < tmp_n_pnts / 2; k++) + std::swap (_ply_pnt_ids[k], _ply_pnt_ids[tmp_n_pnts - 1 - k]); + } + + for (std::size_t k(0); k < n_pnts; k++) + delete tmp_polygon_pnts[k]; } #if __GNUC__ <= 4 && (__GNUC_MINOR__ < 9) @@ -365,195 +365,195 @@ void Polygon::splitPolygonAtIntersection( std::list<Polygon*>::const_iterator polygon_it) #endif { - GeoLib::Polyline::SegmentIterator seg_it0((*polygon_it)->begin()); - GeoLib::Polyline::SegmentIterator seg_it1((*polygon_it)->begin()); - GeoLib::Point intersection_pnt; - if (!GeoLib::lineSegmentsIntersect(*polygon_it, seg_it0, seg_it1, - intersection_pnt)) - return; - - std::size_t idx0(seg_it0.getSegmentNumber()); - std::size_t idx1(seg_it1.getSegmentNumber()); - // adding intersection point to pnt_vec - std::size_t const intersection_pnt_id (_ply_pnts.size()); - const_cast<std::vector<Point*>&>(_ply_pnts) - .push_back(new GeoLib::Point(intersection_pnt)); - - // split Polygon - if (idx0 > idx1) - std::swap (idx0, idx1); - - GeoLib::Polyline polyline0{(*polygon_it)->getPointsVec()}; - for (std::size_t k(0); k <= idx0; k++) - polyline0.addPoint((*polygon_it)->getPointID(k)); - polyline0.addPoint(intersection_pnt_id); - for (std::size_t k(idx1 + 1); k < (*polygon_it)->getNumberOfPoints(); k++) - polyline0.addPoint((*polygon_it)->getPointID(k)); - - GeoLib::Polyline polyline1{(*polygon_it)->getPointsVec()}; - polyline1.addPoint(intersection_pnt_id); - for (std::size_t k(idx0 + 1); k <= idx1; k++) - polyline1.addPoint((*polygon_it)->getPointID(k)); - polyline1.addPoint(intersection_pnt_id); - - // remove the polygon except the first - if (*polygon_it != this) - delete *polygon_it; - // erase polygon_it and add two new polylines - auto polygon1_it = _simple_polygon_list.insert( - _simple_polygon_list.erase(polygon_it), new GeoLib::Polygon(polyline1)); - auto polygon0_it = _simple_polygon_list.insert( - polygon1_it, new GeoLib::Polygon(polyline0)); - - splitPolygonAtIntersection(polygon0_it); - splitPolygonAtIntersection(polygon1_it); + GeoLib::Polyline::SegmentIterator seg_it0((*polygon_it)->begin()); + GeoLib::Polyline::SegmentIterator seg_it1((*polygon_it)->begin()); + GeoLib::Point intersection_pnt; + if (!GeoLib::lineSegmentsIntersect(*polygon_it, seg_it0, seg_it1, + intersection_pnt)) + return; + + std::size_t idx0(seg_it0.getSegmentNumber()); + std::size_t idx1(seg_it1.getSegmentNumber()); + // adding intersection point to pnt_vec + std::size_t const intersection_pnt_id (_ply_pnts.size()); + const_cast<std::vector<Point*>&>(_ply_pnts) + .push_back(new GeoLib::Point(intersection_pnt)); + + // split Polygon + if (idx0 > idx1) + std::swap (idx0, idx1); + + GeoLib::Polyline polyline0{(*polygon_it)->getPointsVec()}; + for (std::size_t k(0); k <= idx0; k++) + polyline0.addPoint((*polygon_it)->getPointID(k)); + polyline0.addPoint(intersection_pnt_id); + for (std::size_t k(idx1 + 1); k < (*polygon_it)->getNumberOfPoints(); k++) + polyline0.addPoint((*polygon_it)->getPointID(k)); + + GeoLib::Polyline polyline1{(*polygon_it)->getPointsVec()}; + polyline1.addPoint(intersection_pnt_id); + for (std::size_t k(idx0 + 1); k <= idx1; k++) + polyline1.addPoint((*polygon_it)->getPointID(k)); + polyline1.addPoint(intersection_pnt_id); + + // remove the polygon except the first + if (*polygon_it != this) + delete *polygon_it; + // erase polygon_it and add two new polylines + auto polygon1_it = _simple_polygon_list.insert( + _simple_polygon_list.erase(polygon_it), new GeoLib::Polygon(polyline1)); + auto polygon0_it = _simple_polygon_list.insert( + polygon1_it, new GeoLib::Polygon(polyline0)); + + splitPolygonAtIntersection(polygon0_it); + splitPolygonAtIntersection(polygon1_it); } void Polygon::splitPolygonAtPoint (std::list<GeoLib::Polygon*>::iterator polygon_it) { - std::size_t n((*polygon_it)->getNumberOfPoints() - 1), idx0(0), idx1(0); - std::vector<std::size_t> id_vec(n); - std::vector<std::size_t> perm(n); - for (std::size_t k(0); k < n; k++) - { - id_vec[k] = (*polygon_it)->getPointID (k); - perm[k] = k; - } - - BaseLib::quicksort (id_vec, 0, n, perm); - - for (std::size_t k(0); k < n - 1; k++) - if (id_vec[k] == id_vec[k + 1]) - { - idx0 = perm[k]; - idx1 = perm[k + 1]; - - if (idx0 > idx1) - std::swap (idx0, idx1); - - // create two closed polylines - GeoLib::Polyline polyline0{*(*polygon_it)}; - for (std::size_t j(0); j <= idx0; j++) - polyline0.addPoint((*polygon_it)->getPointID(j)); - for (std::size_t j(idx1 + 1); - j < (*polygon_it)->getNumberOfPoints(); j++) - polyline0.addPoint((*polygon_it)->getPointID(j)); - - GeoLib::Polyline polyline1{*(*polygon_it)}; - for (std::size_t j(idx0); j <= idx1; j++) - polyline1.addPoint((*polygon_it)->getPointID(j)); - - // remove the polygon except the first - if (*polygon_it != this) - delete *polygon_it; - // erase polygon_it and add two new polygons - auto polygon1_it = _simple_polygon_list.insert( - _simple_polygon_list.erase(polygon_it), new Polygon(polyline1)); - auto polygon0_it = _simple_polygon_list.insert( - polygon1_it, new Polygon(polyline0)); - - splitPolygonAtPoint(polygon0_it); - splitPolygonAtPoint(polygon1_it); - - return; - } + std::size_t n((*polygon_it)->getNumberOfPoints() - 1), idx0(0), idx1(0); + std::vector<std::size_t> id_vec(n); + std::vector<std::size_t> perm(n); + for (std::size_t k(0); k < n; k++) + { + id_vec[k] = (*polygon_it)->getPointID (k); + perm[k] = k; + } + + BaseLib::quicksort (id_vec, 0, n, perm); + + for (std::size_t k(0); k < n - 1; k++) + if (id_vec[k] == id_vec[k + 1]) + { + idx0 = perm[k]; + idx1 = perm[k + 1]; + + if (idx0 > idx1) + std::swap (idx0, idx1); + + // create two closed polylines + GeoLib::Polyline polyline0{*(*polygon_it)}; + for (std::size_t j(0); j <= idx0; j++) + polyline0.addPoint((*polygon_it)->getPointID(j)); + for (std::size_t j(idx1 + 1); + j < (*polygon_it)->getNumberOfPoints(); j++) + polyline0.addPoint((*polygon_it)->getPointID(j)); + + GeoLib::Polyline polyline1{*(*polygon_it)}; + for (std::size_t j(idx0); j <= idx1; j++) + polyline1.addPoint((*polygon_it)->getPointID(j)); + + // remove the polygon except the first + if (*polygon_it != this) + delete *polygon_it; + // erase polygon_it and add two new polygons + auto polygon1_it = _simple_polygon_list.insert( + _simple_polygon_list.erase(polygon_it), new Polygon(polyline1)); + auto polygon0_it = _simple_polygon_list.insert( + polygon1_it, new Polygon(polyline0)); + + splitPolygonAtPoint(polygon0_it); + splitPolygonAtPoint(polygon1_it); + + return; + } } GeoLib::Polygon* createPolygonFromCircle (GeoLib::Point const& middle_pnt, double radius, std::vector<GeoLib::Point*> & pnts, std::size_t resolution) { - const std::size_t off_set (pnts.size()); - // create points - double angle (boost::math::double_constants::two_pi / resolution); - for (std::size_t k(0); k < resolution; k++) - { - GeoLib::Point* pnt(new GeoLib::Point(middle_pnt)); - (*pnt)[0] += radius * cos (k * angle); - (*pnt)[1] += radius * sin (k * angle); - pnts.push_back (pnt); - } - - // create polygon - GeoLib::Polygon* polygon (new GeoLib::Polygon (pnts, false)); - for (std::size_t k(0); k < resolution; k++) - polygon->addPoint (k + off_set); - polygon->addPoint (off_set); - - return polygon; + const std::size_t off_set (pnts.size()); + // create points + double angle (boost::math::double_constants::two_pi / resolution); + for (std::size_t k(0); k < resolution; k++) + { + GeoLib::Point* pnt(new GeoLib::Point(middle_pnt)); + (*pnt)[0] += radius * cos (k * angle); + (*pnt)[1] += radius * sin (k * angle); + pnts.push_back (pnt); + } + + // create polygon + GeoLib::Polygon* polygon (new GeoLib::Polygon (pnts, false)); + for (std::size_t k(0); k < resolution; k++) + polygon->addPoint (k + off_set); + polygon->addPoint (off_set); + + return polygon; } bool operator==(Polygon const& lhs, Polygon const& rhs) { - if (lhs.getNumberOfPoints() != rhs.getNumberOfPoints()) - return false; - - const std::size_t n(lhs.getNumberOfPoints()); - const std::size_t start_pnt(lhs.getPointID(0)); - - // search start point of first polygon in second polygon - bool nfound(true); - std::size_t k(0); - for (; k < n-1 && nfound; k++) { - if (start_pnt == rhs.getPointID(k)) { - nfound = false; - break; - } - } - - // case: start point not found in second polygon - if (nfound) return false; - - // *** determine direction - // opposite direction - if (k == n-2) { - for (k=1; k<n-1; k++) { - if (lhs.getPointID(k) != rhs.getPointID(n-1-k)) { - return false; - } - } - return true; - } - - // same direction - start point of first polygon at arbitrary position in second polygon - if (lhs.getPointID(1) == rhs.getPointID(k+1)) { - std::size_t j(k+2); - for (; j<n-1; j++) { - if (lhs.getPointID(j-k) != rhs.getPointID(j)) { - return false; - } - } - j=0; // new start point at second polygon - for (; j<k+1; j++) { - if (lhs.getPointID(n-(k+2)+j+1) != rhs.getPointID(j)) { - return false; - } - } - return true; - } else { - // opposite direction with start point of first polygon at arbitrary position - // *** ATTENTION - WARN("operator==(Polygon const& lhs, Polygon const& rhs) - not tested case (implementation is probably buggy) - please contact thomas.fischer@ufz.de mentioning the problem."); - // in second polygon - if (lhs.getPointID(1) == rhs.getPointID(k-1)) { - std::size_t j(k-2); - for (; j>0; j--) { - if (lhs.getPointID(k-2-j) != rhs.getPointID(j)) { - return false; - } - } - // new start point at second polygon - the point n-1 of a polygon is equal to the - // first point of the polygon (for this reason: n-2) - j=n-2; - for (; j>k-1; j--) { - if (lhs.getPointID(n-2+j+k-2) != rhs.getPointID(j)) { - return false; - } - } - return true; - } else { - return false; - } - } + if (lhs.getNumberOfPoints() != rhs.getNumberOfPoints()) + return false; + + const std::size_t n(lhs.getNumberOfPoints()); + const std::size_t start_pnt(lhs.getPointID(0)); + + // search start point of first polygon in second polygon + bool nfound(true); + std::size_t k(0); + for (; k < n-1 && nfound; k++) { + if (start_pnt == rhs.getPointID(k)) { + nfound = false; + break; + } + } + + // case: start point not found in second polygon + if (nfound) return false; + + // *** determine direction + // opposite direction + if (k == n-2) { + for (k=1; k<n-1; k++) { + if (lhs.getPointID(k) != rhs.getPointID(n-1-k)) { + return false; + } + } + return true; + } + + // same direction - start point of first polygon at arbitrary position in second polygon + if (lhs.getPointID(1) == rhs.getPointID(k+1)) { + std::size_t j(k+2); + for (; j<n-1; j++) { + if (lhs.getPointID(j-k) != rhs.getPointID(j)) { + return false; + } + } + j=0; // new start point at second polygon + for (; j<k+1; j++) { + if (lhs.getPointID(n-(k+2)+j+1) != rhs.getPointID(j)) { + return false; + } + } + return true; + } else { + // opposite direction with start point of first polygon at arbitrary position + // *** ATTENTION + WARN("operator==(Polygon const& lhs, Polygon const& rhs) - not tested case (implementation is probably buggy) - please contact thomas.fischer@ufz.de mentioning the problem."); + // in second polygon + if (lhs.getPointID(1) == rhs.getPointID(k-1)) { + std::size_t j(k-2); + for (; j>0; j--) { + if (lhs.getPointID(k-2-j) != rhs.getPointID(j)) { + return false; + } + } + // new start point at second polygon - the point n-1 of a polygon is equal to the + // first point of the polygon (for this reason: n-2) + j=n-2; + for (; j>k-1; j--) { + if (lhs.getPointID(n-2+j+k-2) != rhs.getPointID(j)) { + return false; + } + } + return true; + } else { + return false; + } + } } } // end namespace GeoLib diff --git a/GeoLib/Polygon.h b/GeoLib/Polygon.h index 4881aa0916a07004b50414304fdd54b491332e4f..8ffdb024128c2159add526a35ad9421deaa85bef 100644 --- a/GeoLib/Polygon.h +++ b/GeoLib/Polygon.h @@ -33,9 +33,9 @@ namespace GeoLib */ enum class EdgeType { - TOUCHING, //!< TOUCHING - CROSSING, //!< CROSSING - INESSENTIAL //!< INESSENTIAL + TOUCHING, //!< TOUCHING + CROSSING, //!< CROSSING + INESSENTIAL //!< INESSENTIAL }; /** @@ -44,104 +44,104 @@ enum class EdgeType class Polygon : public Polyline { public: - /** - * constructor checks if the given polyline is closed, - * and assures that the orientation is clock wise. - * @param ply closed Polyline - * @param init if true, check if polyline is closed, calculate bounding box - */ - Polygon(const Polyline &ply, bool init = true); - - Polygon(Polygon const& other); - Polygon& operator=(Polygon const& rhs) = delete; - - virtual ~Polygon(); - - bool initialise (); - - /** - * Method checks if the given point is inside the polygon. - * The method requires that the polygon has clock wise orientation. - * @param pnt the Point - * @return if point is inside the polygon true, else false - */ - bool isPntInPolygon (const GeoLib::Point& pnt) const; - /** - * wrapper for method isPntInPolygon (const GeoLib::Point&) - * @param x x coordinate of point - * @param y y coordinate of point - * @param z z coordinate of point - * @return if point is inside the polygon true, else false - */ - bool isPntInPolygon (double x, double y, double z) const; - - /** - * Checks if the straight line segment is contained within the polygon. - * @param segment the straight line segment that is checked with - * @return true if the straight line segment is within the polygon, else false - */ - bool containsSegment(GeoLib::LineSegment const& segment) const; - - /** - * Method checks if all points of the polyline ply are inside of the polygon. - * @param ply the polyline that should be checked - */ - bool isPolylineInPolygon (const Polyline& ply) const; - /** - * Method checks first if at least one (end!) point of a line segment of the polyline - * is inside of the polygon. If this test fails each line segment of the polyline will - * be tested against each polygon segment for intersection. - * @param ply the polyline that should be checked - * @return true if a part of the polyline is within the polygon - */ - bool isPartOfPolylineInPolygon (const Polyline& ply) const; - - /** - * Calculates the next intersection point between the line segment \c seg - * and the polygon starting with segment \c seg_num. - * @param seg (input) Line segment to compute intersection. - * @param intersection_pnt (output) next intersection point - * @param seg_num (in/out) the number of the polygon segment that is intersecting - * @return true, if there was an intersection, i.e., the \c intersection_pnt - * and \c seg_num contains new valid values - */ - bool getNextIntersectionPointPolygonLine(GeoLib::LineSegment const& seg, - GeoLib::Point& intersection_pnt, - std::size_t& seg_num) const; - - void computeListOfSimplePolygons (); - const std::list<Polygon*>& getListOfSimplePolygons (); - - friend bool operator==(Polygon const& lhs, Polygon const& rhs); + /** + * constructor checks if the given polyline is closed, + * and assures that the orientation is clock wise. + * @param ply closed Polyline + * @param init if true, check if polyline is closed, calculate bounding box + */ + Polygon(const Polyline &ply, bool init = true); + + Polygon(Polygon const& other); + Polygon& operator=(Polygon const& rhs) = delete; + + virtual ~Polygon(); + + bool initialise (); + + /** + * Method checks if the given point is inside the polygon. + * The method requires that the polygon has clock wise orientation. + * @param pnt the Point + * @return if point is inside the polygon true, else false + */ + bool isPntInPolygon (const GeoLib::Point& pnt) const; + /** + * wrapper for method isPntInPolygon (const GeoLib::Point&) + * @param x x coordinate of point + * @param y y coordinate of point + * @param z z coordinate of point + * @return if point is inside the polygon true, else false + */ + bool isPntInPolygon (double x, double y, double z) const; + + /** + * Checks if the straight line segment is contained within the polygon. + * @param segment the straight line segment that is checked with + * @return true if the straight line segment is within the polygon, else false + */ + bool containsSegment(GeoLib::LineSegment const& segment) const; + + /** + * Method checks if all points of the polyline ply are inside of the polygon. + * @param ply the polyline that should be checked + */ + bool isPolylineInPolygon (const Polyline& ply) const; + /** + * Method checks first if at least one (end!) point of a line segment of the polyline + * is inside of the polygon. If this test fails each line segment of the polyline will + * be tested against each polygon segment for intersection. + * @param ply the polyline that should be checked + * @return true if a part of the polyline is within the polygon + */ + bool isPartOfPolylineInPolygon (const Polyline& ply) const; + + /** + * Calculates the next intersection point between the line segment \c seg + * and the polygon starting with segment \c seg_num. + * @param seg (input) Line segment to compute intersection. + * @param intersection_pnt (output) next intersection point + * @param seg_num (in/out) the number of the polygon segment that is intersecting + * @return true, if there was an intersection, i.e., the \c intersection_pnt + * and \c seg_num contains new valid values + */ + bool getNextIntersectionPointPolygonLine(GeoLib::LineSegment const& seg, + GeoLib::Point& intersection_pnt, + std::size_t& seg_num) const; + + void computeListOfSimplePolygons (); + const std::list<Polygon*>& getListOfSimplePolygons (); + + friend bool operator==(Polygon const& lhs, Polygon const& rhs); private: - /** - * Computes all intersections of the straight line segment and the polyline boundary - * @param segment the line segment that will be processed - * @return a possible empty vector containing the intersection points - */ - std::vector<GeoLib::Point> getAllIntersectionPoints( - GeoLib::LineSegment const& segment) const; - - /** - * from book: Computational Geometry and Computer Graphics in C++, page 119 - * get the type of edge with respect to the given point (2d method!) - * @param k number of line segment - * @param pnt point that is edge type computed for - * @return a value of enum EdgeType - */ - EdgeType getEdgeType (std::size_t k, GeoLib::Point const & pnt) const; - - void ensureCWOrientation (); + /** + * Computes all intersections of the straight line segment and the polyline boundary + * @param segment the line segment that will be processed + * @return a possible empty vector containing the intersection points + */ + std::vector<GeoLib::Point> getAllIntersectionPoints( + GeoLib::LineSegment const& segment) const; + + /** + * from book: Computational Geometry and Computer Graphics in C++, page 119 + * get the type of edge with respect to the given point (2d method!) + * @param k number of line segment + * @param pnt point that is edge type computed for + * @return a value of enum EdgeType + */ + EdgeType getEdgeType (std::size_t k, GeoLib::Point const & pnt) const; + + void ensureCWOrientation (); #if __GNUC__ <= 4 && (__GNUC_MINOR__ < 9) - void splitPolygonAtIntersection(std::list<Polygon*>::iterator polygon_it); + void splitPolygonAtIntersection(std::list<Polygon*>::iterator polygon_it); #else - void splitPolygonAtIntersection( - std::list<Polygon*>::const_iterator polygon_it); + void splitPolygonAtIntersection( + std::list<Polygon*>::const_iterator polygon_it); #endif - void splitPolygonAtPoint (std::list<Polygon*>::iterator polygon_it); - std::list<Polygon*> _simple_polygon_list; - AABB _aabb; + void splitPolygonAtPoint (std::list<Polygon*>::iterator polygon_it); + std::list<Polygon*> _simple_polygon_list; + AABB _aabb; }; /** diff --git a/GeoLib/Polyline.cpp b/GeoLib/Polyline.cpp index 25a5d26fed7be6a28693c947efe4d6add3601058..6222675de0aba559f76d0b2fcd797af07d0feb96 100644 --- a/GeoLib/Polyline.cpp +++ b/GeoLib/Polyline.cpp @@ -23,9 +23,9 @@ namespace GeoLib { Polyline::Polyline(const std::vector<Point*>& pnt_vec) : - GeoObject(), _ply_pnts(pnt_vec) + GeoObject(), _ply_pnts(pnt_vec) { - _length.push_back (0.0); + _length.push_back (0.0); } Polyline::Polyline(const Polyline& ply) @@ -37,413 +37,413 @@ Polyline::Polyline(const Polyline& ply) void Polyline::write(std::ostream &os) const { - std::size_t size(_ply_pnt_ids.size()); - for (std::size_t k(0); k < size; k++) - os << *(_ply_pnts[_ply_pnt_ids[k]]) << "\n"; + std::size_t size(_ply_pnt_ids.size()); + for (std::size_t k(0); k < size; k++) + os << *(_ply_pnts[_ply_pnt_ids[k]]) << "\n"; } void Polyline::addPoint(std::size_t pnt_id) { - assert(pnt_id < _ply_pnts.size()); - std::size_t n_pnts (_ply_pnt_ids.size()); + assert(pnt_id < _ply_pnts.size()); + std::size_t n_pnts (_ply_pnt_ids.size()); - // don't insert point if this would result in identical IDs for two adjacent points - if (n_pnts > 0 && _ply_pnt_ids[n_pnts - 1] == pnt_id) - return; + // don't insert point if this would result in identical IDs for two adjacent points + if (n_pnts > 0 && _ply_pnt_ids[n_pnts - 1] == pnt_id) + return; - _ply_pnt_ids.push_back(pnt_id); + _ply_pnt_ids.push_back(pnt_id); - if (n_pnts > 0) - { - double act_dist (std::sqrt(MathLib::sqrDist (*_ply_pnts[_ply_pnt_ids[n_pnts - 1]], - *_ply_pnts[pnt_id]))); - double dist_until_now (0.0); - if (n_pnts > 1) - dist_until_now = _length[n_pnts - 1]; + if (n_pnts > 0) + { + double act_dist (std::sqrt(MathLib::sqrDist (*_ply_pnts[_ply_pnt_ids[n_pnts - 1]], + *_ply_pnts[pnt_id]))); + double dist_until_now (0.0); + if (n_pnts > 1) + dist_until_now = _length[n_pnts - 1]; - _length.push_back (dist_until_now + act_dist); - } + _length.push_back (dist_until_now + act_dist); + } } void Polyline::insertPoint(std::size_t pos, std::size_t pnt_id) { - assert(pnt_id < _ply_pnts.size()); - assert(pos <= _ply_pnt_ids.size()); - - if (pos == _ply_pnt_ids.size()) { - addPoint(pnt_id); - return; - } - - // check if inserting pnt_id would result in two identical IDs for adjacent points - if (pos == 0 && pnt_id == _ply_pnt_ids[0]) { - return; - } else { - if (pos != 0) { - if (pos == (_ply_pnt_ids.size() - 1) && pnt_id == _ply_pnt_ids[pos]) { - return; - } else { - if (pnt_id == _ply_pnt_ids[pos - 1] || pnt_id == _ply_pnt_ids[pos]) { - return; - } - } - } - } - - std::vector<std::size_t>::difference_type const pos_dt( - static_cast<std::vector<std::size_t>::difference_type>(pos)); - std::vector<std::size_t>::iterator it(_ply_pnt_ids.begin() + pos_dt); - _ply_pnt_ids.insert(it, pnt_id); - - if (_ply_pnt_ids.size() > 1) { - // update the _length vector - if (pos == 0) { - // insert at first position - double act_dist(std::sqrt(MathLib::sqrDist(*_ply_pnts[_ply_pnt_ids[1]], - *_ply_pnts[pnt_id]))); - _length.insert(_length.begin() + 1, act_dist); - const std::size_t s(_length.size()); - for (std::size_t k(2); k < s; k++) - _length[k] += _length[1]; - } else { - if (pos == _ply_pnt_ids.size() - 1) { - // insert at last position - double act_dist(std::sqrt(MathLib::sqrDist( - *_ply_pnts[_ply_pnt_ids[_ply_pnt_ids.size() - 2]], - *_ply_pnts[pnt_id]))); - double dist_until_now (0.0); - if (_ply_pnt_ids.size() > 2) - dist_until_now = _length[_ply_pnt_ids.size() - 2]; - - _length.insert(_length.begin() + pos_dt, - dist_until_now + act_dist); - } else { - // insert at arbitrary position within the vector - double dist_until_now (0.0); - if (pos > 1) - dist_until_now = _length[pos - 1]; - double len_seg0(std::sqrt(MathLib::sqrDist( - *_ply_pnts[_ply_pnt_ids[pos - 1]], - *_ply_pnts[pnt_id]))); - double len_seg1(std::sqrt(MathLib::sqrDist( - *_ply_pnts[_ply_pnt_ids[pos + 1]], - *_ply_pnts[pnt_id]))); - double update_dist( - len_seg0 + len_seg1 - (_length[pos] - dist_until_now)); - _length[pos] = dist_until_now + len_seg0; - std::vector<double>::iterator it1(_length.begin() + pos_dt + 1); - _length.insert(it1, _length[pos] + len_seg1); - for (it1 = _length.begin() + pos_dt + 2; it1 != _length.end(); - ++it1) - *it1 += update_dist; - } - } - } + assert(pnt_id < _ply_pnts.size()); + assert(pos <= _ply_pnt_ids.size()); + + if (pos == _ply_pnt_ids.size()) { + addPoint(pnt_id); + return; + } + + // check if inserting pnt_id would result in two identical IDs for adjacent points + if (pos == 0 && pnt_id == _ply_pnt_ids[0]) { + return; + } else { + if (pos != 0) { + if (pos == (_ply_pnt_ids.size() - 1) && pnt_id == _ply_pnt_ids[pos]) { + return; + } else { + if (pnt_id == _ply_pnt_ids[pos - 1] || pnt_id == _ply_pnt_ids[pos]) { + return; + } + } + } + } + + std::vector<std::size_t>::difference_type const pos_dt( + static_cast<std::vector<std::size_t>::difference_type>(pos)); + std::vector<std::size_t>::iterator it(_ply_pnt_ids.begin() + pos_dt); + _ply_pnt_ids.insert(it, pnt_id); + + if (_ply_pnt_ids.size() > 1) { + // update the _length vector + if (pos == 0) { + // insert at first position + double act_dist(std::sqrt(MathLib::sqrDist(*_ply_pnts[_ply_pnt_ids[1]], + *_ply_pnts[pnt_id]))); + _length.insert(_length.begin() + 1, act_dist); + const std::size_t s(_length.size()); + for (std::size_t k(2); k < s; k++) + _length[k] += _length[1]; + } else { + if (pos == _ply_pnt_ids.size() - 1) { + // insert at last position + double act_dist(std::sqrt(MathLib::sqrDist( + *_ply_pnts[_ply_pnt_ids[_ply_pnt_ids.size() - 2]], + *_ply_pnts[pnt_id]))); + double dist_until_now (0.0); + if (_ply_pnt_ids.size() > 2) + dist_until_now = _length[_ply_pnt_ids.size() - 2]; + + _length.insert(_length.begin() + pos_dt, + dist_until_now + act_dist); + } else { + // insert at arbitrary position within the vector + double dist_until_now (0.0); + if (pos > 1) + dist_until_now = _length[pos - 1]; + double len_seg0(std::sqrt(MathLib::sqrDist( + *_ply_pnts[_ply_pnt_ids[pos - 1]], + *_ply_pnts[pnt_id]))); + double len_seg1(std::sqrt(MathLib::sqrDist( + *_ply_pnts[_ply_pnt_ids[pos + 1]], + *_ply_pnts[pnt_id]))); + double update_dist( + len_seg0 + len_seg1 - (_length[pos] - dist_until_now)); + _length[pos] = dist_until_now + len_seg0; + std::vector<double>::iterator it1(_length.begin() + pos_dt + 1); + _length.insert(it1, _length[pos] + len_seg1); + for (it1 = _length.begin() + pos_dt + 2; it1 != _length.end(); + ++it1) + *it1 += update_dist; + } + } + } } void Polyline::removePoint(std::size_t pos) { - if (pos >= _ply_pnt_ids.size()) - return; - - std::vector<std::size_t>::difference_type const pos_dt( - static_cast<std::vector<std::size_t>::difference_type>(pos)); - _ply_pnt_ids.erase(_ply_pnt_ids.begin() + pos_dt); - - if (pos == _ply_pnt_ids.size()) - { - _length.erase(_length.begin() + pos_dt); - return; - } - - const std::size_t n_ply_pnt_ids(_ply_pnt_ids.size()); - if (pos == 0) { - double seg_length(_length[0]); - for (std::size_t k(0); k < n_ply_pnt_ids; k++) - _length[k] = _length[k + 1] - seg_length; - _length.pop_back(); - } else { - const double len_seg0(_length[pos] - _length[pos - 1]); - const double len_seg1(_length[pos + 1] - _length[pos]); - _length.erase(_length.begin() + pos_dt); - const double len_new_seg(std::sqrt(MathLib::sqrDist(*_ply_pnts[_ply_pnt_ids[pos - 1]], - *_ply_pnts[_ply_pnt_ids[pos]]))); - double seg_length_diff(len_new_seg - len_seg0 - len_seg1); - - for (std::size_t k(pos); k < n_ply_pnt_ids; k++) - _length[k] += seg_length_diff; - } + if (pos >= _ply_pnt_ids.size()) + return; + + std::vector<std::size_t>::difference_type const pos_dt( + static_cast<std::vector<std::size_t>::difference_type>(pos)); + _ply_pnt_ids.erase(_ply_pnt_ids.begin() + pos_dt); + + if (pos == _ply_pnt_ids.size()) + { + _length.erase(_length.begin() + pos_dt); + return; + } + + const std::size_t n_ply_pnt_ids(_ply_pnt_ids.size()); + if (pos == 0) { + double seg_length(_length[0]); + for (std::size_t k(0); k < n_ply_pnt_ids; k++) + _length[k] = _length[k + 1] - seg_length; + _length.pop_back(); + } else { + const double len_seg0(_length[pos] - _length[pos - 1]); + const double len_seg1(_length[pos + 1] - _length[pos]); + _length.erase(_length.begin() + pos_dt); + const double len_new_seg(std::sqrt(MathLib::sqrDist(*_ply_pnts[_ply_pnt_ids[pos - 1]], + *_ply_pnts[_ply_pnt_ids[pos]]))); + double seg_length_diff(len_new_seg - len_seg0 - len_seg1); + + for (std::size_t k(pos); k < n_ply_pnt_ids; k++) + _length[k] += seg_length_diff; + } } std::size_t Polyline::getNumberOfPoints() const { - return _ply_pnt_ids.size(); + return _ply_pnt_ids.size(); } std::size_t Polyline::getNumberOfSegments() const { - return _ply_pnt_ids.empty() ? 0 : _ply_pnt_ids.size()-1; + return _ply_pnt_ids.empty() ? 0 : _ply_pnt_ids.size()-1; } bool Polyline::isClosed() const { - if (_ply_pnt_ids.size() < 3) - return false; + if (_ply_pnt_ids.size() < 3) + return false; - if (_ply_pnt_ids.front() == _ply_pnt_ids.back()) - return true; - else - return false; + if (_ply_pnt_ids.front() == _ply_pnt_ids.back()) + return true; + else + return false; } bool Polyline::isCoplanar() const { - std::size_t const n_points (_ply_pnt_ids.size()); - if (n_points < 4) - return true; + std::size_t const n_points (_ply_pnt_ids.size()); + if (n_points < 4) + return true; - GeoLib::Point const& p0 (*this->getPoint(0)); - GeoLib::Point const& p1 (*this->getPoint(1)); - GeoLib::Point const& p2 (*this->getPoint(2)); - for (std::size_t i=3; i<n_points; ++i) - { - if (!GeoLib::isCoplanar(p0, p1, p2, *this->getPoint(i))) - { - DBUG ("Point %d is not coplanar to the first three points of the line.", i); - return false; - } - } - return true; + GeoLib::Point const& p0 (*this->getPoint(0)); + GeoLib::Point const& p1 (*this->getPoint(1)); + GeoLib::Point const& p2 (*this->getPoint(2)); + for (std::size_t i=3; i<n_points; ++i) + { + if (!GeoLib::isCoplanar(p0, p1, p2, *this->getPoint(i))) + { + DBUG ("Point %d is not coplanar to the first three points of the line.", i); + return false; + } + } + return true; } bool Polyline::isPointIDInPolyline(std::size_t pnt_id) const { - return std::find(_ply_pnt_ids.begin(), _ply_pnt_ids.end(), pnt_id) != _ply_pnt_ids.end(); + return std::find(_ply_pnt_ids.begin(), _ply_pnt_ids.end(), pnt_id) != _ply_pnt_ids.end(); } std::size_t Polyline::getPointID(std::size_t i) const { - assert(i < _ply_pnt_ids.size()); - return _ply_pnt_ids[i]; + assert(i < _ply_pnt_ids.size()); + return _ply_pnt_ids[i]; } LineSegment const Polyline::getSegment(std::size_t i) const { - assert(i < getNumberOfSegments()); - return LineSegment(_ply_pnts[_ply_pnt_ids[i]], - _ply_pnts[_ply_pnt_ids[i + 1]], false); + assert(i < getNumberOfSegments()); + return LineSegment(_ply_pnts[_ply_pnt_ids[i]], + _ply_pnts[_ply_pnt_ids[i + 1]], false); } LineSegment Polyline::getSegment(std::size_t i) { - assert(i < getNumberOfSegments()); - return LineSegment(_ply_pnts[_ply_pnt_ids[i]], - _ply_pnts[_ply_pnt_ids[i + 1]], false); + assert(i < getNumberOfSegments()); + return LineSegment(_ply_pnts[_ply_pnt_ids[i]], + _ply_pnts[_ply_pnt_ids[i + 1]], false); } void Polyline::setPointID(std::size_t idx, std::size_t id) { - assert(idx < _ply_pnt_ids.size()); - _ply_pnt_ids[idx] = id; + assert(idx < _ply_pnt_ids.size()); + _ply_pnt_ids[idx] = id; } const Point* Polyline::getPoint(std::size_t i) const { - assert(i < _ply_pnt_ids.size()); - return _ply_pnts[_ply_pnt_ids[i]]; + assert(i < _ply_pnt_ids.size()); + return _ply_pnts[_ply_pnt_ids[i]]; } std::vector<Point*> const& Polyline::getPointsVec () const { - return _ply_pnts; + return _ply_pnts; } double Polyline::getLength (std::size_t k) const { - assert(k < _length.size()); - return _length[k]; + assert(k < _length.size()); + return _length[k]; } Polyline* Polyline::constructPolylineFromSegments(const std::vector<Polyline*> &ply_vec, double prox) { - std::size_t nLines = ply_vec.size(); - - Polyline* new_ply = new Polyline(*ply_vec[0]); - std::vector<GeoLib::Point*> pnt_vec(new_ply->getPointsVec()); - - std::vector<Polyline*> local_ply_vec; - for (std::size_t i = 1; i < nLines; i++) - local_ply_vec.push_back(ply_vec[i]); - - while (!local_ply_vec.empty()) - { - bool ply_found(false); - prox *= prox; // square distance once to save time later - for (std::vector<Polyline*>::iterator it = local_ply_vec.begin(); - it != local_ply_vec.end(); ++it) - { - if (pnt_vec == (*it)->getPointsVec()) - { - std::size_t nPoints((*it)->getNumberOfPoints()); - - //if (new_ply->getPointID(0) == (*it)->getPointID(0)) - if (pointsAreIdentical(pnt_vec, new_ply->getPointID(0), - (*it)->getPointID(0), prox)) - { - Polyline* tmp = new Polyline((*it)->getPointsVec()); - for (std::size_t k = 0; k < nPoints; k++) - tmp->addPoint((*it)->getPointID(nPoints - k - 1)); - - std::size_t new_ply_size(new_ply->getNumberOfPoints()); - for (std::size_t k = 1; k < new_ply_size; k++) - tmp->addPoint(new_ply->getPointID(k)); - delete new_ply; - new_ply = tmp; - ply_found = true; - } - //else if (new_ply->getPointID(0) == (*it)->getPointID(nPoints-1)) - else if (pointsAreIdentical(pnt_vec, new_ply->getPointID(0), - (*it)->getPointID(nPoints - 1), prox)) - { - Polyline* tmp = new Polyline(**it); - std::size_t new_ply_size(new_ply->getNumberOfPoints()); - for (std::size_t k = 1; k < new_ply_size; k++) - tmp->addPoint(new_ply->getPointID(k)); - delete new_ply; - new_ply = tmp; - ply_found = true; - } - //else if (new_ply->getPointID(new_ply->getNumberOfPoints()-1) == (*it)->getPointID(0)) - else if (pointsAreIdentical(pnt_vec, - new_ply->getPointID(new_ply-> - getNumberOfPoints() - - 1), - (*it)->getPointID(0), prox)) - { - for (std::size_t k = 1; k < nPoints; k++) - new_ply->addPoint((*it)->getPointID(k)); - ply_found = true; - } - //else if (new_ply->getPointID(new_ply->getNumberOfPoints()-1) == (*it)->getPointID(nPoints-1)) - else if (pointsAreIdentical(pnt_vec, - new_ply->getPointID(new_ply-> - getNumberOfPoints() - - 1), - (*it)->getPointID(nPoints - 1), prox)) - { - for (std::size_t k = 1; k < nPoints; k++) - new_ply->addPoint((*it)->getPointID(nPoints - k - 1)); - ply_found = true; - } - if (ply_found) - { - local_ply_vec.erase(it); - break; - } - } - else - ERR("Error in Polyline::contructPolylineFromSegments() - Line segments use different point vectors."); - } - - if (!ply_found) - { - ERR("Error in Polyline::contructPolylineFromSegments() - Not all segments are connected."); - new_ply = nullptr; - break; - } - } - return new_ply; + std::size_t nLines = ply_vec.size(); + + Polyline* new_ply = new Polyline(*ply_vec[0]); + std::vector<GeoLib::Point*> pnt_vec(new_ply->getPointsVec()); + + std::vector<Polyline*> local_ply_vec; + for (std::size_t i = 1; i < nLines; i++) + local_ply_vec.push_back(ply_vec[i]); + + while (!local_ply_vec.empty()) + { + bool ply_found(false); + prox *= prox; // square distance once to save time later + for (std::vector<Polyline*>::iterator it = local_ply_vec.begin(); + it != local_ply_vec.end(); ++it) + { + if (pnt_vec == (*it)->getPointsVec()) + { + std::size_t nPoints((*it)->getNumberOfPoints()); + + //if (new_ply->getPointID(0) == (*it)->getPointID(0)) + if (pointsAreIdentical(pnt_vec, new_ply->getPointID(0), + (*it)->getPointID(0), prox)) + { + Polyline* tmp = new Polyline((*it)->getPointsVec()); + for (std::size_t k = 0; k < nPoints; k++) + tmp->addPoint((*it)->getPointID(nPoints - k - 1)); + + std::size_t new_ply_size(new_ply->getNumberOfPoints()); + for (std::size_t k = 1; k < new_ply_size; k++) + tmp->addPoint(new_ply->getPointID(k)); + delete new_ply; + new_ply = tmp; + ply_found = true; + } + //else if (new_ply->getPointID(0) == (*it)->getPointID(nPoints-1)) + else if (pointsAreIdentical(pnt_vec, new_ply->getPointID(0), + (*it)->getPointID(nPoints - 1), prox)) + { + Polyline* tmp = new Polyline(**it); + std::size_t new_ply_size(new_ply->getNumberOfPoints()); + for (std::size_t k = 1; k < new_ply_size; k++) + tmp->addPoint(new_ply->getPointID(k)); + delete new_ply; + new_ply = tmp; + ply_found = true; + } + //else if (new_ply->getPointID(new_ply->getNumberOfPoints()-1) == (*it)->getPointID(0)) + else if (pointsAreIdentical(pnt_vec, + new_ply->getPointID(new_ply-> + getNumberOfPoints() + - 1), + (*it)->getPointID(0), prox)) + { + for (std::size_t k = 1; k < nPoints; k++) + new_ply->addPoint((*it)->getPointID(k)); + ply_found = true; + } + //else if (new_ply->getPointID(new_ply->getNumberOfPoints()-1) == (*it)->getPointID(nPoints-1)) + else if (pointsAreIdentical(pnt_vec, + new_ply->getPointID(new_ply-> + getNumberOfPoints() + - 1), + (*it)->getPointID(nPoints - 1), prox)) + { + for (std::size_t k = 1; k < nPoints; k++) + new_ply->addPoint((*it)->getPointID(nPoints - k - 1)); + ply_found = true; + } + if (ply_found) + { + local_ply_vec.erase(it); + break; + } + } + else + ERR("Error in Polyline::contructPolylineFromSegments() - Line segments use different point vectors."); + } + + if (!ply_found) + { + ERR("Error in Polyline::contructPolylineFromSegments() - Not all segments are connected."); + new_ply = nullptr; + break; + } + } + return new_ply; } void Polyline::closePolyline() { - if (getNumberOfPoints() < 2) { - ERR("Polyline::closePolyline(): Input polyline needs to be composed of at least three points."); - } - if (! isClosed()) { - addPoint(getPointID(0)); - } + if (getNumberOfPoints() < 2) { + ERR("Polyline::closePolyline(): Input polyline needs to be composed of at least three points."); + } + if (! isClosed()) { + addPoint(getPointID(0)); + } } Location Polyline::getLocationOfPoint (std::size_t k, GeoLib::Point const & pnt) const { - assert (k < _ply_pnt_ids.size() - 1); - - GeoLib::Point const& source (*(_ply_pnts[_ply_pnt_ids[k]])); - GeoLib::Point const& dest (*(_ply_pnts[_ply_pnt_ids[k + 1]])); - long double a[2] = {dest[0] - source[0], dest[1] - source[1]}; // vector - long double b[2] = {pnt[0] - source[0], pnt[1] - source[1]}; // vector - - long double det_2x2 (a[0] * b[1] - a[1] * b[0]); - - if (det_2x2 > std::numeric_limits<double>::epsilon()) - return Location::LEFT; - if (std::numeric_limits<double>::epsilon() < std::abs(det_2x2)) - return Location::RIGHT; - if (a[0] * b[0] < 0.0 || a[1] * b[1] < 0.0) - return Location::BEHIND; - if (a[0] * a[0] + a[1] * a[1] < b[0] * b[0] + b[1] * b[1]) - return Location::BEYOND; - if (MathLib::sqrDist (pnt, - *_ply_pnts[_ply_pnt_ids[k]]) < pow(std::numeric_limits<double>::epsilon(),2)) - return Location::SOURCE; - if (MathLib::sqrDist (pnt, - *_ply_pnts[_ply_pnt_ids[k + 1]]) < - std::sqrt(std::numeric_limits<double>::epsilon())) - return Location::DESTINATION; - return Location::BETWEEN; + assert (k < _ply_pnt_ids.size() - 1); + + GeoLib::Point const& source (*(_ply_pnts[_ply_pnt_ids[k]])); + GeoLib::Point const& dest (*(_ply_pnts[_ply_pnt_ids[k + 1]])); + long double a[2] = {dest[0] - source[0], dest[1] - source[1]}; // vector + long double b[2] = {pnt[0] - source[0], pnt[1] - source[1]}; // vector + + long double det_2x2 (a[0] * b[1] - a[1] * b[0]); + + if (det_2x2 > std::numeric_limits<double>::epsilon()) + return Location::LEFT; + if (std::numeric_limits<double>::epsilon() < std::abs(det_2x2)) + return Location::RIGHT; + if (a[0] * b[0] < 0.0 || a[1] * b[1] < 0.0) + return Location::BEHIND; + if (a[0] * a[0] + a[1] * a[1] < b[0] * b[0] + b[1] * b[1]) + return Location::BEYOND; + if (MathLib::sqrDist (pnt, + *_ply_pnts[_ply_pnt_ids[k]]) < pow(std::numeric_limits<double>::epsilon(),2)) + return Location::SOURCE; + if (MathLib::sqrDist (pnt, + *_ply_pnts[_ply_pnt_ids[k + 1]]) < + std::sqrt(std::numeric_limits<double>::epsilon())) + return Location::DESTINATION; + return Location::BETWEEN; } void Polyline::updatePointIDs(const std::vector<std::size_t> &pnt_ids) { - for (auto it = this->_ply_pnt_ids.begin(); it!=this->_ply_pnt_ids.end();) - { - if (pnt_ids[*it] != *it) - { - if (it!=this->_ply_pnt_ids.begin() && (pnt_ids[*it] == pnt_ids[*(it-1)])) - it = this->_ply_pnt_ids.erase(it); - else - { - *it = pnt_ids[*it]; - ++it; - } - } - else - ++it; - } + for (auto it = this->_ply_pnt_ids.begin(); it!=this->_ply_pnt_ids.end();) + { + if (pnt_ids[*it] != *it) + { + if (it!=this->_ply_pnt_ids.begin() && (pnt_ids[*it] == pnt_ids[*(it-1)])) + it = this->_ply_pnt_ids.erase(it); + else + { + *it = pnt_ids[*it]; + ++it; + } + } + else + ++it; + } } double Polyline::getDistanceAlongPolyline(const MathLib::Point3d& pnt, - const double epsilon_radius) const -{ - double dist(-1.0), lambda; - bool found = false; - // loop over all line segments of the polyline - for (std::size_t k = 0; k < getNumberOfPoints() - 1; k++) { - // is the orthogonal projection of the j-th node to the - // line g(lambda) = _ply->getPoint(k) + lambda * (_ply->getPoint(k+1) - _ply->getPoint(k)) - // at the k-th line segment of the polyline, i.e. 0 <= lambda <= 1? - if (MathLib::calcProjPntToLineAndDists(pnt.getCoords(), - (getPoint(k))->getCoords(), (getPoint(k + 1))->getCoords(), - lambda, dist) <= epsilon_radius) { - - double act_length_of_ply(getLength(k)); - double seg_length (getLength(k+1)-getLength(k)); - double lower_lambda (- epsilon_radius / seg_length); - double upper_lambda (1 + epsilon_radius / seg_length); - - if (lower_lambda <= lambda && lambda <= upper_lambda) { - found = true; - dist = act_length_of_ply + dist; - break; - } // end if lambda - } - } // end line segment loop - - if (! found) - dist = -1.0; - return dist; + const double epsilon_radius) const +{ + double dist(-1.0), lambda; + bool found = false; + // loop over all line segments of the polyline + for (std::size_t k = 0; k < getNumberOfPoints() - 1; k++) { + // is the orthogonal projection of the j-th node to the + // line g(lambda) = _ply->getPoint(k) + lambda * (_ply->getPoint(k+1) - _ply->getPoint(k)) + // at the k-th line segment of the polyline, i.e. 0 <= lambda <= 1? + if (MathLib::calcProjPntToLineAndDists(pnt.getCoords(), + (getPoint(k))->getCoords(), (getPoint(k + 1))->getCoords(), + lambda, dist) <= epsilon_radius) { + + double act_length_of_ply(getLength(k)); + double seg_length (getLength(k+1)-getLength(k)); + double lower_lambda (- epsilon_radius / seg_length); + double upper_lambda (1 + epsilon_radius / seg_length); + + if (lower_lambda <= lambda && lambda <= upper_lambda) { + found = true; + dist = act_length_of_ply + dist; + break; + } // end if lambda + } + } // end line segment loop + + if (! found) + dist = -1.0; + return dist; } Polyline::SegmentIterator::SegmentIterator(Polyline const& polyline, @@ -460,131 +460,131 @@ Polyline::SegmentIterator::SegmentIterator(SegmentIterator const& src) Polyline::SegmentIterator& Polyline::SegmentIterator::operator=( SegmentIterator const& rhs) { - if (&rhs == this) - return *this; + if (&rhs == this) + return *this; - _polyline = rhs._polyline; - _segment_number = rhs._segment_number; - return *this; + _polyline = rhs._polyline; + _segment_number = rhs._segment_number; + return *this; } std::size_t Polyline::SegmentIterator::getSegmentNumber() const { - return static_cast<std::size_t>(_segment_number); + return static_cast<std::size_t>(_segment_number); } Polyline::SegmentIterator& Polyline::SegmentIterator::operator++() { - ++_segment_number; - return *this; + ++_segment_number; + return *this; } LineSegment const Polyline::SegmentIterator::operator*() const { - return _polyline->getSegment(_segment_number); + return _polyline->getSegment(_segment_number); } LineSegment Polyline::SegmentIterator::operator*() { - return _polyline->getSegment(_segment_number); + return _polyline->getSegment(_segment_number); } bool Polyline::SegmentIterator::operator==(SegmentIterator const& other) { - return !(*this != other); + return !(*this != other); } bool Polyline::SegmentIterator::operator!=(SegmentIterator const& other) { - return other._segment_number != _segment_number || - other._polyline != _polyline; + return other._segment_number != _segment_number || + other._polyline != _polyline; } Polyline::SegmentIterator& Polyline::SegmentIterator::operator+=( std::vector<GeoLib::Point>::difference_type n) { - if (n < 0) { - _segment_number -= - static_cast<std::vector<GeoLib::Point>::size_type>(-n); - } else { - _segment_number += - static_cast<std::vector<GeoLib::Point>::size_type>(n); - } - if (_segment_number > _polyline->getNumberOfSegments()) - std::abort(); - return *this; + if (n < 0) { + _segment_number -= + static_cast<std::vector<GeoLib::Point>::size_type>(-n); + } else { + _segment_number += + static_cast<std::vector<GeoLib::Point>::size_type>(n); + } + if (_segment_number > _polyline->getNumberOfSegments()) + std::abort(); + return *this; } Polyline::SegmentIterator Polyline::SegmentIterator::operator+( std::vector<GeoLib::Point>::difference_type n) { - SegmentIterator t(*this); - t += n; - return t; + SegmentIterator t(*this); + t += n; + return t; } Polyline::SegmentIterator& Polyline::SegmentIterator::operator-=( std::vector<GeoLib::Point>::difference_type n) { - if (n >= 0) { - _segment_number -= - static_cast<std::vector<GeoLib::Point>::size_type>(n); - } else { - _segment_number += - static_cast<std::vector<GeoLib::Point>::size_type>(-n); - } - if (_segment_number > _polyline->getNumberOfSegments()) - std::abort(); - return *this; + if (n >= 0) { + _segment_number -= + static_cast<std::vector<GeoLib::Point>::size_type>(n); + } else { + _segment_number += + static_cast<std::vector<GeoLib::Point>::size_type>(-n); + } + if (_segment_number > _polyline->getNumberOfSegments()) + std::abort(); + return *this; } Polyline::SegmentIterator Polyline::SegmentIterator::operator-( std::vector<GeoLib::Point>::difference_type n) { - Polyline::SegmentIterator t(*this); - t -= n; - return t; + Polyline::SegmentIterator t(*this); + t -= n; + return t; } std::ostream& operator<< (std::ostream &os, const Polyline &pl) { - pl.write (os); - return os; + pl.write (os); + return os; } bool containsEdge (const Polyline& ply, std::size_t id0, std::size_t id1) { - if (id0 == id1) - { - ERR("no valid edge id0 == id1 == %d.", id0); - return false; - } - if (id0 > id1) - std::swap (id0,id1); - const std::size_t n (ply.getNumberOfPoints() - 1); - for (std::size_t k(0); k < n; k++) - { - std::size_t ply_pnt0 (ply.getPointID (k)); - std::size_t ply_pnt1 (ply.getPointID (k + 1)); - if (ply_pnt0 > ply_pnt1) - std::swap (ply_pnt0, ply_pnt1); - if (ply_pnt0 == id0 && ply_pnt1 == id1) - return true; - } - return false; + if (id0 == id1) + { + ERR("no valid edge id0 == id1 == %d.", id0); + return false; + } + if (id0 > id1) + std::swap (id0,id1); + const std::size_t n (ply.getNumberOfPoints() - 1); + for (std::size_t k(0); k < n; k++) + { + std::size_t ply_pnt0 (ply.getPointID (k)); + std::size_t ply_pnt1 (ply.getPointID (k + 1)); + if (ply_pnt0 > ply_pnt1) + std::swap (ply_pnt0, ply_pnt1); + if (ply_pnt0 == id0 && ply_pnt1 == id1) + return true; + } + return false; } bool operator==(Polyline const& lhs, Polyline const& rhs) { - if (lhs.getNumberOfPoints() != rhs.getNumberOfPoints()) - return false; + if (lhs.getNumberOfPoints() != rhs.getNumberOfPoints()) + return false; - const std::size_t n(lhs.getNumberOfPoints()); - for (std::size_t k(0); k < n; k++) - if (lhs.getPointID(k) != rhs.getPointID(k)) - return false; + const std::size_t n(lhs.getNumberOfPoints()); + for (std::size_t k(0); k < n; k++) + if (lhs.getPointID(k) != rhs.getPointID(k)) + return false; - return true; + return true; } bool pointsAreIdentical(const std::vector<Point*> &pnt_vec, @@ -592,8 +592,8 @@ bool pointsAreIdentical(const std::vector<Point*> &pnt_vec, std::size_t j, double prox) { - if (i == j) - return true; - return MathLib::sqrDist(*pnt_vec[i], *pnt_vec[j]) < prox; + if (i == j) + return true; + return MathLib::sqrDist(*pnt_vec[i], *pnt_vec[j]) < prox; } } // end namespace GeoLib diff --git a/GeoLib/Polyline.h b/GeoLib/Polyline.h index de6c831c5955bed2b3078add2d8797af79470f33..d022a507b1e18ab9124291341374a40d5bc9840a 100644 --- a/GeoLib/Polyline.h +++ b/GeoLib/Polyline.h @@ -30,13 +30,13 @@ namespace GeoLib { enum class Location { - LEFT, - RIGHT, - BEYOND, - BEHIND, - BETWEEN, - SOURCE, - DESTINATION + LEFT, + RIGHT, + BEYOND, + BEHIND, + BETWEEN, + SOURCE, + DESTINATION }; /** @@ -51,192 +51,192 @@ enum class Location class Polyline : public GeoObject { public: - class SegmentIterator final - : public std::iterator<std::forward_iterator_tag, LineSegment> - { - public: - explicit SegmentIterator(Polyline const& polyline, - std::size_t segment_number); + class SegmentIterator final + : public std::iterator<std::forward_iterator_tag, LineSegment> + { + public: + explicit SegmentIterator(Polyline const& polyline, + std::size_t segment_number); - SegmentIterator(SegmentIterator const& src); + SegmentIterator(SegmentIterator const& src); - SegmentIterator() = delete; - ~SegmentIterator() = default; + SegmentIterator() = delete; + ~SegmentIterator() = default; - SegmentIterator& operator=(SegmentIterator const& rhs); + SegmentIterator& operator=(SegmentIterator const& rhs); - std::size_t getSegmentNumber() const; + std::size_t getSegmentNumber() const; - SegmentIterator& operator++(); + SegmentIterator& operator++(); - LineSegment const operator*() const; + LineSegment const operator*() const; - LineSegment operator*(); + LineSegment operator*(); - bool operator==(SegmentIterator const& other); + bool operator==(SegmentIterator const& other); - bool operator!=(SegmentIterator const& other); + bool operator!=(SegmentIterator const& other); - SegmentIterator& operator+=(std::vector<GeoLib::Point>::difference_type n); + SegmentIterator& operator+=(std::vector<GeoLib::Point>::difference_type n); - SegmentIterator operator+(std::vector<GeoLib::Point>::difference_type n); + SegmentIterator operator+(std::vector<GeoLib::Point>::difference_type n); - SegmentIterator& operator-=(std::vector<GeoLib::Point>::difference_type n); - - SegmentIterator operator-(std::vector<GeoLib::Point>::difference_type n); + SegmentIterator& operator-=(std::vector<GeoLib::Point>::difference_type n); + + SegmentIterator operator-(std::vector<GeoLib::Point>::difference_type n); - private: - GeoLib::Polyline const* _polyline; - std::vector<GeoLib::Point*>::size_type _segment_number; - }; + private: + GeoLib::Polyline const* _polyline; + std::vector<GeoLib::Point*>::size_type _segment_number; + }; - friend class Polygon; - /** constructor - * \param pnt_vec a reference to the point vector - */ - Polyline(const std::vector<Point*>& pnt_vec); - /** - * Copy constructor - * @param ply Polyline - */ - Polyline(const Polyline& ply); - Polyline& operator=(Polyline const& other) = delete; - - virtual ~Polyline() {} - - /// return a geometry type - virtual GEOTYPE getGeoType() const {return GEOTYPE::POLYLINE;} - - /** write the points to the stream */ - void write(std::ostream &os) const; - - /** - * Adds an id of a point at the end of the polyline. The id have to be inside - * the (internal) _ply_pnts vector the polyline is based on. - */ - virtual void addPoint(std::size_t pnt_id); - - /** - * Method inserts a new point (that have to be inside the _ply_pnts vector) - * at the given position in the polyline. - * @param pos the position in the polyline, pos have to be a value into the interval [0, number of points) - * @param pnt_id the id of the new point in the vector of points the polyline is based on - */ - virtual void insertPoint(std::size_t pos, std::size_t pnt_id); - - /** - * Method removes a point from the polyline. The connecting line segments will - * be removed and the length of the polyline will be changed. - * @param pos a valid position within the polyline - */ - virtual void removePoint(std::size_t pos); - - /** - * Closes a polyline by adding a line segment that connects start- and end-point. - */ - void closePolyline(); - - /// Update a the PointIDs vector based on given map, e.g. after the corresponding PointVec has changed - void updatePointIDs(const std::vector<std::size_t> &pnt_ids); - - /// Constructs one polyline from a vector of connected polylines. - /// All polylines in this vector need to reference the same point vector. - static Polyline* constructPolylineFromSegments(const std::vector<Polyline*> &ply_vec, - double prox = 0.0); - - /** - * returns the number of points, - * the number of segments is about one smaller - * */ - std::size_t getNumberOfPoints() const; - - std::size_t getNumberOfSegments() const; - - /** returns true if the polyline is closed */ - bool isClosed() const; - - /** returns true if the polyline is coplanar */ - bool isCoplanar() const; - - /** - * Method tests if the given id of a point (within the vector of points the polyline is - * based on) is inside the polyline. - * @param pnt_id the id of the point - * @return true if the point is part of the polyline, else false - */ - bool isPointIDInPolyline(std::size_t pnt_id) const; - - /** - * returns the index of the i-th polyline point - * in the point vector - */ - std::size_t getPointID(std::size_t i) const; - - /** - * Changes a point index for one point in a line - * @param idx Index of point in line - * @param id ID of point in PointVec object - */ - void setPointID(std::size_t idx, std::size_t id); - - /** - * \brief returns the i-th point contained in the polyline - * */ - const Point* getPoint(std::size_t i) const; - - SegmentIterator begin() const - { - return SegmentIterator(*this, 0); - } - - SegmentIterator end() const - { - return SegmentIterator(*this, getNumberOfSegments()); - } - - std::vector<Point*> const& getPointsVec () const; - - /** - * returns the length of the polyline until the k-th line segment - * @param k the k-th line segment - * @return the length of the polyline until the k-th line segment - */ - double getLength (std::size_t k) const; - - /** - * returns the distance along the polyline from the beginning of the polyline - * @param pnt the point on the polyline - * @param epsilon_radius the epsilon - * @return the distance along the polyline between the given point and the beginning of the polyline. - * If the given point is not on the polyine, negative value is returned. - */ - double getDistanceAlongPolyline(const MathLib::Point3d& pnt, - const double epsilon_radius) const; - - friend bool operator==(Polyline const& lhs, Polyline const& rhs); + friend class Polygon; + /** constructor + * \param pnt_vec a reference to the point vector + */ + Polyline(const std::vector<Point*>& pnt_vec); + /** + * Copy constructor + * @param ply Polyline + */ + Polyline(const Polyline& ply); + Polyline& operator=(Polyline const& other) = delete; + + virtual ~Polyline() {} + + /// return a geometry type + virtual GEOTYPE getGeoType() const {return GEOTYPE::POLYLINE;} + + /** write the points to the stream */ + void write(std::ostream &os) const; + + /** + * Adds an id of a point at the end of the polyline. The id have to be inside + * the (internal) _ply_pnts vector the polyline is based on. + */ + virtual void addPoint(std::size_t pnt_id); + + /** + * Method inserts a new point (that have to be inside the _ply_pnts vector) + * at the given position in the polyline. + * @param pos the position in the polyline, pos have to be a value into the interval [0, number of points) + * @param pnt_id the id of the new point in the vector of points the polyline is based on + */ + virtual void insertPoint(std::size_t pos, std::size_t pnt_id); + + /** + * Method removes a point from the polyline. The connecting line segments will + * be removed and the length of the polyline will be changed. + * @param pos a valid position within the polyline + */ + virtual void removePoint(std::size_t pos); + + /** + * Closes a polyline by adding a line segment that connects start- and end-point. + */ + void closePolyline(); + + /// Update a the PointIDs vector based on given map, e.g. after the corresponding PointVec has changed + void updatePointIDs(const std::vector<std::size_t> &pnt_ids); + + /// Constructs one polyline from a vector of connected polylines. + /// All polylines in this vector need to reference the same point vector. + static Polyline* constructPolylineFromSegments(const std::vector<Polyline*> &ply_vec, + double prox = 0.0); + + /** + * returns the number of points, + * the number of segments is about one smaller + * */ + std::size_t getNumberOfPoints() const; + + std::size_t getNumberOfSegments() const; + + /** returns true if the polyline is closed */ + bool isClosed() const; + + /** returns true if the polyline is coplanar */ + bool isCoplanar() const; + + /** + * Method tests if the given id of a point (within the vector of points the polyline is + * based on) is inside the polyline. + * @param pnt_id the id of the point + * @return true if the point is part of the polyline, else false + */ + bool isPointIDInPolyline(std::size_t pnt_id) const; + + /** + * returns the index of the i-th polyline point + * in the point vector + */ + std::size_t getPointID(std::size_t i) const; + + /** + * Changes a point index for one point in a line + * @param idx Index of point in line + * @param id ID of point in PointVec object + */ + void setPointID(std::size_t idx, std::size_t id); + + /** + * \brief returns the i-th point contained in the polyline + * */ + const Point* getPoint(std::size_t i) const; + + SegmentIterator begin() const + { + return SegmentIterator(*this, 0); + } + + SegmentIterator end() const + { + return SegmentIterator(*this, getNumberOfSegments()); + } + + std::vector<Point*> const& getPointsVec () const; + + /** + * returns the length of the polyline until the k-th line segment + * @param k the k-th line segment + * @return the length of the polyline until the k-th line segment + */ + double getLength (std::size_t k) const; + + /** + * returns the distance along the polyline from the beginning of the polyline + * @param pnt the point on the polyline + * @param epsilon_radius the epsilon + * @return the distance along the polyline between the given point and the beginning of the polyline. + * If the given point is not on the polyine, negative value is returned. + */ + double getDistanceAlongPolyline(const MathLib::Point3d& pnt, + const double epsilon_radius) const; + + friend bool operator==(Polyline const& lhs, Polyline const& rhs); protected: - /** - * 2D method - ignores z coordinate. It calculates the location - * of the point relative to the k-th line segment of the polyline. - * (literature reference: - * Computational Geometry and Computer Graphics in C++; Michael J. Laszlo) - * @param k the number of line segment - * @param pnt the point - * @return a value of enum LOCATION - */ - Location getLocationOfPoint (std::size_t k, GeoLib::Point const & pnt) const; - - /** a reference to the vector of pointers to the geometric points */ - const std::vector<Point*> &_ply_pnts; - /** position of pointers to the geometric points */ - std::vector<std::size_t> _ply_pnt_ids; - /** - * the k-th element of the vector contains the length of the polyline until the k-th segment - */ - std::vector<double> _length; + /** + * 2D method - ignores z coordinate. It calculates the location + * of the point relative to the k-th line segment of the polyline. + * (literature reference: + * Computational Geometry and Computer Graphics in C++; Michael J. Laszlo) + * @param k the number of line segment + * @param pnt the point + * @return a value of enum LOCATION + */ + Location getLocationOfPoint (std::size_t k, GeoLib::Point const & pnt) const; + + /** a reference to the vector of pointers to the geometric points */ + const std::vector<Point*> &_ply_pnts; + /** position of pointers to the geometric points */ + std::vector<std::size_t> _ply_pnt_ids; + /** + * the k-th element of the vector contains the length of the polyline until the k-th segment + */ + std::vector<double> _length; private: - LineSegment const getSegment(std::size_t i) const; - LineSegment getSegment(std::size_t i); + LineSegment const getSegment(std::size_t i) const; + LineSegment getSegment(std::size_t i); }; /** overload the output operator for class Polyline */ diff --git a/GeoLib/PolylineWithSegmentMarker.cpp b/GeoLib/PolylineWithSegmentMarker.cpp index 4c86d29c895be1d69bb4c3a6c3fbaf5e4e17f246..51a6929037aef4387d6daa6f0738a7eaa75a9a75 100644 --- a/GeoLib/PolylineWithSegmentMarker.cpp +++ b/GeoLib/PolylineWithSegmentMarker.cpp @@ -17,13 +17,13 @@ namespace GeoLib { PolylineWithSegmentMarker::PolylineWithSegmentMarker(GeoLib::Polyline const& polyline) - : GeoLib::Polyline(polyline) + : GeoLib::Polyline(polyline) { - const std::size_t n_pnts(getNumberOfPoints()); - _marker.resize(n_pnts); - for (std::size_t k(0); k<n_pnts; k++) { - _marker[k] = false; - } + const std::size_t n_pnts(getNumberOfPoints()); + _marker.resize(n_pnts); + for (std::size_t k(0); k<n_pnts; k++) { + _marker[k] = false; + } } PolylineWithSegmentMarker::~PolylineWithSegmentMarker() @@ -32,23 +32,23 @@ PolylineWithSegmentMarker::~PolylineWithSegmentMarker() void PolylineWithSegmentMarker::markSegment(std::size_t seg_num, bool mark_val) { - _marker[seg_num] = mark_val; + _marker[seg_num] = mark_val; } bool PolylineWithSegmentMarker::isSegmentMarked(std::size_t seg_num) const { - return _marker[seg_num]; + return _marker[seg_num]; } void PolylineWithSegmentMarker::addPoint(std::size_t pnt_id) { - Polyline::addPoint(pnt_id); - _marker.push_back(false); + Polyline::addPoint(pnt_id); + _marker.push_back(false); } void PolylineWithSegmentMarker::insertPoint(std::size_t pos, std::size_t pnt_id) { - Polyline::insertPoint(pos, pnt_id); - _marker.insert(_marker.begin()+pos, _marker[pos]); + Polyline::insertPoint(pos, pnt_id); + _marker.insert(_marker.begin()+pos, _marker[pos]); } } // end GeoLib diff --git a/GeoLib/PolylineWithSegmentMarker.h b/GeoLib/PolylineWithSegmentMarker.h index 4f748b9a9e57cd6a400664ded30f64ae148a4459..8f58d1d199dcb4e80b829a4afff1c94c6176f21c 100644 --- a/GeoLib/PolylineWithSegmentMarker.h +++ b/GeoLib/PolylineWithSegmentMarker.h @@ -25,37 +25,37 @@ namespace GeoLib { */ class PolylineWithSegmentMarker: public GeoLib::Polyline { public: - PolylineWithSegmentMarker(GeoLib::Polyline const& polyline); - virtual ~PolylineWithSegmentMarker(); - /** - * Method marks the segment (default mark is true). - * @param seg_num the segment number that should be marked - * @param mark_val the value of the flag (true or false) - */ - void markSegment(std::size_t seg_num, bool mark_val = true); - /** - * Method returns the value of the mark for the given segment. - * @param seg_num segment number - * @return either true if the segment is marked or false else - */ - bool isSegmentMarked(std::size_t seg_num) const; - - /** - * Method calls @see Polyline::addPoint() and initializes the mark of the - * corresponding line segment. - * @see Polyline::addPoint() - */ - virtual void addPoint(std::size_t pnt_id); - - /** - * Method calls the @see Polyline::insertPoint() and initializes the inserted line segment with the same - * value the previous line segment had. - * @see Polyline::insertPoint() - */ - virtual void insertPoint(std::size_t pos, std::size_t pnt_id); + PolylineWithSegmentMarker(GeoLib::Polyline const& polyline); + virtual ~PolylineWithSegmentMarker(); + /** + * Method marks the segment (default mark is true). + * @param seg_num the segment number that should be marked + * @param mark_val the value of the flag (true or false) + */ + void markSegment(std::size_t seg_num, bool mark_val = true); + /** + * Method returns the value of the mark for the given segment. + * @param seg_num segment number + * @return either true if the segment is marked or false else + */ + bool isSegmentMarked(std::size_t seg_num) const; + + /** + * Method calls @see Polyline::addPoint() and initializes the mark of the + * corresponding line segment. + * @see Polyline::addPoint() + */ + virtual void addPoint(std::size_t pnt_id); + + /** + * Method calls the @see Polyline::insertPoint() and initializes the inserted line segment with the same + * value the previous line segment had. + * @see Polyline::insertPoint() + */ + virtual void insertPoint(std::size_t pos, std::size_t pnt_id); private: - std::vector<bool> _marker; + std::vector<bool> _marker; }; } diff --git a/GeoLib/QuadTree.h b/GeoLib/QuadTree.h index 7e8f16403797a31c7e2493929c1b01a48811ad22..bfd5c340bc0236abbde26e776b58330370dc32cc 100644 --- a/GeoLib/QuadTree.h +++ b/GeoLib/QuadTree.h @@ -36,461 +36,461 @@ namespace GeoLib template <typename POINT> class QuadTree { public: - enum class Quadrant { - NE = 0, //!< north east - NW, //!< north west - SW, //!< south west - SE //!< south east - }; - /** - * This is the constructor for class QuadTree. It takes two points - * (lower left and the upper right points). - * @param ll lower left point of the square - * @param ur upper right point of the square - */ - QuadTree(POINT const& ll, POINT const& ur, std::size_t max_points_per_node) : - _father (nullptr), _ll (ll), _ur (ur), _depth (0), _is_leaf (true), - _max_points_per_node (max_points_per_node) - { - assert (_max_points_per_node > 0); - - // init children - for (std::size_t k(0); k < 4; k++) - _children[k] = nullptr; - - if ((_ur[0] - _ll[0]) > (_ur[1] - _ll[1])) - _ur[1] = _ll[1] + _ur[0] - _ll[0]; - else - _ur[0] = _ll[0] + _ur[1] - _ll[1]; - - DBUG("QuadTree(): lower left: (%f,%f,%f), upper right: (%f,%f,%f), depth: %d", _ll[0], _ll[1], _ll[2], _ur[0], _ur[1], _ur[2], _depth); - } - - /** - * destructor - */ - ~QuadTree() - { - for (std::size_t k(0); k < 4; k++) { - delete _children[k]; - } - } - - /** - * This method adds the given point to the quadtree. If necessary, - * the quadtree will be extended. - * @param pnt the point - * @return If the point can be inserted the method returns true, else false. - */ - bool addPoint (POINT const* pnt) - { - if ((*pnt)[0] < _ll[0]) return false; - if ((*pnt)[0] >= _ur[0]) return false; - if ((*pnt)[1] < _ll[1]) return false; - if ((*pnt)[1] >= _ur[1]) return false; - - if (!_is_leaf) { - for (std::size_t k(0); k < 4; k++) { - if (_children[k]->addPoint (pnt)) - return true; - } - return false; - } - - // check if point is already in quadtree - bool pnt_in_quadtree (false); - for (std::size_t k(0); k < _pnts.size() && !pnt_in_quadtree; k++) { - const double v0((*(_pnts[k]))[0] - (*pnt)[0]); - const double v1((*(_pnts[k]))[1] - (*pnt)[1]); - const double sqr_dist (v0*v0 + v1*v1); - if (sqr_dist < std::numeric_limits<double>::epsilon()) - pnt_in_quadtree = true; - } - if (!pnt_in_quadtree) - _pnts.push_back (pnt); - else - return false; - - if (_pnts.size () > _max_points_per_node) - splitNode (); - return true; - } - - /** - * This method balances the quadtree, i.e., it will be inserted nodes - * such that the depth between neighbored leafs is at most one. If you want - * to create a mesh (for instance with GMSH) you can use this method to - * improve the mesh quality. The balance method should be used after - * inserting all points. - */ - void balance () - { - std::list<QuadTree<POINT>*> leaf_list; - getLeafs (leaf_list); - - while (!leaf_list.empty()) - { - QuadTree<POINT>* node (leaf_list.front()); - leaf_list.pop_front (); - - if (node->isLeaf()) - if (needToRefine (node)) - { - node->splitNode (); - leaf_list.push_back (node->getChild(Quadrant::NE)); - leaf_list.push_back (node->getChild(Quadrant::NW)); - leaf_list.push_back (node->getChild(Quadrant::SW)); - leaf_list.push_back (node->getChild(Quadrant::SE)); - - // check if north neighbor has to be refined - QuadTree<POINT>* north_neighbor (node->getNorthNeighbor()); - if (north_neighbor != nullptr) - if (north_neighbor->getDepth() < node->getDepth ()) - if (north_neighbor->isLeaf()) - leaf_list.push_back (north_neighbor); - - // check if west neighbor has to be refined - QuadTree<POINT>* west_neighbor (node->getWestNeighbor()); - if (west_neighbor != nullptr) - if (west_neighbor->getDepth() < node->getDepth ()) - if (west_neighbor->isLeaf()) - leaf_list.push_back (west_neighbor); - - // check if south neighbor has to be refined - QuadTree<POINT>* south_neighbor (node->getSouthNeighbor()); - if (south_neighbor != nullptr) - if (south_neighbor->getDepth() < node->getDepth ()) - if (south_neighbor->isLeaf()) - leaf_list.push_back (south_neighbor); - - // check if east neighbor has to be refined - QuadTree<POINT>* east_neighbor (node->getEastNeighbor()); - if (east_neighbor != nullptr) - if (east_neighbor->getDepth() < node->getDepth ()) - if (east_neighbor->isLeaf()) - leaf_list.push_back (east_neighbor); - - } - } - } - - /** - * add all leafs of the quadtree to the list - * @param leaf_list list of leafs - */ - void getLeafs (std::list<QuadTree<POINT>*>& leaf_list) - { - if (_is_leaf) - leaf_list.push_back (this); - else - for (std::size_t k(0); k < 4; k++) - _children[k]->getLeafs (leaf_list); - - } - - const std::vector<POINT const*>& getPoints () const { return _pnts; } - - void getSquarePoints (POINT& ll, POINT& ur) const - { - ll = _ll; - ur = _ur; - } - - void getLeaf (const POINT& pnt, POINT& ll, POINT& ur) - { - if (this->isLeaf()) - { - ll = _ll; - ur = _ur; - } - else - { - if (pnt[0] <= 0.5 * (_ur[0] + _ll[0])) // WEST - { - if (pnt[1] <= 0.5 * (_ur[1] + _ll[1])) // SOUTH - _children[static_cast<int>(Quadrant::SW)]->getLeaf (pnt, ll, ur); - else // NORTH - _children[static_cast<int>(Quadrant::NW)]->getLeaf (pnt, ll, ur); - } - else // EAST - { - if (pnt[1] <= 0.5 * (_ur[1] + _ll[1])) // SOUTH - _children[static_cast<int>(Quadrant::SE)]->getLeaf (pnt, ll, ur); - else // NORTH - _children[static_cast<int>(Quadrant::NE)]->getLeaf (pnt, ll, ur); - } - } - } - - QuadTree<POINT> const* getFather () - { - return _father; - } - - QuadTree<POINT> const* getChild (Quadrant quadrant) const - { - return _children[quadrant]; - } - - /** - * Method calculates the maximum depth of the QuadTree instance. It is used within - * the method GMSHAdaptiveMeshDensity::getSteinerPoints(). - * @param max_depth (input/output) at the entry max_depth contains the maximum depth up to now - */ - void getMaxDepth (std::size_t &max_depth) const - { - if (max_depth < _depth) - max_depth = _depth; - - for (std::size_t k(0); k<4; k++) { - if (_children[k]) { - _children[k]->getMaxDepth(max_depth); - } - } - } - - /** - * Method returns the depth of the current QuadTree node. - * @return the depth of the current QuadTree node - */ - std::size_t getDepth () const { return _depth; } + enum class Quadrant { + NE = 0, //!< north east + NW, //!< north west + SW, //!< south west + SE //!< south east + }; + /** + * This is the constructor for class QuadTree. It takes two points + * (lower left and the upper right points). + * @param ll lower left point of the square + * @param ur upper right point of the square + */ + QuadTree(POINT const& ll, POINT const& ur, std::size_t max_points_per_node) : + _father (nullptr), _ll (ll), _ur (ur), _depth (0), _is_leaf (true), + _max_points_per_node (max_points_per_node) + { + assert (_max_points_per_node > 0); + + // init children + for (std::size_t k(0); k < 4; k++) + _children[k] = nullptr; + + if ((_ur[0] - _ll[0]) > (_ur[1] - _ll[1])) + _ur[1] = _ll[1] + _ur[0] - _ll[0]; + else + _ur[0] = _ll[0] + _ur[1] - _ll[1]; + + DBUG("QuadTree(): lower left: (%f,%f,%f), upper right: (%f,%f,%f), depth: %d", _ll[0], _ll[1], _ll[2], _ur[0], _ur[1], _ur[2], _depth); + } + + /** + * destructor + */ + ~QuadTree() + { + for (std::size_t k(0); k < 4; k++) { + delete _children[k]; + } + } + + /** + * This method adds the given point to the quadtree. If necessary, + * the quadtree will be extended. + * @param pnt the point + * @return If the point can be inserted the method returns true, else false. + */ + bool addPoint (POINT const* pnt) + { + if ((*pnt)[0] < _ll[0]) return false; + if ((*pnt)[0] >= _ur[0]) return false; + if ((*pnt)[1] < _ll[1]) return false; + if ((*pnt)[1] >= _ur[1]) return false; + + if (!_is_leaf) { + for (std::size_t k(0); k < 4; k++) { + if (_children[k]->addPoint (pnt)) + return true; + } + return false; + } + + // check if point is already in quadtree + bool pnt_in_quadtree (false); + for (std::size_t k(0); k < _pnts.size() && !pnt_in_quadtree; k++) { + const double v0((*(_pnts[k]))[0] - (*pnt)[0]); + const double v1((*(_pnts[k]))[1] - (*pnt)[1]); + const double sqr_dist (v0*v0 + v1*v1); + if (sqr_dist < std::numeric_limits<double>::epsilon()) + pnt_in_quadtree = true; + } + if (!pnt_in_quadtree) + _pnts.push_back (pnt); + else + return false; + + if (_pnts.size () > _max_points_per_node) + splitNode (); + return true; + } + + /** + * This method balances the quadtree, i.e., it will be inserted nodes + * such that the depth between neighbored leafs is at most one. If you want + * to create a mesh (for instance with GMSH) you can use this method to + * improve the mesh quality. The balance method should be used after + * inserting all points. + */ + void balance () + { + std::list<QuadTree<POINT>*> leaf_list; + getLeafs (leaf_list); + + while (!leaf_list.empty()) + { + QuadTree<POINT>* node (leaf_list.front()); + leaf_list.pop_front (); + + if (node->isLeaf()) + if (needToRefine (node)) + { + node->splitNode (); + leaf_list.push_back (node->getChild(Quadrant::NE)); + leaf_list.push_back (node->getChild(Quadrant::NW)); + leaf_list.push_back (node->getChild(Quadrant::SW)); + leaf_list.push_back (node->getChild(Quadrant::SE)); + + // check if north neighbor has to be refined + QuadTree<POINT>* north_neighbor (node->getNorthNeighbor()); + if (north_neighbor != nullptr) + if (north_neighbor->getDepth() < node->getDepth ()) + if (north_neighbor->isLeaf()) + leaf_list.push_back (north_neighbor); + + // check if west neighbor has to be refined + QuadTree<POINT>* west_neighbor (node->getWestNeighbor()); + if (west_neighbor != nullptr) + if (west_neighbor->getDepth() < node->getDepth ()) + if (west_neighbor->isLeaf()) + leaf_list.push_back (west_neighbor); + + // check if south neighbor has to be refined + QuadTree<POINT>* south_neighbor (node->getSouthNeighbor()); + if (south_neighbor != nullptr) + if (south_neighbor->getDepth() < node->getDepth ()) + if (south_neighbor->isLeaf()) + leaf_list.push_back (south_neighbor); + + // check if east neighbor has to be refined + QuadTree<POINT>* east_neighbor (node->getEastNeighbor()); + if (east_neighbor != nullptr) + if (east_neighbor->getDepth() < node->getDepth ()) + if (east_neighbor->isLeaf()) + leaf_list.push_back (east_neighbor); + + } + } + } + + /** + * add all leafs of the quadtree to the list + * @param leaf_list list of leafs + */ + void getLeafs (std::list<QuadTree<POINT>*>& leaf_list) + { + if (_is_leaf) + leaf_list.push_back (this); + else + for (std::size_t k(0); k < 4; k++) + _children[k]->getLeafs (leaf_list); + + } + + const std::vector<POINT const*>& getPoints () const { return _pnts; } + + void getSquarePoints (POINT& ll, POINT& ur) const + { + ll = _ll; + ur = _ur; + } + + void getLeaf (const POINT& pnt, POINT& ll, POINT& ur) + { + if (this->isLeaf()) + { + ll = _ll; + ur = _ur; + } + else + { + if (pnt[0] <= 0.5 * (_ur[0] + _ll[0])) // WEST + { + if (pnt[1] <= 0.5 * (_ur[1] + _ll[1])) // SOUTH + _children[static_cast<int>(Quadrant::SW)]->getLeaf (pnt, ll, ur); + else // NORTH + _children[static_cast<int>(Quadrant::NW)]->getLeaf (pnt, ll, ur); + } + else // EAST + { + if (pnt[1] <= 0.5 * (_ur[1] + _ll[1])) // SOUTH + _children[static_cast<int>(Quadrant::SE)]->getLeaf (pnt, ll, ur); + else // NORTH + _children[static_cast<int>(Quadrant::NE)]->getLeaf (pnt, ll, ur); + } + } + } + + QuadTree<POINT> const* getFather () + { + return _father; + } + + QuadTree<POINT> const* getChild (Quadrant quadrant) const + { + return _children[quadrant]; + } + + /** + * Method calculates the maximum depth of the QuadTree instance. It is used within + * the method GMSHAdaptiveMeshDensity::getSteinerPoints(). + * @param max_depth (input/output) at the entry max_depth contains the maximum depth up to now + */ + void getMaxDepth (std::size_t &max_depth) const + { + if (max_depth < _depth) + max_depth = _depth; + + for (std::size_t k(0); k<4; k++) { + if (_children[k]) { + _children[k]->getMaxDepth(max_depth); + } + } + } + + /** + * Method returns the depth of the current QuadTree node. + * @return the depth of the current QuadTree node + */ + std::size_t getDepth () const { return _depth; } private: - QuadTree<POINT>* getChild (Quadrant quadrant) - { - return _children[static_cast<int>(quadrant)]; - } - - bool isLeaf () const { return _is_leaf; } - - bool isChild (QuadTree<POINT> const* const tree, Quadrant quadrant) const - { - if (_children[static_cast<int>(quadrant)] == tree) return true; - return false; - } - - QuadTree<POINT>* getNorthNeighbor () const - { - if (this->_father == nullptr) // root of QuadTree - return nullptr; - - if (this->_father->isChild (this, Quadrant::SW)) - return this->_father->getChild (Quadrant::NW); - if (this->_father->isChild (this, Quadrant::SE)) - return this->_father->getChild (Quadrant::NE); - - QuadTree<POINT>* north_neighbor (this->_father->getNorthNeighbor ()); - if (north_neighbor == nullptr) - return nullptr; - if (north_neighbor->isLeaf()) - return north_neighbor; - - if (this->_father->isChild (this, Quadrant::NW)) - return north_neighbor->getChild (Quadrant::SW); - else - return north_neighbor->getChild (Quadrant::SE); - } - - QuadTree<POINT>* getSouthNeighbor () const - { - if (this->_father == nullptr) // root of QuadTree - return nullptr; - - if (this->_father->isChild (this, Quadrant::NW)) - return this->_father->getChild (Quadrant::SW); - if (this->_father->isChild (this, Quadrant::NE)) - return this->_father->getChild (Quadrant::SE); - - QuadTree<POINT>* south_neighbor (this->_father->getSouthNeighbor ()); - if (south_neighbor == nullptr) - return nullptr; - if (south_neighbor->isLeaf()) - return south_neighbor; - - if (this->_father->isChild (this, Quadrant::SW)) - return south_neighbor->getChild (Quadrant::NW); - else - return south_neighbor->getChild (Quadrant::NE); - } - - QuadTree<POINT>* getEastNeighbor () const - { - if (this->_father == nullptr) // root of QuadTree - return nullptr; - - if (this->_father->isChild (this, Quadrant::NW)) - return this->_father->getChild (Quadrant::NE); - if (this->_father->isChild (this, Quadrant::SW)) - return this->_father->getChild (Quadrant::SE); - - QuadTree<POINT>* east_neighbor (this->_father->getEastNeighbor ()); - if (east_neighbor == nullptr) - return nullptr; - if (east_neighbor->isLeaf()) - return east_neighbor; - - if (this->_father->isChild (this, Quadrant::SE)) - return east_neighbor->getChild (Quadrant::SW); - else - return east_neighbor->getChild (Quadrant::NW); - } - - QuadTree<POINT>* getWestNeighbor () const - { - if (this->_father == nullptr) // root of QuadTree - return nullptr; - - if (this->_father->isChild (this, Quadrant::NE)) - return this->_father->getChild (Quadrant::NW); - if (this->_father->isChild (this, Quadrant::SE)) - return this->_father->getChild (Quadrant::SW); - - QuadTree<POINT>* west_neighbor (this->_father->getWestNeighbor ()); - if (west_neighbor == nullptr) - return nullptr; - if (west_neighbor->isLeaf()) - return west_neighbor; - - if (this->_father->isChild (this, Quadrant::SW)) - return west_neighbor->getChild (Quadrant::SE); - else - return west_neighbor->getChild (Quadrant::NE); - } - - /** - * private constructor - * @param ll lower left point - * @param ur upper right point - * @param father father in the tree - * @param depth depth of the node - * @return - */ - QuadTree (POINT const& ll, - POINT const& ur, - QuadTree* father, - std::size_t depth, - std::size_t max_points_per_node) : - _father (father), _ll (ll), _ur (ur), _depth (depth), _is_leaf (true), - _max_points_per_node (max_points_per_node) - { - // init children - for (std::size_t k(0); k < 4; k++) - _children[k] = nullptr; - } - - void splitNode () - { - // create children - POINT mid_point(_ll); - mid_point[0] += (_ur[0] - _ll[0]) / 2.0; - mid_point[1] += (_ur[1] - _ll[1]) / 2.0; - assert(_children[0] == nullptr); - _children[0] = new QuadTree<POINT> (mid_point, _ur, this, _depth + 1, _max_points_per_node); // north east - POINT h_ll(mid_point), h_ur(mid_point); - h_ll[0] = _ll[0]; - h_ur[1] = _ur[1]; - assert(_children[1] == nullptr); - _children[1] = new QuadTree<POINT> (h_ll, h_ur, this, _depth + 1, _max_points_per_node); // north west - assert(_children[2] == nullptr); - _children[2] = new QuadTree<POINT> (_ll, mid_point, this, _depth + 1, _max_points_per_node); // south west - h_ll = _ll; - h_ll[0] = mid_point[0]; - h_ur = _ur; - h_ur[1] = mid_point[1]; - assert(_children[3] == nullptr); - _children[3] = new QuadTree<POINT> (h_ll, h_ur, this, _depth + 1, _max_points_per_node); // south east - - // distribute points to sub quadtrees - for (std::size_t j(0); j < _pnts.size(); j++) { - bool nfound(true); - for (std::size_t k(0); k < 4 && nfound; k++) - if (_children[k]->addPoint(_pnts[j])) nfound = false; - - } - _pnts.clear(); - _is_leaf = false; - } - - bool needToRefine (QuadTree<POINT>* node) - { - QuadTree<POINT>* north_neighbor (node->getNorthNeighbor ()); - if (north_neighbor != nullptr) - { - if (north_neighbor->getDepth() == node->getDepth()) - if (!north_neighbor->isLeaf ()) - { - if (!(north_neighbor->getChild(Quadrant::SW))->isLeaf()) - return true; - if (!(north_neighbor->getChild(Quadrant::SE))->isLeaf()) - return true; - } - } - - QuadTree<POINT>* west_neighbor (node->getWestNeighbor ()); - if (west_neighbor != nullptr) - { - if (west_neighbor->getDepth() == node->getDepth()) - if (!west_neighbor->isLeaf ()) - { - if (!(west_neighbor->getChild(Quadrant::SE))->isLeaf()) - return true; - if (!(west_neighbor->getChild(Quadrant::NE))->isLeaf()) - return true; - } - } - - QuadTree<POINT>* south_neighbor (node->getSouthNeighbor ()); - if (south_neighbor != nullptr) - { - if (south_neighbor->getDepth() == node->getDepth()) - if (!south_neighbor->isLeaf()) - { - if (!(south_neighbor->getChild(Quadrant::NE))->isLeaf()) - return true; - if (!(south_neighbor->getChild(Quadrant::NW))->isLeaf()) - return true; - } - } - - QuadTree<POINT>* east_neighbor (node->getEastNeighbor ()); - if (east_neighbor != nullptr) - { - if (east_neighbor->getDepth() == node->getDepth()) - if (!east_neighbor->isLeaf ()) - { - if (!(east_neighbor->getChild(Quadrant::NW))->isLeaf()) - return true; - if (!(east_neighbor->getChild(Quadrant::SW))->isLeaf()) - return true; - } - } - return false; - } - - QuadTree<POINT>* _father; - /** - * children are sorted: - * _children[0] is north east child - * _children[1] is north west child - * _children[2] is south west child - * _children[3] is south east child - */ - QuadTree<POINT>* _children[4]; - /** - * lower left point of the square - */ - POINT _ll; - /** - * upper right point of the square - */ - POINT _ur; - std::size_t _depth; - std::vector<POINT const*> _pnts; - bool _is_leaf; - /** - * maximum number of points per leaf - */ - const std::size_t _max_points_per_node; + QuadTree<POINT>* getChild (Quadrant quadrant) + { + return _children[static_cast<int>(quadrant)]; + } + + bool isLeaf () const { return _is_leaf; } + + bool isChild (QuadTree<POINT> const* const tree, Quadrant quadrant) const + { + if (_children[static_cast<int>(quadrant)] == tree) return true; + return false; + } + + QuadTree<POINT>* getNorthNeighbor () const + { + if (this->_father == nullptr) // root of QuadTree + return nullptr; + + if (this->_father->isChild (this, Quadrant::SW)) + return this->_father->getChild (Quadrant::NW); + if (this->_father->isChild (this, Quadrant::SE)) + return this->_father->getChild (Quadrant::NE); + + QuadTree<POINT>* north_neighbor (this->_father->getNorthNeighbor ()); + if (north_neighbor == nullptr) + return nullptr; + if (north_neighbor->isLeaf()) + return north_neighbor; + + if (this->_father->isChild (this, Quadrant::NW)) + return north_neighbor->getChild (Quadrant::SW); + else + return north_neighbor->getChild (Quadrant::SE); + } + + QuadTree<POINT>* getSouthNeighbor () const + { + if (this->_father == nullptr) // root of QuadTree + return nullptr; + + if (this->_father->isChild (this, Quadrant::NW)) + return this->_father->getChild (Quadrant::SW); + if (this->_father->isChild (this, Quadrant::NE)) + return this->_father->getChild (Quadrant::SE); + + QuadTree<POINT>* south_neighbor (this->_father->getSouthNeighbor ()); + if (south_neighbor == nullptr) + return nullptr; + if (south_neighbor->isLeaf()) + return south_neighbor; + + if (this->_father->isChild (this, Quadrant::SW)) + return south_neighbor->getChild (Quadrant::NW); + else + return south_neighbor->getChild (Quadrant::NE); + } + + QuadTree<POINT>* getEastNeighbor () const + { + if (this->_father == nullptr) // root of QuadTree + return nullptr; + + if (this->_father->isChild (this, Quadrant::NW)) + return this->_father->getChild (Quadrant::NE); + if (this->_father->isChild (this, Quadrant::SW)) + return this->_father->getChild (Quadrant::SE); + + QuadTree<POINT>* east_neighbor (this->_father->getEastNeighbor ()); + if (east_neighbor == nullptr) + return nullptr; + if (east_neighbor->isLeaf()) + return east_neighbor; + + if (this->_father->isChild (this, Quadrant::SE)) + return east_neighbor->getChild (Quadrant::SW); + else + return east_neighbor->getChild (Quadrant::NW); + } + + QuadTree<POINT>* getWestNeighbor () const + { + if (this->_father == nullptr) // root of QuadTree + return nullptr; + + if (this->_father->isChild (this, Quadrant::NE)) + return this->_father->getChild (Quadrant::NW); + if (this->_father->isChild (this, Quadrant::SE)) + return this->_father->getChild (Quadrant::SW); + + QuadTree<POINT>* west_neighbor (this->_father->getWestNeighbor ()); + if (west_neighbor == nullptr) + return nullptr; + if (west_neighbor->isLeaf()) + return west_neighbor; + + if (this->_father->isChild (this, Quadrant::SW)) + return west_neighbor->getChild (Quadrant::SE); + else + return west_neighbor->getChild (Quadrant::NE); + } + + /** + * private constructor + * @param ll lower left point + * @param ur upper right point + * @param father father in the tree + * @param depth depth of the node + * @return + */ + QuadTree (POINT const& ll, + POINT const& ur, + QuadTree* father, + std::size_t depth, + std::size_t max_points_per_node) : + _father (father), _ll (ll), _ur (ur), _depth (depth), _is_leaf (true), + _max_points_per_node (max_points_per_node) + { + // init children + for (std::size_t k(0); k < 4; k++) + _children[k] = nullptr; + } + + void splitNode () + { + // create children + POINT mid_point(_ll); + mid_point[0] += (_ur[0] - _ll[0]) / 2.0; + mid_point[1] += (_ur[1] - _ll[1]) / 2.0; + assert(_children[0] == nullptr); + _children[0] = new QuadTree<POINT> (mid_point, _ur, this, _depth + 1, _max_points_per_node); // north east + POINT h_ll(mid_point), h_ur(mid_point); + h_ll[0] = _ll[0]; + h_ur[1] = _ur[1]; + assert(_children[1] == nullptr); + _children[1] = new QuadTree<POINT> (h_ll, h_ur, this, _depth + 1, _max_points_per_node); // north west + assert(_children[2] == nullptr); + _children[2] = new QuadTree<POINT> (_ll, mid_point, this, _depth + 1, _max_points_per_node); // south west + h_ll = _ll; + h_ll[0] = mid_point[0]; + h_ur = _ur; + h_ur[1] = mid_point[1]; + assert(_children[3] == nullptr); + _children[3] = new QuadTree<POINT> (h_ll, h_ur, this, _depth + 1, _max_points_per_node); // south east + + // distribute points to sub quadtrees + for (std::size_t j(0); j < _pnts.size(); j++) { + bool nfound(true); + for (std::size_t k(0); k < 4 && nfound; k++) + if (_children[k]->addPoint(_pnts[j])) nfound = false; + + } + _pnts.clear(); + _is_leaf = false; + } + + bool needToRefine (QuadTree<POINT>* node) + { + QuadTree<POINT>* north_neighbor (node->getNorthNeighbor ()); + if (north_neighbor != nullptr) + { + if (north_neighbor->getDepth() == node->getDepth()) + if (!north_neighbor->isLeaf ()) + { + if (!(north_neighbor->getChild(Quadrant::SW))->isLeaf()) + return true; + if (!(north_neighbor->getChild(Quadrant::SE))->isLeaf()) + return true; + } + } + + QuadTree<POINT>* west_neighbor (node->getWestNeighbor ()); + if (west_neighbor != nullptr) + { + if (west_neighbor->getDepth() == node->getDepth()) + if (!west_neighbor->isLeaf ()) + { + if (!(west_neighbor->getChild(Quadrant::SE))->isLeaf()) + return true; + if (!(west_neighbor->getChild(Quadrant::NE))->isLeaf()) + return true; + } + } + + QuadTree<POINT>* south_neighbor (node->getSouthNeighbor ()); + if (south_neighbor != nullptr) + { + if (south_neighbor->getDepth() == node->getDepth()) + if (!south_neighbor->isLeaf()) + { + if (!(south_neighbor->getChild(Quadrant::NE))->isLeaf()) + return true; + if (!(south_neighbor->getChild(Quadrant::NW))->isLeaf()) + return true; + } + } + + QuadTree<POINT>* east_neighbor (node->getEastNeighbor ()); + if (east_neighbor != nullptr) + { + if (east_neighbor->getDepth() == node->getDepth()) + if (!east_neighbor->isLeaf ()) + { + if (!(east_neighbor->getChild(Quadrant::NW))->isLeaf()) + return true; + if (!(east_neighbor->getChild(Quadrant::SW))->isLeaf()) + return true; + } + } + return false; + } + + QuadTree<POINT>* _father; + /** + * children are sorted: + * _children[0] is north east child + * _children[1] is north west child + * _children[2] is south west child + * _children[3] is south east child + */ + QuadTree<POINT>* _children[4]; + /** + * lower left point of the square + */ + POINT _ll; + /** + * upper right point of the square + */ + POINT _ur; + std::size_t _depth; + std::vector<POINT const*> _pnts; + bool _is_leaf; + /** + * maximum number of points per leaf + */ + const std::size_t _max_points_per_node; }; } diff --git a/GeoLib/Raster.cpp b/GeoLib/Raster.cpp index bdb197417c5fcbf24d897fa9abc975e7106ec8a3..7df27f57eb5ffdc515a6130a7ce8f033a86bb491 100644 --- a/GeoLib/Raster.cpp +++ b/GeoLib/Raster.cpp @@ -28,153 +28,153 @@ namespace GeoLib { void Raster::refineRaster(std::size_t scaling) { - double *new_raster_data(new double[_header.n_rows*_header.n_cols*scaling*scaling]); - - for (std::size_t row(0); row<_header.n_rows; row++) { - for (std::size_t col(0); col<_header.n_cols; col++) { - const std::size_t idx(row*_header.n_cols+col); - for (std::size_t new_row(row*scaling); new_row<(row+1)*scaling; new_row++) { - const std::size_t idx0(new_row*_header.n_cols*scaling); - for (std::size_t new_col(col*scaling); new_col<(col+1)*scaling; new_col++) { - new_raster_data[idx0+new_col] = _raster_data[idx]; - } - } - } - } - - std::swap(_raster_data, new_raster_data); - _header.cell_size /= scaling; - _header.n_cols *= scaling; - _header.n_rows *= scaling; - - delete [] new_raster_data; + double *new_raster_data(new double[_header.n_rows*_header.n_cols*scaling*scaling]); + + for (std::size_t row(0); row<_header.n_rows; row++) { + for (std::size_t col(0); col<_header.n_cols; col++) { + const std::size_t idx(row*_header.n_cols+col); + for (std::size_t new_row(row*scaling); new_row<(row+1)*scaling; new_row++) { + const std::size_t idx0(new_row*_header.n_cols*scaling); + for (std::size_t new_col(col*scaling); new_col<(col+1)*scaling; new_col++) { + new_raster_data[idx0+new_col] = _raster_data[idx]; + } + } + } + } + + std::swap(_raster_data, new_raster_data); + _header.cell_size /= scaling; + _header.n_cols *= scaling; + _header.n_rows *= scaling; + + delete [] new_raster_data; } Raster::~Raster() { - delete [] _raster_data; + delete [] _raster_data; } Raster* Raster::getRasterFromSurface(Surface const& sfc, double cell_size, double no_data_val) { - MathLib::Point3d const& ll(sfc.getAABB().getMinPoint()); - MathLib::Point3d const& ur(sfc.getAABB().getMaxPoint()); - - const std::size_t n_cols = static_cast<std::size_t>(std::abs(ur[0]-ll[0]) / cell_size)+1; - const std::size_t n_rows = static_cast<std::size_t>(std::abs(ur[1]-ll[1]) / cell_size)+1; - const std::size_t n_triangles(sfc.getNTriangles()); - double *z_vals (new double[n_cols*n_rows]); - std::size_t k(0); - - for (std::size_t r(0); r < n_cols; r++) { - for (std::size_t c(0); c < n_rows; c++) { - GeoLib::Point const test_pnt = { ll[0] + r*cell_size, ll[1] + c*cell_size, 0}; - for (k=0; k<n_triangles; k++) { - if (sfc[k]->containsPoint2D(test_pnt)) { - GeoLib::Triangle const * const tri (sfc[k]); - // compute coefficients c0, c1, c2 for the plane f(x,y) = c0 x + c1 y + c2 - double coeff[3] = {0.0, 0.0, 0.0}; - GeoLib::getPlaneCoefficients(*tri, coeff); - z_vals[r*n_rows+c] = coeff[0] * test_pnt[0] + coeff[1] * test_pnt[1] + coeff[2]; - break; - } - } - if (k==n_triangles) { - z_vals[r*n_rows+c] = no_data_val; - } - } - } - - RasterHeader header = {std::size_t(n_cols), std::size_t(n_rows), MathLib::Point3d(ll), cell_size, static_cast<double>(-9999)}; - return new Raster(header, z_vals, z_vals+n_cols*n_rows); + MathLib::Point3d const& ll(sfc.getAABB().getMinPoint()); + MathLib::Point3d const& ur(sfc.getAABB().getMaxPoint()); + + const std::size_t n_cols = static_cast<std::size_t>(std::abs(ur[0]-ll[0]) / cell_size)+1; + const std::size_t n_rows = static_cast<std::size_t>(std::abs(ur[1]-ll[1]) / cell_size)+1; + const std::size_t n_triangles(sfc.getNTriangles()); + double *z_vals (new double[n_cols*n_rows]); + std::size_t k(0); + + for (std::size_t r(0); r < n_cols; r++) { + for (std::size_t c(0); c < n_rows; c++) { + GeoLib::Point const test_pnt = { ll[0] + r*cell_size, ll[1] + c*cell_size, 0}; + for (k=0; k<n_triangles; k++) { + if (sfc[k]->containsPoint2D(test_pnt)) { + GeoLib::Triangle const * const tri (sfc[k]); + // compute coefficients c0, c1, c2 for the plane f(x,y) = c0 x + c1 y + c2 + double coeff[3] = {0.0, 0.0, 0.0}; + GeoLib::getPlaneCoefficients(*tri, coeff); + z_vals[r*n_rows+c] = coeff[0] * test_pnt[0] + coeff[1] * test_pnt[1] + coeff[2]; + break; + } + } + if (k==n_triangles) { + z_vals[r*n_rows+c] = no_data_val; + } + } + } + + RasterHeader header = {std::size_t(n_cols), std::size_t(n_rows), MathLib::Point3d(ll), cell_size, static_cast<double>(-9999)}; + return new Raster(header, z_vals, z_vals+n_cols*n_rows); } double Raster::getValueAtPoint(const MathLib::Point3d &pnt) const { - if (pnt[0]>=_header.origin[0] && pnt[0]<(_header.origin[0]+(_header.cell_size*_header.n_cols)) && - pnt[1]>=_header.origin[1] && pnt[1]<(_header.origin[1]+(_header.cell_size*_header.n_rows))) - { - int cell_x = static_cast<int>(std::floor((pnt[0] - _header.origin[0])/_header.cell_size)); - int cell_y = static_cast<int>(std::floor((pnt[1] - _header.origin[1])/_header.cell_size)); - - // use raster boundary values if node is outside raster due to rounding errors or floating point arithmetic - cell_x = (cell_x < 0) ? 0 : ((cell_x > static_cast<int>(_header.n_cols)) ? - static_cast<int>(_header.n_cols-1) : cell_x); - cell_y = (cell_y < 0) ? 0 : ((cell_y > static_cast<int>(_header.n_rows)) ? - static_cast<int>(_header.n_rows-1) : cell_y); - - const std::size_t index = cell_y*_header.n_cols+cell_x; - return _raster_data[index]; - } - return _header.no_data; + if (pnt[0]>=_header.origin[0] && pnt[0]<(_header.origin[0]+(_header.cell_size*_header.n_cols)) && + pnt[1]>=_header.origin[1] && pnt[1]<(_header.origin[1]+(_header.cell_size*_header.n_rows))) + { + int cell_x = static_cast<int>(std::floor((pnt[0] - _header.origin[0])/_header.cell_size)); + int cell_y = static_cast<int>(std::floor((pnt[1] - _header.origin[1])/_header.cell_size)); + + // use raster boundary values if node is outside raster due to rounding errors or floating point arithmetic + cell_x = (cell_x < 0) ? 0 : ((cell_x > static_cast<int>(_header.n_cols)) ? + static_cast<int>(_header.n_cols-1) : cell_x); + cell_y = (cell_y < 0) ? 0 : ((cell_y > static_cast<int>(_header.n_rows)) ? + static_cast<int>(_header.n_rows-1) : cell_y); + + const std::size_t index = cell_y*_header.n_cols+cell_x; + return _raster_data[index]; + } + return _header.no_data; } double Raster::interpolateValueAtPoint(MathLib::Point3d const& pnt) const { - // position in raster - double const xPos ((pnt[0] - _header.origin[0]) / _header.cell_size); - double const yPos ((pnt[1] - _header.origin[1]) / _header.cell_size); - // raster cell index - double const xIdx (std::floor(xPos)); //carry out computions in double - double const yIdx (std::floor(yPos)); // so not to over- or underflow. - - // weights for bilinear interpolation - double const half_delta = 0.5*_header.cell_size; - double const xShift = std::fabs(xPos-(xIdx+half_delta)) / _header.cell_size; - double const yShift = std::fabs(yPos-(yIdx+half_delta)) / _header.cell_size; - std::array<double,4> weight = {{ (1-xShift)*(1-yShift), xShift*(1-yShift), xShift*yShift, (1-xShift)*yShift }}; - - // neighbors to include in interpolation - int const xShiftIdx = (xPos-xIdx-half_delta>=0) ? 1 : -1; - int const yShiftIdx = (yPos-yIdx-half_delta>=0) ? 1 : -1; - std::array<int,4> const x_nb = {{ 0, xShiftIdx, xShiftIdx, 0 }}; - std::array<int,4> const y_nb = {{ 0, 0, yShiftIdx, yShiftIdx }}; - - // get pixel values - std::array<double,4> pix_val; - unsigned no_data_count (0); - for (unsigned j=0; j<4; ++j) - { - // check if neighbour pixel is still on the raster, otherwise substitute - // a no data value. This also allows the cast to unsigned type. - if ( (xIdx + x_nb[j]) < 0 || - (yIdx + y_nb[j]) < 0 || - (xIdx + x_nb[j]) > (_header.n_cols-1) || - (yIdx + y_nb[j]) > (_header.n_rows-1) ) - pix_val[j] = _header.no_data; - else - pix_val[j] = _raster_data[ - static_cast<std::size_t>(yIdx + y_nb[j]) * _header.n_cols + - static_cast<std::size_t>(xIdx + x_nb[j])]; - - // remove no data values - if (std::fabs(pix_val[j] - _header.no_data) < std::numeric_limits<double>::epsilon()) - { - weight[j] = 0; - no_data_count++; - } - } - - // adjust weights if necessary - if (no_data_count > 0) - { - if (no_data_count == 4) // if there is absolutely no data just use the default value - return _header.no_data; - - const double norm = 1.0 / (weight[0]+weight[1]+weight[2]+weight[3]); - std::for_each(weight.begin(), weight.end(), [&norm](double &val){val*=norm;}); - } - - // new value - return MathLib::scalarProduct<double,4>(weight.data(), pix_val.data()); - } + // position in raster + double const xPos ((pnt[0] - _header.origin[0]) / _header.cell_size); + double const yPos ((pnt[1] - _header.origin[1]) / _header.cell_size); + // raster cell index + double const xIdx (std::floor(xPos)); //carry out computions in double + double const yIdx (std::floor(yPos)); // so not to over- or underflow. + + // weights for bilinear interpolation + double const half_delta = 0.5*_header.cell_size; + double const xShift = std::fabs(xPos-(xIdx+half_delta)) / _header.cell_size; + double const yShift = std::fabs(yPos-(yIdx+half_delta)) / _header.cell_size; + std::array<double,4> weight = {{ (1-xShift)*(1-yShift), xShift*(1-yShift), xShift*yShift, (1-xShift)*yShift }}; + + // neighbors to include in interpolation + int const xShiftIdx = (xPos-xIdx-half_delta>=0) ? 1 : -1; + int const yShiftIdx = (yPos-yIdx-half_delta>=0) ? 1 : -1; + std::array<int,4> const x_nb = {{ 0, xShiftIdx, xShiftIdx, 0 }}; + std::array<int,4> const y_nb = {{ 0, 0, yShiftIdx, yShiftIdx }}; + + // get pixel values + std::array<double,4> pix_val; + unsigned no_data_count (0); + for (unsigned j=0; j<4; ++j) + { + // check if neighbour pixel is still on the raster, otherwise substitute + // a no data value. This also allows the cast to unsigned type. + if ( (xIdx + x_nb[j]) < 0 || + (yIdx + y_nb[j]) < 0 || + (xIdx + x_nb[j]) > (_header.n_cols-1) || + (yIdx + y_nb[j]) > (_header.n_rows-1) ) + pix_val[j] = _header.no_data; + else + pix_val[j] = _raster_data[ + static_cast<std::size_t>(yIdx + y_nb[j]) * _header.n_cols + + static_cast<std::size_t>(xIdx + x_nb[j])]; + + // remove no data values + if (std::fabs(pix_val[j] - _header.no_data) < std::numeric_limits<double>::epsilon()) + { + weight[j] = 0; + no_data_count++; + } + } + + // adjust weights if necessary + if (no_data_count > 0) + { + if (no_data_count == 4) // if there is absolutely no data just use the default value + return _header.no_data; + + const double norm = 1.0 / (weight[0]+weight[1]+weight[2]+weight[3]); + std::for_each(weight.begin(), weight.end(), [&norm](double &val){val*=norm;}); + } + + // new value + return MathLib::scalarProduct<double,4>(weight.data(), pix_val.data()); + } bool Raster::isPntOnRaster(MathLib::Point3d const& pnt) const { - if ((pnt[0]<_header.origin[0]) || (pnt[0]>_header.origin[0]+(_header.n_cols*_header.cell_size)) || - (pnt[1]<_header.origin[1]) || (pnt[1]>_header.origin[1]+(_header.n_rows*_header.cell_size))) - return false; - return true; + if ((pnt[0]<_header.origin[0]) || (pnt[0]>_header.origin[0]+(_header.n_cols*_header.cell_size)) || + (pnt[1]<_header.origin[1]) || (pnt[1]>_header.origin[1]+(_header.n_rows*_header.cell_size))) + return false; + return true; } } // end namespace GeoLib diff --git a/GeoLib/Raster.h b/GeoLib/Raster.h index 5f78009d3ee0dfe822d1a7786dba6774ae54214d..fc8890dfa50cfc6f0eeb1c039059bc09560ba9b9 100644 --- a/GeoLib/Raster.h +++ b/GeoLib/Raster.h @@ -21,11 +21,11 @@ namespace GeoLib { /// Contains the relevant information when handling with geoscientific raster data struct RasterHeader { - std::size_t n_cols; // width - std::size_t n_rows; // height - MathLib::Point3d origin; // lower left corner - double cell_size; // edge length of each pixel - double no_data; // no data value + std::size_t n_cols; // width + std::size_t n_rows; // height + MathLib::Point3d origin; // lower left corner + double cell_size; // edge length of each pixel + double no_data; // no data value }; /** @@ -38,70 +38,70 @@ struct RasterHeader */ class Raster { public: - typedef double const* const_iterator; - typedef double* iterator; - - /** - * @brief Constructor for an object of class Raster. The raster data have - * to be handed over via input iterators. Deploying iterators has the - * advantage that the use of the class is independent from the input - * container. - * @param header meta-information about the raster (height, width, etc.) - * @param begin input iterator pointing to the first element of the data - * @param end input iterator pointing to the last element of the data, end have to be reachable from begin - */ - template<typename InputIterator> - Raster(RasterHeader header, InputIterator begin, InputIterator end) : - _header(header), _raster_data(new double[_header.n_cols*_header.n_rows]) - { - iterator raster_it(_raster_data); - for (InputIterator it(begin); it != end; ++it) { - *raster_it = *it; - raster_it++; - } - } - - /// Returns the complete header information - RasterHeader const& getHeader() const { return _header; } - - /** - * Refine the raster using scaling as a refinement parameter. - */ - void refineRaster(std::size_t scaling); - - /** - * Constant iterator that is pointing to the first raster pixel value. - * @return constant iterator - */ - const_iterator begin() const { return _raster_data; } - /** - * Constant iterator that is pointing to the last raster pixel value. - * @return constant iterator - */ - const_iterator end() const { return _raster_data + _header.n_rows*_header.n_cols; } - - /** - * Returns the raster value at the position of the given point. - */ - double getValueAtPoint(const MathLib::Point3d &pnt) const; - - /// Interpolates the elevation of the given point based on the 8-neighbourhood of the raster cell it is located on - double interpolateValueAtPoint(const MathLib::Point3d &pnt) const; - - /// Checks if the given point is located within the (x,y)-extension of the raster. - bool isPntOnRaster(MathLib::Point3d const& node) const; - - ~Raster(); - - /// Creates a Raster based on a GeoLib::Surface - static Raster* getRasterFromSurface(Surface const& sfc, double cell_size, double no_data_val = -9999); + typedef double const* const_iterator; + typedef double* iterator; + + /** + * @brief Constructor for an object of class Raster. The raster data have + * to be handed over via input iterators. Deploying iterators has the + * advantage that the use of the class is independent from the input + * container. + * @param header meta-information about the raster (height, width, etc.) + * @param begin input iterator pointing to the first element of the data + * @param end input iterator pointing to the last element of the data, end have to be reachable from begin + */ + template<typename InputIterator> + Raster(RasterHeader header, InputIterator begin, InputIterator end) : + _header(header), _raster_data(new double[_header.n_cols*_header.n_rows]) + { + iterator raster_it(_raster_data); + for (InputIterator it(begin); it != end; ++it) { + *raster_it = *it; + raster_it++; + } + } + + /// Returns the complete header information + RasterHeader const& getHeader() const { return _header; } + + /** + * Refine the raster using scaling as a refinement parameter. + */ + void refineRaster(std::size_t scaling); + + /** + * Constant iterator that is pointing to the first raster pixel value. + * @return constant iterator + */ + const_iterator begin() const { return _raster_data; } + /** + * Constant iterator that is pointing to the last raster pixel value. + * @return constant iterator + */ + const_iterator end() const { return _raster_data + _header.n_rows*_header.n_cols; } + + /** + * Returns the raster value at the position of the given point. + */ + double getValueAtPoint(const MathLib::Point3d &pnt) const; + + /// Interpolates the elevation of the given point based on the 8-neighbourhood of the raster cell it is located on + double interpolateValueAtPoint(const MathLib::Point3d &pnt) const; + + /// Checks if the given point is located within the (x,y)-extension of the raster. + bool isPntOnRaster(MathLib::Point3d const& node) const; + + ~Raster(); + + /// Creates a Raster based on a GeoLib::Surface + static Raster* getRasterFromSurface(Surface const& sfc, double cell_size, double no_data_val = -9999); private: - void setCellSize(double cell_size); - void setNoDataVal (double no_data_val); + void setCellSize(double cell_size); + void setNoDataVal (double no_data_val); - GeoLib::RasterHeader _header; - double* _raster_data; + GeoLib::RasterHeader _header; + double* _raster_data; }; } diff --git a/GeoLib/SensorData.cpp b/GeoLib/SensorData.cpp index a5954f0c53f5d21e86e8f3c202d337ee2b89853b..f818117cefc0ae5b3aa4108acfc69d18d6fba1f5 100644 --- a/GeoLib/SensorData.cpp +++ b/GeoLib/SensorData.cpp @@ -25,17 +25,17 @@ SensorData::SensorData(const std::string &file_name) : _start(0), _end(0), _step_size(0), _time_unit(TimeStepType::NONE) { - this->readDataFromFile(file_name); + this->readDataFromFile(file_name); } SensorData::SensorData(std::vector<std::size_t> time_steps) : _start(time_steps[0]), _end(time_steps[time_steps.size()-1]), _step_size(0), _time_unit(TimeStepType::NONE), _time_steps(time_steps) { - for (std::size_t i=1; i<time_steps.size(); i++) - { - if (time_steps[i-1]>=time_steps[i]) - ERR("Error in SensorData() - Time series has no order!"); - } + for (std::size_t i=1; i<time_steps.size(); i++) + { + if (time_steps[i-1]>=time_steps[i]) + ERR("Error in SensorData() - Time series has no order!"); + } } SensorData::SensorData(std::size_t first_timestep, std::size_t last_timestep, std::size_t step_size) @@ -45,129 +45,129 @@ SensorData::SensorData(std::size_t first_timestep, std::size_t last_timestep, st SensorData::~SensorData() { - for (std::vector<float>* vec : _data_vecs) - delete vec; + for (std::vector<float>* vec : _data_vecs) + delete vec; } void SensorData::addTimeSeries( const std::string &data_name, std::vector<float> *data, const std::string &data_unit_string ) { - this->addTimeSeries(SensorData::convertString2SensorDataType(data_name), data, data_unit_string); + this->addTimeSeries(SensorData::convertString2SensorDataType(data_name), data, data_unit_string); } void SensorData::addTimeSeries(SensorDataType data_name, std::vector<float> *data, const std::string &data_unit_string) { - if (_step_size>0) { - if (((_end-_start)/_step_size) != data->size()) { - WARN("Warning in SensorData::addTimeSeries() - Lengths of time series does not match number of time steps."); - return; - } - } else { - if (data->size() != _time_steps.size()) { - WARN("Warning in SensorData::addTimeSeries() - Lengths of time series does not match number of time steps."); - return; - } - } - - _vec_names.push_back(data_name); - _data_vecs.push_back(data); - _data_unit_string.push_back(data_unit_string); + if (_step_size>0) { + if (((_end-_start)/_step_size) != data->size()) { + WARN("Warning in SensorData::addTimeSeries() - Lengths of time series does not match number of time steps."); + return; + } + } else { + if (data->size() != _time_steps.size()) { + WARN("Warning in SensorData::addTimeSeries() - Lengths of time series does not match number of time steps."); + return; + } + } + + _vec_names.push_back(data_name); + _data_vecs.push_back(data); + _data_unit_string.push_back(data_unit_string); } const std::vector<float>* SensorData::getTimeSeries(SensorDataType time_series_name) const { - for (std::size_t i=0; i<_vec_names.size(); i++) - { - if (time_series_name == _vec_names[i]) - return _data_vecs[i]; - } - ERR("Error in SensorData::getTimeSeries() - Time series \"%d\" not found.", time_series_name); - return nullptr; + for (std::size_t i=0; i<_vec_names.size(); i++) + { + if (time_series_name == _vec_names[i]) + return _data_vecs[i]; + } + ERR("Error in SensorData::getTimeSeries() - Time series \"%d\" not found.", time_series_name); + return nullptr; } std::string SensorData::getDataUnit(SensorDataType time_series_name) const { - for (std::size_t i=0; i<_vec_names.size(); i++) - { - if (time_series_name == _vec_names[i]) - return _data_unit_string[i]; - } - ERR("Error in SensorData::getDataUnit() - Time series \"%d\" not found.", time_series_name); - return ""; + for (std::size_t i=0; i<_vec_names.size(); i++) + { + if (time_series_name == _vec_names[i]) + return _data_unit_string[i]; + } + ERR("Error in SensorData::getDataUnit() - Time series \"%d\" not found.", time_series_name); + return ""; } int SensorData::readDataFromFile(const std::string &file_name) { - std::ifstream in( file_name.c_str() ); - - if (!in.is_open()) - { - INFO("SensorData::readDataFromFile() - Could not open file %s.", file_name.c_str()); - return 0; - } - - std::string line(""); - - /* first line contains field names */ - getline(in, line); - std::list<std::string> fields = BaseLib::splitString(line, '\t'); - std::list<std::string>::const_iterator it (fields.begin()); - std::size_t nFields = fields.size(); - - if (nFields<2) - return 0; - - std::size_t nDataArrays(nFields-1); - - //create vectors necessary to hold the data - for (std::size_t i=0; i<nDataArrays; i++) - { - this->_vec_names.push_back(SensorData::convertString2SensorDataType(*++it)); - this->_data_unit_string.push_back(""); - std::vector<float> *data = new std::vector<float>; - this->_data_vecs.push_back(data); - } - - while ( getline(in, line) ) - { - fields = BaseLib::splitString(line, '\t'); - - if (nFields == fields.size()) - { - it = fields.begin(); - std::size_t pos(it->rfind(".")); - std::size_t current_time_step = (pos == std::string::npos) ? atoi((it++)->c_str()) : BaseLib::strDate2int(*it++); - this->_time_steps.push_back(current_time_step); - - for (std::size_t i=0; i<nDataArrays; i++) - this->_data_vecs[i]->push_back(static_cast<float>(strtod((it++)->c_str(), 0))); - } - else - return 0; - } - - in.close(); - - this->_start = this->_time_steps[0]; - this->_end = this->_time_steps[this->_time_steps.size()-1]; - - return 1; + std::ifstream in( file_name.c_str() ); + + if (!in.is_open()) + { + INFO("SensorData::readDataFromFile() - Could not open file %s.", file_name.c_str()); + return 0; + } + + std::string line(""); + + /* first line contains field names */ + getline(in, line); + std::list<std::string> fields = BaseLib::splitString(line, '\t'); + std::list<std::string>::const_iterator it (fields.begin()); + std::size_t nFields = fields.size(); + + if (nFields<2) + return 0; + + std::size_t nDataArrays(nFields-1); + + //create vectors necessary to hold the data + for (std::size_t i=0; i<nDataArrays; i++) + { + this->_vec_names.push_back(SensorData::convertString2SensorDataType(*++it)); + this->_data_unit_string.push_back(""); + std::vector<float> *data = new std::vector<float>; + this->_data_vecs.push_back(data); + } + + while ( getline(in, line) ) + { + fields = BaseLib::splitString(line, '\t'); + + if (nFields == fields.size()) + { + it = fields.begin(); + std::size_t pos(it->rfind(".")); + std::size_t current_time_step = (pos == std::string::npos) ? atoi((it++)->c_str()) : BaseLib::strDate2int(*it++); + this->_time_steps.push_back(current_time_step); + + for (std::size_t i=0; i<nDataArrays; i++) + this->_data_vecs[i]->push_back(static_cast<float>(strtod((it++)->c_str(), 0))); + } + else + return 0; + } + + in.close(); + + this->_start = this->_time_steps[0]; + this->_end = this->_time_steps[this->_time_steps.size()-1]; + + return 1; } std::string SensorData::convertSensorDataType2String(SensorDataType t) { - if (SensorDataType::EVAPORATION == t) return "Evaporation"; - else if (SensorDataType::PRECIPITATION == t) return "Precipitation"; - else if (SensorDataType::TEMPERATURE == t) return "Temperature"; - // pls leave this as last choice - else return "Unknown"; + if (SensorDataType::EVAPORATION == t) return "Evaporation"; + else if (SensorDataType::PRECIPITATION == t) return "Precipitation"; + else if (SensorDataType::TEMPERATURE == t) return "Temperature"; + // pls leave this as last choice + else return "Unknown"; } SensorDataType SensorData::convertString2SensorDataType(const std::string &s) { - if ((s.compare("Evaporation")==0) || (s.compare("EVAPORATION")==0)) return SensorDataType::EVAPORATION; - else if ((s.compare("Precipitation")==0) || (s.compare("PRECIPITATION")==0)) return SensorDataType::PRECIPITATION; - else if ((s.compare("Temperature")==0) || (s.compare("TEMPERATURE")==0)) return SensorDataType::TEMPERATURE; - else return SensorDataType::OTHER; + if ((s.compare("Evaporation")==0) || (s.compare("EVAPORATION")==0)) return SensorDataType::EVAPORATION; + else if ((s.compare("Precipitation")==0) || (s.compare("PRECIPITATION")==0)) return SensorDataType::PRECIPITATION; + else if ((s.compare("Temperature")==0) || (s.compare("TEMPERATURE")==0)) return SensorDataType::TEMPERATURE; + else return SensorDataType::OTHER; } diff --git a/GeoLib/SensorData.h b/GeoLib/SensorData.h index 2ab489a19d5d7b07feaf99762a25249927a844e5..fea582b7a90908b2251b8ccfa2a2dd5015c6685d 100644 --- a/GeoLib/SensorData.h +++ b/GeoLib/SensorData.h @@ -28,11 +28,11 @@ */ enum class SensorDataType { - OTHER = 0, - PRECIPITATION, - EVAPORATION, - TEMPERATURE - // please expand if necessary + OTHER = 0, + PRECIPITATION, + EVAPORATION, + TEMPERATURE + // please expand if necessary }; /** @@ -43,15 +43,15 @@ enum class SensorDataType */ enum class TimeStepType { - NONE = 0, - SECONDS, - MINUTES, - DAYS, - WEEKS, - MONTHS, - YEARS, - DATE, // time series is given as a vector of dates - DATETIME // time series is given as a vector of date + time + NONE = 0, + SECONDS, + MINUTES, + DAYS, + WEEKS, + MONTHS, + YEARS, + DATE, // time series is given as a vector of dates + DATETIME // time series is given as a vector of date + time }; /** @@ -63,71 +63,71 @@ enum class TimeStepType class SensorData { public: - /// Constructor using file name (automatically reads the file and fills all data structures) - SensorData(const std::string &file_name); + /// Constructor using file name (automatically reads the file and fills all data structures) + SensorData(const std::string &file_name); - /// Constructor using a time step vector valid for all time series that will be added later - SensorData(std::vector<std::size_t> time_steps); + /// Constructor using a time step vector valid for all time series that will be added later + SensorData(std::vector<std::size_t> time_steps); - /// Constructor using time step bounds for all time series that will be added later - SensorData(std::size_t first_timestep, std::size_t last_timestep, std::size_t step_size); + /// Constructor using time step bounds for all time series that will be added later + SensorData(std::size_t first_timestep, std::size_t last_timestep, std::size_t step_size); - ~SensorData(); + ~SensorData(); - /// Adds a time series that needs to conform to the time step vector specified in the constructor. - /// Optionally a unit for the time series can be given. - /// The name is converted to SensorDataType enum. - void addTimeSeries( const std::string &data_name, std::vector<float> *data, const std::string &data_unit_string = "" ); + /// Adds a time series that needs to conform to the time step vector specified in the constructor. + /// Optionally a unit for the time series can be given. + /// The name is converted to SensorDataType enum. + void addTimeSeries( const std::string &data_name, std::vector<float> *data, const std::string &data_unit_string = "" ); - /// Adds a time series that needs to conform to the time step vector specified in the constructor. - /// Optionally a unit for the time series can be given. - void addTimeSeries( SensorDataType data_name, std::vector<float> *data, const std::string &data_unit_string = "" ); + /// Adds a time series that needs to conform to the time step vector specified in the constructor. + /// Optionally a unit for the time series can be given. + void addTimeSeries( SensorDataType data_name, std::vector<float> *data, const std::string &data_unit_string = "" ); - /// Returns the time series with the given name - const std::vector<float>* getTimeSeries(SensorDataType time_series_name) const; + /// Returns the time series with the given name + const std::vector<float>* getTimeSeries(SensorDataType time_series_name) const; - /// Returns all time series names contained in this container - const std::vector<SensorDataType>& getTimeSeriesNames() const { return _vec_names; } + /// Returns all time series names contained in this container + const std::vector<SensorDataType>& getTimeSeriesNames() const { return _vec_names; } - /// Returns the time step vector (if it exists) - const std::vector<std::size_t>& getTimeSteps() const { return _time_steps; } + /// Returns the time step vector (if it exists) + const std::vector<std::size_t>& getTimeSteps() const { return _time_steps; } - /// Returns the first time step - std::size_t getStartTime() const { return _start; } + /// Returns the first time step + std::size_t getStartTime() const { return _start; } - /// Returns the last time step - std::size_t getEndTime() const { return _end; } + /// Returns the last time step + std::size_t getEndTime() const { return _end; } - /// Returns the interval between time steps (Returns "0" if a vector is given!) - std::size_t getStepSize() const { return _step_size; } + /// Returns the interval between time steps (Returns "0" if a vector is given!) + std::size_t getStepSize() const { return _step_size; } - /// Allows to set a unit for the time steps - void setTimeUnit(TimeStepType t) { _time_unit = t; } + /// Allows to set a unit for the time steps + void setTimeUnit(TimeStepType t) { _time_unit = t; } - /// Returns the unit the time steps - TimeStepType getTimeUnit() const { return _time_unit; } + /// Returns the unit the time steps + TimeStepType getTimeUnit() const { return _time_unit; } - /// Returns the data unit of the given time series - std::string getDataUnit(SensorDataType t) const; + /// Returns the data unit of the given time series + std::string getDataUnit(SensorDataType t) const; - /// Converts Sensor Data Types to Strings - static std::string convertSensorDataType2String(SensorDataType t); + /// Converts Sensor Data Types to Strings + static std::string convertSensorDataType2String(SensorDataType t); - /// Converts Strings to Sensor Data Types - static SensorDataType convertString2SensorDataType(const std::string &s); + /// Converts Strings to Sensor Data Types + static SensorDataType convertString2SensorDataType(const std::string &s); private: - /// Reads a CSV-file with time series data and fills the container. - int readDataFromFile(const std::string &file_name); - - std::size_t _start; - std::size_t _end; - std::size_t _step_size; - TimeStepType _time_unit; - std::vector<std::string> _data_unit_string; - std::vector<std::size_t> _time_steps; - std::vector<SensorDataType> _vec_names; - std::vector< std::vector<float>* > _data_vecs; + /// Reads a CSV-file with time series data and fills the container. + int readDataFromFile(const std::string &file_name); + + std::size_t _start; + std::size_t _end; + std::size_t _step_size; + TimeStepType _time_unit; + std::vector<std::string> _data_unit_string; + std::vector<std::size_t> _time_steps; + std::vector<SensorDataType> _vec_names; + std::vector< std::vector<float>* > _data_vecs; }; diff --git a/GeoLib/SimplePolygonTree.cpp b/GeoLib/SimplePolygonTree.cpp index e288664a2a824275518438c1c6a7cccce5b74ad9..669784ae2d57abca6326ac9566253c8396e76af9 100644 --- a/GeoLib/SimplePolygonTree.cpp +++ b/GeoLib/SimplePolygonTree.cpp @@ -17,41 +17,41 @@ namespace GeoLib { SimplePolygonTree::SimplePolygonTree(Polygon * polygon, SimplePolygonTree * parent) : - _node_polygon (polygon), _parent (parent) + _node_polygon (polygon), _parent (parent) {} SimplePolygonTree::~SimplePolygonTree() { - for (auto * child : _children) { - delete child; - } + for (auto * child : _children) { + delete child; + } } bool SimplePolygonTree::isPolygonInside (const SimplePolygonTree* polygon_hierarchy) const { - return _node_polygon->isPolylineInPolygon(*(polygon_hierarchy->getPolygon())); + return _node_polygon->isPolylineInPolygon(*(polygon_hierarchy->getPolygon())); } void SimplePolygonTree::insertSimplePolygonTree (SimplePolygonTree* polygon_hierarchy) { - const Polygon* polygon (polygon_hierarchy->getPolygon()); - bool nfound (true); - for (std::list<SimplePolygonTree*>::const_iterator it (_children.begin()); - it != _children.end() && nfound; ++it) { - if (((*it)->getPolygon())->isPolylineInPolygon (*(polygon))) { - (*it)->insertSimplePolygonTree (polygon_hierarchy); - nfound = false; - } - } - if (nfound) { - _children.push_back (polygon_hierarchy); - polygon_hierarchy->setParent(this); - } + const Polygon* polygon (polygon_hierarchy->getPolygon()); + bool nfound (true); + for (std::list<SimplePolygonTree*>::const_iterator it (_children.begin()); + it != _children.end() && nfound; ++it) { + if (((*it)->getPolygon())->isPolylineInPolygon (*(polygon))) { + (*it)->insertSimplePolygonTree (polygon_hierarchy); + nfound = false; + } + } + if (nfound) { + _children.push_back (polygon_hierarchy); + polygon_hierarchy->setParent(this); + } } const Polygon* SimplePolygonTree::getPolygon () const { - return _node_polygon; + return _node_polygon; } } // end namespace GeoLib diff --git a/GeoLib/SimplePolygonTree.h b/GeoLib/SimplePolygonTree.h index d5b547efe37542d7c5fe4fda06ad6f1824671e8a..d2c2a6a660aee44c738902d1da3510c333ea9d05 100644 --- a/GeoLib/SimplePolygonTree.h +++ b/GeoLib/SimplePolygonTree.h @@ -31,53 +31,53 @@ namespace GeoLib class SimplePolygonTree { public: - /** Creates a node of a tree containing a simple polygon. - * @param polygon the polygon represented by this tree node - * @param parent pointer to the parent node within the tree or nullptr - * (if SimplePolygonTree node is the root node of the tree) - */ - SimplePolygonTree(Polygon* polygon, SimplePolygonTree* parent); - /** Destructor: Attention: does not destroy the polygon! */ - virtual ~SimplePolygonTree(); - /** Checks if the polygon represented by the given polygon tree node - * is inside this node polygon. - */ - bool isPolygonInside (const SimplePolygonTree* polygon_tree) const; - /** Either insert the given SimplePolygonTree in one of the existing - * children or as a new child. - */ - void insertSimplePolygonTree (SimplePolygonTree* polygon_tree); + /** Creates a node of a tree containing a simple polygon. + * @param polygon the polygon represented by this tree node + * @param parent pointer to the parent node within the tree or nullptr + * (if SimplePolygonTree node is the root node of the tree) + */ + SimplePolygonTree(Polygon* polygon, SimplePolygonTree* parent); + /** Destructor: Attention: does not destroy the polygon! */ + virtual ~SimplePolygonTree(); + /** Checks if the polygon represented by the given polygon tree node + * is inside this node polygon. + */ + bool isPolygonInside (const SimplePolygonTree* polygon_tree) const; + /** Either insert the given SimplePolygonTree in one of the existing + * children or as a new child. + */ + void insertSimplePolygonTree (SimplePolygonTree* polygon_tree); - /** - * get the polygon represented by the tree node - * @return the polygon - */ - const Polygon* getPolygon () const; + /** + * get the polygon represented by the tree node + * @return the polygon + */ + const Polygon* getPolygon () const; - /** returns the number of children */ - std::size_t getNChildren() const { return _children.size(); } + /** returns the number of children */ + std::size_t getNChildren() const { return _children.size(); } protected: - /** - * the polygon this node stands for - */ - Polygon* _node_polygon; - /** - * the polygon represented by this node is contained in the - * polygon represented by the parent node in the tree - */ - SimplePolygonTree* _parent; - /** - * list of polygons (represented by SimplePolygonTree nodes) contained - * in the _node_polygon - */ - std::list<SimplePolygonTree*> _children; + /** + * the polygon this node stands for + */ + Polygon* _node_polygon; + /** + * the polygon represented by this node is contained in the + * polygon represented by the parent node in the tree + */ + SimplePolygonTree* _parent; + /** + * list of polygons (represented by SimplePolygonTree nodes) contained + * in the _node_polygon + */ + std::list<SimplePolygonTree*> _children; private: - void setParent(SimplePolygonTree* parent) - { - _parent = parent; - } + void setParent(SimplePolygonTree* parent) + { + _parent = parent; + } }; /** @@ -86,26 +86,26 @@ private: template <typename POLYGONTREETYPE> void createPolygonTrees (std::list<POLYGONTREETYPE*>& list_of_simple_polygon_hierarchies) { - typedef typename std::list<POLYGONTREETYPE*>::const_iterator CIT; - typedef typename std::list<POLYGONTREETYPE*>::iterator IT; - for (CIT it0(list_of_simple_polygon_hierarchies.begin()); - it0 != list_of_simple_polygon_hierarchies.end(); ++it0) { - IT it1 = list_of_simple_polygon_hierarchies.begin(); - while (it1 != list_of_simple_polygon_hierarchies.end()) { - if (it0 == it1) { // don't check same polygons - ++it1; - // skip test if it1 points to the end after increment - if (it1 == list_of_simple_polygon_hierarchies.end()) - break; - } - if ((*it0)->isPolygonInside(*it1)) { - (*it0)->insertSimplePolygonTree(*it1); - it1 = list_of_simple_polygon_hierarchies.erase(it1); - } else { - ++it1; - } - } - } + typedef typename std::list<POLYGONTREETYPE*>::const_iterator CIT; + typedef typename std::list<POLYGONTREETYPE*>::iterator IT; + for (CIT it0(list_of_simple_polygon_hierarchies.begin()); + it0 != list_of_simple_polygon_hierarchies.end(); ++it0) { + IT it1 = list_of_simple_polygon_hierarchies.begin(); + while (it1 != list_of_simple_polygon_hierarchies.end()) { + if (it0 == it1) { // don't check same polygons + ++it1; + // skip test if it1 points to the end after increment + if (it1 == list_of_simple_polygon_hierarchies.end()) + break; + } + if ((*it0)->isPolygonInside(*it1)) { + (*it0)->insertSimplePolygonTree(*it1); + it1 = list_of_simple_polygon_hierarchies.erase(it1); + } else { + ++it1; + } + } + } } diff --git a/GeoLib/Station.cpp b/GeoLib/Station.cpp index c8f0d45570dd0e6f5f5d563dac443282f37787d7..47d8b84ded8a2384391c8519f848b7ef1f28205f 100644 --- a/GeoLib/Station.cpp +++ b/GeoLib/Station.cpp @@ -23,62 +23,62 @@ namespace GeoLib { Station::Station(double x, double y, double z, std::string name) : - Point (x,y,z), _name(name), _type(Station::StationType::STATION), - _station_value(0.0), _sensor_data(nullptr) + Point (x,y,z), _name(name), _type(Station::StationType::STATION), + _station_value(0.0), _sensor_data(nullptr) {} Station::Station(Point* coords, std::string name) : - Point (*coords), _name(name), _type(Station::StationType::STATION), - _station_value(0.0), _sensor_data(nullptr) + Point (*coords), _name(name), _type(Station::StationType::STATION), + _station_value(0.0), _sensor_data(nullptr) {} Station::Station(Station const& src) : - Point(src), _name(src._name), _type(src._type), - _station_value(src._station_value), _sensor_data(nullptr) + Point(src), _name(src._name), _type(src._type), + _station_value(src._station_value), _sensor_data(nullptr) {} Station::~Station() { - delete this->_sensor_data; + delete this->_sensor_data; } Station* Station::createStation(const std::string & line) { - Station* station = new Station(); - std::list<std::string> fields = BaseLib::splitString(line, '\t'); + Station* station = new Station(); + std::list<std::string> fields = BaseLib::splitString(line, '\t'); - if (fields.size() >= 3) - { - auto it = fields.begin(); - station->_name = *it; - (*station)[0] = std::strtod((BaseLib::replaceString(",", ".", *(++it))).c_str(), nullptr); - (*station)[1] = std::strtod((BaseLib::replaceString(",", ".", *(++it))).c_str(), nullptr); - if (++it != fields.end()) - (*station)[2] = std::strtod((BaseLib::replaceString(",", ".", *it)).c_str(), nullptr); - } - else - { - INFO("Station::createStation() - Unexpected file format."); - delete station; - return nullptr; - } - return station; + if (fields.size() >= 3) + { + auto it = fields.begin(); + station->_name = *it; + (*station)[0] = std::strtod((BaseLib::replaceString(",", ".", *(++it))).c_str(), nullptr); + (*station)[1] = std::strtod((BaseLib::replaceString(",", ".", *(++it))).c_str(), nullptr); + if (++it != fields.end()) + (*station)[2] = std::strtod((BaseLib::replaceString(",", ".", *it)).c_str(), nullptr); + } + else + { + INFO("Station::createStation() - Unexpected file format."); + delete station; + return nullptr; + } + return station; } Station* Station::createStation(const std::string &name, double x, double y, double z) { - Station* station = new Station(); - station->_name = name; - (*station)[0] = x; - (*station)[1] = y; - (*station)[2] = z; - return station; + Station* station = new Station(); + station->_name = name; + (*station)[0] = x; + (*station)[1] = y; + (*station)[2] = z; + return station; } bool isStation(GeoLib::Point const* pnt) { - GeoLib::Station const* bh(dynamic_cast<GeoLib::Station const*>(pnt)); - return bh != nullptr; + GeoLib::Station const* bh(dynamic_cast<GeoLib::Station const*>(pnt)); + return bh != nullptr; } } // namespace diff --git a/GeoLib/Station.h b/GeoLib/Station.h index b269b8c694f6faccf88d0288ae6cd24581fc559d..243c9ccea8d753fe51d16b2cdcd567da803aae2e 100644 --- a/GeoLib/Station.h +++ b/GeoLib/Station.h @@ -37,69 +37,69 @@ namespace GeoLib class Station : public Point { public: - /// Signals if the object is a "simple" Station or a Borehole (i.e. containing borehole-specific information). - enum class StationType - { - INVALID = 0, - STATION, - BOREHOLE - }; - - /** - * \brief Constructor - * - * Constructor initialising a Station object - * \param x The x-coordinate of the station. - * \param y The y-coordinate of the station. - * \param z The z-coordinate of the station. - * \param name The name of the station. - */ - Station(double x = 0.0, - double y = 0.0, - double z = 0.0, - std::string name = ""); - - Station(Point* coords, std::string name = ""); - - /** - * Constructor copies the source object - * @param src the Station object that should be copied - */ - Station(Station const& src); - - virtual ~Station(); - - /// Returns the name of the station. - std::string const& getName() const { return _name; } - - /// Returns the GeoSys-station-type for the station. - StationType type() const { return _type; } - - /// Creates a Station-object from information contained in a string (assuming the string has the right format) - static Station* createStation(const std::string &line); - - /// Creates a new station object based on the given parameters. - static Station* createStation(const std::string &name, double x, double y, double z); - - /// Returns the specific value for this station - double getStationValue() { return this->_station_value; } - - /// Allows to set a specific value for this station (e.g. for classification) - void setStationValue(double station_value) { this->_station_value = station_value; } - - /// Allows to add sensor data from a CSV file to the observation site - void addSensorDataFromCSV(const std::string &file_name) { this->_sensor_data = new SensorData(file_name); } - - /// Returns all the sensor data for this observation site - const SensorData* getSensorData() { return this->_sensor_data; } + /// Signals if the object is a "simple" Station or a Borehole (i.e. containing borehole-specific information). + enum class StationType + { + INVALID = 0, + STATION, + BOREHOLE + }; + + /** + * \brief Constructor + * + * Constructor initialising a Station object + * \param x The x-coordinate of the station. + * \param y The y-coordinate of the station. + * \param z The z-coordinate of the station. + * \param name The name of the station. + */ + Station(double x = 0.0, + double y = 0.0, + double z = 0.0, + std::string name = ""); + + Station(Point* coords, std::string name = ""); + + /** + * Constructor copies the source object + * @param src the Station object that should be copied + */ + Station(Station const& src); + + virtual ~Station(); + + /// Returns the name of the station. + std::string const& getName() const { return _name; } + + /// Returns the GeoSys-station-type for the station. + StationType type() const { return _type; } + + /// Creates a Station-object from information contained in a string (assuming the string has the right format) + static Station* createStation(const std::string &line); + + /// Creates a new station object based on the given parameters. + static Station* createStation(const std::string &name, double x, double y, double z); + + /// Returns the specific value for this station + double getStationValue() { return this->_station_value; } + + /// Allows to set a specific value for this station (e.g. for classification) + void setStationValue(double station_value) { this->_station_value = station_value; } + + /// Allows to add sensor data from a CSV file to the observation site + void addSensorDataFromCSV(const std::string &file_name) { this->_sensor_data = new SensorData(file_name); } + + /// Returns all the sensor data for this observation site + const SensorData* getSensorData() { return this->_sensor_data; } protected: - std::string _name; - StationType _type; // GeoSys Station Type + std::string _name; + StationType _type; // GeoSys Station Type private: - double _station_value; - SensorData* _sensor_data; + double _station_value; + SensorData* _sensor_data; }; diff --git a/GeoLib/StationBorehole.cpp b/GeoLib/StationBorehole.cpp index 338d84c17002506306e160d63f84bcc7dbaecd8e..b97620986c8035c2caeb63881484c72a529abd6b 100644 --- a/GeoLib/StationBorehole.cpp +++ b/GeoLib/StationBorehole.cpp @@ -31,205 +31,205 @@ namespace GeoLib //////////////////////// StationBorehole::StationBorehole(double x, double y, double z, const std::string &name) : - Station (x, y, z, name), _depth(0), _date(0) + Station (x, y, z, name), _depth(0), _date(0) { - _type = Station::StationType::BOREHOLE; + _type = Station::StationType::BOREHOLE; - // add first point of borehole - _profilePntVec.push_back(this); - _soilName.push_back(""); + // add first point of borehole + _profilePntVec.push_back(this); + _soilName.push_back(""); } StationBorehole::~StationBorehole(void) { - // deletes profile vector of borehole, starting at layer 1 - // the first point is NOT deleted as it points to the station object itself - for (std::size_t k(1); k < _profilePntVec.size(); k++) - delete _profilePntVec[k]; + // deletes profile vector of borehole, starting at layer 1 + // the first point is NOT deleted as it points to the station object itself + for (std::size_t k(1); k < _profilePntVec.size(); k++) + delete _profilePntVec[k]; } int StationBorehole::find(const std::string &str) { - std::size_t size = _soilName.size(); - for (std::size_t i = 0; i < size; i++) - if (_soilName[i].find(str) == 0) - return 1; - return 0; + std::size_t size = _soilName.size(); + for (std::size_t i = 0; i < size; i++) + if (_soilName[i].find(str) == 0) + return 1; + return 0; } int StationBorehole::readStratigraphyFile(const std::string &path, std::vector<std::list<std::string> > &data) { - std::string line; - std::ifstream in( path.c_str() ); + std::string line; + std::ifstream in( path.c_str() ); - if (!in.is_open()) - { - WARN("StationBorehole::readStratigraphyFile() - Could not open file %s.", path.c_str()); - return 0; - } + if (!in.is_open()) + { + WARN("StationBorehole::readStratigraphyFile() - Could not open file %s.", path.c_str()); + return 0; + } - while ( getline(in, line) ) - { - std::list<std::string> fields = BaseLib::splitString(line, '\t'); - data.push_back(fields); - } + while ( getline(in, line) ) + { + std::list<std::string> fields = BaseLib::splitString(line, '\t'); + data.push_back(fields); + } - in.close(); + in.close(); - return 1; + return 1; } int StationBorehole::addStratigraphy(const std::string &path, StationBorehole* borehole) { - std::vector<std::list<std::string> > data; - if (readStratigraphyFile(path, data)) - { - std::size_t size = data.size(); - for (std::size_t i = 0; i < size; i++) - addLayer(data[i], borehole); - - // check if a layer is missing - size = borehole->_soilName.size(); - INFO("StationBorehole::addStratigraphy ToDo"); - // for (std::size_t i=0; i<size; i++) - // { - // if ((borehole->_soilLayerThickness[i] == -1) ||(borehole->_soilName[i].compare("") == 0)) - // { - // borehole->_soilLayerThickness.clear(); - // borehole->_soilName.clear(); - // - // WARN("StationBorehole::addStratigraphy() - Profile incomplete (Borehole %s, Layer %d missing)", borehole->_name.c_str(), i+1); - // - // return 0; - // } - // } - } - else - borehole->addSoilLayer(borehole->getDepth(), "depth"); - - return 1; + std::vector<std::list<std::string> > data; + if (readStratigraphyFile(path, data)) + { + std::size_t size = data.size(); + for (std::size_t i = 0; i < size; i++) + addLayer(data[i], borehole); + + // check if a layer is missing + size = borehole->_soilName.size(); + INFO("StationBorehole::addStratigraphy ToDo"); + // for (std::size_t i=0; i<size; i++) + // { + // if ((borehole->_soilLayerThickness[i] == -1) ||(borehole->_soilName[i].compare("") == 0)) + // { + // borehole->_soilLayerThickness.clear(); + // borehole->_soilName.clear(); + // + // WARN("StationBorehole::addStratigraphy() - Profile incomplete (Borehole %s, Layer %d missing)", borehole->_name.c_str(), i+1); + // + // return 0; + // } + // } + } + else + borehole->addSoilLayer(borehole->getDepth(), "depth"); + + return 1; } int StationBorehole::addLayer(std::list<std::string> fields, StationBorehole* borehole) { - if (fields.size() >= 4) /* check if there are enough fields to create a borehole object */ - { - if (fields.front().compare(borehole->_name) == 0) /* check if the name of the borehole matches the name in the data */ - { - fields.pop_front(); - - // int layer = atoi(fields.front().c_str()); - fields.pop_front(); - - ERR("StationBorehole::addLayer - assuming correct order"); - double thickness(strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), 0)); - fields.pop_front(); - borehole->addSoilLayer(thickness, fields.front()); - } - } - else - { - WARN("StationBorehole::addLayer() - Unexpected file format (Borehole %s).", borehole->_name.c_str()); - return 0; - } - return 1; + if (fields.size() >= 4) /* check if there are enough fields to create a borehole object */ + { + if (fields.front().compare(borehole->_name) == 0) /* check if the name of the borehole matches the name in the data */ + { + fields.pop_front(); + + // int layer = atoi(fields.front().c_str()); + fields.pop_front(); + + ERR("StationBorehole::addLayer - assuming correct order"); + double thickness(strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), 0)); + fields.pop_front(); + borehole->addSoilLayer(thickness, fields.front()); + } + } + else + { + WARN("StationBorehole::addLayer() - Unexpected file format (Borehole %s).", borehole->_name.c_str()); + return 0; + } + return 1; } int StationBorehole::addStratigraphy(const std::vector<Point*> &profile, const std::vector<std::string> &soil_names) { - if (((profile.size()-1) == soil_names.size()) && (soil_names.size()>0)) - { - this->_profilePntVec.push_back(profile[0]); - std::size_t nLayers = soil_names.size(); - for (std::size_t i=0; i<nLayers; i++) - { - this->_profilePntVec.push_back(profile[i+1]); - this->_soilName.push_back(soil_names[i]); - } - return 1; - } - - ERR("Error in StationBorehole::addStratigraphy() - Length of parameter vectors does not match."); - return 0; + if (((profile.size()-1) == soil_names.size()) && (soil_names.size()>0)) + { + this->_profilePntVec.push_back(profile[0]); + std::size_t nLayers = soil_names.size(); + for (std::size_t i=0; i<nLayers; i++) + { + this->_profilePntVec.push_back(profile[i+1]); + this->_soilName.push_back(soil_names[i]); + } + return 1; + } + + ERR("Error in StationBorehole::addStratigraphy() - Length of parameter vectors does not match."); + return 0; } int StationBorehole::addStratigraphies(const std::string &path, std::vector<Point*>* boreholes) { - std::vector<std::list<std::string> > data; - - if (readStratigraphyFile(path, data)) - { - std::string name; - - std::size_t it = 0; - std::size_t nBoreholes = data.size(); - for (std::size_t i = 0; i < nBoreholes; i++) - { - std::list<std::string> fields = data[i]; - - if (fields.size() >= 4) - { - name = static_cast<StationBorehole*>((*boreholes)[it])->_name; - if ( fields.front().compare(name) != 0 ) - if (it < boreholes->size() - 1) - it++; - - fields.pop_front(); - //the method just assumes that layers are read in correct order - fields.pop_front(); - double thickness (strtod(BaseLib::replaceString(",", ".", - fields.front()).c_str(), 0)); - fields.pop_front(); - std::string soil_name (fields.front()); - fields.pop_front(); - static_cast<StationBorehole*>((*boreholes)[it])->addSoilLayer( - thickness, - soil_name); - } - else - ERR("Error in StationBorehole::addStratigraphies() - Unexpected file format."); - //return 0; - } - } - else - createSurrogateStratigraphies(boreholes); - - return 1; + std::vector<std::list<std::string> > data; + + if (readStratigraphyFile(path, data)) + { + std::string name; + + std::size_t it = 0; + std::size_t nBoreholes = data.size(); + for (std::size_t i = 0; i < nBoreholes; i++) + { + std::list<std::string> fields = data[i]; + + if (fields.size() >= 4) + { + name = static_cast<StationBorehole*>((*boreholes)[it])->_name; + if ( fields.front().compare(name) != 0 ) + if (it < boreholes->size() - 1) + it++; + + fields.pop_front(); + //the method just assumes that layers are read in correct order + fields.pop_front(); + double thickness (strtod(BaseLib::replaceString(",", ".", + fields.front()).c_str(), 0)); + fields.pop_front(); + std::string soil_name (fields.front()); + fields.pop_front(); + static_cast<StationBorehole*>((*boreholes)[it])->addSoilLayer( + thickness, + soil_name); + } + else + ERR("Error in StationBorehole::addStratigraphies() - Unexpected file format."); + //return 0; + } + } + else + createSurrogateStratigraphies(boreholes); + + return 1; } StationBorehole* StationBorehole::createStation(const std::string &line) { - StationBorehole* borehole = new StationBorehole(); - std::list<std::string> fields = BaseLib::splitString(line, '\t'); - - if (fields.size() >= 5) - { - borehole->_name = fields.front(); - fields.pop_front(); - (*borehole)[0] = strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), nullptr); - fields.pop_front(); - (*borehole)[1] = strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), nullptr); - fields.pop_front(); - (*borehole)[2] = strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), nullptr); - fields.pop_front(); - borehole->_depth = strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), nullptr); - fields.pop_front(); - if (fields.empty()) - borehole->_date = 0; - else - { - borehole->_date = BaseLib::strDate2int(fields.front()); - fields.pop_front(); - } - } - else - { - WARN("Station::createStation() - Unexpected file format."); - delete borehole; - return nullptr; - } - return borehole; + StationBorehole* borehole = new StationBorehole(); + std::list<std::string> fields = BaseLib::splitString(line, '\t'); + + if (fields.size() >= 5) + { + borehole->_name = fields.front(); + fields.pop_front(); + (*borehole)[0] = strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), nullptr); + fields.pop_front(); + (*borehole)[1] = strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), nullptr); + fields.pop_front(); + (*borehole)[2] = strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), nullptr); + fields.pop_front(); + borehole->_depth = strtod(BaseLib::replaceString(",", ".", fields.front()).c_str(), nullptr); + fields.pop_front(); + if (fields.empty()) + borehole->_date = 0; + else + { + borehole->_date = BaseLib::strDate2int(fields.front()); + fields.pop_front(); + } + } + else + { + WARN("Station::createStation() - Unexpected file format."); + delete borehole; + return nullptr; + } + return borehole; } StationBorehole* StationBorehole::createStation(const std::string &name, @@ -239,65 +239,65 @@ StationBorehole* StationBorehole::createStation(const std::string &name, double depth, const std::string &date) { - StationBorehole* station = new StationBorehole(); - station->_name = name; - (*station)[0] = x; - (*station)[1] = y; - (*station)[2] = z; - station->_depth = depth; - if (date.compare("0000-00-00") != 0) - station->_date = BaseLib::xmlDate2int(date); - return station; + StationBorehole* station = new StationBorehole(); + station->_name = name; + (*station)[0] = x; + (*station)[1] = y; + (*station)[2] = z; + station->_depth = depth; + if (date.compare("0000-00-00") != 0) + station->_date = BaseLib::xmlDate2int(date); + return station; } void StationBorehole::createSurrogateStratigraphies(std::vector<Point*>* boreholes) { - std::size_t nBoreholes = boreholes->size(); - for (std::size_t i = 0; i < nBoreholes; i++) - { - StationBorehole* bore = static_cast<StationBorehole*>((*boreholes)[i]); - bore->addSoilLayer(bore->getDepth(), "depth"); - } + std::size_t nBoreholes = boreholes->size(); + for (std::size_t i = 0; i < nBoreholes; i++) + { + StationBorehole* bore = static_cast<StationBorehole*>((*boreholes)[i]); + bore->addSoilLayer(bore->getDepth(), "depth"); + } } void StationBorehole::addSoilLayer ( double thickness, const std::string &soil_name) { - /* - // TF - Altmark - if (_profilePntVec.empty()) - addSoilLayer ((*this)[0], (*this)[1], (*this)[2]-thickness, soil_name); - else { - std::size_t idx (_profilePntVec.size()); - // read coordinates from last above - double x((*_profilePntVec[idx-1])[0]); - double y((*_profilePntVec[idx-1])[1]); - double z((*_profilePntVec[idx-1])[2]-thickness); - addSoilLayer (x, y, z, soil_name); - } - */ - - // KR - Bode - if (_profilePntVec.empty()) - addSoilLayer ((*this)[0], (*this)[1], (*this)[2], ""); - - std::size_t idx (_profilePntVec.size()); - double x((*_profilePntVec[idx - 1])[0]); - double y((*_profilePntVec[idx - 1])[1]); - double z((*_profilePntVec[0])[2] - thickness); - addSoilLayer (x, y, z, soil_name); + /* + // TF - Altmark + if (_profilePntVec.empty()) + addSoilLayer ((*this)[0], (*this)[1], (*this)[2]-thickness, soil_name); + else { + std::size_t idx (_profilePntVec.size()); + // read coordinates from last above + double x((*_profilePntVec[idx-1])[0]); + double y((*_profilePntVec[idx-1])[1]); + double z((*_profilePntVec[idx-1])[2]-thickness); + addSoilLayer (x, y, z, soil_name); + } + */ + + // KR - Bode + if (_profilePntVec.empty()) + addSoilLayer ((*this)[0], (*this)[1], (*this)[2], ""); + + std::size_t idx (_profilePntVec.size()); + double x((*_profilePntVec[idx - 1])[0]); + double y((*_profilePntVec[idx - 1])[1]); + double z((*_profilePntVec[0])[2] - thickness); + addSoilLayer (x, y, z, soil_name); } void StationBorehole::addSoilLayer ( double x, double y, double z, const std::string &soil_name) { - _profilePntVec.push_back (new Point (x, y, z)); - _soilName.push_back(soil_name); + _profilePntVec.push_back (new Point (x, y, z)); + _soilName.push_back(soil_name); } bool isBorehole(GeoLib::Point const* pnt) { - GeoLib::StationBorehole const* bh( - dynamic_cast<GeoLib::StationBorehole const*>(pnt)); - return bh != nullptr; + GeoLib::StationBorehole const* bh( + dynamic_cast<GeoLib::StationBorehole const*>(pnt)); + return bh != nullptr; } } // namespace diff --git a/GeoLib/StationBorehole.h b/GeoLib/StationBorehole.h index 5c5ae62e3ad40c321884554190a0d31235a24d50..75aabe6a4a4e5dd97c5946b97306ce4e1709e446 100644 --- a/GeoLib/StationBorehole.h +++ b/GeoLib/StationBorehole.h @@ -33,88 +33,88 @@ namespace GeoLib class StationBorehole : public Station { public: - /** constructor initialises the borehole with the given coordinates */ - StationBorehole(double x = 0.0, double y = 0.0, double z = 0.0, const std::string &name = ""); - ~StationBorehole(void); - - /// Creates a StationBorehole-object from a string (assuming the string has the right format) - static StationBorehole* createStation(const std::string &line); - - /// Creates a new borehole object based on the given parameters. - static StationBorehole* createStation(const std::string &name, - double x, - double y, - double z, - double depth, - const std::string &date = ""); - - /// Adds a stratigraphy to a borehole given a vector of points of length "n" and a vector of soil names of length "n-1". - int addStratigraphy(const std::vector<Point*> &profile, const std::vector<std::string> &soil_names); - - /// Reads the stratigraphy for a specified station from a file - static int addStratigraphy(const std::string &path, StationBorehole* borehole); - - /** - * \brief Reads all stratigraphy information from a file in one go. - * - * Reads all stratigraphy information from a file in one go. - * Be very careful when using this method -- it is pretty fast but it checks nothing and just - * assumes that everything is in right order and will work out fine! - */ - static int addStratigraphies(const std::string &path, std::vector<Point*>* boreholes); - - /// Finds the given string in the vector of soil-names - int find(const std::string &str); - - // Returns the depth of the borehole - double getDepth() const { return _depth; } - - /// Returns the date entry for the borehole - double getDate() const { return _date; } - - /// Returns a reference to a vector of Points representing the stratigraphy of the borehole (incl. the station-point itself) - const std::vector<Point*> &getProfile() const { return _profilePntVec; } - - /// Returns a reference to a vector of soil names for the stratigraphy of the borehole - const std::vector<std::string> &getSoilNames() const { return _soilName; } - - /// Sets the depth of the borehole - void setDepth( double depth ) { _depth = depth; } - - /// Add a soil layer to the boreholes stratigraphy. - void addSoilLayer ( double thickness, const std::string &soil_name); - - /** - * Add a soil layer to the boreholes stratigraphy. - * Note: The given coordinates always mark THE END of the soil layer. The reason behind this is - * that the beginning of the first layer is identical with the position of the borehole. For each - * layer following the beginning is already given by the end of the last layer. This also saves - * a seperate entry in the profile vector for the end of the borehole which in the given notation - * is just the coordinate given for the last soil layer (i.e. the end of that layer). - */ - void addSoilLayer ( double x, double y, double z, const std::string &soil_name); + /** constructor initialises the borehole with the given coordinates */ + StationBorehole(double x = 0.0, double y = 0.0, double z = 0.0, const std::string &name = ""); + ~StationBorehole(void); + + /// Creates a StationBorehole-object from a string (assuming the string has the right format) + static StationBorehole* createStation(const std::string &line); + + /// Creates a new borehole object based on the given parameters. + static StationBorehole* createStation(const std::string &name, + double x, + double y, + double z, + double depth, + const std::string &date = ""); + + /// Adds a stratigraphy to a borehole given a vector of points of length "n" and a vector of soil names of length "n-1". + int addStratigraphy(const std::vector<Point*> &profile, const std::vector<std::string> &soil_names); + + /// Reads the stratigraphy for a specified station from a file + static int addStratigraphy(const std::string &path, StationBorehole* borehole); + + /** + * \brief Reads all stratigraphy information from a file in one go. + * + * Reads all stratigraphy information from a file in one go. + * Be very careful when using this method -- it is pretty fast but it checks nothing and just + * assumes that everything is in right order and will work out fine! + */ + static int addStratigraphies(const std::string &path, std::vector<Point*>* boreholes); + + /// Finds the given string in the vector of soil-names + int find(const std::string &str); + + // Returns the depth of the borehole + double getDepth() const { return _depth; } + + /// Returns the date entry for the borehole + double getDate() const { return _date; } + + /// Returns a reference to a vector of Points representing the stratigraphy of the borehole (incl. the station-point itself) + const std::vector<Point*> &getProfile() const { return _profilePntVec; } + + /// Returns a reference to a vector of soil names for the stratigraphy of the borehole + const std::vector<std::string> &getSoilNames() const { return _soilName; } + + /// Sets the depth of the borehole + void setDepth( double depth ) { _depth = depth; } + + /// Add a soil layer to the boreholes stratigraphy. + void addSoilLayer ( double thickness, const std::string &soil_name); + + /** + * Add a soil layer to the boreholes stratigraphy. + * Note: The given coordinates always mark THE END of the soil layer. The reason behind this is + * that the beginning of the first layer is identical with the position of the borehole. For each + * layer following the beginning is already given by the end of the last layer. This also saves + * a seperate entry in the profile vector for the end of the borehole which in the given notation + * is just the coordinate given for the last soil layer (i.e. the end of that layer). + */ + void addSoilLayer ( double x, double y, double z, const std::string &soil_name); private: - /// Adds a layer for the specified borehole profile based on the information given in the stringlist - static int addLayer(std::list<std::string> fields, StationBorehole* borehole); + /// Adds a layer for the specified borehole profile based on the information given in the stringlist + static int addLayer(std::list<std::string> fields, StationBorehole* borehole); - /// Creates fake stratigraphies of only one layer with a thickness equal to the borehole depth - static void createSurrogateStratigraphies(std::vector<Point*>* boreholes); + /// Creates fake stratigraphies of only one layer with a thickness equal to the borehole depth + static void createSurrogateStratigraphies(std::vector<Point*>* boreholes); - /// Reads the specified file containing borehole stratigraphies into an vector of stringlists - static int readStratigraphyFile(const std::string &path, - std::vector<std::list<std::string> > &data); + /// Reads the specified file containing borehole stratigraphies into an vector of stringlists + static int readStratigraphyFile(const std::string &path, + std::vector<std::list<std::string> > &data); - //long profile_type; - //std::vector<long> _soilType; - double _depth; // depth of the borehole - int _date; // date when the borehole has been drilled + //long profile_type; + //std::vector<long> _soilType; + double _depth; // depth of the borehole + int _date; // date when the borehole has been drilled - /// Contains the names for all the soil layers - std::vector<std::string> _soilName; + /// Contains the names for all the soil layers + std::vector<std::string> _soilName; - /// Contains the points for the lower boundaries of all layers - std::vector<Point*> _profilePntVec; + /// Contains the points for the lower boundaries of all layers + std::vector<Point*> _profilePntVec; }; bool isBorehole(GeoLib::Point const* pnt); diff --git a/GeoLib/Surface.cpp b/GeoLib/Surface.cpp index 3e7cac6b9322d4c96253aa139573b99aa2bddac5..3b8b55fad2946baf4e0e27a80d20ebe157245ffb 100644 --- a/GeoLib/Surface.cpp +++ b/GeoLib/Surface.cpp @@ -32,118 +32,118 @@ namespace GeoLib { Surface::Surface (const std::vector<Point*> &pnt_vec) : - GeoObject(), _sfc_pnts(pnt_vec), _bounding_volume(nullptr), - _surface_grid(nullptr) + GeoObject(), _sfc_pnts(pnt_vec), _bounding_volume(nullptr), + _surface_grid(nullptr) {} Surface::~Surface () { - for (std::size_t k(0); k < _sfc_triangles.size(); k++) - delete _sfc_triangles[k]; + for (std::size_t k(0); k < _sfc_triangles.size(); k++) + delete _sfc_triangles[k]; } void Surface::addTriangle(std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c) { - assert (pnt_a < _sfc_pnts.size() && pnt_b < _sfc_pnts.size() && pnt_c < _sfc_pnts.size()); - - // Check if two points of the triangle have identical IDs - if (pnt_a == pnt_b || pnt_a == pnt_c || pnt_b == pnt_c) - return; - - // Adding a new triangle invalides the surface grid. - _surface_grid.reset(); - - _sfc_triangles.push_back(new Triangle(_sfc_pnts, pnt_a, pnt_b, pnt_c)); - if (!_bounding_volume) { - std::vector<std::size_t> ids(3); - ids[0] = pnt_a; - ids[1] = pnt_b; - ids[2] = pnt_c; - _bounding_volume.reset(new AABB(_sfc_pnts, ids)); - } else { - _bounding_volume->update(*_sfc_pnts[pnt_a]); - _bounding_volume->update(*_sfc_pnts[pnt_b]); - _bounding_volume->update(*_sfc_pnts[pnt_c]); - } + assert (pnt_a < _sfc_pnts.size() && pnt_b < _sfc_pnts.size() && pnt_c < _sfc_pnts.size()); + + // Check if two points of the triangle have identical IDs + if (pnt_a == pnt_b || pnt_a == pnt_c || pnt_b == pnt_c) + return; + + // Adding a new triangle invalides the surface grid. + _surface_grid.reset(); + + _sfc_triangles.push_back(new Triangle(_sfc_pnts, pnt_a, pnt_b, pnt_c)); + if (!_bounding_volume) { + std::vector<std::size_t> ids(3); + ids[0] = pnt_a; + ids[1] = pnt_b; + ids[2] = pnt_c; + _bounding_volume.reset(new AABB(_sfc_pnts, ids)); + } else { + _bounding_volume->update(*_sfc_pnts[pnt_a]); + _bounding_volume->update(*_sfc_pnts[pnt_b]); + _bounding_volume->update(*_sfc_pnts[pnt_c]); + } } Surface* Surface::createSurface(const Polyline &ply) { - if (!ply.isClosed()) { - WARN("Error in Surface::createSurface() - Polyline is not closed."); - return nullptr; - } - - if (ply.getNumberOfPoints() > 2) { - // create empty surface - Surface *sfc(new Surface(ply.getPointsVec())); - - Polygon* polygon (new Polygon (ply)); - polygon->computeListOfSimplePolygons (); - - // create surfaces from simple polygons - const std::list<GeoLib::Polygon*>& list_of_simple_polygons (polygon->getListOfSimplePolygons()); - for (std::list<GeoLib::Polygon*>::const_iterator simple_polygon_it (list_of_simple_polygons.begin()); - simple_polygon_it != list_of_simple_polygons.end(); ++simple_polygon_it) { - - std::list<GeoLib::Triangle> triangles; - GeoLib::EarClippingTriangulation(*simple_polygon_it, triangles); - - // add Triangles to Surface - std::list<GeoLib::Triangle>::const_iterator it (triangles.begin()); - while (it != triangles.end()) { - sfc->addTriangle ((*it)[0], (*it)[1], (*it)[2]); - ++it; - } - } - delete polygon; - if (sfc->getNTriangles() == 0) { - WARN("Surface::createSurface(): Triangulation does not contain any triangle."); - delete sfc; - return nullptr; - } - return sfc; - } else { - WARN("Error in Surface::createSurface() - Polyline consists of less than three points and therefore cannot be triangulated."); - return nullptr; - } + if (!ply.isClosed()) { + WARN("Error in Surface::createSurface() - Polyline is not closed."); + return nullptr; + } + + if (ply.getNumberOfPoints() > 2) { + // create empty surface + Surface *sfc(new Surface(ply.getPointsVec())); + + Polygon* polygon (new Polygon (ply)); + polygon->computeListOfSimplePolygons (); + + // create surfaces from simple polygons + const std::list<GeoLib::Polygon*>& list_of_simple_polygons (polygon->getListOfSimplePolygons()); + for (std::list<GeoLib::Polygon*>::const_iterator simple_polygon_it (list_of_simple_polygons.begin()); + simple_polygon_it != list_of_simple_polygons.end(); ++simple_polygon_it) { + + std::list<GeoLib::Triangle> triangles; + GeoLib::EarClippingTriangulation(*simple_polygon_it, triangles); + + // add Triangles to Surface + std::list<GeoLib::Triangle>::const_iterator it (triangles.begin()); + while (it != triangles.end()) { + sfc->addTriangle ((*it)[0], (*it)[1], (*it)[2]); + ++it; + } + } + delete polygon; + if (sfc->getNTriangles() == 0) { + WARN("Surface::createSurface(): Triangulation does not contain any triangle."); + delete sfc; + return nullptr; + } + return sfc; + } else { + WARN("Error in Surface::createSurface() - Polyline consists of less than three points and therefore cannot be triangulated."); + return nullptr; + } } std::size_t Surface::getNTriangles () const { - return _sfc_triangles.size(); + return _sfc_triangles.size(); } const Triangle* Surface::operator[] (std::size_t i) const { - assert (i < _sfc_triangles.size()); - return _sfc_triangles[i]; + assert (i < _sfc_triangles.size()); + return _sfc_triangles[i]; } bool Surface::isPntInBoundingVolume(MathLib::Point3d const& pnt) const { - return _bounding_volume->containsPoint (pnt); + return _bounding_volume->containsPoint (pnt); } bool Surface::isPntInSfc(MathLib::Point3d const& pnt) const { - // Mutable _surface_grid is constructed if method is called the first time. - if (_surface_grid == nullptr) { - _surface_grid.reset(new SurfaceGrid(this)); - } - return _surface_grid->isPointInSurface( - pnt, std::numeric_limits<double>::epsilon()); + // Mutable _surface_grid is constructed if method is called the first time. + if (_surface_grid == nullptr) { + _surface_grid.reset(new SurfaceGrid(this)); + } + return _surface_grid->isPointInSurface( + pnt, std::numeric_limits<double>::epsilon()); } const Triangle* Surface::findTriangle (MathLib::Point3d const& pnt) const { - for (std::size_t k(0); k<_sfc_triangles.size(); k++) { - if (_sfc_triangles[k]->containsPoint (pnt)) { - return _sfc_triangles[k]; - } - } - return nullptr; + for (std::size_t k(0); k<_sfc_triangles.size(); k++) { + if (_sfc_triangles[k]->containsPoint (pnt)) { + return _sfc_triangles[k]; + } + } + return nullptr; } } // end namespace diff --git a/GeoLib/Surface.h b/GeoLib/Surface.h index 67908462a60a469275c3cf4810733778ba900725..28c96d077caa394e02e58e4bce333a325206ed6d 100644 --- a/GeoLib/Surface.h +++ b/GeoLib/Surface.h @@ -39,69 +39,69 @@ class SurfaceGrid; class Surface : public GeoObject { public: - Surface(const std::vector<Point*> &pnt_vec); - virtual ~Surface (); - - /// return a geometry type - virtual GEOTYPE getGeoType() const {return GEOTYPE::SURFACE;} - - /** - * adds three indices describing a triangle and updates the bounding box - * */ - void addTriangle (std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c); - - /// Triangulates a new surface based on closed polyline. - static Surface* createSurface(const Polyline &ply); - - /** - * returns the number of triangles describing the Surface - * */ - std::size_t getNTriangles () const; - - /** \brief const access operator for the access to the i-th Triangle of the surface. - */ - const Triangle* operator[] (std::size_t i) const; - - /** - * is the given point in the bounding volume of the surface - */ - bool isPntInBoundingVolume(MathLib::Point3d const& pnt) const; - - /** - * is the given point pnt located in the surface - * @param pnt the point - * @return true if the point is contained in the surface - */ - bool isPntInSfc(MathLib::Point3d const& pnt) const; - - /** - * find a triangle in which the given point is located - * @param pnt the point - * @return a pointer to a triangle. nullptr is returned if the point is not - * contained in the surface - */ - const Triangle* findTriangle(MathLib::Point3d const& pnt) const; - - const std::vector<Point*> *getPointVec() const { return &_sfc_pnts; } - - /** - * method allows access to the internal axis aligned bounding box - * @return axis aligned bounding box - */ - AABB const& getAABB () const { return *_bounding_volume; } + Surface(const std::vector<Point*> &pnt_vec); + virtual ~Surface (); + + /// return a geometry type + virtual GEOTYPE getGeoType() const {return GEOTYPE::SURFACE;} + + /** + * adds three indices describing a triangle and updates the bounding box + * */ + void addTriangle (std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c); + + /// Triangulates a new surface based on closed polyline. + static Surface* createSurface(const Polyline &ply); + + /** + * returns the number of triangles describing the Surface + * */ + std::size_t getNTriangles () const; + + /** \brief const access operator for the access to the i-th Triangle of the surface. + */ + const Triangle* operator[] (std::size_t i) const; + + /** + * is the given point in the bounding volume of the surface + */ + bool isPntInBoundingVolume(MathLib::Point3d const& pnt) const; + + /** + * is the given point pnt located in the surface + * @param pnt the point + * @return true if the point is contained in the surface + */ + bool isPntInSfc(MathLib::Point3d const& pnt) const; + + /** + * find a triangle in which the given point is located + * @param pnt the point + * @return a pointer to a triangle. nullptr is returned if the point is not + * contained in the surface + */ + const Triangle* findTriangle(MathLib::Point3d const& pnt) const; + + const std::vector<Point*> *getPointVec() const { return &_sfc_pnts; } + + /** + * method allows access to the internal axis aligned bounding box + * @return axis aligned bounding box + */ + AABB const& getAABB () const { return *_bounding_volume; } protected: - /** a vector of pointers to Points */ - const std::vector<Point*> &_sfc_pnts; - /** position of pointers to the geometric points */ - std::vector<Triangle*> _sfc_triangles; - /** bounding volume is an axis aligned bounding box */ - std::unique_ptr<AABB> _bounding_volume; - /// The surface grid is a helper data structure to accelerate the point - /// search. The method addTriangle() invalidates/resets the surface grid. - /// A valid surface grid is created in case the const method isPntInSfc() is - /// called and a valid surface grid is not existing. - mutable std::unique_ptr<SurfaceGrid> _surface_grid; + /** a vector of pointers to Points */ + const std::vector<Point*> &_sfc_pnts; + /** position of pointers to the geometric points */ + std::vector<Triangle*> _sfc_triangles; + /** bounding volume is an axis aligned bounding box */ + std::unique_ptr<AABB> _bounding_volume; + /// The surface grid is a helper data structure to accelerate the point + /// search. The method addTriangle() invalidates/resets the surface grid. + /// A valid surface grid is created in case the const method isPntInSfc() is + /// called and a valid surface grid is not existing. + mutable std::unique_ptr<SurfaceGrid> _surface_grid; }; } diff --git a/GeoLib/SurfaceGrid.cpp b/GeoLib/SurfaceGrid.cpp index 62e4cf991e875a2691fbb1d12d877418b8faec7e..a109aa1b43e8e36a245fdc53d7f30904f16e9a2e 100644 --- a/GeoLib/SurfaceGrid.cpp +++ b/GeoLib/SurfaceGrid.cpp @@ -23,186 +23,186 @@ namespace GeoLib { SurfaceGrid::SurfaceGrid(Surface const*const sfc) : - AABB(sfc->getAABB()), _n_steps({{1,1,1}}) + AABB(sfc->getAABB()), _n_steps({{1,1,1}}) { - // enlarge the bounding, such that the points with maximal coordinates - // fits into the grid - for (std::size_t k(0); k<3; ++k) { - _max_pnt[k] += std::abs(_max_pnt[k]) * 1e-6; - if (std::abs(_max_pnt[k]) < std::numeric_limits<double>::epsilon()) { - _max_pnt[k] = (_max_pnt[k] - _min_pnt[k]) * (1.0 + 1e-6); - } - } - - std::array<double, 3> delta{{ _max_pnt[0] - _min_pnt[0], - _max_pnt[1] - _min_pnt[1], _max_pnt[2] - _min_pnt[2] }}; - - if (delta[0] < std::numeric_limits<double>::epsilon()) { - const double max_delta(std::max(delta[1], delta[2])); - _min_pnt[0] -= max_delta * 0.5e-3; - _max_pnt[0] += max_delta * 0.5e-3; - delta[0] = _max_pnt[0] - _min_pnt[0]; - } - - if (delta[1] < std::numeric_limits<double>::epsilon()) { - const double max_delta(std::max(delta[0], delta[2])); - _min_pnt[1] -= max_delta * 0.5e-3; - _max_pnt[1] += max_delta * 0.5e-3; - delta[1] = _max_pnt[1] - _min_pnt[1]; - } - - if (delta[2] < std::numeric_limits<double>::epsilon()) { - const double max_delta(std::max(delta[0], delta[1])); - _min_pnt[2] -= max_delta * 0.5e-3; - _max_pnt[2] += max_delta * 0.5e-3; - delta[2] = _max_pnt[2] - _min_pnt[2]; - } - - const std::size_t n_tris(sfc->getNTriangles()); - const std::size_t n_tris_per_cell(5); - - std::bitset<3> dim; // all bits are set to zero. - for (std::size_t k(0); k<3; ++k) - if (std::abs(delta[k]) >= std::numeric_limits<double>::epsilon()) - dim[k] = true; - - // *** condition: n_tris / n_cells < n_tris_per_cell - // where n_cells = _n_steps[0] * _n_steps[1] * _n_steps[2] - // *** with _n_steps[0] = ceil(pow(n_tris*delta[0]*delta[0]/(n_tris_per_cell*delta[1]*delta[2]), 1/3.))); - // _n_steps[1] = _n_steps[0] * delta[1]/delta[0], - // _n_steps[2] = _n_steps[0] * delta[2]/delta[0] - auto sc_ceil = [](double v){ - return static_cast<std::size_t>(std::ceil(v)); - }; - switch (dim.count()) { - case 3: // 3d case - _n_steps[0] = sc_ceil(std::cbrt( - n_tris*delta[0]*delta[0]/(n_tris_per_cell*delta[1]*delta[2]))); - _n_steps[1] = sc_ceil(_n_steps[0] * std::min(delta[1] / delta[0], 100.0)); - _n_steps[2] = sc_ceil(_n_steps[0] * std::min(delta[2] / delta[0], 100.0)); - break; - case 2: // 2d cases - if (dim[0] && dim[2]) { // 2d case: xz plane, y = const - _n_steps[0] = sc_ceil(std::sqrt(n_tris*delta[0]/(n_tris_per_cell*delta[2]))); - _n_steps[2] = sc_ceil(_n_steps[0]*delta[2]/delta[0]); - } - else if (dim[0] && dim[1]) { // 2d case: xy plane, z = const - _n_steps[0] = sc_ceil(std::sqrt(n_tris*delta[0]/(n_tris_per_cell*delta[1]))); - _n_steps[1] = sc_ceil(_n_steps[0] * delta[1]/delta[0]); - } - else if (dim[1] && dim[2]) { // 2d case: yz plane, x = const - _n_steps[1] = sc_ceil(std::sqrt(n_tris*delta[1]/(n_tris_per_cell*delta[2]))); - _n_steps[2] = sc_ceil(n_tris * delta[2] / (n_tris_per_cell*delta[1])); - } - break; - case 1: // 1d cases - for (std::size_t k(0); k<3; ++k) { - if (dim[k]) { - _n_steps[k] = sc_ceil(static_cast<double>(n_tris)/n_tris_per_cell); - } - } - } - - // some frequently used expressions to fill the grid vectors - for (std::size_t k(0); k<3; k++) { - _step_sizes[k] = delta[k] / _n_steps[k]; - _inverse_step_sizes[k] = 1.0 / _step_sizes[k]; - } - - _triangles_in_grid_box.resize(_n_steps[0]*_n_steps[1]*_n_steps[2]); - sortTrianglesInGridCells(sfc); + // enlarge the bounding, such that the points with maximal coordinates + // fits into the grid + for (std::size_t k(0); k<3; ++k) { + _max_pnt[k] += std::abs(_max_pnt[k]) * 1e-6; + if (std::abs(_max_pnt[k]) < std::numeric_limits<double>::epsilon()) { + _max_pnt[k] = (_max_pnt[k] - _min_pnt[k]) * (1.0 + 1e-6); + } + } + + std::array<double, 3> delta{{ _max_pnt[0] - _min_pnt[0], + _max_pnt[1] - _min_pnt[1], _max_pnt[2] - _min_pnt[2] }}; + + if (delta[0] < std::numeric_limits<double>::epsilon()) { + const double max_delta(std::max(delta[1], delta[2])); + _min_pnt[0] -= max_delta * 0.5e-3; + _max_pnt[0] += max_delta * 0.5e-3; + delta[0] = _max_pnt[0] - _min_pnt[0]; + } + + if (delta[1] < std::numeric_limits<double>::epsilon()) { + const double max_delta(std::max(delta[0], delta[2])); + _min_pnt[1] -= max_delta * 0.5e-3; + _max_pnt[1] += max_delta * 0.5e-3; + delta[1] = _max_pnt[1] - _min_pnt[1]; + } + + if (delta[2] < std::numeric_limits<double>::epsilon()) { + const double max_delta(std::max(delta[0], delta[1])); + _min_pnt[2] -= max_delta * 0.5e-3; + _max_pnt[2] += max_delta * 0.5e-3; + delta[2] = _max_pnt[2] - _min_pnt[2]; + } + + const std::size_t n_tris(sfc->getNTriangles()); + const std::size_t n_tris_per_cell(5); + + std::bitset<3> dim; // all bits are set to zero. + for (std::size_t k(0); k<3; ++k) + if (std::abs(delta[k]) >= std::numeric_limits<double>::epsilon()) + dim[k] = true; + + // *** condition: n_tris / n_cells < n_tris_per_cell + // where n_cells = _n_steps[0] * _n_steps[1] * _n_steps[2] + // *** with _n_steps[0] = ceil(pow(n_tris*delta[0]*delta[0]/(n_tris_per_cell*delta[1]*delta[2]), 1/3.))); + // _n_steps[1] = _n_steps[0] * delta[1]/delta[0], + // _n_steps[2] = _n_steps[0] * delta[2]/delta[0] + auto sc_ceil = [](double v){ + return static_cast<std::size_t>(std::ceil(v)); + }; + switch (dim.count()) { + case 3: // 3d case + _n_steps[0] = sc_ceil(std::cbrt( + n_tris*delta[0]*delta[0]/(n_tris_per_cell*delta[1]*delta[2]))); + _n_steps[1] = sc_ceil(_n_steps[0] * std::min(delta[1] / delta[0], 100.0)); + _n_steps[2] = sc_ceil(_n_steps[0] * std::min(delta[2] / delta[0], 100.0)); + break; + case 2: // 2d cases + if (dim[0] && dim[2]) { // 2d case: xz plane, y = const + _n_steps[0] = sc_ceil(std::sqrt(n_tris*delta[0]/(n_tris_per_cell*delta[2]))); + _n_steps[2] = sc_ceil(_n_steps[0]*delta[2]/delta[0]); + } + else if (dim[0] && dim[1]) { // 2d case: xy plane, z = const + _n_steps[0] = sc_ceil(std::sqrt(n_tris*delta[0]/(n_tris_per_cell*delta[1]))); + _n_steps[1] = sc_ceil(_n_steps[0] * delta[1]/delta[0]); + } + else if (dim[1] && dim[2]) { // 2d case: yz plane, x = const + _n_steps[1] = sc_ceil(std::sqrt(n_tris*delta[1]/(n_tris_per_cell*delta[2]))); + _n_steps[2] = sc_ceil(n_tris * delta[2] / (n_tris_per_cell*delta[1])); + } + break; + case 1: // 1d cases + for (std::size_t k(0); k<3; ++k) { + if (dim[k]) { + _n_steps[k] = sc_ceil(static_cast<double>(n_tris)/n_tris_per_cell); + } + } + } + + // some frequently used expressions to fill the grid vectors + for (std::size_t k(0); k<3; k++) { + _step_sizes[k] = delta[k] / _n_steps[k]; + _inverse_step_sizes[k] = 1.0 / _step_sizes[k]; + } + + _triangles_in_grid_box.resize(_n_steps[0]*_n_steps[1]*_n_steps[2]); + sortTrianglesInGridCells(sfc); } void SurfaceGrid::sortTrianglesInGridCells(Surface const*const sfc) { - for (std::size_t l(0); l<sfc->getNTriangles(); l++) { - if (! sortTriangleInGridCells((*sfc)[l])) { - Point const& p0(*((*sfc)[l]->getPoint(0))); - Point const& p1(*((*sfc)[l]->getPoint(1))); - Point const& p2(*((*sfc)[l]->getPoint(2))); - ERR("Sorting triangle %d [(%f,%f,%f), (%f,%f,%f), (%f,%f,%f) into " - "grid.", - l, p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2] - ); - std::abort(); - } - } + for (std::size_t l(0); l<sfc->getNTriangles(); l++) { + if (! sortTriangleInGridCells((*sfc)[l])) { + Point const& p0(*((*sfc)[l]->getPoint(0))); + Point const& p1(*((*sfc)[l]->getPoint(1))); + Point const& p2(*((*sfc)[l]->getPoint(2))); + ERR("Sorting triangle %d [(%f,%f,%f), (%f,%f,%f), (%f,%f,%f) into " + "grid.", + l, p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], p2[0], p2[1], p2[2] + ); + std::abort(); + } + } } bool SurfaceGrid::sortTriangleInGridCells(Triangle const*const triangle) { - // compute grid coordinates for each triangle point - boost::optional<std::array<std::size_t, 3> const> c_p0( - getGridCellCoordinates(*(triangle->getPoint(0)))); - if (!c_p0) - return false; - boost::optional<std::array<std::size_t, 3> const> c_p1( - getGridCellCoordinates(*(triangle->getPoint(1)))); - if (!c_p1) - return false; - boost::optional<std::array<std::size_t, 3> const> c_p2( - getGridCellCoordinates(*(triangle->getPoint(2)))); - if (!c_p2) - return false; - - // determine interval in grid (grid cells the triangle will be inserted) - std::size_t const i_min(std::min(std::min((*c_p0)[0], (*c_p1)[0]), (*c_p2)[0])); - std::size_t const i_max(std::max(std::max((*c_p0)[0], (*c_p1)[0]), (*c_p2)[0])); - std::size_t const j_min(std::min(std::min((*c_p0)[1], (*c_p1)[1]), (*c_p2)[1])); - std::size_t const j_max(std::max(std::max((*c_p0)[1], (*c_p1)[1]), (*c_p2)[1])); - std::size_t const k_min(std::min(std::min((*c_p0)[2], (*c_p1)[2]), (*c_p2)[2])); - std::size_t const k_max(std::max(std::max((*c_p0)[2], (*c_p1)[2]), (*c_p2)[2])); - - const std::size_t n_plane(_n_steps[0]*_n_steps[1]); - - // insert the triangle into the grid cells - for (std::size_t i(i_min); i<=i_max; i++) { - for (std::size_t j(j_min); j<=j_max; j++) { - for (std::size_t k(k_min); k<=k_max; k++) { - _triangles_in_grid_box[i+j*_n_steps[0]+k*n_plane].push_back(triangle); - } - } - } - - return true; + // compute grid coordinates for each triangle point + boost::optional<std::array<std::size_t, 3> const> c_p0( + getGridCellCoordinates(*(triangle->getPoint(0)))); + if (!c_p0) + return false; + boost::optional<std::array<std::size_t, 3> const> c_p1( + getGridCellCoordinates(*(triangle->getPoint(1)))); + if (!c_p1) + return false; + boost::optional<std::array<std::size_t, 3> const> c_p2( + getGridCellCoordinates(*(triangle->getPoint(2)))); + if (!c_p2) + return false; + + // determine interval in grid (grid cells the triangle will be inserted) + std::size_t const i_min(std::min(std::min((*c_p0)[0], (*c_p1)[0]), (*c_p2)[0])); + std::size_t const i_max(std::max(std::max((*c_p0)[0], (*c_p1)[0]), (*c_p2)[0])); + std::size_t const j_min(std::min(std::min((*c_p0)[1], (*c_p1)[1]), (*c_p2)[1])); + std::size_t const j_max(std::max(std::max((*c_p0)[1], (*c_p1)[1]), (*c_p2)[1])); + std::size_t const k_min(std::min(std::min((*c_p0)[2], (*c_p1)[2]), (*c_p2)[2])); + std::size_t const k_max(std::max(std::max((*c_p0)[2], (*c_p1)[2]), (*c_p2)[2])); + + const std::size_t n_plane(_n_steps[0]*_n_steps[1]); + + // insert the triangle into the grid cells + for (std::size_t i(i_min); i<=i_max; i++) { + for (std::size_t j(j_min); j<=j_max; j++) { + for (std::size_t k(k_min); k<=k_max; k++) { + _triangles_in_grid_box[i+j*_n_steps[0]+k*n_plane].push_back(triangle); + } + } + } + + return true; } boost::optional<std::array<std::size_t, 3>> SurfaceGrid::getGridCellCoordinates(MathLib::Point3d const& p) const { - std::array<std::size_t, 3> coords{{ - static_cast<std::size_t>((p[0]-_min_pnt[0]) * _inverse_step_sizes[0]), - static_cast<std::size_t>((p[1]-_min_pnt[1]) * _inverse_step_sizes[1]), - static_cast<std::size_t>((p[2]-_min_pnt[2]) * _inverse_step_sizes[2]) - }}; - - if (coords[0]>=_n_steps[0] || coords[1]>=_n_steps[1] || coords[2]>=_n_steps[2]) { - DBUG("Computed indices (%d,%d,%d), max grid cell indices (%d,%d,%d)", - coords[0], coords[1], coords[2], _n_steps[0], _n_steps[1], _n_steps[2]); - return boost::optional<std::array<std::size_t, 3>>(); - } - return boost::optional<std::array<std::size_t, 3>>(coords); + std::array<std::size_t, 3> coords{{ + static_cast<std::size_t>((p[0]-_min_pnt[0]) * _inverse_step_sizes[0]), + static_cast<std::size_t>((p[1]-_min_pnt[1]) * _inverse_step_sizes[1]), + static_cast<std::size_t>((p[2]-_min_pnt[2]) * _inverse_step_sizes[2]) + }}; + + if (coords[0]>=_n_steps[0] || coords[1]>=_n_steps[1] || coords[2]>=_n_steps[2]) { + DBUG("Computed indices (%d,%d,%d), max grid cell indices (%d,%d,%d)", + coords[0], coords[1], coords[2], _n_steps[0], _n_steps[1], _n_steps[2]); + return boost::optional<std::array<std::size_t, 3>>(); + } + return boost::optional<std::array<std::size_t, 3>>(coords); } bool SurfaceGrid::isPointInSurface(MathLib::Point3d const& p, double eps) const { - boost::optional<std::array<std::size_t,3>> optional_c(getGridCellCoordinates(p)); - if (!optional_c) { - return false; - } - std::array<std::size_t,3> c(optional_c.get()); - - std::size_t const grid_cell_idx(c[0]+c[1]*_n_steps[0]+c[2]*_n_steps[0]*_n_steps[1]); - std::vector<Triangle const*> const& triangles(_triangles_in_grid_box[grid_cell_idx]); - bool nfound(true); - const std::size_t n_triangles(triangles.size()); - for (std::size_t k(0); k < n_triangles && nfound; k++) { - if (triangles[k]->containsPoint(p, eps)) { - nfound = false; - } - } - - return !nfound; + boost::optional<std::array<std::size_t,3>> optional_c(getGridCellCoordinates(p)); + if (!optional_c) { + return false; + } + std::array<std::size_t,3> c(optional_c.get()); + + std::size_t const grid_cell_idx(c[0]+c[1]*_n_steps[0]+c[2]*_n_steps[0]*_n_steps[1]); + std::vector<Triangle const*> const& triangles(_triangles_in_grid_box[grid_cell_idx]); + bool nfound(true); + const std::size_t n_triangles(triangles.size()); + for (std::size_t k(0); k < n_triangles && nfound; k++) { + if (triangles[k]->containsPoint(p, eps)) { + nfound = false; + } + } + + return !nfound; } } // end namespace GeoLib diff --git a/GeoLib/SurfaceGrid.h b/GeoLib/SurfaceGrid.h index e67588e49bac085108f59dc7becbc59af948d39c..67c4febdb526acefb33e350c83287efca91cfb8b 100644 --- a/GeoLib/SurfaceGrid.h +++ b/GeoLib/SurfaceGrid.h @@ -29,19 +29,19 @@ class Surface; class SurfaceGrid : public AABB { public: - explicit SurfaceGrid(GeoLib::Surface const*const sfc); - bool isPointInSurface(MathLib::Point3d const & pnt, - double eps = std::numeric_limits<double>::epsilon()) const; + explicit SurfaceGrid(GeoLib::Surface const*const sfc); + bool isPointInSurface(MathLib::Point3d const & pnt, + double eps = std::numeric_limits<double>::epsilon()) const; private: - void sortTrianglesInGridCells(GeoLib::Surface const*const surface); - bool sortTriangleInGridCells(GeoLib::Triangle const*const triangle); - boost::optional<std::array<std::size_t,3>> - getGridCellCoordinates(MathLib::Point3d const& p) const; - std::array<double,3> _step_sizes; - std::array<double,3> _inverse_step_sizes; - std::array<std::size_t,3> _n_steps; - std::vector<std::vector<GeoLib::Triangle const*>> _triangles_in_grid_box; + void sortTrianglesInGridCells(GeoLib::Surface const*const surface); + bool sortTriangleInGridCells(GeoLib::Triangle const*const triangle); + boost::optional<std::array<std::size_t,3>> + getGridCellCoordinates(MathLib::Point3d const& p) const; + std::array<double,3> _step_sizes; + std::array<double,3> _inverse_step_sizes; + std::array<std::size_t,3> _n_steps; + std::vector<std::vector<GeoLib::Triangle const*>> _triangles_in_grid_box; }; } // end namespace GeoLib diff --git a/GeoLib/TemplateVec.h b/GeoLib/TemplateVec.h index 07cccfae36ff7c0890fa70873257b6611ac0e67f..c10fc8a2c29174e3037feefc907230301eb1f359 100644 --- a/GeoLib/TemplateVec.h +++ b/GeoLib/TemplateVec.h @@ -38,203 +38,203 @@ namespace GeoLib template <class T> class TemplateVec { protected: - typedef std::pair<std::string, std::size_t> NameIdPair; - typedef std::map<std::string, std::size_t> NameIdMap; + typedef std::pair<std::string, std::size_t> NameIdPair; + typedef std::map<std::string, std::size_t> NameIdMap; public: - /** - * Constructor of class TemlateVec. - * @param name unique name of the project the elements belonging to. - * In order to access the data elements a unique name is required. - * @param data_vec Vector of data elements. - * @attention{TemplateVec will take the ownership of the vector - * and also its elements, - * i.e. delete its elements and delete the vector itself!} - * @param elem_name_map Names of data elements can be given by a - * std::map<std::string, std::size_t>. Here the std::string is the name - * of the element and the value for std::size_t stands for an index in - * the data_vec. - */ - TemplateVec (const std::string &name, std::unique_ptr<std::vector<T*>> data_vec, - NameIdMap* elem_name_map = nullptr) : - _name(name), _data_vec(std::move(data_vec)), _name_id_map (elem_name_map) - { - if (_data_vec == nullptr) - { - ERR("Constructor TemplateVec: vector of data elements is a nullptr."); - std::abort(); - } - - if (!_name_id_map) - _name_id_map = new NameIdMap; - } - - /** - * destructor, deletes all data elements - */ - virtual ~TemplateVec () - { - for (std::size_t k(0); k < size(); k++) delete (*_data_vec)[k]; - delete _name_id_map; - } - - /** sets the name of the vector of geometric objects - * the data elements belonging to - * \param n the name as standard string */ - void setName (const std::string & n) { _name = n; } - /** - * the name, the data element belonging to - * @return the name of the object - */ - std::string getName () const { return _name; } - - /// Returns the begin of the name id mapping structure - NameIdMap::const_iterator getNameIDMapBegin() const { return _name_id_map->cbegin(); } - - /// Returns the end of the name id mapping structure - NameIdMap::const_iterator getNameIDMapEnd() const { return _name_id_map->cend(); } - - /** - * @return the number of data elements - */ - std::size_t size () const { return _data_vec->size(); } - - /** - * get a pointer to a standard vector containing the data elements - * @return the data elements - */ - const std::vector<T*>* getVector () const { return _data_vec.get(); } - - /** - * search the vector of names for the ID of the geometric element with the given name - * @param name the name of the geometric element - * @param id the id of the geometric element - */ - bool getElementIDByName (const std::string& name, std::size_t &id) const - { - auto it (_name_id_map->find (name)); - - if (it != _name_id_map->end()) - { - id = it->second; - return true; - } - else return false; - } - - /// Returns an element with the given name. - const T* getElementByName (const std::string& name) const - { - std::size_t id; - bool ret (getElementIDByName (name, id)); - if (ret) - return (*_data_vec)[id]; - else - return nullptr; - } - - /** - * The method returns true if there is a name associated - * with the given id, else method returns false. - * @param id the id - * @param element_name if a name associated with the id - * is found name is assigned to element_name - * @return if there is name associated with the given id: - * true, else false - */ - bool getNameOfElementByID (std::size_t id, std::string& element_name) const - { - // search in map for id - auto it = findFirstElementByID(id); - if (it == _name_id_map->end()) { - return false; - } - element_name = it->first; - return true; - } - - /// Return the name of an element based on its ID. - void setNameOfElementByID (std::size_t id, std::string const& element_name) - { - _name_id_map->insert(NameIdPair(element_name, id)); - } - - /** - * The method returns true if the given element of type T - * can be found and the element has a name, else method returns false. - * @param data the data element, one wants to know the name - * @param name the name of the data element (if the data element is - * found and the data element has a name) - * @return if element is found and has a name: true, else false - */ - bool getNameOfElement (const T* data, std::string& name) const - { - for (std::size_t k(0); k < _data_vec->size(); k++) - if ((*_data_vec)[k] == data) - return getNameOfElementByID (k, name); - - return false; - } - - /// Adds a new element to the vector. - virtual void push_back (T* data_element, std::string const* const name = nullptr) - { - _data_vec->push_back (data_element); - if (!name || name->empty()) - return; - - std::map<std::string, std::size_t>::const_iterator it( - _name_id_map->find(*name) - ); - if (it == _name_id_map->end()) { - _name_id_map->insert(NameIdPair(*name, _data_vec->size() - 1)); - } else { - WARN("Name \"%s\" exists already. The object will be inserted " - "without a name", name->c_str()); - } - } - - /// Sets the given name for the element of the given ID. - void setNameForElement(std::size_t id, std::string const& name) - { - // Erase id if found in map. - auto it = findFirstElementByID(id); - if (it != _name_id_map->end()) - _name_id_map->erase(it); - - if (!name.empty()) { - //insert new or revised name - _name_id_map->insert(NameIdPair(name, id)); - } - } + /** + * Constructor of class TemlateVec. + * @param name unique name of the project the elements belonging to. + * In order to access the data elements a unique name is required. + * @param data_vec Vector of data elements. + * @attention{TemplateVec will take the ownership of the vector + * and also its elements, + * i.e. delete its elements and delete the vector itself!} + * @param elem_name_map Names of data elements can be given by a + * std::map<std::string, std::size_t>. Here the std::string is the name + * of the element and the value for std::size_t stands for an index in + * the data_vec. + */ + TemplateVec (const std::string &name, std::unique_ptr<std::vector<T*>> data_vec, + NameIdMap* elem_name_map = nullptr) : + _name(name), _data_vec(std::move(data_vec)), _name_id_map (elem_name_map) + { + if (_data_vec == nullptr) + { + ERR("Constructor TemplateVec: vector of data elements is a nullptr."); + std::abort(); + } + + if (!_name_id_map) + _name_id_map = new NameIdMap; + } + + /** + * destructor, deletes all data elements + */ + virtual ~TemplateVec () + { + for (std::size_t k(0); k < size(); k++) delete (*_data_vec)[k]; + delete _name_id_map; + } + + /** sets the name of the vector of geometric objects + * the data elements belonging to + * \param n the name as standard string */ + void setName (const std::string & n) { _name = n; } + /** + * the name, the data element belonging to + * @return the name of the object + */ + std::string getName () const { return _name; } + + /// Returns the begin of the name id mapping structure + NameIdMap::const_iterator getNameIDMapBegin() const { return _name_id_map->cbegin(); } + + /// Returns the end of the name id mapping structure + NameIdMap::const_iterator getNameIDMapEnd() const { return _name_id_map->cend(); } + + /** + * @return the number of data elements + */ + std::size_t size () const { return _data_vec->size(); } + + /** + * get a pointer to a standard vector containing the data elements + * @return the data elements + */ + const std::vector<T*>* getVector () const { return _data_vec.get(); } + + /** + * search the vector of names for the ID of the geometric element with the given name + * @param name the name of the geometric element + * @param id the id of the geometric element + */ + bool getElementIDByName (const std::string& name, std::size_t &id) const + { + auto it (_name_id_map->find (name)); + + if (it != _name_id_map->end()) + { + id = it->second; + return true; + } + else return false; + } + + /// Returns an element with the given name. + const T* getElementByName (const std::string& name) const + { + std::size_t id; + bool ret (getElementIDByName (name, id)); + if (ret) + return (*_data_vec)[id]; + else + return nullptr; + } + + /** + * The method returns true if there is a name associated + * with the given id, else method returns false. + * @param id the id + * @param element_name if a name associated with the id + * is found name is assigned to element_name + * @return if there is name associated with the given id: + * true, else false + */ + bool getNameOfElementByID (std::size_t id, std::string& element_name) const + { + // search in map for id + auto it = findFirstElementByID(id); + if (it == _name_id_map->end()) { + return false; + } + element_name = it->first; + return true; + } + + /// Return the name of an element based on its ID. + void setNameOfElementByID (std::size_t id, std::string const& element_name) + { + _name_id_map->insert(NameIdPair(element_name, id)); + } + + /** + * The method returns true if the given element of type T + * can be found and the element has a name, else method returns false. + * @param data the data element, one wants to know the name + * @param name the name of the data element (if the data element is + * found and the data element has a name) + * @return if element is found and has a name: true, else false + */ + bool getNameOfElement (const T* data, std::string& name) const + { + for (std::size_t k(0); k < _data_vec->size(); k++) + if ((*_data_vec)[k] == data) + return getNameOfElementByID (k, name); + + return false; + } + + /// Adds a new element to the vector. + virtual void push_back (T* data_element, std::string const* const name = nullptr) + { + _data_vec->push_back (data_element); + if (!name || name->empty()) + return; + + std::map<std::string, std::size_t>::const_iterator it( + _name_id_map->find(*name) + ); + if (it == _name_id_map->end()) { + _name_id_map->insert(NameIdPair(*name, _data_vec->size() - 1)); + } else { + WARN("Name \"%s\" exists already. The object will be inserted " + "without a name", name->c_str()); + } + } + + /// Sets the given name for the element of the given ID. + void setNameForElement(std::size_t id, std::string const& name) + { + // Erase id if found in map. + auto it = findFirstElementByID(id); + if (it != _name_id_map->end()) + _name_id_map->erase(it); + + if (!name.empty()) { + //insert new or revised name + _name_id_map->insert(NameIdPair(name, id)); + } + } private: - NameIdMap::const_iterator - findFirstElementByID(std::size_t const& id) const - { - return std::find_if(_name_id_map->begin(), _name_id_map->end(), - [id](NameIdPair const& elem) { return elem.second == id; }); - } + NameIdMap::const_iterator + findFirstElementByID(std::size_t const& id) const + { + return std::find_if(_name_id_map->begin(), _name_id_map->end(), + [id](NameIdPair const& elem) { return elem.second == id; }); + } protected: - /** copy constructor doesn't have an implementation */ - // compiler does not create a (possible unwanted) copy constructor - TemplateVec (const TemplateVec &); - /** assignment operator doesn't have an implementation */ - // this way the compiler does not create a (possible unwanted) assignment operator - TemplateVec& operator= (const TemplateVec& rhs); - - /** the name of the object */ - std::string _name; - - /** - * pointer to a vector of data elements - */ - std::unique_ptr<std::vector <T*>> _data_vec; - /** - * store names associated with the element ids - */ - NameIdMap* _name_id_map; + /** copy constructor doesn't have an implementation */ + // compiler does not create a (possible unwanted) copy constructor + TemplateVec (const TemplateVec &); + /** assignment operator doesn't have an implementation */ + // this way the compiler does not create a (possible unwanted) assignment operator + TemplateVec& operator= (const TemplateVec& rhs); + + /** the name of the object */ + std::string _name; + + /** + * pointer to a vector of data elements + */ + std::unique_ptr<std::vector <T*>> _data_vec; + /** + * store names associated with the element ids + */ + NameIdMap* _name_id_map; }; } // end namespace GeoLib diff --git a/GeoLib/Triangle.cpp b/GeoLib/Triangle.cpp index 49f2db925d15ebbb55920b31bc4b912b70ea73ad..02d4be34bd6fa6fa651f17bc0b0344e58f668579 100644 --- a/GeoLib/Triangle.cpp +++ b/GeoLib/Triangle.cpp @@ -22,101 +22,101 @@ namespace GeoLib { Triangle::Triangle (std::vector<Point *> const &pnt_vec) : - _pnts(pnt_vec), _initialized (false), _longest_edge (0.0) + _pnts(pnt_vec), _initialized (false), _longest_edge (0.0) { - assert(!_pnts.empty()); - _pnt_ids[0] = std::numeric_limits<std::size_t>::max(); - _pnt_ids[1] = std::numeric_limits<std::size_t>::max(); - _pnt_ids[2] = std::numeric_limits<std::size_t>::max(); + assert(!_pnts.empty()); + _pnt_ids[0] = std::numeric_limits<std::size_t>::max(); + _pnt_ids[1] = std::numeric_limits<std::size_t>::max(); + _pnt_ids[2] = std::numeric_limits<std::size_t>::max(); } Triangle::Triangle (std::vector<Point *> const &pnt_vec, - std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c) : - _pnts(pnt_vec), _initialized (true), _longest_edge (0.0) + std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c) : + _pnts(pnt_vec), _initialized (true), _longest_edge (0.0) { - assert(!_pnts.empty()); - _pnt_ids[0] = pnt_a; - _pnt_ids[1] = pnt_b; - _pnt_ids[2] = pnt_c; - _longest_edge = MathLib::sqrDist (*_pnts[_pnt_ids[0]], *_pnts[_pnt_ids[1]]); - double tmp (MathLib::sqrDist (*_pnts[_pnt_ids[1]], *_pnts[_pnt_ids[2]])); - if (tmp > _longest_edge) _longest_edge = tmp; - tmp = MathLib::sqrDist (*_pnts[_pnt_ids[0]], *_pnts[_pnt_ids[2]]); - if (tmp > _longest_edge) _longest_edge = tmp; - _longest_edge = sqrt (_longest_edge); + assert(!_pnts.empty()); + _pnt_ids[0] = pnt_a; + _pnt_ids[1] = pnt_b; + _pnt_ids[2] = pnt_c; + _longest_edge = MathLib::sqrDist (*_pnts[_pnt_ids[0]], *_pnts[_pnt_ids[1]]); + double tmp (MathLib::sqrDist (*_pnts[_pnt_ids[1]], *_pnts[_pnt_ids[2]])); + if (tmp > _longest_edge) _longest_edge = tmp; + tmp = MathLib::sqrDist (*_pnts[_pnt_ids[0]], *_pnts[_pnt_ids[2]]); + if (tmp > _longest_edge) _longest_edge = tmp; + _longest_edge = sqrt (_longest_edge); } void Triangle::setTriangle (std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c) { - assert (pnt_a < _pnts.size() && pnt_b < _pnts.size() && pnt_c < _pnts.size()); - _pnt_ids[0] = pnt_a; - _pnt_ids[1] = pnt_b; - _pnt_ids[2] = pnt_c; - - _longest_edge = MathLib::sqrDist (*_pnts[_pnt_ids[0]], *_pnts[_pnt_ids[1]]); - double tmp (MathLib::sqrDist (*_pnts[_pnt_ids[1]], *_pnts[_pnt_ids[2]])); - if (tmp > _longest_edge) _longest_edge = tmp; - tmp = MathLib::sqrDist (*_pnts[_pnt_ids[0]], *_pnts[_pnt_ids[2]]); - if (tmp > _longest_edge) _longest_edge = tmp; - _longest_edge = sqrt (_longest_edge); + assert (pnt_a < _pnts.size() && pnt_b < _pnts.size() && pnt_c < _pnts.size()); + _pnt_ids[0] = pnt_a; + _pnt_ids[1] = pnt_b; + _pnt_ids[2] = pnt_c; + + _longest_edge = MathLib::sqrDist (*_pnts[_pnt_ids[0]], *_pnts[_pnt_ids[1]]); + double tmp (MathLib::sqrDist (*_pnts[_pnt_ids[1]], *_pnts[_pnt_ids[2]])); + if (tmp > _longest_edge) _longest_edge = tmp; + tmp = MathLib::sqrDist (*_pnts[_pnt_ids[0]], *_pnts[_pnt_ids[2]]); + if (tmp > _longest_edge) _longest_edge = tmp; + _longest_edge = sqrt (_longest_edge); } bool Triangle::containsPoint(MathLib::Point3d const& q, double eps) const { - GeoLib::Point const& a(*(_pnts[_pnt_ids[0]])); - GeoLib::Point const& b(*(_pnts[_pnt_ids[1]])); - GeoLib::Point const& c(*(_pnts[_pnt_ids[2]])); - return GeoLib::isPointInTriangle(q, a, b, c, eps); + GeoLib::Point const& a(*(_pnts[_pnt_ids[0]])); + GeoLib::Point const& b(*(_pnts[_pnt_ids[1]])); + GeoLib::Point const& c(*(_pnts[_pnt_ids[2]])); + return GeoLib::isPointInTriangle(q, a, b, c, eps); } bool Triangle::containsPoint2D (Point const& pnt) const { - GeoLib::Point const& a (*(_pnts[_pnt_ids[0]])); - GeoLib::Point const& b (*(_pnts[_pnt_ids[1]])); - GeoLib::Point const& c (*(_pnts[_pnt_ids[2]])); - - // criterion: p-a = u0 * (b-a) + u1 * (c-a); 0 <= u0, u1 <= 1, u0+u1 <= 1 - MathLib::DenseMatrix<double> mat (2,2); - mat(0,0) = b[0] - a[0]; - mat(0,1) = c[0] - a[0]; - mat(1,0) = b[1] - a[1]; - mat(1,1) = c[1] - a[1]; - double y[2] = {pnt[0]-a[0], pnt[1]-a[1]}; - - MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> gauss; - gauss.solve(mat, y, true); - - const double delta (std::numeric_limits<double>::epsilon()); - const double upper (1+delta); - - // check if u0 and u1 fulfills the condition (with some delta) - if (-delta <= y[0] && y[0] <= upper && -delta <= y[1] && y[1] <= upper && y[0] + y[1] <= upper) { - return true; - } - return false; + GeoLib::Point const& a (*(_pnts[_pnt_ids[0]])); + GeoLib::Point const& b (*(_pnts[_pnt_ids[1]])); + GeoLib::Point const& c (*(_pnts[_pnt_ids[2]])); + + // criterion: p-a = u0 * (b-a) + u1 * (c-a); 0 <= u0, u1 <= 1, u0+u1 <= 1 + MathLib::DenseMatrix<double> mat (2,2); + mat(0,0) = b[0] - a[0]; + mat(0,1) = c[0] - a[0]; + mat(1,0) = b[1] - a[1]; + mat(1,1) = c[1] - a[1]; + double y[2] = {pnt[0]-a[0], pnt[1]-a[1]}; + + MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> gauss; + gauss.solve(mat, y, true); + + const double delta (std::numeric_limits<double>::epsilon()); + const double upper (1+delta); + + // check if u0 and u1 fulfills the condition (with some delta) + if (-delta <= y[0] && y[0] <= upper && -delta <= y[1] && y[1] <= upper && y[0] + y[1] <= upper) { + return true; + } + return false; } void getPlaneCoefficients(Triangle const& tri, double c[3]) { - GeoLib::Point const& p0 (*(tri.getPoint(0))); - GeoLib::Point const& p1 (*(tri.getPoint(1))); - GeoLib::Point const& p2 (*(tri.getPoint(2))); - MathLib::DenseMatrix<double> mat (3,3); - mat(0,0) = p0[0]; - mat(0,1) = p0[1]; - mat(0,2) = 1.0; - mat(1,0) = p1[0]; - mat(1,1) = p1[1]; - mat(1,2) = 1.0; - mat(2,0) = p2[0]; - mat(2,1) = p2[1]; - mat(2,2) = 1.0; - c[0] = p0[2]; - c[1] = p1[2]; - c[2] = p2[2]; - - MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> gauss; - gauss.solve (mat, c); + GeoLib::Point const& p0 (*(tri.getPoint(0))); + GeoLib::Point const& p1 (*(tri.getPoint(1))); + GeoLib::Point const& p2 (*(tri.getPoint(2))); + MathLib::DenseMatrix<double> mat (3,3); + mat(0,0) = p0[0]; + mat(0,1) = p0[1]; + mat(0,2) = 1.0; + mat(1,0) = p1[0]; + mat(1,1) = p1[1]; + mat(1,2) = 1.0; + mat(2,0) = p2[0]; + mat(2,1) = p2[1]; + mat(2,2) = 1.0; + c[0] = p0[2]; + c[1] = p1[2]; + c[2] = p2[2]; + + MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> gauss; + gauss.solve (mat, c); } } // end namespace GeoLib diff --git a/GeoLib/Triangle.h b/GeoLib/Triangle.h index 77557beb9aa9028e94eb1fa67f9a9df3769b4be8..0f88e4515a00a70fa1acbe92618cd965c58e47b6 100644 --- a/GeoLib/Triangle.h +++ b/GeoLib/Triangle.h @@ -31,61 +31,61 @@ class Point; class Triangle { public: - /** - * construction of object, initialization of reference to point vector - */ - Triangle (std::vector<Point *> const &pnt_vec); - - /** - * construction of object, initialization of reference to point vector, - * saves the three indices describing a triangle - */ - Triangle (std::vector<Point *> const &pnt_vec, std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c); - - /** - * saves three indices describing a triangle - * */ - void setTriangle (std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c); - - /** \brief const access operator to access the index - * of the i-th triangle point - */ - const std::size_t& operator[] (std::size_t i) const { - assert (i < 3); - return _pnt_ids[i]; - } - - /** - * \brief const access operator to access the i-th triangle Point - */ - const Point* getPoint (std::size_t i) const { - assert (i < 3); - return _pnts[_pnt_ids[i]]; - } - - /** - * Checks if point q is within the triangle, uses GeoLib::isPointInTriangle(). - * @param q The input point. - * @param eps Checks the 'epsilon'-neighbourhood - * @return true, if point is in triangle, else false - */ - bool containsPoint(MathLib::Point3d const& q, double eps = std::numeric_limits<float>::epsilon()) const; - - /** - * projects the triangle points to the x-y-plane and - * checks if point pnt is contained into the triangle - * @param pnt the point to test for - * @return true, if the point is into the projected triangle - */ - bool containsPoint2D (Point const& pnt) const; + /** + * construction of object, initialization of reference to point vector + */ + Triangle (std::vector<Point *> const &pnt_vec); + + /** + * construction of object, initialization of reference to point vector, + * saves the three indices describing a triangle + */ + Triangle (std::vector<Point *> const &pnt_vec, std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c); + + /** + * saves three indices describing a triangle + * */ + void setTriangle (std::size_t pnt_a, std::size_t pnt_b, std::size_t pnt_c); + + /** \brief const access operator to access the index + * of the i-th triangle point + */ + const std::size_t& operator[] (std::size_t i) const { + assert (i < 3); + return _pnt_ids[i]; + } + + /** + * \brief const access operator to access the i-th triangle Point + */ + const Point* getPoint (std::size_t i) const { + assert (i < 3); + return _pnts[_pnt_ids[i]]; + } + + /** + * Checks if point q is within the triangle, uses GeoLib::isPointInTriangle(). + * @param q The input point. + * @param eps Checks the 'epsilon'-neighbourhood + * @return true, if point is in triangle, else false + */ + bool containsPoint(MathLib::Point3d const& q, double eps = std::numeric_limits<float>::epsilon()) const; + + /** + * projects the triangle points to the x-y-plane and + * checks if point pnt is contained into the triangle + * @param pnt the point to test for + * @return true, if the point is into the projected triangle + */ + bool containsPoint2D (Point const& pnt) const; protected: - /** a vector of pointers to points */ - const std::vector<Point*> &_pnts; - /** position of pointers to the geometric points */ - std::size_t _pnt_ids[3]; - bool _initialized; - double _longest_edge; + /** a vector of pointers to points */ + const std::vector<Point*> &_pnts; + /** position of pointers to the geometric points */ + std::size_t _pnt_ids[3]; + bool _initialized; + double _longest_edge; }; void getPlaneCoefficients(Triangle const& tri, double c[3]);