44#include < vector>
55#include < cstring>
66#include < iomanip>
7-
7+ # include < liblzf/lzf.h >
88
99namespace openlidarmap ::io {
1010
@@ -78,42 +78,6 @@ bool ParsePCDHeader(std::ifstream& file, PCDHeader& header) {
7878 return true ;
7979}
8080
81- double UnpackBinary (const char * data_ptr, char type, int size) {
82- switch (type) {
83- case ' F' : {
84- if (size == 4 ) {
85- float value;
86- std::memcpy (&value, data_ptr, sizeof (float ));
87- return static_cast <double >(value);
88- } else if (size == 8 ) {
89- double value;
90- std::memcpy (&value, data_ptr, sizeof (double ));
91- return value;
92- }
93- break ;
94- }
95- case ' I' : {
96- switch (size) {
97- case 1 : return static_cast <double >(*reinterpret_cast <const int8_t *>(data_ptr));
98- case 2 : return static_cast <double >(*reinterpret_cast <const int16_t *>(data_ptr));
99- case 4 : return static_cast <double >(*reinterpret_cast <const int32_t *>(data_ptr));
100- case 8 : return static_cast <double >(*reinterpret_cast <const int64_t *>(data_ptr));
101- }
102- break ;
103- }
104- case ' U' : {
105- switch (size) {
106- case 1 : return static_cast <double >(*reinterpret_cast <const uint8_t *>(data_ptr));
107- case 2 : return static_cast <double >(*reinterpret_cast <const uint16_t *>(data_ptr));
108- case 4 : return static_cast <double >(*reinterpret_cast <const uint32_t *>(data_ptr));
109- case 8 : return static_cast <double >(*reinterpret_cast <const uint64_t *>(data_ptr));
110- }
111- break ;
112- }
113- }
114- throw std::runtime_error (" Unsupported PCD data type or size" );
115- }
116-
11781small_gicp::PointCloud::Ptr PCDLoader::load (const std::string& file_path) {
11882 std::ifstream file (file_path, std::ios::binary);
11983 if (!file) {
@@ -140,7 +104,6 @@ small_gicp::PointCloud::Ptr PCDLoader::load(const std::string& file_path) {
140104 throw std::runtime_error (" Missing XYZ fields in PCD file" );
141105 }
142106
143- // Reset file position and search for DATA line
144107 file.clear ();
145108 file.seekg (0 );
146109
@@ -182,6 +145,79 @@ small_gicp::PointCloud::Ptr PCDLoader::load(const std::string& file_path) {
182145 }
183146 points_read++;
184147 }
148+ } else if (header.is_compressed ) {
149+ file.clear ();
150+ file.seekg (0 );
151+
152+ std::string line;
153+ while (std::getline (file, line)) {
154+ if (line.find (" DATA binary_compressed" ) != std::string::npos) {
155+ break ;
156+ }
157+ }
158+
159+ uint32_t compressed_size = 0 , uncompressed_size = 0 ;
160+ if (!file.read (reinterpret_cast <char *>(&compressed_size), sizeof (compressed_size)) ||
161+ !file.read (reinterpret_cast <char *>(&uncompressed_size), sizeof (uncompressed_size))) {
162+ throw std::runtime_error (" Failed to read size info" );
163+ }
164+
165+ // Allocate buffers
166+ std::vector<char > compressed_data (compressed_size);
167+ std::vector<char > uncompressed_data (uncompressed_size);
168+
169+ // Read compressed data
170+ if (!file.read (compressed_data.data (), compressed_size)) {
171+ throw std::runtime_error (" Failed to read compressed data" );
172+ }
173+
174+ // Decompress using LZF
175+ int result = lzf_decompress (
176+ compressed_data.data (), compressed_size,
177+ uncompressed_data.data (), uncompressed_size
178+ );
179+
180+ if (result != uncompressed_size) {
181+ throw std::runtime_error (" LZF decompression failed" );
182+ }
183+
184+ // Points are stored field by field
185+ int strip_size = header.points ;
186+ points.resize (header.points );
187+
188+ // Process each coordinate field
189+ for (const auto & field : header.fields ) {
190+ const char * base_ptr = uncompressed_data.data () + field.offset * strip_size;
191+
192+ if (field.name == " x" ) {
193+ for (int i = 0 ; i < header.points ; i++) {
194+ float value;
195+ std::memcpy (&value, base_ptr + i * field.size , sizeof (float ));
196+ points[i][0 ] = value;
197+ }
198+ } else if (field.name == " y" ) {
199+ for (int i = 0 ; i < header.points ; i++) {
200+ float value;
201+ std::memcpy (&value, base_ptr + i * field.size , sizeof (float ));
202+ points[i][1 ] = value;
203+ }
204+ } else if (field.name == " z" ) {
205+ for (int i = 0 ; i < header.points ; i++) {
206+ float value;
207+ std::memcpy (&value, base_ptr + i * field.size , sizeof (float ));
208+ points[i][2 ] = value;
209+ points[i][3 ] = 1.0 ;
210+ }
211+ }
212+ }
213+
214+ // Apply range filtering
215+ auto it = std::remove_if (points.begin (), points.end (),
216+ [this ](const Eigen::Vector4d& p) {
217+ const double norm = p.head <3 >().norm ();
218+ return norm < config_.preprocess_ .min_range || norm > config_.preprocess_ .max_range ;
219+ });
220+ points.erase (it, points.end ());
185221 } else {
186222 std::string line;
187223 while (std::getline (file, line) && points.size () < header.points ) {
0 commit comments