Commit 9d11f9fd authored by Khaled Mammou's avatar Khaled Mammou Committed by David Flynn
Browse files

m43591/geometry: look-ahead for neighbour occupancy retrieval

parent 06f95885
......@@ -57,6 +57,7 @@ file(GLOB PROJECT_IN_FILES
file(GLOB PROJECT_INC_FILES
"AttributeDecoder.h"
"AttributeEncoder.h"
"OctreeNeighMap.h"
"PCCKdTree.h"
"PCCMath.h"
"PCCMisc.h"
......@@ -81,6 +82,7 @@ file(GLOB PROJECT_INC_FILES
file(GLOB PROJECT_CPP_FILES
"AttributeDecoder.cpp"
"AttributeEncoder.cpp"
"OctreeNeighMap.cpp"
"RAHT.cpp"
"TMC3.cpp"
"osspecific.cpp"
......
/* 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 "OctreeNeighMap.h"
#include <iostream>
namespace pcc {
//============================================================================
void
updateGeometryOccupancyAtlas(
const PCCVector3<uint32_t>& currentPosition,
const int nodeSizeLog2,
const pcc::ringbuf<PCCOctree3Node>& fifo,
const pcc::ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd,
MortonMap3D* occupancyAtlas,
PCCVector3<uint32_t>* atlasOrigin)
{
const uint32_t mask = (1 << occupancyAtlas->cubeSizeLog2()) - 1;
const int shift = occupancyAtlas->cubeSizeLog2() + nodeSizeLog2;
const auto currentOrigin = currentPosition >> shift;
// only refresh the atlas if the current position lies outside the
// the current atlas.
if (*atlasOrigin == currentOrigin) {
return;
}
*atlasOrigin = currentOrigin;
occupancyAtlas->clearUpdates();
for (auto it = fifo.begin(); it != fifoCurrLvlEnd; ++it) {
if (currentOrigin != it->pos >> shift)
break;
const uint32_t x = (it->pos[0] >> nodeSizeLog2) & mask;
const uint32_t y = (it->pos[1] >> nodeSizeLog2) & mask;
const uint32_t z = (it->pos[2] >> nodeSizeLog2) & mask;
occupancyAtlas->setByte(x, y, z, it->siblingOccupancy);
}
}
//----------------------------------------------------------------------------
uint32_t
makeGeometryNeighPattern(
const PCCVector3<uint32_t>& position,
const int nodeSizeLog2,
const MortonMap3D& occupancyAtlas)
{
const int mask = occupancyAtlas.cubeSize() - 1;
const int cubeSizeMinusOne = mask;
const int32_t x = (position[0] >> nodeSizeLog2) & mask;
const int32_t y = (position[1] >> nodeSizeLog2) & mask;
const int32_t z = (position[2] >> nodeSizeLog2) & mask;
uint32_t neighPattern;
if (
x > 0 && x < cubeSizeMinusOne && y > 0 && y < cubeSizeMinusOne && z > 0
&& z < cubeSizeMinusOne) {
neighPattern = occupancyAtlas.get(x + 1, y, z);
neighPattern |= occupancyAtlas.get(x - 1, y, z) << 1;
neighPattern |= occupancyAtlas.get(x, y - 1, z) << 2;
neighPattern |= occupancyAtlas.get(x, y + 1, z) << 3;
neighPattern |= occupancyAtlas.get(x, y, z - 1) << 4;
neighPattern |= occupancyAtlas.get(x, y, z + 1) << 5;
} else {
neighPattern = occupancyAtlas.getWithCheck(x + 1, y, z);
neighPattern |= occupancyAtlas.getWithCheck(x - 1, y, z) << 1;
neighPattern |= occupancyAtlas.getWithCheck(x, y - 1, z) << 2;
neighPattern |= occupancyAtlas.getWithCheck(x, y + 1, z) << 3;
neighPattern |= occupancyAtlas.getWithCheck(x, y, z - 1) << 4;
neighPattern |= occupancyAtlas.getWithCheck(x, y, z + 1) << 5;
}
return neighPattern;
}
//============================================================================
} // namespace pcc
\ No newline at end of file
/* 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.
*/
#pragma once
#include "PCCMath.h"
#include "PCCTMC3Common.h"
#include "ringbuf.h"
#include "tables.h"
#include <cassert>
#include <memory>
#include <vector>
namespace pcc {
//============================================================================
// Provides a mapping of (x,y,z) co-ordinate to a bit flag.
//
// Internal representation uses a morton code to access an array of flags.
//
// Updates to the array are made byte-wise, allowing 8 flags (in morton order)
// to be stored in a single operation.
class MortonMap3D {
public:
void resize(const uint32_t cubeSizeLog2)
{
assert(cubeSizeLog2 < 10);
const uint32_t halfCubeSizeLog2 = cubeSizeLog2 ? cubeSizeLog2 - 1 : 0;
_cubeSizeLog2 = cubeSizeLog2;
_cubeSize = 1 << cubeSizeLog2;
_bufferSizeInBytes = 1 << (3 * halfCubeSizeLog2);
_buffer.reset(new uint8_t[_bufferSizeInBytes]);
_updates.reserve(1 << 16);
}
int cubeSize() const { return _cubeSize; }
int cubeSizeLog2() const { return _cubeSizeLog2; }
void clear()
{
memset(_buffer.get(), 0, _bufferSizeInBytes);
_updates.resize(0);
}
void clearUpdates()
{
for (const auto byteIndex : _updates) {
_buffer[byteIndex] = uint8_t(0);
}
_updates.resize(0);
}
void setByte(
const int32_t x, const int32_t y, const int32_t z, const uint8_t value)
{
assert(
x >= 0 && y >= 0 && z >= 0 && x < _cubeSize && y < _cubeSize
&& z < _cubeSize);
if (value) {
const uint32_t byteIndex = getByteIndex(x, y, z);
_buffer[byteIndex] = value;
_updates.push_back(byteIndex);
}
}
uint32_t get(const int32_t x, const int32_t y, const int32_t z) const
{
assert(
x >= 0 && y >= 0 && z >= 0 && x < _cubeSize && y < _cubeSize
&& z < _cubeSize);
return (_buffer[getByteIndex(x, y, z)] >> getBitIndex(x, y, z)) & 1;
}
uint32_t
getWithCheck(const int32_t x, const int32_t y, const int32_t z) const
{
if (
x < 0 || x >= _cubeSize || y < 0 || y >= _cubeSize || z < 0
|| z >= _cubeSize) {
return false;
}
return get(x, y, z);
}
private:
int32_t getBitIndex(const int32_t x, const int32_t y, const int32_t z) const
{
return (z & 1) + ((y & 1) << 1) + ((x & 1) << 2);
}
uint32_t
getByteIndex(const int32_t x, const int32_t y, const int32_t z) const
{
return kMortonCode256X[x >> 1] | kMortonCode256Y[y >> 1]
| kMortonCode256Z[z >> 1];
}
int _cubeSize = 0;
int _cubeSizeLog2 = 0;
uint32_t _bufferSizeInBytes = 0;
std::unique_ptr<uint8_t[]> _buffer;
// A list of indexes in _buffer that are dirty
std::vector<uint32_t> _updates;
};
//============================================================================
// determine the occupancy pattern of the six neighbours of the node at
// @position.
uint32_t makeGeometryNeighPattern(
const PCCVector3<uint32_t>& currentPosition,
const int nodeSizeLog2,
const MortonMap3D& occupancyAtlas);
// populate (if necessary) the occupancy atlas with occupancy information
// from @fifo.
void updateGeometryOccupancyAtlas(
const PCCVector3<uint32_t>& position,
const int nodeSizeLog2,
const ringbuf<PCCOctree3Node>& fifo,
const ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd,
MortonMap3D* occupancyAtlas,
PCCVector3<uint32_t>* atlasOrigin);
} // namespace pcc
......@@ -115,6 +115,13 @@ public:
data[2] <<= val;
return *this;
}
PCCVector3& operator>>=(int val)
{
data[0] >>= val;
data[1] >>= val;
data[2] >>= val;
return *this;
}
PCCVector3& operator/=(const T a)
{
assert(a != 0);
......@@ -201,6 +208,16 @@ public:
return PCCVector3<T>(
lhs.data[0] / rhs, lhs.data[1] / rhs, lhs.data[2] / rhs);
}
friend PCCVector3 operator<<(const PCCVector3& lhs, int val)
{
return PCCVector3<T>(
lhs.data[0] << val, lhs.data[1] << val, lhs.data[2] << val);
}
friend PCCVector3 operator>>(const PCCVector3& lhs, int val)
{
return PCCVector3<T>(
lhs.data[0] >> val, lhs.data[1] >> val, lhs.data[2] >> val);
}
bool operator<(const PCCVector3& rhs) const
{
if (data[0] == rhs.data[0]) {
......
......@@ -90,6 +90,9 @@ struct PCCOctree3Node {
// The current node's number of siblings plus one.
// ie, the number of child nodes present in this node's parent.
uint8_t numSiblingsPlus1;
// The occupancy map used describing the current node and its siblings.
uint8_t siblingOccupancy;
};
struct PCCNeighborInfo {
......
......@@ -42,6 +42,7 @@
#include "ringbuf.h"
#include "AttributeDecoder.h"
#include "OctreeNeighMap.h"
#include "PCCMisc.h"
#include "PCCPointSet.h"
#include "PCCTMC3Common.h"
......@@ -185,6 +186,9 @@ private:
PCCReadFromBuffer<uint8_t>(bitstream.buffer, u8value, bitstream.size);
neighbourContextRestriction = bool(u8value);
PCCReadFromBuffer<uint8_t>(bitstream.buffer, u8value, bitstream.size);
neighbourAvailBoundaryLog2 = u8value;
PCCReadFromBuffer<uint8_t>(bitstream.buffer, u8value, bitstream.size);
inferredDirectCodingModeEnabled = bool(u8value);
......@@ -604,6 +608,7 @@ private:
node00.pos = uint32_t(0);
node00.neighPattern = 0;
node00.numSiblingsPlus1 = 8;
node00.siblingOccupancy = 0;
fifo.push_back(node00);
size_t processedPointCount = 0;
......@@ -615,15 +620,32 @@ private:
// ie, the number of nodes added to the next level of the tree
int numNodesNextLvl = 0;
PCCVector3<uint32_t> occupancyAtlasOrigin(0xffffffff);
MortonMap3D occupancyAtlas;
if (neighbourAvailBoundaryLog2) {
occupancyAtlas.resize(neighbourAvailBoundaryLog2);
occupancyAtlas.clear();
}
for (; !fifo.empty(); fifo.pop_front()) {
if (fifo.begin() == fifoCurrLvlEnd) {
// transition to the next level
fifoCurrLvlEnd = fifo.end();
nodeSizeLog2--;
numNodesNextLvl = 0;
occupancyAtlasOrigin = 0xffffffff;
}
PCCOctree3Node& node0 = fifo.front();
if (neighbourAvailBoundaryLog2) {
updateGeometryOccupancyAtlas(
node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas,
&occupancyAtlasOrigin);
node0.neighPattern =
makeGeometryNeighPattern(node0.pos, nodeSizeLog2, occupancyAtlas);
}
// decode occupancy pattern
uint8_t occupancy = decodeGeometryOccupancy(
&arithmeticDecoder, ctxSingleChild, ctxEquiProb, ctxOccupancy, node0);
......@@ -678,6 +700,7 @@ private:
child.pos[1] = node0.pos[1] + (y << childSizeLog2);
child.pos[2] = node0.pos[2] + (z << childSizeLog2);
child.numSiblingsPlus1 = numOccupied;
child.siblingOccupancy = occupancy;
bool idcmEnabled = inferredDirectCodingModeEnabled;
if (isDirectModeEligible(idcmEnabled, nodeSizeLog2, node0, child)) {
......@@ -699,9 +722,11 @@ private:
numNodesNextLvl++;
updateGeometryNeighState(
neighbourContextRestriction, fifo.end(), numNodesNextLvl,
childSizeLog2, child, i, node0.neighPattern, occupancy);
if (!neighbourAvailBoundaryLog2) {
updateGeometryNeighState(
neighbourContextRestriction, fifo.end(), numNodesNextLvl,
childSizeLog2, child, i, node0.neighPattern, occupancy);
}
}
}
......@@ -745,6 +770,11 @@ private:
// occupancy during geometry coding.
bool neighbourContextRestriction;
// Defines the size of the neighbour availiability volume (aka
// look-ahead cube size) for occupancy searches. A value of 0
// indicates that the feature is disabled.
int neighbourAvailBoundaryLog2;
// Controls the use of early termination of the geometry tree
// by directly coding the position of isolated points.
bool inferredDirectCodingModeEnabled;
......
......@@ -46,6 +46,7 @@
#include "ringbuf.h"
#include "AttributeEncoder.h"
#include "OctreeNeighMap.h"
#include "PCCMisc.h"
#include "PCCPointSet.h"
#include "PCCPointSetProcessing.h"
......@@ -67,6 +68,11 @@ struct PCCTMC3Encoder3Parameters {
// are direct siblings are available.
bool neighbourContextRestriction;
// Defines the size of the neighbour availiability volume (aka
// look-ahead cube size) for occupancy searches. A value of 0
// indicates that the feature is disabled.
int neighbourAvailBoundaryLog2;
// Controls the use of early termination of the geometry tree
// by directly coding the position of isolated points.
bool inferredDirectCodingModeEnabled;
......@@ -589,6 +595,7 @@ private:
node00.pos = uint32_t(0);
node00.neighPattern = 0;
node00.numSiblingsPlus1 = 8;
node00.siblingOccupancy = 0;
fifo.push_back(node00);
// map of pointCloud idx to DM idx, used to reorder the points
......@@ -605,11 +612,19 @@ private:
// ie, the number of nodes added to the next level of the tree
int numNodesNextLvl = 0;
MortonMap3D occupancyAtlas;
if (params.neighbourAvailBoundaryLog2) {
occupancyAtlas.resize(params.neighbourAvailBoundaryLog2);
occupancyAtlas.clear();
}
PCCVector3<uint32_t> occupancyAtlasOrigin(0xffffffff);
for (; !fifo.empty(); fifo.pop_front()) {
if (fifo.begin() == fifoCurrLvlEnd) {
// transition to the next level
fifoCurrLvlEnd = fifo.end();
numNodesNextLvl = 0;
occupancyAtlasOrigin = 0xffffffff;
nodeSizeLog2--;
}
......@@ -641,6 +656,15 @@ private:
}
}
if (params.neighbourAvailBoundaryLog2) {
updateGeometryOccupancyAtlas(
node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas,
&occupancyAtlasOrigin);
node0.neighPattern =
makeGeometryNeighPattern(node0.pos, nodeSizeLog2, occupancyAtlas);
}
// encode child occupancy map
assert(occupancy > 0);
encodeGeometryOccupancy(
......@@ -699,6 +723,7 @@ private:
childPointsStartIdx += childCounts[i];
child.end = childPointsStartIdx;
child.numSiblingsPlus1 = numSiblings;
child.siblingOccupancy = occupancy;
bool idcmEnabled = params.inferredDirectCodingModeEnabled;
if (isDirectModeEligible(idcmEnabled, nodeSizeLog2, node0, child)) {
......@@ -723,9 +748,13 @@ private:
numNodesNextLvl++;
updateGeometryNeighState(
params.neighbourContextRestriction, fifo.end(), numNodesNextLvl,
childSizeLog2, child, i, node0.neighPattern, occupancy);
// NB: when neighbourAvailBoundaryLog2 is set, an alternative
// implementation is used to calculate neighPattern.
if (!params.neighbourAvailBoundaryLog2) {
updateGeometryNeighState(
params.neighbourContextRestriction, fifo.end(), numNodesNextLvl,
childSizeLog2, child, i, node0.neighPattern, occupancy);
}
}
}
......@@ -779,6 +808,10 @@ private:
uint8_t(params.neighbourContextRestriction), bitstream.buffer,
bitstream.size);
PCCWriteToBuffer<uint8_t>(
uint8_t(params.neighbourAvailBoundaryLog2), bitstream.buffer,
bitstream.size);
PCCWriteToBuffer<uint8_t>(
uint8_t(params.inferredDirectCodingModeEnabled), bitstream.buffer,
bitstream.size);
......
......@@ -248,6 +248,11 @@ ParseParameters(int argc, char* argv[], Parameters& params)
params.encodeParameters.neighbourContextRestriction, false,
"Limit geometry octree occupancy contextualisation to sibling nodes")
("neighbourAvailBoundaryLog2",
params.encodeParameters.neighbourAvailBoundaryLog2, 0,
"Defines the avaliability volume for neighbour occupancy lookups."
" 0: unconstrained")
("inferredDirectCodingMode",
params.encodeParameters.inferredDirectCodingModeEnabled, true,
"Permits early termination of the geometry octree for isolated points")
......
......@@ -337,3 +337,140 @@ const uint8_t pcc::kOccMapBit7CtxIdx[128 * 4] = {
71, 74, 88, 106, 101, 63, 60, 107, 101, 68, 80, 108, 100, 77, 60,
105, 102, 109, 77, 109, 109, 110, 91, 111, 91, 112, 63, 113, 106, 94,
91, 114};
//============================================================================
const uint32_t pcc::kMortonCode256X[256] = {
0x00000000, 0x00000001, 0x00000008, 0x00000009, 0x00000040, 0x00000041,
0x00000048, 0x00000049, 0x00000200, 0x00000201, 0x00000208, 0x00000209,
0x00000240, 0x00000241, 0x00000248, 0x00000249, 0x00001000, 0x00001001,
0x00001008, 0x00001009, 0x00001040, 0x00001041, 0x00001048, 0x00001049,
0x00001200, 0x00001201, 0x00001208, 0x00001209, 0x00001240, 0x00001241,
0x00001248, 0x00001249, 0x00008000, 0x00008001, 0x00008008, 0x00008009,
0x00008040, 0x00008041, 0x00008048, 0x00008049, 0x00008200, 0x00008201,
0x00008208, 0x00008209, 0x00008240, 0x00008241, 0x00008248, 0x00008249,
0x00009000, 0x00009001, 0x00009008, 0x00009009, 0x00009040, 0x00009041,
0x00009048, 0x00009049, 0x00009200, 0x00009201, 0x00009208, 0x00009209,
0x00009240, 0x00009241, 0x00009248, 0x00009249, 0x00040000, 0x00040001,
0x00040008, 0x00040009, 0x00040040, 0x00040041, 0x00040048, 0x00040049,
0x00040200, 0x00040201, 0x00040208, 0x00040209, 0x00040240, 0x00040241,
0x00040248, 0x00040249, 0x00041000, 0x00041001, 0x00041008, 0x00041009,
0x00041040, 0x00041041, 0x00041048, 0x00041049, 0x00041200, 0x00041201,
0x00041208, 0x00041209, 0x00041240, 0x00041241, 0x00041248, 0x00041249,
0x00048000, 0x00048001, 0x00048008, 0x00048009, 0x00048040, 0x00048041,
0x00048048, 0x00048049, 0x00048200, 0x00048201, 0x00048208, 0x00048209,
0x00048240, 0x00048241, 0x00048248, 0x00048249, 0x00049000, 0x00049001,
0x00049008, 0x00049009, 0x00049040, 0x00049041, 0x00049048, 0x00049049,
0x00049200, 0x00049201, 0x00049208, 0x00049209, 0x00049240, 0x00049241,
0x00049248, 0x00049249, 0x00200000, 0x00200001, 0x00200008, 0x00200009,
0x00200040, 0x00200041, 0x00200048, 0x00200049, 0x00200200, 0x00200201,
0x00200208, 0x00200209, 0x00200240, 0x00200241, 0x00200248, 0x00200249,
0x00201000, 0x00201001, 0x00201008, 0x00201009, 0x00201040, 0x00201041,
0x00201048, 0x00201049, 0x00201200, 0x00201201, 0x00201208, 0x00201209,
0x00201240, 0x00201241, 0x00201248, 0x00201249, 0x00208000, 0x00208001,
0x00208008, 0x00208009, 0x00208040, 0x00208041, 0x00208048, 0x00208049,
0x00208200, 0x00208201, 0x00208208, 0x00208209, 0x00208240, 0x00208241,
0x00208248, 0x00208249, 0x00209000, 0x00209001, 0x00209008, 0x00209009,
0x00209040, 0x00209041, 0x00209048, 0x00209049, 0x00209200, 0x00209201,
0x00209208, 0x00209209, 0x00209240, 0x00209241, 0x00209248, 0x00209249,
0x00240000, 0x00240001, 0x00240008, 0x00240009, 0x00240040, 0x00240041,
0x00240048, 0x00240049, 0x00240200, 0x00240201, 0x00240208, 0x00240209,
0x00240240, 0x00240241, 0x00240248, 0x00240249, 0x00241000, 0x00241001,
0x00241008, 0x00241009, 0x00241040, 0x00241041, 0x00241048, 0x00241049,
0x00241200, 0x00241201, 0x00241208, 0x00241209, 0x00241240, 0x00241241,
0x00241248, 0x00241249, 0x00248000, 0x00248001, 0x00248008, 0x00248009,
0x00248040, 0x00248041, 0x00248048, 0x00248049, 0x00248200, 0x00248201,
0x00248208, 0x00248209, 0x00248240, 0x00248241, 0x00248248, 0x00248249,
0x00249000, 0x00249001, 0x00249008, 0x00249009, 0x00249040, 0x00249041,
0x00249048, 0x00249049, 0x00249200, 0x00249201, 0x00249208, 0x00249209,
0x00249240, 0x00249241, 0x00249248, 0x00249249};
const uint32_t pcc::kMortonCode256Y[256] = {
0x00000000, 0x00000002, 0x00000010, 0x00000012, 0x00000080, 0x00000082,
0x00000090, 0x00000092, 0x00000400, 0x00000402, 0x00000410, 0x00000412,
0x00000480, 0x00000482, 0x00000490, 0x00000492, 0x00002000, 0x00002002,
0x00002010, 0x00002012, 0x00002080, 0x00002082, 0x00002090, 0x00002092,
0x00002400, 0x00002402, 0x00002410, 0x00002412, 0x00002480, 0x00002482,
0x00002490, 0x00002492, 0x00010000, 0x00010002, 0x00010010, 0x00010012,
0x00010080, 0x00010082, 0x00010090, 0x00010092, 0x00010400, 0x00010402,
0x00010410, 0x00010412, 0x00010480, 0x00010482, 0x00010490, 0x00010492,
0x00012000, 0x00012002, 0x00012010, 0x00012012, 0x00012080, 0x00012082,
0x00012090, 0x00012092, 0x00012400, 0x00012402, 0x00012410, 0x00012412,
0x00012480, 0x00012482, 0x00012490, 0x00012492, 0x00080000, 0x00080002,
0x00080010, 0x00080012, 0x00080080, 0x00080082, 0x00080090, 0x00080092,
0x00080400, 0x00080402, 0x00080410, 0x00080412, 0x00080480, 0x00080482,
0x00080490, 0x00080492, 0x00082000, 0x00082002, 0x00082010, 0x00082012,
0x00082080, 0x00082082, 0x00082090, 0x00082092, 0x00082400, 0x00082402,
0x00082410, 0x00082412, 0x00082480, 0x00082482, 0x00082490, 0x00082492,
0x00090000, 0x00090002, 0x00090010, 0x00090012, 0x00090080, 0x00090082,
0x00090090, 0x00090092, 0x00090400, 0x00090402, 0x00090410, 0x00090412,
0x00090480, 0x00090482, 0x00090490, 0x00090492, 0x00092000, 0x00092002,