Home > front end >  Construct n-dimensional boost point
Construct n-dimensional boost point

Time:01-31

Problem: boost/geometry/geometries/point.hpp point template does not provide a way to construct an n-dimensional point type with non-zero values.

For example:

#include <boost/geometry/geometries/point.hpp>
namespace bg = boost::geometry;

...
typedef bg::model::point<double,4,bg::cs::cartesian> point;

auto nDimPoint1 = point(); // creates a point with 4 values each 0
auto nDimPoint2 = point(1,2,3,4); // !!!compiler error!!! since point's template does not provide a strategy past 3 dimensions.

// workaround, but must be hard-coded
nDimPoint1.set<0>(1);
nDimPoint1.set<1>(2);
nDimPoint1.set<2>(3);
nDimPoint1.set<3>(4);

What I've tried: After reading through boost's documentation I was not able to find any examples with n-dimensional points, though it is possible I missed them.

I did encounter creating custom point classes and registering them, but the built in point class accomplishes exactly what I want. Unfortunately I can't solve this by inheriting from the base point since the point representation is a private variable.

Point's template contains a private array variable, m_values, by creating a new constructor which takes a vector and copying the vector into m_values I was able to fix the issue.

I'm also pretty new to C 's templates, since I usually use C and python. Is it possible to extend the Point template outside the Point.hpp file to include the n-dimensional constructor I want? Or is there a better way of building n-dimensional points in boost such as cast from vector?

Ideally (imho) boost would provide a generic copy constructor which accepts std::vector and copies each value into its internal array.

Related questions: In this question Defining a dimensional point in Boost.Geometry, the author is attempting to utilize point for rtree (I am also attempting to do this), however the accepted answer claims this is not possible and a second solution https://stackoverflow.com/a/62777496/10448495, claims to solve the issue, but I don't see how it can work.

CodePudding user response:

You are right. The model::point class template doesn't afford direct/aggregate initialization and it's not possible to add that (m_values is private e.g., but also there is optional access-tracking debug metadata that would get out of sync).

Note the class is documented

\details Defines a neutral point class, fulfilling the Point Concept.
    Library users can use this point class, or use their own point classes.
    This point class is used in most of the samples and tests of Boost.Geometry
    This point class is used occasionally within the library, where a temporary
    point class is necessary.

And:

\tparam DimensionCount number of coordinates, usually 2 or 3

So, you can - and probably should - use your own type. The simplest thing would be to use an array directly (so, just the m_values member data really). There's very little magic about that:

Live On Compiler Explorer

#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/adapted/std_array.hpp>
#include <fmt/ranges.h>
namespace bg = boost::geometry;

BOOST_GEOMETRY_REGISTER_STD_ARRAY_CS(bg::cs::cartesian)

using point = std::array<double, 4>;

int main() {
    auto a = point(); // creates a point with 4 values each 0
    auto b = point{1, 2, 3, 4}; 

    // generic Boost code will still work:
    bg::set<0>(a, 10);
    bg::set<1>(a, 20);
    bg::set<2>(a, 30);
    bg::set<3>(a, 40);

    fmt::print("default:{}, a:{}, b:{}\n", point{}, a, b);
}
    

Prints

default:[0, 0, 0, 0], a:[10, 20, 30, 40], b:[1, 2, 3, 4]
  •  Tags:  
  • Related