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 #include <algorithm>
25 #include <climits>
26 #include "LEPCC.h"
27 #include "BitStuffer2.h"
28 #include "Common.h"
29 #include "utl_const_array.h"
30
31 using namespace std;
32 using namespace lepcc;
33
34 // -------------------------------------------------------------------------- ;
35
ComputeNumBytesNeededToEncode(uint32 nPts,const Point3D * pts,double maxXErr,double maxYErr,double maxZErr,int64 & nBytes)36 ErrCode LEPCC::ComputeNumBytesNeededToEncode(uint32 nPts, const Point3D* pts,
37 double maxXErr, double maxYErr, double maxZErr, int64& nBytes)
38 {
39 nBytes = -1;
40 m_numBytesNeeded = 0;
41
42 if (!nPts || !pts || maxXErr <= 0 || maxYErr <= 0 || maxZErr <= 0)
43 return ErrCode::WrongParam;
44
45 m_maxError = Point3D(maxXErr, maxYErr, maxZErr);
46
47 m_extent3D = Compute3DExtent(nPts, pts);
48
49 ErrCode errCode;
50 if ((errCode = Quantize(nPts, pts)) != ErrCode::Ok)
51 return errCode;
52
53 if ((errCode = ConvertToDeltaModel()) != ErrCode::Ok)
54 return errCode;
55
56 nBytes = HeaderSize();
57
58 nBytes += ComputeNumBytes_CutInSegments(m_yDeltaVec, m_sectionSize);
59 nBytes += ComputeNumBytes_CutInSegments(m_numPointsPerRowVec, m_sectionSize);
60 nBytes += ComputeNumBytes_CutInSegments(m_xDeltaVec, m_sectionSize);
61 nBytes += ComputeNumBytes_CutInSegments(m_zVec, m_sectionSize);
62
63 m_numBytesNeeded = nBytes;
64
65 return ErrCode::Ok;
66 }
67
68 // -------------------------------------------------------------------------- ;
69
GetOrigPointIndexes(std::vector<uint32> & origPointIndexVec) const70 void LEPCC::GetOrigPointIndexes(std::vector<uint32>& origPointIndexVec) const
71 {
72 size_t nPts = m_cell3DVec.size();
73 origPointIndexVec.resize(nPts);
74
75 for (size_t i = 0; i < nPts; i++)
76 origPointIndexVec[i] = m_cell3DVec[i].origPtIndex;
77 }
78
GetOrigPointIndexes(uint32 * origPointIndexVec,int maxPtCount) const79 bool LEPCC::GetOrigPointIndexes(uint32* origPointIndexVec, int maxPtCount) const
80 {
81 size_t nPts = m_cell3DVec.size();
82 if (maxPtCount < (int)nPts)
83 return false;
84 for (size_t i = 0; i < nPts; i++)
85 origPointIndexVec[i] = m_cell3DVec[i].origPtIndex;
86 return true;
87 }
88
89 // -------------------------------------------------------------------------- ;
90
Encode(Byte ** ppByte,int64 bufferSize) const91 ErrCode LEPCC::Encode(Byte** ppByte, int64 bufferSize) const
92 {
93 if (!ppByte)
94 return ErrCode::WrongParam;
95
96 if (bufferSize <= HeaderSize() || bufferSize < m_numBytesNeeded)
97 return ErrCode::BufferTooSmall;
98
99 Byte* ptr = *ppByte;
100 Byte* ptrStart = ptr; // keep for later
101
102 TopHeader topHd;
103 memcpy(ptr, &topHd, sizeof(topHd));
104 ptr += sizeof(topHd);
105
106 Header1 hd1;
107 hd1.blobSize = 0; // overide later when done
108 hd1.extent3D = m_extent3D;
109 hd1.maxError3D = m_maxError;
110 hd1.numPoints = (uint32)m_zVec.size();
111
112 memcpy(ptr, &hd1, sizeof(hd1));
113 ptr += sizeof(hd1);
114
115 *ppByte = ptr;
116
117 if (!Encode_CutInSegments(ppByte, m_yDeltaVec, m_sectionSize))
118 return ErrCode::Failed;
119 if (!Encode_CutInSegments(ppByte, m_numPointsPerRowVec, m_sectionSize))
120 return ErrCode::Failed;
121 if (!Encode_CutInSegments(ppByte, m_xDeltaVec, m_sectionSize))
122 return ErrCode::Failed;
123 if (!Encode_CutInSegments(ppByte, m_zVec, m_sectionSize))
124 return ErrCode::Failed;
125
126 // add blob size
127 int64 numBytes = (int64)(*ppByte - ptrStart);
128 memcpy(ptrStart + sizeof(topHd), &numBytes, sizeof(numBytes)); // overide with the real num bytes
129
130 // add check sum
131 topHd.checkSum = Common::ComputeChecksumFletcher32(ptrStart + sizeof(topHd), (numBytes - sizeof(topHd)));
132 memcpy(ptrStart, &topHd, sizeof(topHd));
133
134 if (numBytes != m_numBytesNeeded)
135 return ErrCode::Failed;
136
137 return ErrCode::Ok;
138 }
139
140 // -------------------------------------------------------------------------- ;
141
GetBlobSize(const Byte * pByte,int64 bufferSize,uint32 & blobSize)142 ErrCode LEPCC::GetBlobSize(const Byte* pByte, int64 bufferSize, uint32& blobSize)
143 {
144 blobSize = 0;
145
146 if (!pByte)
147 return ErrCode::WrongParam;
148
149 TopHeader refHd;
150 Header1 hd1;
151 if (bufferSize < (int64)(sizeof(refHd) + sizeof(hd1.blobSize)))
152 return ErrCode::BufferTooSmall;
153
154 if (0 != memcmp(pByte, refHd.fileKey, refHd.FileKeyLength())) // file key
155 return ErrCode::NotLepcc;
156
157 // get blob size
158 pByte += sizeof(refHd);
159 int64 nBytes = 0;
160 memcpy(&nBytes, pByte, sizeof(nBytes));
161
162 if (nBytes < bufferSize || nBytes > UINT_MAX)
163 return ErrCode::Failed;
164
165 blobSize = (uint32)nBytes;
166 return ErrCode::Ok;
167 }
168
169 // -------------------------------------------------------------------------- ;
170
GetNumPointsFromHeader(const Byte * pByte,int64 bufferSize,uint32 & nPts)171 ErrCode LEPCC::GetNumPointsFromHeader(const Byte* pByte, int64 bufferSize, uint32& nPts)
172 {
173 nPts = 0;
174
175 TopHeader topHd;
176 Header1 hd1;
177 ErrCode errCode;
178 if ((errCode = ReadHeaders(pByte, bufferSize, topHd, hd1)) != ErrCode::Ok)
179 return errCode;
180
181 nPts = hd1.numPoints;
182 return ErrCode::Ok;
183 }
184
185 // -------------------------------------------------------------------------- ;
186
GetExtent3DFromHeader(const Byte * pByte,int64 bufferSize,Extent3D & ext)187 ErrCode LEPCC::GetExtent3DFromHeader(const Byte* pByte, int64 bufferSize, Extent3D& ext)
188 {
189 ext = Extent3D();
190
191 TopHeader topHd;
192 Header1 hd1;
193 ErrCode errCode;
194 if ((errCode = ReadHeaders(pByte, bufferSize, topHd, hd1)) != ErrCode::Ok)
195 return errCode;
196
197 ext = hd1.extent3D;
198 return ErrCode::Ok;
199 }
200
201 // -------------------------------------------------------------------------- ;
202
Decode(const Byte ** ppByte,int64 bufferSize,uint32 & nPtsInOut,Point3D * pts)203 ErrCode LEPCC::Decode(const Byte** ppByte, int64 bufferSize, uint32& nPtsInOut, Point3D* pts)
204 {
205 if (!ppByte || !*ppByte || !nPtsInOut || !pts)
206 return ErrCode::WrongParam;
207
208 int headerSize = HeaderSize();
209
210 if (bufferSize <= headerSize)
211 return ErrCode::BufferTooSmall;
212
213 const Byte* ptr = *ppByte;
214 const Byte* ptrStart = ptr; // keep for later
215
216 TopHeader topHd;
217 Header1 hd1;
218 ErrCode errCode;
219 if ((errCode = ReadHeaders(ptr, bufferSize, topHd, hd1)) != ErrCode::Ok)
220 return errCode;
221
222 ptr += headerSize;
223
224 if (bufferSize < hd1.blobSize)
225 return ErrCode::BufferTooSmall;
226
227 // test check sum
228 uint32 checkSum = Common::ComputeChecksumFletcher32(ptrStart + sizeof(topHd), hd1.blobSize - sizeof(topHd));
229 if (checkSum != topHd.checkSum)
230 return ErrCode::WrongCheckSum;
231
232 int64 numBytes = hd1.blobSize;
233 m_extent3D = hd1.extent3D;
234 m_maxError = hd1.maxError3D;
235
236 if (hd1.numPoints > nPtsInOut)
237 return ErrCode::OutArrayTooSmall;
238
239 *ppByte = ptr;
240
241 if (!Decode_CutInSegments(ppByte, m_yDeltaVec))
242 return ErrCode::Failed;
243 if (!Decode_CutInSegments(ppByte, m_numPointsPerRowVec))
244 return ErrCode::Failed;
245 if (!Decode_CutInSegments(ppByte, m_xDeltaVec))
246 return ErrCode::Failed;
247 if (!Decode_CutInSegments(ppByte, m_zVec))
248 return ErrCode::Failed;
249
250 Point3D p0 = m_extent3D.lower;
251 Point3D p1 = m_extent3D.upper;
252
253 Point3D cw(2 * m_maxError.x, 2 * m_maxError.y, 2 * m_maxError.z);
254
255 // reconstruct the points
256 int cnt = 0;
257 int iy = 0;
258 int nRows = (int)m_yDeltaVec.size();
259
260 for (int i = 0; i < nRows; i++)
261 {
262 iy += m_yDeltaVec[i];
263 int ix = 0;
264 int nPts = m_numPointsPerRowVec[i];
265
266 for (int j = 0; j < nPts; j++)
267 {
268 ix += m_xDeltaVec[cnt];
269 int iz = m_zVec[cnt];
270
271 double x = p0.x + ix * cw.x;
272 double y = p0.y + iy * cw.y;
273 double z = p0.z + iz * cw.z;
274
275 pts[cnt] = Point3D(min(x, p1.x), min(y, p1.y), min(z, p1.z)); // ensure we don't go outside the orig extent
276 cnt++;
277 }
278 }
279
280 nPtsInOut = hd1.numPoints;
281
282 int64 nBytesRead = (int64)(*ppByte - ptrStart);
283 if (nBytesRead != hd1.blobSize || nBytesRead > bufferSize)
284 return ErrCode::Failed;
285
286 return ErrCode::Ok;
287 }
288
289 // -------------------------------------------------------------------------- ;
290
Clear()291 void LEPCC::Clear()
292 {
293 m_cell3DVec.clear();
294 m_yDeltaVec.clear();
295 m_numPointsPerRowVec.clear();
296 m_xDeltaVec.clear();
297 m_zVec.clear();
298 }
299
300 // -------------------------------------------------------------------------- ;
301 // -------------------------------------------------------------------------- ;
302
HeaderSize()303 int LEPCC::HeaderSize()
304 {
305 return (int)(sizeof(TopHeader) + sizeof(Header1));
306 }
307
308 // -------------------------------------------------------------------------- ;
309
Compute3DExtent(uint32 nPts,const Point3D * pts) const310 Extent3D LEPCC::Compute3DExtent(uint32 nPts, const Point3D* pts) const
311 {
312 if (!nPts || !pts)
313 return Extent3D();
314
315 Extent3D ext;
316 ext.lower = pts[0];
317 ext.upper = ext.lower;
318
319 const_array<Point3D> pointArr(pts, nPts); // safe wrapper
320
321 for (uint32 i = 0; i < nPts; i++)
322 {
323 ext.lower.x = min(ext.lower.x, pointArr[i].x);
324 ext.lower.y = min(ext.lower.y, pointArr[i].y);
325 ext.lower.z = min(ext.lower.z, pointArr[i].z);
326
327 ext.upper.x = max(ext.upper.x, pointArr[i].x);
328 ext.upper.y = max(ext.upper.y, pointArr[i].y);
329 ext.upper.z = max(ext.upper.z, pointArr[i].z);
330 }
331
332 return ext;
333 }
334
335 // -------------------------------------------------------------------------- ;
336
Quantize(uint32 nPts,const Point3D * pts)337 ErrCode LEPCC::Quantize(uint32 nPts, const Point3D* pts)
338 {
339 if (!nPts || !pts)
340 return ErrCode::WrongParam;
341
342 Point3D p0 = m_extent3D.lower;
343 Point3D p1 = m_extent3D.upper;
344
345 Point3D cw(2 * m_maxError.x, 2 * m_maxError.y, 2 * m_maxError.z);
346
347 int64 nx64 = (int64)((p1.x - p0.x) / cw.x + 0.5) + 1;
348 int64 ny64 = (int64)((p1.y - p0.y) / cw.y + 0.5) + 1;
349 int64 nz64 = (int64)((p1.z - p0.z) / cw.z + 0.5) + 1;
350
351 if (nx64 <= 0 || ny64 <= 0 || nz64 <= 0 || nx64 > INT_MAX || ny64 > INT_MAX || nz64 > INT_MAX)
352 return ErrCode::QuantizeVirtualRasterTooBig;
353
354 int nx = (int)nx64;
355 int ny = (int)ny64;
356 int nz = (int)nz64;
357
358 m_cell3DVec.resize(0);
359 m_cell3DVec.reserve(nPts);
360
361 const_array<Point3D> pointArr(pts, nPts); // safe wrapper
362
363 for (uint32 i = 0; i < nPts; i++)
364 {
365 int ix = (int)((pointArr[i].x - p0.x) / cw.x + 0.5); // relative to (x0, y0, z0)
366 int iy = (int)((pointArr[i].y - p0.y) / cw.y + 0.5);
367 int iz = (int)((pointArr[i].z - p0.z) / cw.z + 0.5);
368
369 if (ix >= nx || iy >= ny || iz >= nz)
370 return ErrCode::QuantizeIndexOutOfRange;
371
372 int64 cellIndex = (int64)iy * (int64)nx + (int64)ix;
373 Cell3D cell3D = { ix, iy, iz, (int)i, cellIndex };
374
375 m_cell3DVec.push_back(cell3D);
376 }
377
378 return ErrCode::Ok;
379 }
380
381 // -------------------------------------------------------------------------- ;
382
ConvertToDeltaModel()383 ErrCode LEPCC::ConvertToDeltaModel()
384 {
385 if (m_cell3DVec.empty())
386 return ErrCode::Failed;
387
388 int numPoints = (int)m_cell3DVec.size();
389
390 // sort the points, top to bottom, left to right
391 std::sort(m_cell3DVec.begin(), m_cell3DVec.end(), MyLessThanOp());
392
393 m_yDeltaVec.resize(0);
394 m_numPointsPerRowVec.resize(0);
395
396 uint32 nPtsPerRow = 0;
397 int prevRow = 0;
398 int yCurr = m_cell3DVec[0].y;
399
400 for (int i = 0; i < numPoints; i++)
401 {
402 int iy = m_cell3DVec[i].y;
403
404 if (iy == yCurr)
405 nPtsPerRow++;
406 else
407 {
408 m_yDeltaVec.push_back((uint32)(yCurr - prevRow));
409 m_numPointsPerRowVec.push_back(nPtsPerRow);
410
411 nPtsPerRow = 1;
412 prevRow = yCurr;
413 yCurr = iy;
414 }
415 }
416
417 m_yDeltaVec.push_back((uint32)(yCurr - prevRow));
418 m_numPointsPerRowVec.push_back(nPtsPerRow);
419
420 m_xDeltaVec.resize(0);
421 m_xDeltaVec.reserve(numPoints);
422
423 m_zVec.resize(0);
424 m_zVec.reserve(numPoints);
425
426 int numOccupiedRows = (int)m_yDeltaVec.size();
427 int iy = 0;
428 int cnt = 0;
429
430 for (int i = 0; i < numOccupiedRows; i++)
431 {
432 iy += m_yDeltaVec[i];
433 int prevCol = 0;
434
435 for (int j = 0; j < (int)m_numPointsPerRowVec[i]; j++)
436 {
437 const Cell3D& pt = m_cell3DVec[cnt++];
438 if (pt.y != iy)
439 return ErrCode::Failed;
440
441 int xDelta = pt.x - prevCol; // can be 0 if > 1 point per cell
442 m_xDeltaVec.push_back((uint32)xDelta);
443 prevCol = pt.x;
444
445 m_zVec.push_back((uint32)pt.z);
446 }
447 }
448
449 return ErrCode::Ok;
450 }
451
452 // -------------------------------------------------------------------------- ;
453
ComputeNumBytes_CutInSegments(const vector<uint32> & dataVec,int sectionSize) const454 int LEPCC::ComputeNumBytes_CutInSegments(const vector<uint32>& dataVec, int sectionSize) const
455 {
456 int numSections = (int)((dataVec.size() + (sectionSize - 1)) / sectionSize);
457 int lenLastSection = (int)(dataVec.size() - (numSections - 1) * sectionSize);
458
459 int nBytes = 0;
460 uint32 totalMax = 0;
461
462 vector<uint32> sectionMinVec;
463 sectionMinVec.reserve(numSections);
464
465 BitStuffer2 bitStuffer2;
466
467 for (int i = 0; i < numSections; i++)
468 {
469 int len = (i < numSections - 1) ? sectionSize : lenLastSection;
470
471 const uint32* pData = &dataVec[i * sectionSize];
472 uint32 minElem = pData[0], maxElem = minElem;
473
474 for (int j = 0; j < len; j++)
475 {
476 minElem = min(minElem, pData[j]);
477 maxElem = max(maxElem, pData[j]);
478 }
479
480 sectionMinVec.push_back(minElem);
481 totalMax = max(totalMax, maxElem);
482
483 uint32 range = maxElem - minElem;
484 nBytes += bitStuffer2.ComputeNumBytesNeededSimple((uint32)len, range);
485 }
486
487 uint32 maxOfSectionMins = *max_element(sectionMinVec.begin(), sectionMinVec.end());
488 nBytes += bitStuffer2.ComputeNumBytesNeededSimple((uint32)numSections, maxOfSectionMins);
489
490 //// compare to undivided and take the better
491 //int nBytesUndivided = (int)bitStuffer2.ComputeNumBytesNeededSimple((uint32)dataVec.size(), totalMax);
492 //return 1 + min(nBytes, nBytesUndivided);
493
494 return nBytes;
495 }
496
497 // -------------------------------------------------------------------------- ;
498
Encode_CutInSegments(Byte ** ppByte,const std::vector<uint32> & dataVec,int sectionSize) const499 bool LEPCC::Encode_CutInSegments(Byte** ppByte, const std::vector<uint32>& dataVec, int sectionSize) const
500 {
501 if (!ppByte || dataVec.empty() || sectionSize <= 0)
502 return false;
503
504 int numSections = (int)((dataVec.size() + (sectionSize - 1)) / sectionSize);
505 int lenLastSection = (int)(dataVec.size() - (numSections - 1) * sectionSize);
506
507 // collect all mins, one for each section
508 vector<uint32> sectionMinVec;
509 sectionMinVec.reserve(numSections);
510 vector<uint32>::const_iterator it, it0 = dataVec.begin();
511
512 for (int i = 0; i < numSections; i++)
513 {
514 int len = (i < numSections - 1) ? sectionSize : lenLastSection;
515 it = it0 + i * sectionSize;
516
517 uint32 minElem = *min_element(it, it + len);
518 sectionMinVec.push_back(minElem);
519 }
520
521 // write out these mins bit stuffed
522 BitStuffer2 bitStuffer2;
523 if (!bitStuffer2.EncodeSimple(ppByte, sectionMinVec))
524 return false;
525
526 // now to the sections
527 vector<uint32> zeroBasedDataVec(sectionSize, 0);
528
529 for (int i = 0; i < numSections; i++)
530 {
531 int len = (i < numSections - 1) ? sectionSize : lenLastSection;
532 const uint32* pData = &dataVec[i * sectionSize];
533
534 zeroBasedDataVec.resize(len);
535 uint32 minElem = sectionMinVec[i];
536
537 for (int j = 0; j < len; j++)
538 zeroBasedDataVec[j] = pData[j] - minElem;
539
540 if (!bitStuffer2.EncodeSimple(ppByte, zeroBasedDataVec))
541 return false;
542 }
543
544 return true;
545 }
546
547 // -------------------------------------------------------------------------- ;
548
Decode_CutInSegments(const Byte ** ppByte,std::vector<uint32> & dataVec) const549 bool LEPCC::Decode_CutInSegments(const Byte** ppByte, std::vector<uint32>& dataVec) const
550 {
551 if (!ppByte || !(*ppByte))
552 return false;
553
554 dataVec.resize(0);
555
556 // decode the section mins
557 vector<uint32> sectionMinVec, zeroBasedDataVec;
558 BitStuffer2 bitStuffer2;
559 if (!bitStuffer2.Decode(ppByte, sectionMinVec, 3))
560 return false;
561
562 int numSections = (int)sectionMinVec.size();
563
564 dataVec.reserve(numSections * m_sectionSize);
565
566 for (int i = 0; i < numSections; i++)
567 {
568 if (!bitStuffer2.Decode(ppByte, zeroBasedDataVec, 3))
569 return false;
570
571 int len = (int)zeroBasedDataVec.size();
572 uint32 minElem = sectionMinVec[i];
573
574 for (int j = 0; j < len; j++)
575 dataVec.push_back(zeroBasedDataVec[j] + minElem);
576 }
577
578 return true;
579 }
580
581 // -------------------------------------------------------------------------- ;
582
ReadHeaders(const Byte * pByte,int64 bufferSize,TopHeader & topHd,Header1 & hd1)583 ErrCode LEPCC::ReadHeaders(const Byte* pByte, int64 bufferSize, TopHeader& topHd, Header1& hd1)
584 {
585 if (!pByte)
586 return ErrCode::WrongParam;
587
588 if (bufferSize <= HeaderSize())
589 return ErrCode::BufferTooSmall;
590
591 TopHeader refHd;
592 if (0 != memcmp(pByte, refHd.fileKey, refHd.FileKeyLength())) // file key
593 return ErrCode::NotLepcc;
594
595 memcpy(&topHd, pByte, sizeof(topHd));
596 pByte += sizeof(topHd);
597
598 if (topHd.version > kCurrVersion) // this reader is outdated
599 return ErrCode::WrongVersion;
600
601 memcpy(&hd1, pByte, sizeof(hd1));
602 return ErrCode::Ok;
603 }
604
605 // -------------------------------------------------------------------------- ;
606
607