1 /*
2 Copyright 2016 Esri
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8 http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 
16 A local copy of the license and additional notices are located with the
17 source distribution at:
18 
19 http://github.com/Esri/lepcc/
20 
21 Contributors:  Thomas Maurer
22 */
23 
24 // Test_C_Api.cpp
25 //
26 
27 #include <cstring>
28 #include <cmath>
29 #include <stdio.h>
30 #include <iostream>
31 #include <vector>
32 #include <algorithm>
33 #include <chrono>
34 #include "lepcc_c_api.h"
35 #include "lepcc_types.h"
36 
37 using namespace std;
38 using namespace std::chrono;
39 using namespace lepcc;
40 
41 // -------------------------------------------------------------------------- ;
42 
43 int ReadBlobSize(lepcc_ContextHdl ctx, FILE* fp);
44 
HasError(ErrCode errCode,const string & fctName)45 int HasError(ErrCode errCode, const string& fctName)
46 {
47   if (errCode != ErrCode::Ok)
48     printf("Error in main(): %s failed. Error code = %d\n", fctName.c_str(), errCode);
49   return (int)errCode;
50 }
51 
52 // -------------------------------------------------------------------------- ;
53 
main(int argc,char * argv[])54 int main(int argc, char* argv[])
55 {
56   {
57     // open a small test binary slpk blob which has some LEPCC blobs embedded
58 
59     string fnIn = "../testData/SMALL_AUTZEN_LAS_All.slpk";
60     string fnGT = "../testData/SMALL_AUTZEN_LAS_All.bin";    // decoded ground truth stored as raw binary arrays
61     bool bWriteGT = false;    // toggle between write or read the ground truth
62 
63     FILE* fp = 0;
64     fp = fopen(fnIn.c_str(), "rb");
65     if (!fp)
66     {
67       printf("Error in main(): Cannot read from file %s.\n", fnIn.c_str());
68       return 0;
69     }
70 
71     fseek(fp, 0, SEEK_END);
72     size_t len = ftell(fp);
73     rewind(fp);
74 
75     vector<Byte> byteVec(len, 0);
76     fread(&byteVec[0], 1, len, fp);
77     fclose(fp);
78 
79     FILE* fpGT = 0;
80     fpGT = fopen(fnGT.c_str(), bWriteGT ? "wb" : "rb");
81     if (!fpGT)
82     {
83       printf("Error in main(): Cannot open file %s.\n", fnGT.c_str());
84       return 0;
85     }
86 
87     // search for LEPCC blobs
88 
89     vector<string> magicStrings;
90     magicStrings.push_back("LEPCC     ");
91     magicStrings.push_back("ClusterRGB");
92     magicStrings.push_back("Intensity ");
93 
94     lepcc_ContextHdl ctx = lepcc_createContext();
95     int nInfo = lepcc_getBlobInfoSize();
96     ErrCode errCode;
97 
98     size_t magicLen = 10;
99     for (size_t pos = 0; pos < len - magicLen; pos++)
100     {
101       for (size_t blobType = 0; blobType < magicStrings.size(); blobType++)
102       {
103         if (0 == memcmp(&byteVec[pos], magicStrings[blobType].c_str(), magicLen))
104         {
105           const Byte* ptr = &byteVec[pos];
106           uint32 blobSize = 0;
107           lepcc_blobType bt;
108           errCode = (ErrCode)lepcc_getBlobInfo(ctx, ptr, nInfo, &bt, &blobSize);
109           if (HasError(errCode, "lepcc_getBlobInfo()"))
110             return 0;
111 
112           switch (blobType)
113           {
114           case 0:
115           {
116             uint32 nPts = 0;
117             errCode = (ErrCode)lepcc_getPointCount(ctx, ptr, len - pos, &nPts);
118             if (HasError(errCode, "lepcc_getPointCount()"))
119               return 0;
120 
121             vector<Point3D> ptVec(nPts);
122             errCode = (ErrCode)lepcc_decodeXYZ(ctx, &ptr, len - pos, &nPts, (double*)(&ptVec[0]));
123             if (HasError(errCode, "lepcc_decodeXYZ()"))
124               return 0;
125 
126             printf("decode xyz blob succeeded.\n");
127 
128             if (bWriteGT)
129             {
130               fwrite(&nPts, 4, 1, fpGT);
131               fwrite(&ptVec[0], sizeof(Point3D), nPts, fpGT);
132             }
133             else
134             {
135               uint32 nPts2 = 0;
136               fread(&nPts2, 4, 1, fpGT);
137               if (nPts2 != nPts)
138               {
139                 printf("Error in main(): mismatch in number of elements %d vs %d\n", nPts, nPts2);
140                 return 0;
141               }
142               vector<Point3D> ptVec2(nPts);
143               fread(&ptVec2[0], sizeof(Point3D), nPts, fpGT);
144 
145               // compare
146               double dxMax(0), dyMax(0), dzMax(0);
147               for (int i = 0; i < (int)nPts; i++)
148               {
149                 const Point3D* p = &ptVec[i];
150                 const Point3D* q = &ptVec2[i];
151 
152                 double dx = abs(q->x - p->x);
153                 double dy = abs(q->y - p->y);
154                 double dz = abs(q->z - p->z);
155 
156                 dxMax = max(dx, dxMax);
157                 dyMax = max(dy, dyMax);
158                 dzMax = max(dz, dzMax);
159               }
160 
161               printf("number of points = %d, dxMax = %f, dyMax = %f, dzMax = %f\n", nPts, dxMax, dyMax, dzMax);
162             }
163           }
164           break;
165 
166           case 1:
167           {
168             uint32 nPts = 0;
169             errCode = (ErrCode)lepcc_getRGBCount(ctx, ptr, len - pos, &nPts);
170             if (HasError(errCode, "lepcc_getRGBCount()"))
171               return 0;
172 
173             vector<RGB_t> rgbVec(nPts);
174             errCode = (ErrCode)lepcc_decodeRGB(ctx, &ptr, len - pos, &nPts, (Byte*)(&rgbVec[0]));
175             if (HasError(errCode, "lepcc_decodeRGB()"))
176               return 0;
177 
178             printf("decode RGB blob succeeded.\n");
179 
180             if (bWriteGT)
181             {
182               fwrite(&nPts, 4, 1, fpGT);
183               fwrite(&rgbVec[0], sizeof(RGB_t), nPts, fpGT);
184             }
185             else
186             {
187               uint32 nPts2 = 0;
188               fread(&nPts2, 4, 1, fpGT);
189               if (nPts2 != nPts)
190               {
191                 printf("Error in main(): mismatch in number of elements %d vs %d\n", nPts, nPts2);
192                 return 0;
193               }
194               vector<RGB_t> rgbVec2(nPts);
195               fread(&rgbVec2[0], sizeof(RGB_t), nPts, fpGT);
196 
197               // compare
198               double dxMax(0), dyMax(0), dzMax(0);
199               for (int i = 0; i < (int)nPts; i++)
200               {
201                 const RGB_t* p = &rgbVec[i];
202                 const RGB_t* q = &rgbVec2[i];
203 
204                 double dx = abs(q->r - p->r);
205                 double dy = abs(q->g - p->g);
206                 double dz = abs(q->b - p->b);
207 
208                 dxMax = max(dx, dxMax);
209                 dyMax = max(dy, dyMax);
210                 dzMax = max(dz, dzMax);
211               }
212 
213               printf("number of points = %d, dxMax = %f, dyMax = %f, dzMax = %f\n", nPts, dxMax, dyMax, dzMax);
214             }
215           }
216           break;
217 
218           case 2:
219           {
220             uint32 nPts = 0;
221             errCode = (ErrCode)lepcc_getIntensityCount(ctx, ptr, len - pos, &nPts);
222             if (HasError(errCode, "lepcc_getIntensityCount()"))
223               return 0;
224 
225             vector<unsigned short> intensityVec(nPts);
226             errCode = (ErrCode)lepcc_decodeIntensity(ctx, &ptr, len - pos, &nPts, (unsigned short*)(&intensityVec[0]));
227             if (HasError(errCode, "lepcc_decodeIntensity()"))
228               return 0;
229 
230             printf("decode intensity blob succeeded.\n");
231 
232             if (bWriteGT)
233             {
234               fwrite(&nPts, 4, 1, fpGT);
235               fwrite(&intensityVec[0], sizeof(unsigned short), nPts, fpGT);
236             }
237             else
238             {
239               uint32 nPts2 = 0;
240               fread(&nPts2, 4, 1, fpGT);
241               if (nPts2 != nPts)
242               {
243                 printf("Error in main(): mismatch in number of elements %d vs %d\n", nPts, nPts2);
244                 return 0;
245               }
246               vector<unsigned short> intensityVec2(nPts);
247               fread(&intensityVec2[0], sizeof(unsigned short), nPts, fpGT);
248 
249               // compare
250               double dxMax(0);
251               for (int i = 0; i < (int)nPts; i++)
252               {
253                 int intensity0 = intensityVec[i];
254                 int intensity1 = intensityVec2[i];
255                 double dx = abs(intensity1 - intensity0);
256                 dxMax = max(dx, dxMax);
257               }
258 
259               printf("number of points = %d, dxMax = %f\n", nPts, dxMax);
260             }
261           }
262           break;
263 
264           default:
265             printf("Error in main(): Test for this LEPCC blob type not implemented.\n");
266           }
267 
268           pos += blobSize - 1;
269         }
270       }
271     }
272 
273     fclose(fpGT);
274     return 0;
275   }
276 
277   // -------------- see below for examples on how to encode and decode --------
278 
279   double maxXErr = 9e-8, maxYErr = maxXErr;
280   double maxZErr = 0.01;
281 
282   int mode = 0;    // 0 - computeCompressedSize, 1 - encode, 2 - decode, 3 - test
283 
284   bool origHasXYZ = false;
285   bool origHasRGB = false;
286   bool decodHasRGB = origHasRGB;
287   bool origHasIntensity = true;
288 
289   string fn, fnOut;
290 
291   if (mode != 2)
292   {
293     //fn = "tilesXYZ.bin";
294     //fn = "tilesXYZ_RGB.bin";
295     //fn = "heritage_rgb_only.bin";
296     fn = "sonoma18_intensity_only.bin";
297     fnOut = "tilesCompressed.bin";
298   }
299   else
300   {
301     fn = "tilesCompressed.bin";
302     fnOut = "tilesUncompressed.bin";
303   }
304 
305   FILE* fp = 0;
306   fp = fopen( fn.c_str(), "rb");
307   if (!fp)
308   {
309     printf("Error in main(): Cannot read from file %s.\n", fn.c_str());  return 0;
310   }
311 
312   FILE* fpOut = 0;
313   if (mode == 1 || mode == 2)    //  || mode == 0)
314   {
315     fpOut = fopen(fnOut.c_str(), "wb");
316     if (!fpOut)
317     {
318       printf("Error in main(): Cannot write to file %s.\n", fnOut.c_str());  return 0;
319     }
320     fclose(fpOut);
321     fpOut = fopen(fnOut.c_str(), "ab");    // open again in append mode
322   }
323 
324   double totalNumPoints = 0, totalNumTiles = 0;
325   double minPts = 1e16, maxPts = 0;
326   double maxDecErrX = 0, maxDecErrY = 0, maxDecErrZ = 0;
327   double maxDecErrRGB = 0, totalDecErrRGB = 0;
328   double maxDecErrIntensity = 0, totalDecErrIntensity = 0;
329   int64 totalNumBytesCompressed = 0;
330 
331   lepcc_ContextHdl ctx = lepcc_createContext();
332   lepcc_ContextHdl ctxDec = lepcc_createContext();
333   lepcc_status hr;
334 
335   vector<Point3D> ptVec, decPtVec;
336   vector<RGB_t> rgbVec, sortedRgbVec, decRgbVec;
337   vector<Byte> byteVec;
338   vector<uint16> intensityVec, decIntensityVec;
339   vector<uint32> orderVec;
340 
341   high_resolution_clock::time_point t0 = high_resolution_clock::now();
342 
343   if (mode != 2)    // simulate, encode, or test
344   {
345     bool done = false;
346     while (!done)    // tile loop
347     {
348       int nPts = 0;
349 
350       if (origHasXYZ)
351       {
352         fread(&nPts, 4, 1, fp);
353         if (nPts == 0)    // eof
354         {
355           done = true;
356           continue;
357         }
358         ptVec.resize(nPts);
359         fread(&ptVec[0], sizeof(Point3D), nPts, fp);
360       }
361 
362       //memset(&ptVec[0], 0, sizeof(Point3D) * nPts);    // set points to all 0
363 
364       if (origHasRGB)
365       {
366         int nPts2 = 0;
367         fread(&nPts2, 4, 1, fp);
368         if (nPts2 == 0)    // eof
369         {
370           done = true;
371           continue;
372         }
373         if (origHasXYZ && nPts2 != nPts)
374           return 0;
375 
376         nPts = nPts2;
377         rgbVec.resize(nPts);
378         fread(&rgbVec[0], sizeof(RGB_t), nPts, fp);
379       }
380 
381       if (origHasIntensity)
382       {
383         int nPts2 = 0;
384         fread(&nPts2, 4, 1, fp);
385         if (nPts2 == 0)    // eof
386         {
387           done = true;
388           continue;
389         }
390         if (origHasXYZ && nPts2 != nPts)
391           return 0;
392 
393         nPts = nPts2;
394         intensityVec.resize(nPts);
395         fread(&intensityVec[0], sizeof(uint16), nPts, fp);
396       }
397 
398       uint32 nBytesXYZ = 0;
399       if (ptVec.size() > 0)
400       {
401         orderVec.resize(nPts);
402         hr = lepcc_computeCompressedSizeXYZ(ctx, nPts, (const double*)(&ptVec[0]), maxXErr, maxYErr, maxZErr, &nBytesXYZ, (uint32*)(&orderVec[0]));
403         if (hr)
404         {
405           printf("Error in main(): lepcc_computeCompressedSizeXYZ(...) failed.\n");  return 0;
406         }
407       }
408 
409       uint32 nBytesRGB = 0;
410       if (rgbVec.size() > 0)
411       {
412         if (orderVec.size() > 0)    // resort the RGB values to point order
413         {
414           sortedRgbVec.resize(nPts);
415           for (int i = 0; i < nPts; i++)
416             sortedRgbVec[i] = rgbVec[orderVec[i]];
417 
418           hr = lepcc_computeCompressedSizeRGB(ctx, nPts, (const Byte*)(&sortedRgbVec[0]), &nBytesRGB);
419         }
420         else
421           hr = lepcc_computeCompressedSizeRGB(ctx, nPts, (const Byte*)(&rgbVec[0]), &nBytesRGB);
422 
423         if (hr)
424         {
425           printf("Error in main(): lepcc_computeCompressedSizeRGB(...) failed.\n");  return 0;
426         }
427       }
428 
429       uint32 nBytesIntensity = 0;
430       if (intensityVec.size() > 0)
431       {
432         //for (int i = 0; i < (int)intensityVec.size(); i++)
433         //  intensityVec[i] = 0;
434 
435         hr = lepcc_computeCompressedSizeIntensity(ctx, nPts, &intensityVec[0], &nBytesIntensity);
436 
437         if (hr)
438         {
439           printf("Error in main(): lepcc_computeCompressedSizeIntensity(...) failed.\n");  return 0;
440         }
441       }
442 
443       int64 nBytes = nBytesXYZ + nBytesRGB + nBytesIntensity;
444 
445       // stats
446       totalNumBytesCompressed += nBytes;
447       totalNumPoints += nPts;
448       totalNumTiles++;
449 
450       minPts = (std::min)(minPts, (double)nPts);
451       maxPts = (std::max)(maxPts, (double)nPts);
452 
453       //printf("nTiles = %d, minPtsPerTile = %d, maxPtsPerTile = %d, nPtsTotal = %d\n", (int)totalNumTiles, (int)minPts, (int)maxPts, (int)totalNumPoints);
454 
455       if (mode > 0)    // encode, or test
456       {
457         byteVec.resize((size_t)nBytes);
458         Byte* buffer = &byteVec[0];
459         Byte* pByte = buffer;
460 
461         // encode
462         if (ptVec.size() > 0)
463           if ((hr = lepcc_encodeXYZ(ctx, &pByte, nBytesXYZ)))
464           {
465             printf("Error in main(): lepcc_encodeXYZ(...) failed.\n");  return 0;
466           }
467 
468         if (rgbVec.size() > 0)
469           if ((hr = lepcc_encodeRGB(ctx, &pByte, nBytesRGB)))
470           {
471             printf("Error in main(): lepcc_encodeRGB(...) failed.\n");  return 0;
472           }
473 
474         if (intensityVec.size() > 0)
475           if ((hr = lepcc_encodeIntensity(ctx, &pByte, nBytesIntensity, &intensityVec[0], nPts)))
476           {
477             printf("Error in main(): lepcc_encodeIntensity(...) failed.\n");  return 0;
478           }
479 
480         if (mode == 1)    // encode
481         {
482           fwrite(buffer, 1, (size_t)nBytes, fpOut);    // append this byte blob to output stream
483         }
484 
485         else if (mode == 3)    // test mode: compare decoded points to orig for this tile right away
486         {
487           const Byte* pByte = buffer;    // same buffer
488           uint32 nPts2 = 0;
489 
490           if (!lepcc_getPointCount(ctxDec, pByte, nBytesXYZ, &nPts2) && nPts2 > 0)
491           {
492             decPtVec.resize(nPts2);
493             if ((hr = lepcc_decodeXYZ(ctxDec, &pByte, nBytesXYZ, &nPts2, (double*)(&decPtVec[0]))))
494             {
495               printf("Error in main(): lepcc_decodeXYZ(...) failed.\n");  return 0;
496             }
497 
498             // compare
499             for (int i = 0; i < (int)nPts2; i++)
500             {
501               int k = orderVec[i];
502               const Point3D* p = &ptVec[k];
503               const Point3D* q = &decPtVec[i];
504 
505               double dx = abs(q->x - p->x);
506               double dy = abs(q->y - p->y);
507               double dz = abs(q->z - p->z);
508 
509               maxDecErrX = max(dx, maxDecErrX);
510               maxDecErrY = max(dy, maxDecErrY);
511               maxDecErrZ = max(dz, maxDecErrZ);
512             }
513           }
514 
515           if (!lepcc_getRGBCount(ctxDec, pByte, nBytesRGB, &nPts2) && nPts2 > 0)
516           {
517             decRgbVec.resize(nPts2);
518             if ((hr = lepcc_decodeRGB(ctxDec, &pByte, nBytesRGB, &nPts2, (Byte*)(&decRgbVec[0]))))
519             {
520               printf("Error in main(): lepcc_decodeRGB(...) failed.\n");  return 0;
521             }
522 
523             // compare
524             bool resortedColors = !orderVec.empty();
525 
526             for (int i = 0; i < (int)nPts2; i++)
527             {
528               int k = resortedColors ? orderVec[i] : i;
529               RGB_t rgbEnc = rgbVec[k];
530               RGB_t rgbDec = decRgbVec[i];
531 
532               double dx = rgbDec.r - rgbEnc.r;
533               double dy = rgbDec.g - rgbEnc.g;
534               double dz = rgbDec.b - rgbEnc.b;
535               double delta = sqrt(dx * dx + dy * dy + dz * dz);
536 
537               maxDecErrRGB = max(delta, maxDecErrRGB);
538               totalDecErrRGB += delta;
539             }
540           }
541 
542           if (!lepcc_getIntensityCount(ctxDec, pByte, nBytesIntensity, &nPts2) && nPts2 > 0)
543           {
544             decIntensityVec.resize(nPts2);
545             if ((hr = lepcc_decodeIntensity(ctxDec, &pByte, nBytesIntensity, &nPts2, &decIntensityVec[0])))
546             {
547               printf("Error in main(): lepcc_decodeIntensity(...) failed.\n");  return 0;
548             }
549 
550             // compare
551             bool resortedColors = !orderVec.empty();
552 
553             for (int i = 0; i < (int)nPts2; i++)
554             {
555               int k = resortedColors ? orderVec[i] : i;
556               uint16 intensEnc = intensityVec[k];
557               uint16 intensDec = decIntensityVec[i];
558               double delta = abs(intensDec - intensEnc);
559               maxDecErrIntensity = max(delta, maxDecErrIntensity);
560               totalDecErrIntensity += delta;
561             }
562           }
563         }    // if (mode == 3)
564       }    // if (mode > 0)
565     }    // while (!done)
566   }    // if (mode <= 1)
567 
568   else if (mode == 2)    // decode
569   {
570     bool done = false;
571     while (!done)
572     {
573       // get info from blob header, for XYZ blob
574       int nBytes = 0;
575       int nPts = 0;
576 
577       if (origHasXYZ)
578       {
579         nBytes = ReadBlobSize(ctxDec, fp);
580 
581         if (nBytes == 0)
582         {
583           done = true;
584           continue;
585         }
586         if (nBytes < 0)
587         {
588           printf("Error in main(): Read in bad num bytes for blob.\n");  return 0;
589         }
590       }
591 
592       if (nBytes > 0)
593       {
594         byteVec.resize((size_t)nBytes);
595         fread(&byteVec[0], 1, (size_t)nBytes, fp);    // read it from file
596 
597         const Byte* pByte = &byteVec[0];
598         uint32 nPts2 = 0;
599         if ((hr = lepcc_getPointCount(ctxDec, pByte, nBytes, &nPts2)) && nPts2 > 0)
600         {
601           printf("Error in main(): lepcc_getPointCount(...) failed.\n");  return 0;
602         }
603 
604         decPtVec.resize(nPts2);
605         if ((hr = lepcc_decodeXYZ(ctxDec, &pByte, nBytes, &nPts2, (double*)(&decPtVec[0]))))
606         {
607           printf("Error in main(): lepcc_decodeXYZ(...) failed.\n");  return 0;
608         }
609 
610         // write out the uncompressed points
611         nPts = nPts2;
612         fwrite(&nPts2, sizeof(int), 1, fpOut);
613         fwrite(&decPtVec[0], sizeof(Point3D), nPts2, fpOut);
614       }
615 
616       // get info from blob header, for RGB blob
617       nBytes = 0;
618 
619       if (decodHasRGB)
620       {
621         nBytes = ReadBlobSize(ctxDec, fp);
622 
623         if (nBytes == 0)
624         {
625           done = true;
626           continue;
627         }
628         if (nBytes < 0)
629         {
630           printf("Error in main(): Read in bad num bytes for blob.\n");  return 0;
631         }
632       }
633 
634       if (nBytes > 0)
635       {
636         byteVec.resize((size_t)nBytes);
637         fread(&byteVec[0], 1, (size_t)nBytes, fp);    // read it from file
638 
639         const Byte* pByte = &byteVec[0];
640         uint32 nPts2 = 0;
641         if ((hr = lepcc_getRGBCount(ctxDec, pByte, nBytes, &nPts2)) && nPts2 > 0)
642         {
643           printf("Error in main(): lepcc_getRGBCount(...) failed.\n");  return 0;
644         }
645 
646         decRgbVec.resize(nPts2);
647         if ((hr = lepcc_decodeRGB(ctxDec, &pByte, nBytes, &nPts2, (Byte*)(&decRgbVec[0]))))
648         {
649           printf("Error in main(): lepcc_decodeRGB(...) failed.\n");  return 0;
650         }
651 
652         // write out the uncompressed colors
653         nPts = nPts2;
654         fwrite(&nPts2, sizeof(int), 1, fpOut);
655         fwrite(&decRgbVec[0], sizeof(RGB_t), nPts2, fpOut);
656       }
657 
658       totalNumTiles++;
659       totalNumPoints += nPts;
660     }
661 
662     int stopSign = 0;
663     fwrite(&stopSign, sizeof(int), 1, fpOut);
664   }
665 
666   lepcc_deleteContext(&ctx);
667 
668   high_resolution_clock::time_point t1 = high_resolution_clock::now();
669   auto duration = duration_cast<milliseconds>(t1 - t0).count();
670 
671   double nBytesPerPt = (double)totalNumBytesCompressed / (double)totalNumPoints;
672 
673   std::cout << "tiles  =  " << totalNumTiles << endl;
674   std::cout << "points =  " << totalNumPoints << endl;
675 
676   if (mode < 2)
677   {
678     std::cout << "points per tile [min, max] =  [ " << minPts << ", " << maxPts << " ]" << endl;
679     std::cout << "total num bytes compressed  =  " << totalNumBytesCompressed << endl;
680     std::cout << "num bytes per point         =  " << nBytesPerPt << endl;
681   }
682   else if (mode == 3)
683   {
684     std::cout << "max decoding error in [x, y, z] = [ " << maxDecErrX << ", " << maxDecErrY << ", " << maxDecErrZ << " ]" << endl;
685     std::cout << "max decoding error in RGB = " << maxDecErrRGB << endl;
686     std::cout << "mean decoding error in RGB = " << totalDecErrRGB / totalNumPoints << endl;
687     std::cout << "max decoding error in intensity = " << maxDecErrIntensity << endl;
688     std::cout << "mean decoding error in intensity = " << totalDecErrIntensity / totalNumPoints << endl;
689   }
690 
691   std::cout << "total time    = " << duration << " ms" << endl;
692   std::cout << "time per tile = " << ((int)((duration / totalNumTiles) * 1000 + 0.5)) * 0.001 << " ms" << endl;
693 
694   fclose(fp);
695 
696   if (fpOut)
697     fclose(fpOut);
698 
699   return 0;
700 }
701 
702 // -------------------------------------------------------------------------- ;
703 
704 // only for this little test program;
705 // a real app should keep track of the order compressed blobs are written to the stream, and their sizes;
706 
ReadBlobSize(lepcc_ContextHdl ctx,FILE * fp)707 int ReadBlobSize(lepcc_ContextHdl ctx, FILE* fp)
708 {
709   Byte buffer[64];
710   int nBytes = 0;
711   int nInfo = lepcc_getBlobInfoSize();
712 
713   if (nInfo == fread(buffer, 1, nInfo, fp))
714   {
715     lepcc_blobType bt;
716     uint32 blobSize = 0;
717     ErrCode errCode = (ErrCode)lepcc_getBlobInfo(ctx, buffer, nInfo, &bt, &blobSize);
718     nBytes = (errCode == ErrCode::Ok) ? (int)blobSize : -1;
719     fseek(fp, -nInfo, SEEK_CUR);  // reset
720   }
721 
722   return nBytes;
723 }
724 
725 // -------------------------------------------------------------------------- ;
726