1

I have the 2D array of doubles (3D coordinates) and I want to create a vector of 3D points from it. The straightforward way is, of course, the simple loop, but may be more elegant solution using stl algorithms exists? Here is what I have got:

#include <algorithm>
#include <iterator>
#include <vector>

struct point_3d
{
  /**
   * Default constructor -- set everything to 0
  */
  point_3d() :
    x(0.0), y(0.0), z(0.0)
  {}

  /**
   * To define 3D point from array of doubles
  */
  point_3d(const double crd[]) :
    x(crd[0]),
    y(crd[1]),
    z(crd[2])
  {}

  /**
   * To define 3D point from 3 coordinates
  */
  point_3d(const double &_x, const double &_y, const double &_z) :
    x(_x), y(_y), z(_z)
  {}
  double x, y, z;
}; //struct point_3d

//Right-angle tetrahedron
const int num_vertices = 4;

const double coordinates[num_vertices][3] = 
{{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};

/**
 * Simple, but unelegant function.
*/
void build_tetrahedron_vertices(std::vector<point_3d>& points)
{
  points.clear();
  for(int i = 0; i < num_vertices; ++i)
    points.push_back(point_3d(coordinates[i]));
}//build_vector_of_points


/**
 * Something more elegant?
*/
void build_tetrahedron_vertices_nice(std::vector<point_3d>& points)
{
  points.clear();
  //this does not compile, but may be something else will work?
  std::for_each(&(coordinates[0]), &(coordinates[num_vertices]),
                std::back_inserter(points));
}//build_vector_of_points_nice

int main()
{
  std::vector<point_3d> points;
  build_tetrahedron_vertices(points);
  return 0;
}

The above code is for illustration purposes only to show the basic requirement -- 2D array of basic types exists, I need to build the vector of objects from it.

I have control over point_3d class, so may add more constructors if required.

one_two_three
  • 501
  • 2
  • 10

2 Answers2

6

You can construct a point_3d from each of the 1d arrays, so I'd just use the std::vector constructor that takes two iterators, and let each of the 1d arrays be used to implictly construct a point_3d

std::vector<point_3d> build_tetrahedron_vertices()
{
    return std::vector<point_3d>{std::begin(coordinates), std::end(coordinates)}; 
}

Then you can simply call it as

std::vector<point_3d> points = build_tetrahedron_vertices();

And due to return value optimization, you don't need to worry about an extra copy of this vector being performed.

Working demo

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
1

Despite the great answer already provided, you could use some stl functions. From your example of build_tetrahedron_vertices_nice, you could use basically the same syntax you have, but with std::copy instead of std::for_each

void build_tetrahedron_vertices_nice(std::vector<point_3d> & points)
{
    std::copy(&coordinates[0], &coordinates[num_vertices], std::back_inserter(points));
}
hlscalon
  • 7,304
  • 4
  • 33
  • 40