PCCMath.h 12.4 KB
Newer Older
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
1
/* The copyright in this software is being made available under the BSD
David Flynn's avatar
David Flynn committed
2
3
4
 * Licence, included below.  This software may be subject to other third
 * party and contributor rights, including patent rights, and no such
 * rights are granted under this licence.
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
5
 *
David Flynn's avatar
David Flynn committed
6
 * Copyright (c) 2017-2018, ISO/IEC
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
7
8
9
10
11
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
David Flynn's avatar
David Flynn committed
12
13
14
15
16
17
18
19
20
21
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of the ISO/IEC nor the names of its contributors
 *   may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
22
23
24
25
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
David Flynn's avatar
David Flynn committed
26
27
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
28
29
30
31
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
David Flynn's avatar
David Flynn committed
32
33
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
34
35
36
37
38
39
 */

#ifndef PCCMath_h
#define PCCMath_h

#include <assert.h>
David Flynn's avatar
David Flynn committed
40
#include <cstddef>
41
42
#include <iostream>
#include <limits>
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
43
44
45
#include <math.h>
#include <string.h>

46
#include "PCCMisc.h"
47
#include "tables.h"
48

49
50
#include <algorithm>

Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
51
52
namespace pcc {
/// Vector dim 3
53
template<typename T>
54
class Vec3 {
55
public:
56
57
58
59
60
61
  T* begin() { return &data[0]; }
  const T* begin() const { return &data[0]; }

  T* end() { return &data[3]; }
  const T* end() const { return &data[3]; }

62
63
  T& operator[](size_t i)
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
64
65
66
    assert(i < 3);
    return data[i];
  }
67
68
  const T& operator[](size_t i) const
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
69
70
71
72
    assert(i < 3);
    return data[i];
  }
  size_t getElementCount() const { return 3; }
73

74
75
76
77
78
79
  T& x() { return data[0]; }
  T& y() { return data[1]; }
  T& z() { return data[2]; }
  const T& x() const { return data[0]; }
  const T& y() const { return data[1]; }
  const T& z() const { return data[2]; }
80

Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
81
82
  T getNorm() const { return static_cast<T>(sqrt(getNorm2())); }
  T getNorm2() const { return (*this) * (*this); }
83
84
85
86
  T getNormInf() const
  {
    return std::max(data[2], std::max(abs(data[0]), abs(data[1])));
  }
87
  Vec3& operator=(const Vec3& rhs)
88
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
89
90
91
    memcpy(data, rhs.data, sizeof(data));
    return *this;
  }
92
  Vec3& operator+=(const Vec3& rhs)
93
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
94
95
96
97
98
    data[0] += rhs.data[0];
    data[1] += rhs.data[1];
    data[2] += rhs.data[2];
    return *this;
  }
99
  Vec3& operator-=(const Vec3& rhs)
100
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
101
102
103
104
105
    data[0] -= rhs.data[0];
    data[1] -= rhs.data[1];
    data[2] -= rhs.data[2];
    return *this;
  }
106
  Vec3& operator-=(const T a)
107
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
108
109
110
111
112
    data[0] -= a;
    data[1] -= a;
    data[2] -= a;
    return *this;
  }
113
  Vec3& operator+=(const T a)
114
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
115
116
117
118
119
    data[0] += a;
    data[1] += a;
    data[2] += a;
    return *this;
  }
120
  Vec3& operator<<=(int val)
121
  {
122
123
124
125
126
    data[0] <<= val;
    data[1] <<= val;
    data[2] <<= val;
    return *this;
  }
127
  Vec3& operator>>=(int val)
128
129
130
131
132
133
  {
    data[0] >>= val;
    data[1] >>= val;
    data[2] >>= val;
    return *this;
  }
134
  Vec3& operator/=(const T a)
135
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
136
137
138
139
140
141
    assert(a != 0);
    data[0] /= a;
    data[1] /= a;
    data[2] /= a;
    return *this;
  }
142
  Vec3& operator*=(const T a)
143
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
144
145
146
147
148
    data[0] *= a;
    data[1] *= a;
    data[2] *= a;
    return *this;
  }
149
  Vec3& operator=(const T a)
150
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
151
152
153
154
155
    data[0] = a;
    data[1] = a;
    data[2] = a;
    return *this;
  }
156
  Vec3& operator=(const T* const rhs)
157
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
158
159
160
161
162
    data[0] = rhs[0];
    data[1] = rhs[1];
    data[2] = rhs[2];
    return *this;
  }
163
  T operator*(const Vec3& rhs) const
164
165
166
167
  {
    return (
      data[0] * rhs.data[0] + data[1] * rhs.data[1] + data[2] * rhs.data[2]);
  }
168
169
  Vec3 operator-() const { return Vec3<T>(-data[0], -data[1], -data[2]); }
  friend Vec3 operator+(const Vec3& lhs, const Vec3& rhs)
170
  {
171
    return Vec3<T>(
172
173
174
      lhs.data[0] + rhs.data[0], lhs.data[1] + rhs.data[1],
      lhs.data[2] + rhs.data[2]);
  }
175
  friend Vec3 operator+(const T lhs, const Vec3& rhs)
176
  {
177
    return Vec3<T>(lhs + rhs.data[0], lhs + rhs.data[1], lhs + rhs.data[2]);
178
  }
179
  friend Vec3 operator+(const Vec3& lhs, const T rhs)
180
  {
181
    return Vec3<T>(lhs.data[0] + rhs, lhs.data[1] + rhs, lhs.data[2] + rhs);
182
  }
183
  friend Vec3 operator-(const Vec3& lhs, const Vec3& rhs)
184
  {
185
    return Vec3<T>(
186
187
188
      lhs.data[0] - rhs.data[0], lhs.data[1] - rhs.data[1],
      lhs.data[2] - rhs.data[2]);
  }
189
  friend Vec3 operator-(const T lhs, const Vec3& rhs)
190
  {
191
    return Vec3<T>(lhs - rhs.data[0], lhs - rhs.data[1], lhs - rhs.data[2]);
192
  }
193
  friend Vec3 operator-(const Vec3& lhs, const T rhs)
194
  {
195
    return Vec3<T>(lhs.data[0] - rhs, lhs.data[1] - rhs, lhs.data[2] - rhs);
196
  }
197
  friend Vec3 operator*(const T lhs, const Vec3& rhs)
198
  {
199
    return Vec3<T>(lhs * rhs.data[0], lhs * rhs.data[1], lhs * rhs.data[2]);
200
  }
201
  friend Vec3 operator*(const Vec3& lhs, const T rhs)
202
  {
203
    return Vec3<T>(lhs.data[0] * rhs, lhs.data[1] * rhs, lhs.data[2] * rhs);
204
  }
205
  friend Vec3 operator/(const Vec3& lhs, const T rhs)
206
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
207
    assert(rhs != 0);
208
    return Vec3<T>(lhs.data[0] / rhs, lhs.data[1] / rhs, lhs.data[2] / rhs);
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
209
  }
210
  friend Vec3 operator<<(const Vec3& lhs, int val)
211
  {
212
    return Vec3<T>(lhs.data[0] << val, lhs.data[1] << val, lhs.data[2] << val);
213
  }
214
  friend Vec3 operator>>(const Vec3& lhs, int val)
215
  {
216
    return Vec3<T>(lhs.data[0] >> val, lhs.data[1] >> val, lhs.data[2] >> val);
217
  }
218
  bool operator<(const Vec3& rhs) const
219
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
220
221
222
223
224
225
226
227
    if (data[0] == rhs.data[0]) {
      if (data[1] == rhs.data[1]) {
        return (data[2] < rhs.data[2]);
      }
      return (data[1] < rhs.data[1]);
    }
    return (data[0] < rhs.data[0]);
  }
228
  bool operator>(const Vec3& rhs) const
229
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
230
231
232
233
234
235
236
237
    if (data[0] == rhs.data[0]) {
      if (data[1] == rhs.data[1]) {
        return (data[2] > rhs.data[2]);
      }
      return (data[1] > rhs.data[1]);
    }
    return (data[0] > rhs.data[0]);
  }
238
  bool operator==(const Vec3& rhs) const
239
240
241
242
  {
    return (
      data[0] == rhs.data[0] && data[1] == rhs.data[1]
      && data[2] == rhs.data[2]);
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
243
  }
244
  bool operator!=(const Vec3& rhs) const
245
246
247
248
  {
    return (
      data[0] != rhs.data[0] || data[1] != rhs.data[1]
      || data[2] != rhs.data[2]);
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
249
  }
250
  friend std::ostream& operator<<(std::ostream& os, const Vec3& vec)
251
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
252
253
254
    os << vec[0] << " " << vec[1] << " " << vec[2] << std::endl;
    return os;
  }
255
  friend std::istream& operator>>(std::istream& is, Vec3& vec)
256
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
257
258
259
    is >> vec[0] >> vec[1] >> vec[2];
    return is;
  }
260
261
  Vec3(const T a) { data[0] = data[1] = data[2] = a; }
  Vec3(const T x, const T y, const T z)
262
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
263
264
265
266
    data[0] = x;
    data[1] = y;
    data[2] = z;
  }
267
  Vec3(const Vec3& vec)
268
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
269
270
271
272
    data[0] = vec.data[0];
    data[1] = vec.data[1];
    data[2] = vec.data[2];
  }
273
274
  Vec3() = default;
  ~Vec3(void) = default;
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
275

276
private:
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
277
278
279
  T data[3];
};

280
template<typename T>
281
struct Box3 {
282
283
284
  Vec3<T> min;
  Vec3<T> max;
  bool contains(const Vec3<T> point) const
285
286
287
288
  {
    return !(
      point.x() < min.x() || point.x() > max.x() || point.y() < min.y()
      || point.y() > max.y() || point.z() < min.z() || point.z() > max.z());
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
289
290
  }

291
  Box3 merge(const Box3& box)
292
  {
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
293
294
295
296
297
298
299
300
301
    min.x() = std::min(min.x(), box.min.x());
    min.y() = std::min(min.y(), box.min.y());
    min.z() = std::min(min.z(), box.min.z());
    max.x() = std::max(max.x(), box.max.x());
    max.y() = std::max(max.y(), box.max.y());
    max.z() = std::max(max.z(), box.max.z());
    return box;
  }

302
  bool intersects(const Box3& box) const
303
304
305
306
  {
    return max.x() >= box.min.x() && min.x() <= box.max.x()
      && max.y() >= box.min.y() && min.y() <= box.max.y()
      && max.z() >= box.min.z() && min.z() <= box.max.z();
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
307
308
  }

309
  T getDist2(const Vec3<T>& point) const
310
311
312
313
314
315
316
  {
    const T dx = std::max(std::max(min[0] - point[0], 0.0), point[0] - max[0]);
    const T dy = std::max(std::max(min[1] - point[1], 0.0), point[1] - max[1]);
    const T dz = std::max(std::max(min[2] - point[2], 0.0), point[2] - max[2]);
    return dx * dx + dy * dy + dz * dz;
  }

317
  friend std::ostream& operator<<(std::ostream& os, const Box3& box)
318
319
320
  {
    os << box.min[0] << " " << box.min[1] << " " << box.min[2] << " "
       << box.max[0] << " " << box.max[1] << " " << box.max[2] << std::endl;
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
321
322
    return os;
  }
323
  friend std::istream& operator>>(std::istream& is, Box3& box)
324
325
326
  {
    is >> box.min[0] >> box.min[1] >> box.min[2] >> box.max[0] >> box.max[1]
      >> box.max[2];
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
327
328
329
330
    return is;
  }
};

331
332
333
334
335
336
337
338
339
340
//---------------------------------------------------------------------------
// element-wise multiplication of two vectors

template<typename T>
Vec3<T>
times(Vec3<T> lhs, const Vec3<T>& rhs)
{
  return Vec3<T>{lhs[0] * rhs[0], lhs[1] * rhs[1], lhs[2] * rhs[2]};
}

341
342
343
344
//---------------------------------------------------------------------------

typedef DEPRECATED_MSVC Vec3<double> PCCVector3D DEPRECATED;
typedef DEPRECATED_MSVC Vec3<double> PCCPoint3D DEPRECATED;
345
typedef DEPRECATED_MSVC Box3<double> PCCBox3D DEPRECATED;
346
347
348
349
350
351
typedef DEPRECATED_MSVC Vec3<uint8_t> PCCColor3B DEPRECATED;

template<typename T>
using PCCVector3 DEPRECATED = Vec3<T>;

//---------------------------------------------------------------------------
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
352

353
354
355
356
template<typename T>
T
PCCClip(const T& n, const T& lower, const T& upper)
{
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
357
358
  return std::max(lower, std::min(n, upper));
}
359
360
361
362
363
template<typename T>
bool
PCCApproximatelyEqual(
  T a, T b, T epsilon = std::numeric_limits<double>::epsilon())
{
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
364
365
  return fabs(a - b) <= ((fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}
366
367

//---------------------------------------------------------------------------
Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
368

369
inline int64_t
370
371
372
mortonAddr(const int32_t x, const int32_t y, const int32_t z)
{
  assert(x >= 0 && y >= 0 && z >= 0);
373
  int64_t answer = kMortonCode256X[(x >> 16) & 0xFF]
374
375
376
377
378
    | kMortonCode256Y[(y >> 16) & 0xFF] | kMortonCode256Z[(z >> 16) & 0xFF];
  answer = answer << 24 | kMortonCode256X[(x >> 8) & 0xFF]
    | kMortonCode256Y[(y >> 8) & 0xFF] | kMortonCode256Z[(z >> 8) & 0xFF];
  answer = answer << 24 | kMortonCode256X[x & 0xFF] | kMortonCode256Y[y & 0xFF]
    | kMortonCode256Z[z & 0xFF];
379
380
  return answer;
}
381
382

//---------------------------------------------------------------------------
383
// Convert a vector position to morton order address.
384
385

template<typename T>
386
int64_t
387
mortonAddr(const Vec3<T>& vec)
388
{
389
  return mortonAddr(int(vec.x()), int(vec.y()), int(vec.z()));
390
391
}

392
393
//---------------------------------------------------------------------------

394
395
396
397
398
399
inline int64_t
PCCClip(const int64_t& n, const int64_t& lower, const int64_t& upper)
{
  return std::max(lower, std::min(n, upper));
}

400
401
402
403
404
405
406
407
408
409
410
411
412
413
//---------------------------------------------------------------------------
// Integer division of @x by 2^shift, rounding intermediate half values
// to +Inf.

inline int64_t
divExp2RoundHalfUp(int64_t x, int shift)
{
  if (!shift)
    return x;

  int64_t half = 1 << (shift - 1);
  return (x + half) >> shift;
}

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
//---------------------------------------------------------------------------
// Integer division of @scalar by 2^shift, rounding intermediate half values
// away from zero.

inline int64_t
divExp2RoundHalfInf(int64_t scalar, int shift)
{
  if (!shift)
    return scalar;

  int64_t s0 = 1 << (shift - 1);
  return scalar >= 0 ? (s0 + scalar) >> shift : -((s0 - scalar) >> shift);
}

//---------------------------------------------------------------------------
// Integer division of @scalar by 2^shift, rounding intermediate half values
// away from zero.

inline uint64_t
divExp2RoundHalfInf(uint64_t scalar, int shift)
{
  if (!shift)
    return scalar;

  return ((1 << (shift - 1)) + scalar) >> shift;
}

//---------------------------------------------------------------------------
// Component-wise integer division of @vec by 2^shift, rounding intermediate
// half values away from zero.

template<typename T>
inline Vec3<T>
divExp2RoundHalfInf(Vec3<T> vec, int shift)
{
  for (int k = 0; k < 3; ++k)
    vec[k] = divExp2RoundHalfInf(vec[k], shift);

  return vec;
}

//---------------------------------------------------------------------------

457
458
} /* namespace pcc */

Khaled Mammou's avatar
TMC3v0  
Khaled Mammou committed
459
#endif /* PCCMath_h */