Voyant API 1.0.0
Loading...
Searching...
No Matches
voyant_frame.hpp
Go to the documentation of this file.
1// Copyright (c) 2024-2025 Voyant Photonics, Inc.
2// All rights reserved.
3
4#pragma once
5
7#include <cstdint>
8#include <iomanip>
9#include <optional>
10#include <ostream>
12#include <sstream>
13#include <string>
14#include <utility>
15#include <vector>
16#include <voyant_types_ffi.hpp>
17
22static_assert(sizeof(PointData) == 36, "PointDataV1 is frozen at 36 bytes");
23
25inline bool isValidPoint(const PointData& point)
26{
27 return point.drop_reason == DROP_REASON_VALID;
28}
29
37inline bool setPointsXyz(std::vector<PointData>& points, const std::vector<VoyantVec3>& positions)
38{
39 if (points.size() != positions.size())
40 {
41 return false;
42 }
43 if (points.empty())
44 {
45 return true;
46 }
47 return voyant_points_set_xyz(points.data(), points.size(), positions.data());
48}
49
68{
69public:
71 VoyantFrame() = default;
72
73 const std::vector<PointData>& points() const
74 {
75 return points_;
76 }
77 std::vector<PointData>& points()
78 {
79 return points_;
80 }
81
82 size_t nPoints() const
83 {
84 return points_.size();
85 }
86
88 size_t nValidPoints() const
89 {
90 size_t n = 0;
91 for (const PointData& point : points_)
92 {
93 n += isValidPoint(point) ? 1 : 0;
94 }
95 return n;
96 }
97
103 bool carriesState() const
104 {
105 return meta_.state_provenance == static_cast<uint8_t>(StateProvenance::Measured);
106 }
107
110 std::optional<SensorState> sensorState() const
111 {
112 if (!carriesState())
113 {
114 return std::nullopt;
115 }
117 }
118
121 std::optional<HostState> hostState() const
122 {
123 if (!carriesState())
124 {
125 return std::nullopt;
126 }
128 }
129
131 uint32_t frameIndex() const
132 {
133 return meta_.frame_index;
134 }
135
137 int64_t timestampSeconds() const
138 {
139 return meta_.timestamp_seconds;
140 }
141
143 int32_t timestampNanoseconds() const
144 {
145 return meta_.timestamp_nanoseconds;
146 }
147
151 double timestamp() const
152 {
153 return static_cast<double>(meta_.timestamp_seconds) + static_cast<double>(meta_.timestamp_nanoseconds) * 1e-9;
154 }
155
158 std::string deviceId() const
159 {
160 char buf[32];
161 voyant_frame_device_id(&meta_, buf, sizeof(buf));
162 return buf;
163 }
164
167 VoyantFrame withPoints(std::vector<PointData> points) const
168 {
169 // Copy only the metadata: copy-constructing from *this would deep-copy this
170 // frame's points just to overwrite them.
171 VoyantFrame derived;
172 derived.meta_ = meta_;
173 derived.points_ = std::move(points);
174 return derived;
175 }
176
187
198 static std::optional<VoyantFrame> synthetic(std::vector<PointData> points, const SyntheticFrameDesc& desc)
199 {
200 VoyantFrame frame;
201 if (!voyant_synthetic_frame_meta(static_cast<uint8_t>(desc.source), desc.timestampSeconds,
202 desc.timestampNanoseconds, desc.frameIndex, &frame.meta_))
203 {
204 return std::nullopt;
205 }
206 frame.points_ = std::move(points);
207 return frame;
208 }
209
211 // An overload rather than `desc = {}` — GCC rejects brace-init default
212 // arguments for nested aggregate types (bug 88165).
213 static std::optional<VoyantFrame> synthetic(std::vector<PointData> points)
214 {
215 return synthetic(std::move(points), SyntheticFrameDesc{});
216 }
217
228
239 static std::optional<VoyantFrame> stateless(std::vector<PointData> points, const StatelessFrameDesc& desc)
240 {
241 VoyantFrame frame;
242 if (!voyant_stateless_frame_meta(static_cast<uint8_t>(desc.source), desc.serialNumber, desc.timestampSeconds,
243 desc.timestampNanoseconds, desc.frameIndex, &frame.meta_))
244 {
245 return std::nullopt;
246 }
247 frame.points_ = std::move(points);
248 return frame;
249 }
250
252 static std::optional<VoyantFrame> stateless(std::vector<PointData> points)
253 {
254 return stateless(std::move(points), StatelessFrameDesc{});
255 }
256
271 std::optional<VoyantFrame> withSdl(const SdlCommandParams& params) const
272 {
273 VoyantFrame derived;
274 derived.meta_ = meta_;
275 if (!voyant_frame_meta_with_sdl(&derived.meta_, params.req_state, params.frame_rate_fps, params.hfov_deg,
276 params.hfov_center_deg, params.ramp_bandwidth_ghz))
277 {
278 return std::nullopt;
279 }
280 derived.points_ = points_;
281 return derived;
282 }
283
291 std::vector<VoyantVec3> xyz() const
292 {
293 std::vector<VoyantVec3> out(points_.size());
294 if (!points_.empty())
295 {
296 voyant_points_xyz(points_.data(), points_.size(), out.data());
297 }
298 return out;
299 }
300
302 std::string describe() const;
303
304private:
307 {
308 VoyantFrameMeta meta = meta_;
309 meta.n_points = points_.size();
310 return meta;
311 }
312
313 VoyantFrameMeta meta_{}; // zeroed: provenance Unknown, i.e. carries no state
314 std::vector<PointData> points_;
315
316 // The producers fill meta_/points_ directly; keeping that access friend-only
317 // means no user code can construct a frame claiming real (Measured) state.
318 friend class CarbonClient;
319 friend class VoyantPlayback;
320 friend class VoyantRecorder;
321};
322
324inline std::ostream& operator<<(std::ostream& os, const VoyantFrame& frame)
325{
326 std::ios_base::fmtflags flags(os.flags());
327 std::streamsize prec = os.precision();
328 os << "VoyantFrame(frame_index=" << frame.frameIndex() << ", n_points=" << frame.nPoints()
329 << ", n_valid_points=" << frame.nValidPoints() << std::fixed << std::setprecision(6)
330 << ", timestamp=" << frame.timestamp() << ", device_id=" << frame.deviceId() << ")";
331 os.flags(flags);
332 os.precision(prec);
333 return os;
334}
335
336inline std::string VoyantFrame::describe() const
337{
338 std::ostringstream out;
339 out << *this;
340 if (!carriesState())
341 {
342 out << "\n NO SENSOR STATE — none was recorded for this frame."
343 "\n Points are real; health, calibration, SDL and time-sync are not"
344 "\n available, and device identity and timestamps may be unset.";
345 return out.str();
346 }
347 const SensorState state = *sensorState();
348 out << "\n " << state.device << "\n " << state.sdl << "\n " << *hostState();
349 return out.str();
350}
A point-cloud frame: points plus the sensor/host state snapshots and frame metadata recorded with the...
Definition voyant_frame.hpp:68
static std::optional< VoyantFrame > synthetic(std::vector< PointData > points)
synthetic() with an all-default identity: Unknown source, zeroed timeline.
Definition voyant_frame.hpp:213
bool carriesState() const
Definition voyant_frame.hpp:103
uint32_t frameIndex() const
Device frame counter.
Definition voyant_frame.hpp:131
friend class CarbonClient
Definition voyant_frame.hpp:318
std::optional< SensorState > sensorState() const
Definition voyant_frame.hpp:110
std::vector< VoyantVec3 > xyz() const
Definition voyant_frame.hpp:291
size_t nPoints() const
Definition voyant_frame.hpp:82
static std::optional< VoyantFrame > stateless(std::vector< PointData > points)
stateless() with an all-default identity: Unknown source, zeroed timeline.
Definition voyant_frame.hpp:252
std::string describe() const
A one-screen summary of the frame and its state snapshots.
Definition voyant_frame.hpp:336
std::string deviceId() const
Definition voyant_frame.hpp:158
int64_t timestampSeconds() const
Whole seconds of the frame-start time since the Unix epoch.
Definition voyant_frame.hpp:137
int32_t timestampNanoseconds() const
Sub-second remainder of the frame-start time, in nanoseconds (0..=999999999).
Definition voyant_frame.hpp:143
static std::optional< VoyantFrame > stateless(std::vector< PointData > points, const StatelessFrameDesc &desc)
Build a frame from points that arrived without the sensor's heartbeat — a bag, a CSV — so it declares...
Definition voyant_frame.hpp:239
friend class VoyantPlayback
Definition voyant_frame.hpp:319
static std::optional< VoyantFrame > synthetic(std::vector< PointData > points, const SyntheticFrameDesc &desc)
Build a frame of generated data — a simulated scene, a scripted test cloud — that records and replays...
Definition voyant_frame.hpp:198
std::vector< PointData > points_
Definition voyant_frame.hpp:314
friend class VoyantRecorder
Definition voyant_frame.hpp:320
size_t nValidPoints() const
Count of valid returns (see isValidPoint()); computed per call.
Definition voyant_frame.hpp:88
std::optional< VoyantFrame > withSdl(const SdlCommandParams &params) const
A new frame whose SDL state reads as if the sensor had applied params (status Applied); everything el...
Definition voyant_frame.hpp:271
VoyantFrame()=default
An empty frame that carries no state; see the class docs.
VoyantFrameMeta toMeta() const
This frame's transfer fields with n_points refreshed from the vector.
Definition voyant_frame.hpp:306
VoyantFrame withPoints(std::vector< PointData > points) const
Definition voyant_frame.hpp:167
std::vector< PointData > & points()
Definition voyant_frame.hpp:77
std::optional< HostState > hostState() const
Definition voyant_frame.hpp:121
double timestamp() const
Definition voyant_frame.hpp:151
const std::vector< PointData > & points() const
Definition voyant_frame.hpp:73
VoyantFrameMeta meta_
Definition voyant_frame.hpp:313
Definition voyant_types_ffi.hpp:443
uint8_t drop_reason
Definition voyant_types_ffi.hpp:484
Definition carbon_client_ffi.hpp:49
float frame_rate_fps
Definition carbon_client_ffi.hpp:59
float hfov_deg
Definition carbon_client_ffi.hpp:51
uint8_t req_state
Definition carbon_client_ffi.hpp:50
float ramp_bandwidth_ghz
Definition carbon_client_ffi.hpp:60
float hfov_center_deg
Definition carbon_client_ffi.hpp:58
Definition voyant_types_ffi.hpp:350
DeviceInfo device
Definition voyant_types_ffi.hpp:354
SdlDeviceState sdl
Definition voyant_types_ffi.hpp:351
Definition voyant_types_ffi.hpp:365
uintptr_t n_points
Definition voyant_types_ffi.hpp:395
Definition voyant_frame.hpp:221
uint32_t frameIndex
Definition voyant_frame.hpp:226
int64_t timestampSeconds
Definition voyant_frame.hpp:224
uint32_t serialNumber
Definition voyant_frame.hpp:223
int32_t timestampNanoseconds
Definition voyant_frame.hpp:225
ProductId source
Definition voyant_frame.hpp:222
Identity and timeline of a synthetic() frame; zeros are valid.
Definition voyant_frame.hpp:179
int32_t timestampNanoseconds
Definition voyant_frame.hpp:184
ProductId source
Definition voyant_frame.hpp:182
uint32_t frameIndex
Definition voyant_frame.hpp:185
int64_t timestampSeconds
Definition voyant_frame.hpp:183
bool isValidPoint(const PointData &point)
Whether a point is a valid return.
Definition voyant_frame.hpp:25
PointDataV1 PointData
Definition voyant_frame.hpp:21
bool setPointsXyz(std::vector< PointData > &points, const std::vector< VoyantVec3 > &positions)
Definition voyant_frame.hpp:37
std::ostream & operator<<(std::ostream &os, const VoyantFrame &frame)
One-line frame summary, printed for every frame in typical receive loops.
Definition voyant_frame.hpp:324
bool voyant_synthetic_frame_meta(uint8_t source, int64_t timestamp_seconds, int32_t timestamp_nanoseconds, uint32_t frame_index, VoyantFrameMeta *out)
bool voyant_points_xyz(const PointDataV1 *points, uintptr_t n_points, VoyantVec3 *out)
bool voyant_points_set_xyz(PointDataV1 *points, uintptr_t n_points, const VoyantVec3 *positions)
SensorState voyant_frame_sensor_state(const VoyantFrameMeta *meta)
uintptr_t voyant_frame_device_id(const VoyantFrameMeta *meta, char *buf, uintptr_t capacity)
ProductId
Definition voyant_types_ffi.hpp:28
@ Unknown
Definition voyant_types_ffi.hpp:29
HostState voyant_frame_host_state(const VoyantFrameMeta *meta)
bool voyant_stateless_frame_meta(uint8_t source, uint32_t serial_number, int64_t timestamp_seconds, int32_t timestamp_nanoseconds, uint32_t frame_index, VoyantFrameMeta *out)
@ Measured
Definition voyant_types_ffi.hpp:162
bool voyant_frame_meta_with_sdl(VoyantFrameMeta *meta, uint8_t req_state, float frame_rate_fps, float hfov_deg, float hfov_center_deg, float ramp_bandwidth_ghz)