UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
obj.hpp
1
42#ifndef UFO_CLOUD_IO_OBJ_HPP
43#define UFO_CLOUD_IO_OBJ_HPP
44
45// UFO
46#include <ufo/cloud/point_cloud.hpp>
47#include <ufo/core/normal.hpp>
48#include <ufo/io/cloud_properties.hpp>
49#include <ufo/io/file_handler.hpp>
50#include <ufo/numeric/vec.hpp>
51#include <ufo/vision/color.hpp>
52
53// STL
54#include <cstdio>
55#include <filesystem>
56#include <print>
57
58namespace ufo
59{
60[[nodiscard]] CloudProperties cloudPropertiesOBJ(std::filesystem::path const& file);
61
62template <std::size_t Dim, class T, class... Ts>
63bool readOBJ(std::filesystem::path const& file, PointCloud<Dim, T, Ts...>& pc)
64{
65 FileHandler fp(file.c_str(), "rb");
66
67 if (!fp) {
68 std::println(stderr, "[UFO | Read OBJ] Failed to open file: {}", file.string());
69 return false;
70 }
71
72 std::size_t num_points{};
73 std::size_t num_normals{};
74 for (char line[1024]; nullptr != std::fgets(line, sizeof line, fp.get());) {
75 Vec3d p;
76 FineRGB c;
77 Normal n;
78 if (auto num_fields = std::sscanf(line, "v %lf %lf %lf %f %f %f", &p.x, &p.y, &p.z,
79 &c.red, &c.green, &c.blue);
80 3 <= num_fields) {
81 ++num_points;
82
83 if (4 == num_fields) {
84 // TODO: Correct?
85 p /= static_cast<double>(c.red);
86 }
87
88 if constexpr ((is_color_v<Ts> || ...)) {
89 if (6 == num_fields) {
90 if (pc.size() < num_points) {
91 pc.push_back(convert<Vec<Dim, T>>(p), convert<first_color_t<Ts...>>(c));
92 } else {
93 view<Vec<Dim, T>>(pc)[num_points - 1] = convert<Vec<Dim, T>>(p);
94 view<first_color_t<Ts...>>(pc)[num_points - 1] =
95 convert<first_color_t<Ts...>>(c);
96 }
97 }
98 }
99
100 if (3 == num_fields || 4 == num_fields) {
101 if (pc.size() < num_points) {
102 pc.push_back(convert<Vec<Dim, T>>(p));
103 } else {
104 view<Vec<Dim, T>>(pc)[num_points - 1] = convert<Vec<Dim, T>>(p);
105 }
106 } else {
107 std::println(stderr, "[UFO | Read OBJ] Unknown format of line: {}", line);
108 return false;
109 }
110 } else if constexpr ((is_normal_v<Ts> || ...)) {
111 if (auto num_fields = std::sscanf(line, "vn %f %f %f", &n.x, &n.y, &n.z);
112 3 == num_fields) {
113 ++num_normals;
114 if (pc.size() < num_normals) {
115 pc.push_back(n);
116 } else {
117 view<Normal>(pc)[num_normals - 1] = n;
118 }
119 }
120 }
121 }
122
123 return true;
124}
125
126template <std::size_t Dim, class T, class... Ts>
127bool writeOBJ(std::filesystem::path const& file, PointCloud<Dim, T, Ts...> const& pc)
128{
129 FileHandler fp(file.c_str(), "wb");
130
131 if (!fp) {
132 std::println(stderr, "[UFO | Write OBJ] Failed to create file: {}", file.string());
133 return false;
134 }
135
136 std::println(fp.get(), "Created by UFO");
137
138 std::size_t size = pc.size();
139 auto points = view<Vec<Dim, T>>(pc);
140 for (std::size_t i{}; size > i; ++i) {
141 auto p = convert<Vec<3, T>>(points[i]);
142 if constexpr (std::is_same_v<T, float>) {
143 std::print(fp.get(), "v {:.6} {:.6} {:.6}", p.x, p.y, p.z);
144 } else if constexpr (std::is_floating_point_v<T>) {
145 std::print(fp.get(), "v {:.10} {:.10} {:.10}", p.x, p.y, p.z);
146 } else {
147 std::print(fp.get(), "v {} {} {}", p.x, p.y, p.z);
148 }
149 if constexpr ((is_color_v<Ts> || ...)) {
150 auto c = convert<FineRGB>(view<first_color_t<Ts...>>(pc)[i]);
151 std::println(fp.get(), " {:.6} {:.6} {:.6}", c.red, c.green, c.blue);
152 } else {
153 std::print(fp.get(), "\n");
154 }
155 if constexpr ((is_normal_v<Ts> || ...)) {
156 auto n = view<Normal>(pc)[i];
157 std::println(fp.get(), "vn {:.6} {:.6} {:.6}", n.x, n.y, n.z);
158 }
159 }
160
161 return true;
162}
163} // namespace ufo
164
165#endif // UFO_CLOUD_IO_OBJ_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