geometry_trisoup_decoder.cpp 21.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* The copyright in this software is being made available under the BSD
 * 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.
 *
 * Copyright (c) 2017-2018, ISO/IEC
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * 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.
 *
 * 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
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * 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)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <cstdio>

#include "geometry_trisoup.h"

40
#include "pointset_processing.h"
41
42
43
44
45
46
47
#include "geometry.h"
#include "geometry_octree.h"

namespace pcc {

//============================================================================

48
49
50
51
52
53
54
55
// The number of fractional bits used in trisoup triangle voxelisation
const int kTrisoupFpBits = 8;

// The value 1 in fixed-point representation
const int kTrisoupFpOne = 1 << (kTrisoupFpBits);

//============================================================================

56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
bool
operator<(const TrisoupSegment& s1, const TrisoupSegment& s2)
{
  // assert all quantities are at most 21 bits
  uint64_t s1startpos = (uint64_t(s1.startpos[0]) << 42)
    | (uint64_t(s1.startpos[1]) << 21) | s1.startpos[2];

  uint64_t s2startpos = (uint64_t(s2.startpos[0]) << 42)
    | (uint64_t(s2.startpos[1]) << 21) | s2.startpos[2];

  if (s1startpos < s2startpos)
    return true;

  if (s1startpos != s2startpos)
    return false;

  uint64_t s1endpos = (uint64_t(s1.endpos[0]) << 42)
    | (uint64_t(s1.endpos[1]) << 21) | s1.endpos[2];

  uint64_t s2endpos = (uint64_t(s2.endpos[0]) << 42)
    | (uint64_t(s2.endpos[1]) << 21) | s2.endpos[2];

  if (s1endpos < s2endpos)
    return true;

  if (s1endpos == s2endpos)
    if (s1.index < s2.index)  // stable sort
      return true;

  return false;
}

//============================================================================

void
decodeGeometryTrisoup(
  const GeometryParameterSet& gps,
  const GeometryBrickHeader& gbh,
  PCCPointSet3& pointCloud,
95
  EntropyDecoder* arithmeticDecoder)
96
97
{
  // trisoup uses octree coding until reaching the triangulation level.
98
  // todo(df): pass trisoup node size rather than 0?
99
  pcc::ringbuf<PCCOctree3Node> nodes;
100
  decodeGeometryOctree(gps, gbh, 0, pointCloud, arithmeticDecoder, &nodes);
101

102
  int blockWidth = 1 << gps.trisoup_node_size_log2;
103
104

  uint32_t symbolCount;
105
106
  AdaptiveBitModel ctxTemp;
  StaticBitModel ctxBypass;
107
108

  // Decode segind from bitstream.
109
  symbolCount = arithmeticDecoder->decodeExpGolomb(0, ctxBypass, ctxTemp);
110

Satoru KUMA's avatar
Satoru KUMA committed
111
112
113
  //AdaptiveMAryModel multiSymbolSegindModel0(256);
  AdaptiveBitModel ctxTempSeg;
  
114
115
  std::vector<bool> segind;
  for (uint32_t i = 0; i < symbolCount; i++) {
Satoru KUMA's avatar
Satoru KUMA committed
116
117
    bool c = !!(arithmeticDecoder->decode(ctxTempSeg));
    segind.push_back(c);
118
119
120
  }

  // Decode vertices from bitstream.
121
122
  symbolCount = arithmeticDecoder->decodeExpGolomb(0, ctxBypass, ctxTemp);
  AdaptiveMAryModel multiSymbolVerticesModel0(blockWidth);
123
124
125
126
127
128
129
  std::vector<uint8_t> vertices;
  for (uint32_t i = 0; i < symbolCount; i++) {
    const uint8_t c = arithmeticDecoder->decode(multiSymbolVerticesModel0);
    vertices.push_back(c);
  }

  // Compute refinedVertices.
130
  int32_t maxval = (1 << gbh.geomMaxNodeSizeLog2(gps)) - 1;
131
132
133
134
135
  decodeTrisoupCommon(nodes, segind, vertices, pointCloud, blockWidth, maxval);
}

//============================================================================

136
137
138
template<typename T>
Vec3<T>
crossProduct(const Vec3<T> a, const Vec3<T> b)
139
{
140
  Vec3<T> ret;
141
142
143
144
145
146
147
148
  ret[0] = a[1] * b[2] - a[2] * b[1];
  ret[1] = a[2] * b[0] - a[0] * b[2];
  ret[2] = a[0] * b[1] - a[1] * b[0];
  return ret;
}

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

149
150
Vec3<int32_t>
truncate(const Vec3<int64_t> in, const int32_t offset)
151
{
152
153
154
155
156
157
158
159
160
161
162
163
  Vec3<int32_t> out;
  out[0] = (int32_t)in[0] + offset;
  out[1] = (int32_t)in[1] + offset;
  out[2] = (int32_t)in[2] + offset;
  if (out[0] < 0)
    out[0] = 0;
  if (out[1] < 0)
    out[1] = 0;
  if (out[2] < 0)
    out[2] = 0;

  return out;
164
165
}

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//---------------------------------------------------------------------------
// An integer approximation of atan2().
// x, y, and the returned result are fixed-point integers with
// kTrisoupFpBits fractional bits

int32_t
trisoupAtan2(int32_t x, int32_t y)
{
  assert(x != 0 && y != 0);
  if (y == 0) {
    if (x < 0)
      return 804;  // PI * (1<< kTrisoupFpBits)
    else
      return 0;
  } else if (x == 0) {
    if (y > 0)
      return 402;  // (PI/2)   * (1<< kTrisoupFpBits)
    else
      return 1206;  // (PI*3/2) * (1<< kTrisoupFpBits)
  } else {
    int idx = 0;
    int z = abs((y << 8) / x);  //rad is calc in (x>0 && y>0) domain
    if (z <= 256) {             //1<<kTrisoupFpBits
      idx = z / 12;             //0.05<<kTrisoupFpBits
    } else {
191
      idx = z > 40 ? 40 : z;
192
193
    }

194
    static const int kAtanLut[41] = {
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
      0,   12,  25,  38,  50,  62,  74,  86,  97,  108, 118, 128, 138, 147,
      156, 164, 172, 180, 187, 194, 201, 283, 319, 339, 351, 359, 365, 370,
      373, 376, 378, 380, 382, 383, 385, 386, 387, 387, 388, 389, 389};
    int atan = kAtanLut[idx];

    //offset
    if (x < 0 && y > 0)
      atan += 402;  // + PI/2
    else if (x < 0 && y < 0)
      atan += 804;  // + PI
    else if (x > 0 && y < 0)
      atan += 1206;  // + PI*3/2
    return atan;
  }
}

211
212
213
//---------------------------------------------------------------------------

bool
214
boundaryinsidecheck(const Vec3<int32_t> a, const int bbsize)
215
216
217
218
219
220
221
222
223
224
225
226
227
228
{
  if (a[0] < 0 || a[0] > bbsize)
    return false;
  if (a[1] < 0 || a[1] > bbsize)
    return false;
  if (a[2] < 0 || a[2] > bbsize)
    return false;
  return true;
}

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

bool
rayIntersectsTriangle(
229
230
231
232
233
234
  const Vec3<int64_t> rayOrigin,
  const Vec3<int64_t> rayVector,
  const Vec3<int64_t> TriangleVertex0,
  const Vec3<int64_t> TriangleVertex1,
  const Vec3<int64_t> TriangleVertex2,
  Vec3<int64_t>& outIntersectionPoint)
235
{
236
237
238
239
240
241
242
  Vec3<int64_t> edge1 = TriangleVertex1 - TriangleVertex0;
  Vec3<int64_t> edge2 = TriangleVertex2 - TriangleVertex0;
  Vec3<int64_t> s = rayOrigin - TriangleVertex0;
  Vec3<int64_t> h = crossProduct(rayVector, edge2);

  int64_t a = (edge1 * h) >> kTrisoupFpBits;
  if (a == 0)
243
244
    return false;

245
246
  int64_t u = (s * h) / a;
  if (u < 0 || u > kTrisoupFpOne)
247
248
    return false;

249
250
251
  Vec3<int64_t> q = crossProduct(s, edge1);
  int64_t v = (rayVector * q) / a;
  if (v < 0 || (u + v) > kTrisoupFpOne)
252
253
    return false;

254
255
  int64_t t = (edge2 * q) / a;
  if (t > 0) {
256
    // ray intersection
257
258
    Vec3<int64_t> IntersectionPoint = (rayVector * t) >> kTrisoupFpBits;
    outIntersectionPoint = rayOrigin + IntersectionPoint;
259
260
261
262
263
    return true;
  } else {
    // There is a line intersection but not a ray intersection
    return false;
  }
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
}

//---------------------------------------------------------------------------
// Trisoup geometry decoding, at both encoder and decoder.
// Compute from leaves, segment indicators, and vertices
// a set of triangles, refine the triangles, and output their vertices.
//
// @param leaves  list of blocks containing the surface
// @param segind, indicators for edges of blocks if they intersect the surface
// @param vertices, locations of intersections

void
decodeTrisoupCommon(
  const ringbuf<PCCOctree3Node>& leaves,
  const std::vector<bool>& segind,
  const std::vector<uint8_t>& vertices,
  PCCPointSet3& pointCloud,
281
282
  int defaultBlockWidth,
  int poistionClipValue)
283
284
285
286
287
288
289
{
  // Put all leaves' sgements into a list.
  std::vector<TrisoupSegment> segments;
  for (int i = 0; i < leaves.size(); i++) {
    auto leaf = leaves[i];

    // Width of block.
290
291
    // in future, may override with leaf blockWidth
    const int32_t blockWidth = defaultBlockWidth;
292
293

    // Eight corners of block.
294
295
296
297
298
299
300
301
    const Vec3<int32_t> pos000({0, 0, 0});
    const Vec3<int32_t> posW00({blockWidth, 0, 0});
    const Vec3<int32_t> pos0W0({0, blockWidth, 0});
    const Vec3<int32_t> posWW0({blockWidth, blockWidth, 0});
    const Vec3<int32_t> pos00W({0, 0, blockWidth});
    const Vec3<int32_t> posW0W({blockWidth, 0, blockWidth});
    const Vec3<int32_t> pos0WW({0, blockWidth, blockWidth});
    const Vec3<int32_t> posWWW({blockWidth, blockWidth, blockWidth});
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366

    // x: left to right; y: bottom to top; z: far to near
    segments.push_back(  // far bottom edge
      {leaf.pos + pos000, leaf.pos + posW00, 12 * i + 0, -1, -1});
    segments.push_back(  // far left edge
      {leaf.pos + pos000, leaf.pos + pos0W0, 12 * i + 1, -1, -1});
    segments.push_back(  // far top edge
      {leaf.pos + pos0W0, leaf.pos + posWW0, 12 * i + 2, -1, -1});
    segments.push_back(  // far right edge
      {leaf.pos + posW00, leaf.pos + posWW0, 12 * i + 3, -1, -1});
    segments.push_back(  // bottom left edge
      {leaf.pos + pos000, leaf.pos + pos00W, 12 * i + 4, -1, -1});
    segments.push_back(  // top left edge
      {leaf.pos + pos0W0, leaf.pos + pos0WW, 12 * i + 5, -1, -1});
    segments.push_back(  // top right edge
      {leaf.pos + posWW0, leaf.pos + posWWW, 12 * i + 6, -1, -1});
    segments.push_back(  // bottom right edge
      {leaf.pos + posW00, leaf.pos + posW0W, 12 * i + 7, -1, -1});
    segments.push_back(  // near bottom edge
      {leaf.pos + pos00W, leaf.pos + posW0W, 12 * i + 8, -1, -1});
    segments.push_back(  // near left edge
      {leaf.pos + pos00W, leaf.pos + pos0WW, 12 * i + 9, -1, -1});
    segments.push_back(  // near top edge
      {leaf.pos + pos0WW, leaf.pos + posWWW, 12 * i + 10, -1, -1});
    segments.push_back(  // near right edge
      {leaf.pos + posW0W, leaf.pos + posWWW, 12 * i + 11, -1, -1});
  }

  // Copy list of segments to another list to be sorted.
  std::vector<TrisoupSegment> sortedSegments;
  for (int i = 0; i < segments.size(); i++)
    sortedSegments.push_back(segments[i]);

  // Sort the list and find unique segments.
  std::sort(sortedSegments.begin(), sortedSegments.end());
  std::vector<TrisoupSegment> uniqueSegments;
  uniqueSegments.push_back(sortedSegments[0]);
  segments[sortedSegments[0].index].uniqueIndex = 0;
  for (int i = 1; i < sortedSegments.size(); i++) {
    if (
      uniqueSegments.back().startpos != sortedSegments[i].startpos
      || uniqueSegments.back().endpos != sortedSegments[i].endpos) {
      // sortedSegment[i] is different from uniqueSegments.back().
      // Start a new uniqueSegment.
      uniqueSegments.push_back(sortedSegments[i]);
    }
    segments[sortedSegments[i].index].uniqueIndex = uniqueSegments.size() - 1;
  }

  // Get vertex for each unique segment that intersects the surface.
  int vertexCount = 0;
  for (int i = 0; i < uniqueSegments.size(); i++) {
    if (segind[i]) {  // intersects the surface
      uniqueSegments[i].vertex = vertices[vertexCount++];
    } else {  // does not intersect the surface
      uniqueSegments[i].vertex = -1;
    }
  }

  // Copy vertices back to original (non-unique, non-sorted) segments.
  for (int i = 0; i < segments.size(); i++) {
    segments[i].vertex = uniqueSegments[segments[i].uniqueIndex].vertex;
  }

  // Create list of refined vertices, one leaf at a time.
367
  std::vector<Vec3<int32_t>> refinedVertices;
368
369
370
371
372
  for (int i = 0; i < leaves.size(); i++) {
    uint32_t blockWidth = 0;

    // Representation for a vertex in preparation for sorting.
    struct Vertex {
373
374
375
      Vec3<int32_t> pos;  // position of vertex
      int32_t theta;      // angle of vertex when projected along dominant axis
      int32_t tiebreaker;  // coordinate of vertex along dominant axis
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
      bool operator()(Vertex v1, Vertex v2)
      {
        if (v1.theta > v2.theta)
          return true;  // sort in decreasing order of theta
        if (v1.theta == v2.theta && v1.tiebreaker < v2.tiebreaker)
          return true;
        return false;
      }
    } vertex;

    // Find up to 12 vertices for this leaf.
    std::vector<Vertex> leafVertices;
    for (int j = 0; j < 12; j++) {
      TrisoupSegment& segment = segments[i * 12 + j];
      if (segment.vertex < 0)
        continue;  // skip segments that do not intersect the surface

      // Get distance along edge of vertex.
      // Vertex code is the index of the voxel along the edge of the block
      // of surface intersection./ Put decoded vertex at center of voxel,
      // unless voxel is first or last along the edge, in which case put the
      // decoded vertex at the start or endpoint of the segment.
398
      Vec3<int32_t> direction = segment.endpos - segment.startpos;
399
400
      blockWidth =
        std::max(direction[0], std::max(direction[1], direction[2]));
401
      int32_t distance;
402
      if (segment.vertex == 0)
403
        distance = 0;
404
      else if (segment.vertex == blockWidth - 1)
405
        distance = blockWidth << kTrisoupFpBits;
406
      else  // 0 < segment.vertex < blockWidth-1
407
408
        distance = (int32_t)(
          (segment.vertex << kTrisoupFpBits) + (1 << (kTrisoupFpBits - 1)));
409
410

      // Get 3D position of point of intersection.
411
412
413
414
      Vec3<int32_t> point(
        segment.startpos[0] << kTrisoupFpBits,
        segment.startpos[1] << kTrisoupFpBits,
        segment.startpos[2] << kTrisoupFpBits);
415
416
417
418
419
420
421
422
      if (direction[0] > 0)
        point[0] += distance;
      else if (direction[1] > 0)
        point[1] += distance;
      else  // direction[2] > 0
        point[2] += distance;

      // Add vertex to list of points.
423
      leafVertices.push_back({point, 0, 0});
424
425
426
427
428
429
430
    }

    // Skip leaves that have fewer than 3 vertices.
    if (leafVertices.size() < 3)
      continue;

    // Compute mean of leaf vertices.
431
    Vec3<int32_t> blockCentroid = 0;
432
433
434
    for (int j = 0; j < leafVertices.size(); j++) {
      blockCentroid += leafVertices[j].pos;
    }
435
    blockCentroid /= (int32_t)leafVertices.size();
436
437

    // Compute variance of each component of leaf vertices.
438
    Vec3<int32_t> SS = 0;
439
    for (int j = 0; j < leafVertices.size(); j++) {
440
      Vec3<int32_t> S = leafVertices[j].pos - blockCentroid;
441
      SS += times(S, S) >> kTrisoupFpBits;
442
443
444
    }

    // Dominant axis is the coordinate minimizing the variance.
445
446
447
    int32_t minSS = SS[0];
    int32_t dominantAxis = 0;
    for (int32_t j = 1; j < 3; j++) {
448
449
450
451
452
453
454
455
456
457
      if (minSS > SS[j]) {
        minSS = SS[j];
        dominantAxis = j;
      }
    }

    // Project vertices along dominant axis (i.e., into YZ, XZ, or XY plane).
    // Sort projected vertices by decreasing angle in [-pi,+pi] around center
    // of block (i.e., clockwise from 9:00) breaking ties in angle by
    // increasing distance along the dominant axis.
458
459
460
461
    Vec3<int32_t> bc = leaves[i].pos + (blockWidth / 2);
    Vec3<int32_t> blockCenter = {bc[0] << kTrisoupFpBits,
                                 bc[1] << kTrisoupFpBits,
                                 bc[2] << kTrisoupFpBits};
462
    for (int j = 0; j < leafVertices.size(); j++) {
463
      Vec3<int32_t> S = leafVertices[j].pos - blockCenter;
464
465
      switch (dominantAxis) {
      case 0:  // dominant axis is X so project into YZ plane
466
        leafVertices[j].theta = (int32_t)trisoupAtan2(S[2], S[1]);
467
468
469
        leafVertices[j].tiebreaker = S[0];
        break;
      case 1:  // dominant axis is Y so project into XZ plane
470
        leafVertices[j].theta = (int32_t)trisoupAtan2(S[2], S[0]);
471
472
473
        leafVertices[j].tiebreaker = S[1];
        break;
      case 2:  // dominant axis is Z so project into XY plane
474
        leafVertices[j].theta = (int32_t)trisoupAtan2(S[1], S[0]);
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
        leafVertices[j].tiebreaker = S[2];
        break;
      }
    }
    std::sort(leafVertices.begin(), leafVertices.end(), vertex);

    // Table of triangles that make up an n-gon.
    const int polyTriangles[][3] = {
      {0, 1, 2},                                                  // n = 3
      {0, 1, 2},   {2, 3, 0},                                     // n = 4
      {0, 1, 2},   {2, 3, 4}, {4, 0, 2},                          // n = 5
      {0, 1, 2},   {2, 3, 4}, {4, 5, 0},  {0, 2, 4},              // n = 6
      {0, 1, 2},   {2, 3, 4}, {4, 5, 6},  {6, 0, 2},  {2, 4, 6},  // n = 7
      {0, 1, 2},   {2, 3, 4}, {4, 5, 6},  {6, 7, 0},  {0, 2, 4},
      {4, 6, 0},  // n = 8
      {0, 1, 2},   {2, 3, 4}, {4, 5, 6},  {6, 7, 8},  {8, 0, 2},
      {2, 4, 6},   {6, 8, 2},  // n = 9
      {0, 1, 2},   {2, 3, 4}, {4, 5, 6},  {6, 7, 8},  {8, 9, 0},
      {0, 2, 4},   {4, 6, 8}, {8, 0, 4},  // n = 10
      {0, 1, 2},   {2, 3, 4}, {4, 5, 6},  {6, 7, 8},  {8, 9, 10},
      {10, 0, 2},  {2, 4, 6}, {6, 8, 10}, {10, 2, 6},  // n = 11
      {0, 1, 2},   {2, 3, 4}, {4, 5, 6},  {6, 7, 8},  {8, 9, 10},
      {10, 11, 0}, {0, 2, 4}, {4, 6, 8},  {8, 10, 0}, {0, 4, 8}  // n = 12
    };

    // Divide vertices into triangles according to table
    // and upsample each triangle by an upsamplingFactor.
502
    int triCount = (int)leafVertices.size() - 2;
503
504
505
506
507
    int triStart = (triCount - 1) * triCount / 2;
    for (int triIndex = 0; triIndex < triCount; triIndex++) {
      int j0 = polyTriangles[triStart + triIndex][0];
      int j1 = polyTriangles[triStart + triIndex][1];
      int j2 = polyTriangles[triStart + triIndex][2];
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
      Vec3<int64_t> v0 = {(int64_t)leafVertices[j0].pos[0],
                          (int64_t)leafVertices[j0].pos[1],
                          (int64_t)leafVertices[j0].pos[2]};
      Vec3<int64_t> v1 = {(int64_t)leafVertices[j1].pos[0],
                          (int64_t)leafVertices[j1].pos[1],
                          (int64_t)leafVertices[j1].pos[2]};
      Vec3<int64_t> v2 = {(int64_t)leafVertices[j2].pos[0],
                          (int64_t)leafVertices[j2].pos[1],
                          (int64_t)leafVertices[j2].pos[2]};

      for (int k = 0; k < 3; k++) {
        Vec3<int32_t> foundvoxel = truncate(
          (k == 0 ? v0 : (k == 1 ? v1 : v2)), -(1 << (kTrisoupFpBits - 1)));
        if (boundaryinsidecheck(
              foundvoxel >> kTrisoupFpBits, poistionClipValue)) {
          refinedVertices.push_back(foundvoxel >> kTrisoupFpBits);
524
525
526
527
528
529
530
        }
      }

      int g1, g2;
      const int g1pos[3] = {1, 0, 0};
      const int g2pos[3] = {2, 2, 1};
      for (int direction = 0; direction < 3; direction++) {
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
        Vec3<int64_t> rayVector, rayOrigin, intersection;
        const int startposG1 =
          std::min(
            std::min(v0[g1pos[direction]], v1[g1pos[direction]]),
            v2[g1pos[direction]])
          >> kTrisoupFpBits;
        const int startposG2 =
          std::min(
            std::min(v0[g2pos[direction]], v1[g2pos[direction]]),
            v2[g2pos[direction]])
          >> kTrisoupFpBits;
        const int endposG1 =
          std::max(
            std::max(v0[g1pos[direction]], v1[g1pos[direction]]),
            v2[g1pos[direction]])
          >> kTrisoupFpBits;
        const int endposG2 =
          std::max(
            std::max(v0[g2pos[direction]], v1[g2pos[direction]]),
            v2[g2pos[direction]])
          >> kTrisoupFpBits;
552
553
        for (g1 = startposG1; g1 <= endposG1; g1++) {
          for (g2 = startposG2; g2 <= endposG2; g2++) {
554
            std::vector<Vec3<int64_t>> intersectionVertices;
555
            for (int sign = -1; sign <= 1; sign += 2) {
556
              const int rayStart = (sign > 0 ? -1 : poistionClipValue + 1);
557
              if (direction == 0) {
558
559
                rayOrigin = Vec3<int64_t>(rayStart, g1, g2);
                rayVector = Vec3<int64_t>(sign, 0, 0);
560
              } else if (direction == 1) {
561
562
                rayOrigin = Vec3<int64_t>(g1, rayStart, g2);
                rayVector = Vec3<int64_t>(0, sign, 0);
563
              } else if (direction == 2) {
564
565
                rayOrigin = Vec3<int64_t>(g1, g2, rayStart);
                rayVector = Vec3<int64_t>(0, 0, sign);
566
567
              }
              if (rayIntersectsTriangle(
568
569
570
571
572
573
574
                    rayOrigin << kTrisoupFpBits, rayVector << kTrisoupFpBits,
                    v0, v1, v2, intersection)) {
                Vec3<int32_t> foundvoxel =
                  truncate(intersection, -(1 << (kTrisoupFpBits - 1)));
                if (boundaryinsidecheck(
                      foundvoxel >> kTrisoupFpBits, poistionClipValue)) {
                  refinedVertices.push_back(foundvoxel >> kTrisoupFpBits);
575
576
577
578
                }
              }
            }
          }
579
580
581
582
583
        }
      }
    }
  }

584
585
586
587
588
  std::sort(refinedVertices.begin(), refinedVertices.end());
  refinedVertices.erase(
    std::unique(refinedVertices.begin(), refinedVertices.end()),
    refinedVertices.end());

589
590
  // Move list of points to pointCloud.
  pointCloud.resize(refinedVertices.size());
591
  for (int i = 0; i < refinedVertices.size(); i++) {
592
    pointCloud[i] = refinedVertices[i];
593
  }
594
595
596
597
598
}

//============================================================================

}  // namespace pcc