33#include <NDEVR/Model.h>
35#include <NDEVR/ScanMode.h>
36#include <NDEVR/MaterialRaster.h>
37#include <NDEVR/Angle.h>
38#include <NDEVR/Vertex.h>
39#include <NDEVR/Buffer.h>
40#include <NDEVR/Bounds.h>
41#include <NDEVR/VectorFunctions.h>
42#include <NDEVR/MatrixFunctions.h>
47 typedef AlocatingAlignedBuffer<Scan, 64> ScanBuffer;
56 struct ScanSetupSettings
61 uint01 scan_mesh_reach = 3;
62 bool is_continuous =
false;
63 bool generate_mesh =
true;
64 bool records_color =
false;
65 bool records_distance =
true;
66 bool records_polar =
true;
67 bool records_intensity =
true;
68 bool records_timestamp =
true;
69 bool is_child_of_station =
true;
75 enum ScanTargetBitFlags
89 template<
class t_type>
90 struct PolarScanRecord
92 Vertex<3, t_type> position = Vector<3, t_type>(0.0);
93 Vector<4, t_type> color = Vector<4, t_type>(0.0);
94 Vector<2, Angle<t_type>> coord;
95 Vector<2, Angle<t_type>> raw_coord;
96 t_type distance = 0.0;
97 t_type intensity = 0.0;
98 t_type total_weight = 0.0;
99 t_type max_distance = Constant<t_type>::Min;
100 t_type min_distance = Constant<t_type>::Max;
101 t_type scan_time = 0.0;
102 t_type scan_sweep = 0.0;
112 PolarScanRecord(Angle<t_type> roll, Angle<t_type> pitch)
118 PolarScanRecord(
const Vector<2, Angle<t_type>>& roll_pitch)
124 void updateWeight(t_type weight)
126 t_type weight_conv = weight / total_weight;
127 position *= weight_conv;
128 distance *= weight_conv;
129 intensity *= weight_conv;
130 scan_time *= weight_conv;
131 color *= weight_conv;
132 total_weight = weight;
138 template<
class t_other_type>
139 void updateAverage(
const PolarScanRecord<t_other_type>& record)
141 if (IsValid(record.position))
143 position += (record.total_weight * record.position).
template as<3, t_type>();
144 distance += cast<t_type>(record.total_weight * record.distance);
145 intensity += cast<t_type>(record.total_weight * record.intensity);
146 scan_time += cast<t_type>(record.total_weight * record.scan_time);
147 scan_sweep += cast<t_type>(record.total_weight * record.scan_sweep);
148 color += (record.total_weight * record.color).
template as<4, t_type>();
149 total_weight += cast<t_type>(record.total_weight);
151 if (IsValid(record.distance))
153 max_distance =
getMax(max_distance, cast<t_type>(record.distance));
154 min_distance =
getMin(min_distance, cast<t_type>(record.distance));
164 position = Vector<3, t_type>(0.0);
166 max_distance = Constant<t_type>::Min;
167 min_distance = Constant<t_type>::Max;
175 void autoCalcPositionH(Angle<t_type> roll = Angle<t_type>(DEGREES, 0.0f))
177 Matrix<fltp08> mat = Matrix<fltp08>::RotationMatrix(Vector<3, Angle<t_type>>(roll, coord[PITCH], coord[ROLL]));
178 position = (mat * Vertex<3, fltp08>(0.0, 0.0, distance)).as<3, fltp04>();
183 void autoCalcPositionR(Angle<t_type> yaw = Angle<t_type>(DEGREES, 0.0f))
185 Matrix<fltp08> mat = Matrix<fltp08>::RotationMatrix(Vector<3, Angle<t_type>>(coord, yaw));
186 position = (mat * Vertex<3, fltp08>(0.0, 0.0, distance)).as<3, fltp04>();
192 constexpr fltp08 operator[](uint01 dim)
const
194 return position[dim];
204 static const uint01 Dimensions = 0;
205 static const bool Vector =
false;
206 static const bool Buffer =
false;
207 static const bool Primitive =
true;
208 static const bool Pointer =
false;
209 static const bool Unsigned =
false;
210 static const bool Float =
false;
211 static const bool Integer =
false;
212 static const bool Number =
false;
213 static const bool Enum =
false;
214 static const bool String =
false;
215 static const bool Color =
false;
216 static const bool Boolean =
false;
220 static constexpr ObjectInfo<PolarScanRecord<fltp04>,
false,
false> VectorSub() {
return ObjectInfo<PolarScanRecord<fltp04>,
false,
false>(); }
233 class NDEVR_DESIGN_API Scan :
public Model
238 struct ScanCalibration
241 fltp08 emitter_offset = -0.1335;
243 Angle<fltp08> beam_angle = Angle<fltp08>(0);
244 Angle<fltp08> head_tilt_angle = Angle<fltp08>(0);
245 Angle<fltp08> laser_tilt_angle = Angle<fltp08>(0);
253 explicit Scan(
const Model& model);
258 Scan(
const Model& model,
const ScanSetupSettings& settings);
263 bool needsMeshUpdate(
const void* lock);
267 void clearNeedsMeshUpdate(
const void* lock);
271 void updateScanProperties(
bool scan_ended =
false);
277 void updateScanModel(
bool scan_ended,
bool force_calculate_mesh,
const void* lock);
280 void cacheChannels();
284 Model scanMesh()
const;
288 Model scanCloud()
const;
293 bool hasCalibrationRing(uint04 index)
const;
298 Scan& createCalibrationRing(uint04 index);
303 Scan& calibrationRing(uint04 index);
308 const Scan& calibrationRing(uint04 index)
const;
312 void reserveRecordSpace(uint04 space);
316 void addToRecordQueue(
const PolarScanRecord<fltp04>& record);
321 void splitScan(
const Vector<3, fltp08>& distance,
const void* lock);
325 void finishMoveScan(
const void* lock_ptr);
329 void addSweep(
const void* lock_ptr =
nullptr);
337 void moveScan(
const Vector<3, fltp08>& distance, fltp08 vertex_epsilon, fltp08 motion_only_max_difference,
bool filter_by_direction,
const void* lock_ptr);
342 void setupMesh(
bool add_new_structure,
const void* lock_ptr);
346 void setScannerOrientation(
const Vector<3, Angle<fltp08>>& orientation);
350 void setDeploymentOrientation(
const Vector<3, Angle<fltp08>>& orientation);
354 void setScannerInfo(
const TranslatedString& scanner_info);
358 TranslatedString scannerInfo()
const;
362 void createImageRaster(
const RasterInfo& info);
368 void addImageToRaster(
const ImageData& data,
const Vector<2, Angle<sint04>>& fov,
const Matrix<fltp08>& camera_matrix);
372 bool scanCalibrated()
const;
376 void removeShadowTriangles(fltp04 cuttoff_ratio);
380 Vector<3, Angle<fltp08>> scannerOrientation()
const;
384 Vector<3, Angle<fltp08>> deploymentOrientation()
const;
390 Angle<fltp08> calculateCalibrationConstant(
bool global_yaw,
const void* lock)
const;
396 void calibrateScan(
bool global_yaw, InterpolationValues value = InterpolationValues::e_linear,
const void* lock =
nullptr);
403 void calibrateScan(Angle<fltp08> angle,
bool global_yaw, InterpolationValues value = InterpolationValues::e_linear,
const void* lock =
nullptr);
406 void decalibrateScan();
409 void ensureModelFormat();
412 void updateOlderAngles();
416 Model pointsLayer()
const;
420 Model meshLayer()
const;
424 Model circleScanLayer()
const;
431 void addRecords(
const Buffer<Vertex<3, fltp08>>& positions,
const Vertex<3, fltp08>& scan_center = Vertex<3, fltp08>(0.0),
bool add_to_cloud =
true,
bool add_to_mesh =
true);
436 void createMeshFromScan(
const Vertex<3, fltp08>& scan_center = Vertex<3, fltp08>(0.0),
const void* lock =
nullptr);
440 Bounds<2, Angle<fltp08>> scanBounds()
const;
444 Angle<fltp08> primaryAngleOfSeparation()
const;
448 Vector<2, Angle<fltp08>> anglesOfSeparation()
const;
452 void setAnglesOfSeperation(Vector<2, Angle<fltp08>>& angle);
456 void setScanBounds(
const Bounds<2, Angle<fltp08>>& bounds);
460 Vector<3, Angle<fltp08>> angleCalibrationOffset()
const;
465 void setCalibration(
const ScanCalibration& calibration,
const void* lock =
nullptr);
469 ScanCalibration getCalibration()
const;
477 static constexpr StringView TypeName() {
return "scan"; }
481 static constexpr StringView CalibrationRingTypeName() {
return "calibration_ring"; }
485 TimeSpan scanDuration()
const;
489 void setScanDuration(
const TimeSpan& span);
493 void setIsDynamic(
bool is_dynamic);
496 void setMotionOnlyReference();
500 bool isScanValid()
const;
504 void setValid(
bool is_valid);
510 Buffer<PolarScanRecord<fltp04>> generatePolarRecords(
const Vertex<3, fltp08>& scan_center = Vertex<3, fltp08>(0.0),
const void* lock =
nullptr);
515 void setupScanRecordsFromExisting(
const Vertex<3, fltp08>& scan_center = Vertex<3, fltp08>(0.0),
const void* lock =
nullptr);
520 void addMeshRasterRecord(
const PolarScanRecord<fltp04>& record, sint04 range);
526 void addMeshRasterRecord(
const ZippedRadialMeshOptions& options, Vector<2, Angle<fltp08>> delta,
const PolarScanRecord<fltp04>& record);
530 void blurMeshRecords(sint04 range);
534 void addCloudRecord(
const PolarScanRecord<fltp04>& record);
540 void updateScanColors();
548 [[nodiscard]] TranslatedString createDescription(
bool is_finished);
558 static Angle<fltp08> GetBestRotation(Angle<fltp08> increment,
const Buffer<Vertex<3, fltp08>>& v_a,
const Buffer<Vertex<3, fltp08>>& v_b,
const Matrix<fltp08>& mat,
const Vector<3, fltp08>& up, InfoPipe* pipe =
nullptr);
565 static Angle<fltp08> GetBestRotation_2DAffine(
const Buffer<Vertex<3, fltp08>>& v_a,
const Buffer<Vertex<3, fltp08>>& v_b,
const Matrix<fltp08>& mat);
567 mutable Vector<3, Angle<fltp08>> m_scanner_orientation = Constant<Vector<3, Angle<fltp08>>>::Invalid;
568 mutable Vector<3, Angle<fltp08>> m_deployment_orientation = Constant<Vector<3, Angle<fltp08>>>::Invalid;
569 MaterialRasterBase* m_image_raster =
nullptr;
570 Bounds<1, uint04> m_mesh_write_update_bounds = Constant<Bounds<1, uint04>>::Min;
571 Bounds<3, fltp04> m_scan_record_bounds = Constant<Bounds<3, fltp04>>::Min;
572 PolarScanRecord<fltp08> m_total_avg;
573 Buffer<PolarScanRecord<fltp04>> m_cloud_write_queue;
574 Buffer<PolarScanRecord<fltp04>> m_mesh_write_queue;
575 Buffer<uint04> m_mesh_locations;
576 mutable ScanBuffer m_reference_scans;
577 uint04 m_cloud_intensity_channel = Constant<uint04>::Invalid;
578 uint04 m_cloud_roll_channel = Constant<uint04>::Invalid;
579 uint04 m_cloud_pitch_channel = Constant<uint04>::Invalid;
580 uint04 m_cloud_distance_channel = Constant<uint04>::Invalid;
581 uint04 m_scan_time_channel = Constant<uint04>::Invalid;
582 uint04 m_scan_sweep_channel = Constant<uint04>::Invalid;
583 uint04 m_scan_original_channel = Constant<uint04>::Invalid;
584 uint04 m_scan_sweeps = Constant<uint04>::Invalid;
585 uint04 m_mesh_write_offset = 0;
586 Vertex<3, fltp04> m_split_offset = Vertex<3, fltp04>(0.0);
587 Vertex<3, fltp04> m_last_min_mid_max;
588 bool m_is_dynamic_scan =
false;
589 bool m_needs_raster_update =
false;
590 bool m_needs_channel_update =
true;
591 mutable ScanSetupSettings m_settings;
594 static const uint04 s_scan_mesh = 0;
595 static const uint04 s_scan_cloud = 1;
596 static const uint04 s_calibration_circle_start_ring = 2;
Stores an angle in an optimized internal format with support for efficient trigonometric operations.
A specification of upper and lower bounds in N-dimensions.
A container for Images managed by the ImageFactory.
Base class for painting pixels at a time into a 2D texture.
A core class that represents a node on model hierarchy.
Logic for reading or writing to a string or a user friendly, TranslatedString.
A fixed-size array with N dimensions used as the basis for geometric and mathematical types.
The primary namespace for the NDEVR SDK.
@ BitFlag
Per-vertex bit flags (selected, hidden, etc.).
@ Color
Per-vertex RGBA color.
constexpr t_type getMin(const t_type &left, const t_type &right)
Finds the minimum of the given arguments based on the < operator Author: Tyler Parke Date: 2017-11-05...
float fltp04
Defines an alias representing a 4 byte floating-point number Bit layout is as follows: -Sign: 1 bit a...
constexpr t_type getMax(const t_type &left, const t_type &right)
Finds the max of the given arguments using the > operator The only requirement is that t_type have > ...
ScanMode
The mode that a scanner will collect data in.
@ e_undefined
Scan mode has not been specified.
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
double fltp08
Defines an alias representing an 8 byte floating-point number.
@ DEGREES
Angle measured in degrees (0 to 360 for a full circle).
constexpr HSLColor Constant< HSLColor >::Max
The maximum HSLColor constant with all components at their maximum values.
@ e_mesh
Perform a mesh operation on the selected object.
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved 'invali...
Information about the object.
Stores information for painting pixels at a time into a 2D texture used with MaterialRaster.
Logic for setting up a mesh that is broken apart by latitude and longitude lines with a set angle dif...