Adds CPP implementatinon
This commit is contained in:
parent
f6e691d3db
commit
c72e925ac2
@ -1,9 +1,20 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.11)
|
||||||
|
|
||||||
project(EsriAssignment)
|
project(EsriAssignment)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(json
|
||||||
|
GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent
|
||||||
|
GIT_TAG v3.9.1)
|
||||||
|
FetchContent_GetProperties(json)
|
||||||
|
if(NOT json_POPULATED)
|
||||||
|
FetchContent_Populate(json)
|
||||||
|
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(Protobuf REQUIRED)
|
find_package(Protobuf REQUIRED)
|
||||||
include_directories(${PROTOBUF_INCLUDE_DIR})
|
include_directories(${PROTOBUF_INCLUDE_DIR})
|
||||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
@ -11,4 +22,3 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
|||||||
add_subdirectory(protocol_buffers_definitions)
|
add_subdirectory(protocol_buffers_definitions)
|
||||||
include_directories(src)
|
include_directories(src)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
|
|
||||||
set(assignment_SOURCES
|
set(assignment_SOURCES
|
||||||
main.cpp)
|
main.cpp
|
||||||
|
calc.cpp
|
||||||
|
json_output.cpp
|
||||||
|
proto_loader.cpp)
|
||||||
|
|
||||||
add_executable(main ${assignment_SOURCES})
|
add_executable(main ${assignment_SOURCES})
|
||||||
target_link_libraries(main proto ${PROTOBUF_LIBRARY})
|
target_link_libraries(main PRIVATE proto ${PROTOBUF_LIBRARY})
|
||||||
|
target_link_libraries(main PRIVATE nlohmann_json::nlohmann_json)
|
||||||
|
70
src/calc.cpp
Normal file
70
src/calc.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "calc.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
namespace calc {
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<Position, Position>
|
||||||
|
position_segment(std::vector<Position> const& position, double time)
|
||||||
|
{
|
||||||
|
auto second = std::lower_bound(position.begin(), position.end(), time,
|
||||||
|
[](Position const& pos, double t) {
|
||||||
|
return pos.time < t;
|
||||||
|
});
|
||||||
|
if (second == position.begin()) { // corner case
|
||||||
|
second++;
|
||||||
|
}
|
||||||
|
return std::make_pair(*(second-1), *second);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void interpolate_positions(std::vector<Magnetic>& magnetics, std::vector<Position> const& truth)
|
||||||
|
{
|
||||||
|
for (auto& mag : magnetics) {
|
||||||
|
auto const truth_seg = position_segment(truth, mag.time);
|
||||||
|
for (size_t i = 0; i < mag.position.size(); i++) {
|
||||||
|
mag.position[i] =
|
||||||
|
(truth_seg.second.position[i] - truth_seg.first.position[i]) /
|
||||||
|
(truth_seg.second.time - truth_seg.first.time) *
|
||||||
|
(mag.time - truth_seg.first.time) + truth_seg.first.position[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void crop_temporal_inersection(std::vector<Magnetic>& magnetics, std::vector<Position> const& truth)
|
||||||
|
{
|
||||||
|
auto const mag_first = std::lower_bound(
|
||||||
|
magnetics.begin(), magnetics.end(), truth[0].time,
|
||||||
|
[](Magnetic const& mag, double t) {
|
||||||
|
return mag.time < t;
|
||||||
|
});
|
||||||
|
magnetics.erase(magnetics.begin(), mag_first);
|
||||||
|
auto const mag_last = std::upper_bound(
|
||||||
|
magnetics.begin(), magnetics.end(), truth.back().time,
|
||||||
|
[](double t, Magnetic const& mag) {
|
||||||
|
return t < mag.time;
|
||||||
|
});
|
||||||
|
magnetics.erase(mag_last, magnetics.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::tuple<double, double, double, double>
|
||||||
|
spatial_extent(std::vector<Magnetic> const& mag)
|
||||||
|
{
|
||||||
|
auto [x_min, x_max] = std::minmax_element(
|
||||||
|
std::cbegin(mag), std::cend(mag),
|
||||||
|
[](Magnetic const& a, Magnetic const& b) {
|
||||||
|
return a.position[0] < b.position[0];
|
||||||
|
});
|
||||||
|
auto [y_min, y_max] = std::minmax_element(
|
||||||
|
std::cbegin(mag), std::cend(mag),
|
||||||
|
[](Magnetic const& a, Magnetic const& b) {
|
||||||
|
return a.position[1] < b.position[1];
|
||||||
|
});
|
||||||
|
return std::make_tuple(x_min->position[0], y_min->position[1], x_max->position[0], y_max->position[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
47
src/calc.hpp
Normal file
47
src/calc.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef CALC_HPP_
|
||||||
|
#define CALC_HPP_
|
||||||
|
|
||||||
|
#include "data.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <numeric>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace calc {
|
||||||
|
|
||||||
|
|
||||||
|
template <typename iter_t>
|
||||||
|
double norm(iter_t first, iter_t last)
|
||||||
|
{
|
||||||
|
return std::sqrt(std::inner_product(first, last, first, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<Position, Position>
|
||||||
|
position_segment(std::vector<Position> const& position, double time);
|
||||||
|
|
||||||
|
void interpolate_positions(std::vector<Magnetic>& magnetics, std::vector<Position> const& truth);
|
||||||
|
void crop_temporal_inersection(std::vector<Magnetic>& magnetics, std::vector<Position> const& truth);
|
||||||
|
|
||||||
|
std::tuple<double, double, double, double>
|
||||||
|
spatial_extent(std::vector<Magnetic> const& mag);
|
||||||
|
|
||||||
|
template<typename grid_t, typename avg_grid_t>
|
||||||
|
void average_grid(grid_t& grid, avg_grid_t& average_grid)
|
||||||
|
{
|
||||||
|
for (size_t x = 0; x < grid.size_x(); x++) {
|
||||||
|
for (size_t y = 0; y < grid.size_y(); y++) {
|
||||||
|
auto const& cell = grid[x][y];
|
||||||
|
if (cell.size() > 0) {
|
||||||
|
double const sum = std::accumulate(cell.cbegin(), cell.cend(), 0.0);
|
||||||
|
size_t const n = cell.size();
|
||||||
|
average_grid[x][y] = sum / n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace calc
|
||||||
|
|
||||||
|
#endif // CALC_HPP_
|
31
src/data.hpp
Normal file
31
src/data.hpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef DATA_HPP_
|
||||||
|
#define DATA_HPP_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using Coordinate = std::array<double, 2>;
|
||||||
|
|
||||||
|
|
||||||
|
struct Magnetic {
|
||||||
|
Magnetic(double t, double x, double y, double z) :
|
||||||
|
time(t), field({x, y, z}) {}
|
||||||
|
Magnetic(double t, double x, double y) :
|
||||||
|
time(t), position({x, y}) {}
|
||||||
|
double time;
|
||||||
|
std::array<double, 3> field;
|
||||||
|
Coordinate position;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Position {
|
||||||
|
Position(double t, double x, double y) :
|
||||||
|
time(t), position({x, y}) {}
|
||||||
|
double time;
|
||||||
|
Coordinate position;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Magnetics = std::vector<Magnetic>;
|
||||||
|
using Positions = std::vector<Position>;
|
||||||
|
|
||||||
|
#endif /* DATA_HPP_ */
|
22
src/json_output.cpp
Normal file
22
src/json_output.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
#include "json_output.hpp"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
|
||||||
|
JsonOutput::JsonOutput(char const* file_path) :
|
||||||
|
filePath_(file_path)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
bool JsonOutput::write()
|
||||||
|
{
|
||||||
|
std::ofstream outfile(filePath_);
|
||||||
|
if (!outfile) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
outfile << std::setw(2);
|
||||||
|
outfile << jsonData_ << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
24
src/json_output.hpp
Normal file
24
src/json_output.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef JSONOUTPUT_HPP_
|
||||||
|
#define JSONOUTPUT_HPP_
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
class JsonOutput {
|
||||||
|
public:
|
||||||
|
explicit JsonOutput(char const* file_path);
|
||||||
|
~JsonOutput() = default;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void add(char const* key, T const& obj)
|
||||||
|
{
|
||||||
|
jsonData_[key] = obj;
|
||||||
|
}
|
||||||
|
bool write();
|
||||||
|
|
||||||
|
private:
|
||||||
|
char const* filePath_;
|
||||||
|
::nlohmann::json jsonData_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JSONOUTPUT_HPP_
|
123
src/main.cpp
123
src/main.cpp
@ -1,40 +1,107 @@
|
|||||||
#include <fstream>
|
#include "calc.hpp"
|
||||||
|
#include "json_output.hpp"
|
||||||
|
#include "proto_loader.hpp"
|
||||||
|
#include "spatial_grid.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
#include "protocol_buffers_definitions/recordings.pb.h"
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
using namespace ::indoors::proto;
|
static void print_usage()
|
||||||
|
{
|
||||||
|
std::cout << "ESRI C++ code assignment, E. Nindl 2021\n\n";
|
||||||
|
std::cout << "Usage:\n";
|
||||||
|
std::cout << " executable <input-file[s]> <json-ouput-file>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::tuple<double, double, double, double>
|
||||||
|
total_spatial_extent(std::vector<Magnetics> const& magnetics_recs) {
|
||||||
|
double x_min = std::numeric_limits<double>::max();
|
||||||
|
double y_min = std::numeric_limits<double>::max();
|
||||||
|
double x_max = std::numeric_limits<double>::min();
|
||||||
|
double y_max = std::numeric_limits<double>::min();
|
||||||
|
for (auto const& magnetics : magnetics_recs) {
|
||||||
|
auto const [x_min_i, y_min_i, x_max_i, y_max_i] = ::calc::spatial_extent(magnetics);
|
||||||
|
x_min = std::min(x_min, x_min_i);
|
||||||
|
y_min = std::min(y_min, y_min_i);
|
||||||
|
x_max = std::max(x_max, x_max_i);
|
||||||
|
y_max = std::max(y_max, y_max_i);
|
||||||
|
}
|
||||||
|
return std::make_tuple(x_min, y_min, x_max, y_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool write_output(std::string const& output_file, SpatialGrid<double>& grid)
|
||||||
|
{
|
||||||
|
JsonOutput json_output(output_file.c_str());
|
||||||
|
json_output.add("start_x", grid.start_x());
|
||||||
|
json_output.add("start_y", grid.start_y());
|
||||||
|
json_output.add("spacing", grid.spacing);
|
||||||
|
json_output.add("data", grid.data());
|
||||||
|
return json_output.write();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
// Verify that the version of the library that we linked against is
|
if (argc < 3) {
|
||||||
// compatible with the version of the headers we compiled against.
|
print_usage();
|
||||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
return 1;
|
||||||
|
|
||||||
std::cout << "ESRI C++ code assignment\n";
|
|
||||||
|
|
||||||
Recording recording;
|
|
||||||
Position positions;
|
|
||||||
|
|
||||||
std::fstream input(argv[1], std::ios::in | std::ios::binary);
|
|
||||||
if (!recording.ParseFromIstream(&input)) {
|
|
||||||
std::cerr << "Failed to parse input file.\n";
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
std::cout.precision(17);
|
std::string const output_file{argv[argc - 1]};
|
||||||
for (int i=0; i < recording.magnetics_size(); i++) {
|
std::vector<std::string> input_files;
|
||||||
auto const& s = recording.magnetics(i);
|
for (uint32_t i = 1; i < (argc - 1); i++) {
|
||||||
std::cout << s.t() << ": [" << s.x() << ", " << s.y() << ", " << s.z() << "]\n";
|
input_files.push_back(argv[i]);
|
||||||
}
|
|
||||||
for (int i=0; i < recording.positions_size(); i++) {
|
|
||||||
auto const& s = recording.positions(i);
|
|
||||||
std::cout << s.t() << ": [" << s.x() << ", " << s.y() << "]\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optional: Delete all global objects allocated by libprotobuf.
|
std::vector<Magnetics> magnetics_recs;
|
||||||
google::protobuf::ShutdownProtobufLibrary();
|
std::vector<Positions> groundtruth_recs;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (auto const& input_file : input_files) {
|
||||||
|
ProtoLoader loader(input_file.c_str());
|
||||||
|
magnetics_recs.push_back(loader.magnetics());
|
||||||
|
groundtruth_recs.push_back(loader.groundtruth());
|
||||||
|
}
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
std::cerr << "Error loading input: " << e.what() << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t rec_id = 0; rec_id < magnetics_recs.size(); rec_id++) {
|
||||||
|
Magnetics& magnetics = magnetics_recs[rec_id];
|
||||||
|
Positions& groundtruth = groundtruth_recs[rec_id];
|
||||||
|
::calc::crop_temporal_inersection(magnetics, groundtruth);
|
||||||
|
if (magnetics.size() == 0) {
|
||||||
|
std::cerr << "Error in groundtruth data\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
::calc::interpolate_positions(magnetics, groundtruth);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const [x_min, y_min, x_max, y_max] = total_spatial_extent(magnetics_recs);
|
||||||
|
SpatialGrid<std::vector<double>> grid(x_min, y_min, x_max, y_max);
|
||||||
|
|
||||||
|
for (size_t rec_id = 0; rec_id < magnetics_recs.size(); rec_id++) {
|
||||||
|
Magnetics& magnetics = magnetics_recs[rec_id];
|
||||||
|
Positions& groundtruth = groundtruth_recs[rec_id];
|
||||||
|
for (auto& mag : magnetics) {
|
||||||
|
auto& cell = grid.at(mag.position);
|
||||||
|
double const magnitude = ::calc::norm(mag.field.cbegin(), mag.field.cend());
|
||||||
|
cell.push_back(magnitude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpatialGrid<double> average_grid(x_min, y_min, x_max, y_max);
|
||||||
|
calc::average_grid(grid, average_grid);
|
||||||
|
if (!write_output(output_file, average_grid)) {
|
||||||
|
std::cout << "Error writing output file: " << output_file << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
61
src/proto_loader.cpp
Normal file
61
src/proto_loader.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "proto_loader.hpp"
|
||||||
|
#include "protocol_buffers_definitions/recordings.pb.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ProtoLoader::ProtoLoader(char const* f) :
|
||||||
|
filePath_(f)
|
||||||
|
{
|
||||||
|
// Verify that the version of the library that we linked against is
|
||||||
|
// compatible with the version of the headers we compiled against.
|
||||||
|
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||||
|
|
||||||
|
std::fstream input(filePath_, std::ios::in | std::ios::binary);
|
||||||
|
if (!recording_.ParseFromIstream(&input)) {
|
||||||
|
throw std::runtime_error("Failed to parse input file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ProtoLoader::~ProtoLoader()
|
||||||
|
{
|
||||||
|
// Optional: Delete all global objects allocated by libprotobuf.
|
||||||
|
::google::protobuf::ShutdownProtobufLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Magnetic> ProtoLoader::magnetics() const
|
||||||
|
{
|
||||||
|
double t_prev = 0;
|
||||||
|
std::vector<Magnetic> magnetics;
|
||||||
|
for (int i = 0; i < recording_.magnetics_size(); i++) {
|
||||||
|
auto const& s = recording_.magnetics(i);
|
||||||
|
double const t = s.t();
|
||||||
|
if (t_prev > t) {
|
||||||
|
throw std::runtime_error("Magnetics data not sorted by time");
|
||||||
|
}
|
||||||
|
magnetics.emplace_back(t, s.x(), s.y(), s.z());
|
||||||
|
t_prev = t;
|
||||||
|
}
|
||||||
|
return magnetics;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Position> ProtoLoader::groundtruth() const
|
||||||
|
{
|
||||||
|
double t_prev = 0;
|
||||||
|
std::vector<Position> groundtruth;
|
||||||
|
for (int i=0; i < recording_.positions_size(); i++) {
|
||||||
|
auto const& s = recording_.positions(i);
|
||||||
|
double const t = s.t();
|
||||||
|
if ((t - t_prev) < dt_min) {
|
||||||
|
throw std::runtime_error("Groundtruth data invalid");
|
||||||
|
}
|
||||||
|
groundtruth.emplace_back(t, s.x(), s.y());
|
||||||
|
t_prev = t;
|
||||||
|
}
|
||||||
|
return groundtruth;
|
||||||
|
}
|
24
src/proto_loader.hpp
Normal file
24
src/proto_loader.hpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef PROTOLOADER_HPP_
|
||||||
|
#define PROTOLOADER_HPP_
|
||||||
|
|
||||||
|
#include "data.hpp"
|
||||||
|
#include "protocol_buffers_definitions/recordings.pb.h"
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
class ProtoLoader {
|
||||||
|
public:
|
||||||
|
explicit ProtoLoader(char const* file_path);
|
||||||
|
~ProtoLoader();
|
||||||
|
|
||||||
|
std::vector<Magnetic> magnetics() const;
|
||||||
|
std::vector<Position> groundtruth() const;
|
||||||
|
|
||||||
|
static constexpr double dt_min{1e-3};
|
||||||
|
|
||||||
|
private:
|
||||||
|
char const* filePath_;
|
||||||
|
::indoors::proto::Recording recording_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* PROTOLOADER_HPP_ */
|
69
src/spatial_grid.hpp
Normal file
69
src/spatial_grid.hpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#ifndef SPATIALGRID_HPP_
|
||||||
|
#define SPATIALGRID_HPP_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
template<typename value_t>
|
||||||
|
class SpatialGrid {
|
||||||
|
public:
|
||||||
|
SpatialGrid() = delete;
|
||||||
|
explicit SpatialGrid(double x_start, double y_start, double x_end, double y_end) :
|
||||||
|
offset_({static_cast<size_t>(x_start / spacing), static_cast<size_t>(y_start / spacing)}),
|
||||||
|
size_x_(static_cast<size_t>(std::ceil(x_end / spacing)) - offset_[0]),
|
||||||
|
size_y_(static_cast<size_t>(std::ceil(y_end / spacing)) - offset_[1]),
|
||||||
|
grid_(size_x_, std::vector<value_t>(size_y_))
|
||||||
|
{}
|
||||||
|
~SpatialGrid() = default;
|
||||||
|
|
||||||
|
value_t& at(double x, double y)
|
||||||
|
{
|
||||||
|
size_t const id_x{static_cast<size_t>(x / spacing) - offset_[0]};
|
||||||
|
size_t const id_y{static_cast<size_t>(y / spacing) - offset_[1]};
|
||||||
|
return grid_[id_x][id_y];
|
||||||
|
}
|
||||||
|
value_t& at(std::array<double, 2> pos)
|
||||||
|
{
|
||||||
|
return at(pos[0], pos[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<value_t>& operator[](size_t idx)
|
||||||
|
{
|
||||||
|
return grid_[idx];
|
||||||
|
}
|
||||||
|
size_t size_x() const
|
||||||
|
{
|
||||||
|
return grid_.size();
|
||||||
|
}
|
||||||
|
size_t size_y() const
|
||||||
|
{
|
||||||
|
return grid_[0].size();
|
||||||
|
}
|
||||||
|
size_t start_x() const noexcept
|
||||||
|
{
|
||||||
|
return offset_[0] * spacing;
|
||||||
|
}
|
||||||
|
size_t start_y() const noexcept
|
||||||
|
{
|
||||||
|
return offset_[1] * spacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<value_t>>& data() {
|
||||||
|
return grid_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr size_t spacing{5};
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t const offset_[2];
|
||||||
|
size_t const size_x_;
|
||||||
|
size_t const size_y_;
|
||||||
|
|
||||||
|
std::vector<std::vector<value_t>> grid_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SPATIALGRID_HPP_ */
|
Loading…
Reference in New Issue
Block a user