UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
ufo.hpp
1
42#ifndef UFO_CLOUD_IO_UFO_HPP
43#define UFO_CLOUD_IO_UFO_HPP
44
45// UFO
46#include <ufo/cloud/cloud.hpp>
47#include <ufo/execution/execution.hpp>
48#include <ufo/io/cloud_properties.hpp>
49#include <ufo/numeric/transform.hpp>
50#include <ufo/numeric/vec.hpp>
51#include <ufo/vision/color.hpp>
52
53// STL
54#include <charconv>
55#include <cstddef>
56#include <cstdint>
57#include <cstdio>
58#include <filesystem>
59#include <fstream>
60#include <ios>
61#include <print>
62#include <string>
63
64namespace ufo
65{
66[[nodiscard]] CloudProperties cloudPropertiesUFO(std::filesystem::path const& file);
67
69 Transform3f pose;
70 float timestamp = 0.0f;
71 bool verbose = false;
72};
73
74namespace detail
75{
76template <std::size_t Dim, class T>
77bool readUFOData(std::istream& in, SoAView<Vec<Dim, T>> data, std::string const& type,
78 std::uint64_t size)
79{
80 if ("point" != type) {
81 return false;
82 } else if ((data.size() * sizeof(Vec3f)) != size) {
83 // TODO: Error
84 return false;
85 }
86
87 if constexpr (std::is_same_v<Vec3f, Vec<Dim, T>>) {
88 in.read(reinterpret_cast<char*>(data.data()), data.size_bytes());
89 } else {
90 Vec3f tmp;
91 for (auto& c : data) {
92 in.read(reinterpret_cast<char*>(&tmp), sizeof(tmp));
93 c = static_cast<Vec<Dim, T>>(tmp);
94 }
95 }
96
97 return true;
98}
99
100template <ColorType CT, class T, bool Alpha, bool Weight>
101bool readUFOData(std::istream& in, SoAView<Color<CT, T, Alpha, Weight>> data,
102 std::string const& type, std::uint64_t size)
103{
104 if ("color" != type) {
105 return false;
106 } else if ((data.size() * sizeof(SmallRGBA)) != size) {
107 // TODO: Error
108 return false;
109 }
110
111 if constexpr (std::is_same_v<SmallRGBA, Color<CT, T, Alpha, Weight>>) {
112 in.read(reinterpret_cast<char*>(data.data()), data.size_bytes());
113 } else {
114 SmallRGBA tmp;
115 for (auto& c : data) {
116 in.read(reinterpret_cast<char*>(&tmp), sizeof(tmp));
117 convert(tmp, c);
118 }
119 }
120
121 return true;
122}
123
124template <class T>
125bool readUFOData([[maybe_unused]] std::istream& in, [[maybe_unused]] SoAView<T> data,
126 [[maybe_unused]] std::string const& type,
127 [[maybe_unused]] std::uint64_t size)
128{
129 return false;
130}
131
132template <std::size_t Dim, class T>
133void writeUFOData(std::ostream& out, SoAView<Vec<Dim, T> const> data)
134{
135 out << "point: " << (data.size() * sizeof(Vec3f)) << '\n';
136
137 if constexpr (std::is_same_v<Vec3f, Vec<Dim, T>>) {
138 out.write(reinterpret_cast<char const*>(data.data()), data.size_bytes());
139 } else {
140 for (auto const& p : data) {
141 Vec3f tmp(p);
142 out.write(reinterpret_cast<char const*>(&tmp), sizeof(tmp));
143 }
144 }
145}
146
147template <ColorType CT, class T, bool Alpha, bool Weight>
148void writeUFOData(std::ostream& out, SoAView<Color<CT, T, Alpha, Weight> const> data)
149{
150 out << "color: " << (data.size() * sizeof(SmallRGBA)) << '\n';
151
152 if constexpr (std::is_same_v<SmallRGBA, Color<CT, T, Alpha, Weight>>) {
153 out.write(reinterpret_cast<char const*>(data.data()), data.size_bytes());
154 } else {
155 SmallRGBA tmp;
156 for (auto const& c : data) {
157 convert(c, tmp);
158 out.write(reinterpret_cast<char const*>(&tmp), sizeof(tmp));
159 }
160 }
161}
162
163template <class T>
164void writeUFOData([[maybe_unused]] std::ostream& out,
165 [[maybe_unused]] SoAView<T const> data)
166{
167}
168} // namespace detail
169
170template <class... Ts>
171inline bool readUFO(std::istream& in, Cloud<Ts...>& cloud)
172{
173 std::string line;
174
175 // Header
176
177 std::getline(in, line);
178 if ("# UFO cloud file" != line) {
179 return false;
180 }
181
182 while (std::getline(in, line) && in.good()) {
183 if (line.starts_with('#')) {
184 continue; // Skip comments
185 }
186
187 std::string type = line.substr(0, line.find(':'));
188 std::string value = line.substr(line.find(':') + 1);
189
190 if ("version" == type) {
191 if (" 1.0" != value) {
192 return false;
193 }
194 } else if ("width" == type) {
195 std::size_t v = std::stoull(value);
196 cloud.resize(v);
197 } else if ("height" == type) {
198 // TODO: Implement
199 } else if ("pose" == type) {
200 // TODO: Implement
201 } else if ("timestamp" == type) {
202 // TODO: Implement
203 } else if ("data" == type) {
204 break; // End of header
205 }
206 }
207
208 // Data
209
210 std::string type;
211 std::uint64_t size;
212 while (std::getline(in, line) && in.good()) {
213 auto pos = line.find(':');
214
215 type = line.substr(0, pos);
216
217 auto [ptr, ec] =
218 std::from_chars(line.data() + pos + 2, line.data() + line.size(), size);
219
220 if (ec == std::errc()) {
221 // Good
222 } else if (ec == std::errc::invalid_argument) {
223 // TODO: Error
224 continue;
225 } else if (ec == std::errc::result_out_of_range) {
226 // TODO: Error
227 continue;
228 }
229
230 if ((detail::readUFOData(in, view<Ts>(cloud), type, size) || ...)) {
231 continue;
232 } else {
233 in.seekg(size, std::ios::cur);
234 }
235 }
236
237 return true;
238}
239
240template <class... Ts>
241bool readUFO(std::filesystem::path const& file, Cloud<Ts...>& cloud)
242{
243 std::ifstream ifs;
244 ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
245 ifs.imbue(std::locale());
246 ifs.open(file, std::ios::in | std::ios::binary);
247 return readUFO(ifs, cloud);
248}
249
250template <class... Ts>
251bool writeUFO(std::ostream& out, Cloud<Ts...> const& cloud,
252 CloudUFOOptions const& options = CloudUFOOptions())
253{
254 out << "# UFO cloud file\n";
255
256 out << "# Generated by UFO\n";
257
258 out << "version: 1.0\n";
259 out << "width: " << cloud.size() << '\n';
260 // TODO: Update
261 out << "height: 1\n";
262 out << "# pose: x y z qw qx qy qz\n";
263 auto t = options.pose.translation;
264 auto q = static_cast<Quatf>(options.pose.rotation);
265 out << "pose: " << t.x << ' ' << t.y << ' ' << t.z << ' ' << q.w << ' ' << q.x << ' '
266 << q.y << ' ' << q.z << '\n';
267 // TODO: Update
268 out << "# timestamp: seconds nanoseconds\n";
269 out << "timestamp: " << options.timestamp << '\n';
270 out << "data:\n";
271
272 (detail::writeUFOData(out, view<Ts>(cloud)), ...);
273
274 return true;
275}
276
277template <class... Ts>
278bool writeUFO(std::filesystem::path const& file, Cloud<Ts...> const& cloud,
279 CloudUFOOptions const& options = CloudUFOOptions())
280{
281 std::ofstream ofs;
282 ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit);
283 ofs.imbue(std::locale());
284 ofs.open(file, std::ios::out | std::ios::binary);
285 return writeUFO(ofs, cloud, options);
286}
287} // namespace ufo
288
289#endif // UFO_CLOUD_IO_UFO_HPP
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr To convert(Vec< Dim, U > const &v) noexcept
Converts a vector to a different Vec type, truncating or zero-padding dimensions.
Definition vec.hpp:1059
Rigid-body transform: a rotation matrix plus a translation vector.
Definition transform.hpp:81
A fixed-size arithmetic vector of up to 4 dimensions.
Definition vec.hpp:76