338 lines · 11.5 KB · C++
RawDownload
////  OctalCode.cpp//  libraries/shared/src////  Created by Stephen Birarda on 3/15/13.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "OctalCode.h" #include <algorithm> // std:min#include <cassert>#include <cmath>#include <cstring> #include <QtCore/QDebug> #include "NumericalConstants.h"#include "SharedUtil.h" int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes) {    if (maxBytes == OVERFLOWED_OCTCODE_BUFFER) {        return OVERFLOWED_OCTCODE_BUFFER;    }     assert(octalCode);    if (*octalCode == 255) {        int newMaxBytes = (maxBytes == UNKNOWN_OCTCODE_LENGTH) ? UNKNOWN_OCTCODE_LENGTH : maxBytes - 1;        return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1, newMaxBytes);    } else {        return *octalCode;    }} void printOctalCode(const unsigned char* octalCode) {    if (!octalCode) {        qDebug("NULL");    } else {        QDebug continuedDebug = qDebug().nospace();        for (size_t i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) {            outputBits(octalCode[i], &continuedDebug);        }    }} char sectionValue(const unsigned char* startByte, char startIndexInByte) {    int8_t rightShift = 8 - startIndexInByte - 3;     if (rightShift < 0) {        return ((startByte[0] << -rightShift) & 7) + (startByte[1] >> (8 + rightShift));    } else {        return (startByte[0] >> rightShift) & 7;    }} size_t bytesRequiredForCodeLength(unsigned char threeBitCodes) {    if (threeBitCodes == 0) {        return 1;    } else {        return 1 + ceilf((threeBitCodes * 3) / 8.0f);    }} int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) {    int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode);     int branchStartBit = parentSections * 3;    // Note: this does not appear to be "multi-byte length code" safe. When octal codes are larger than 255 bytes    // long, the length code is stored in two bytes. The "1" below appears to assume that the length is always one    // byte long.    return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8);} unsigned char* childOctalCode(const unsigned char* parentOctalCode, int childNumber) {     // find the length (in number of three bit code sequences)    // in the parent    int parentCodeSections = parentOctalCode        ? numberOfThreeBitSectionsInCode(parentOctalCode)        : 0;     // get the number of bytes used by the parent octal code    size_t parentCodeBytes = bytesRequiredForCodeLength(parentCodeSections);     // child code will have one more section than the parent    size_t childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1);     // create a new buffer to hold the new octal code    unsigned char* newCode = new unsigned char[childCodeBytes];     // copy the parent code to the child    if (parentOctalCode) {        memcpy(newCode, parentOctalCode, parentCodeBytes);    }     // the child octal code has one more set of three bits    *newCode = parentCodeSections + 1;     if (childCodeBytes > parentCodeBytes) {        // we have a new byte due to the addition of the child code        // so set it to zero for correct results when shifting later        newCode[childCodeBytes - 1] = 0;    }     // add the child code bits to newCode     // find the start bit index    int startBit = parentCodeSections * 3;     // calculate the amount of left shift required    // this will be -1 or -2 if there's wrap    int8_t leftShift = 8 - (startBit % 8) - 3;     if (leftShift < 0) {        // we have a wrap-around to accomodate        // right shift for the end of first byte        // left shift for beginning of the second        newCode[(startBit / 8) + 1] += childNumber >> (-1 * leftShift);        newCode[(startBit / 8) + 2] += childNumber << (8 + leftShift);    } else {        // no wraparound, left shift and add        newCode[(startBit / 8) + 1] += (childNumber << leftShift);    }     return newCode;} void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxelPositionSize) {    float output[3];    memset(&output[0], 0, 3 * sizeof(float));    float currentScale = 1.0f;     if (octalCode) {        for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) {            currentScale *= 0.5f;            int sectionIndex = sectionValue(octalCode + 1 + (BITS_IN_OCTAL * i / BITS_IN_BYTE),                                            (BITS_IN_OCTAL * i) % BITS_IN_BYTE);             for (int j = 0; j < BITS_IN_OCTAL; j++) {                output[j] += currentScale * (float)oneAtBit(sectionIndex, (BITS_IN_BYTE - BITS_IN_OCTAL) + j);            }        }    }    voxelPositionSize.x = output[0];    voxelPositionSize.y = output[1];    voxelPositionSize.z = output[2];    voxelPositionSize.s = currentScale;} void copyFirstVertexForCode(const unsigned char* octalCode, float* output) {    memset(output, 0, 3 * sizeof(float));     float currentScale = 0.5f;     for (int i = 0; i < numberOfThreeBitSectionsInCode(octalCode); i++) {        int sectionIndex = sectionValue(octalCode + 1 + (3 * i / 8), (3 * i) % 8);         for (int j = 0; j < 3; j++) {            output[j] += currentScale * (int)oneAtBit(sectionIndex, 5 + j);        }         currentScale *= 0.5f;    }} OctalCodeComparison compareOctalCodes(const unsigned char* codeA, const unsigned char* codeB) {    if (!codeA || !codeB) {        return ILLEGAL_CODE;    }     OctalCodeComparison result = LESS_THAN; // assume it's shallower     size_t numberOfBytes = std::min(bytesRequiredForCodeLength(*codeA), bytesRequiredForCodeLength(*codeB));    int compare = memcmp(codeA, codeB, numberOfBytes);     if (compare < 0) {        result = LESS_THAN;    } else if (compare > 0) {        result = GREATER_THAN;    } else {        int codeLengthA = numberOfThreeBitSectionsInCode(codeA);        int codeLengthB = numberOfThreeBitSectionsInCode(codeB);         if (codeLengthA == codeLengthB) {            // if the memcmp matched exactly, and they were the same length,            // then these must be the same code!            result = EXACT_MATCH;        } else {            // if the memcmp matched exactly, but they aren't the same length,            // then they have a matching common parent, but they aren't the same            if (codeLengthA < codeLengthB) {                result = LESS_THAN;            } else {                result = GREATER_THAN;            }        }    }    return result;}  char getOctalCodeSectionValue(const unsigned char* octalCode, int section) {    int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE);    char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE;    const unsigned char* startByte = octalCode + startAtByte;     return sectionValue(startByte, startIndexInByte);} void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectionValue) {    int byteForSection = (BITS_IN_OCTAL * section / BITS_IN_BYTE);    unsigned char* byteAt = octalCode + 1 + byteForSection;    char bitInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE;    int8_t shiftBy = BITS_IN_BYTE - bitInByte - BITS_IN_OCTAL;    const unsigned char UNSHIFTED_MASK = 0x07;    unsigned char shiftedMask;    unsigned char shiftedValue;    if (shiftBy >=0) {        shiftedMask  = UNSHIFTED_MASK << shiftBy;        shiftedValue = sectionValue << shiftBy;    } else {        shiftedMask  = UNSHIFTED_MASK >> -shiftBy;        shiftedValue = sectionValue >> -shiftBy;    }    unsigned char oldValue = *byteAt & ~shiftedMask;    unsigned char newValue = oldValue | shiftedValue;    *byteAt = newValue;     // If the requested section is partially in the byte, then we    // need to also set the portion of the section value in the next byte    // there's only two cases where this happens, if the bit in byte is    // 6, then it means that 1 extra bit lives in the next byte. If the    // bit in this byte is 7 then 2 extra bits live in the next byte.    const int FIRST_PARTIAL_BIT = 6;    if (bitInByte >= FIRST_PARTIAL_BIT) {        int bitsInFirstByte  = BITS_IN_BYTE  - bitInByte;        int bitsInSecondByte = BITS_IN_OCTAL - bitsInFirstByte;        shiftBy = BITS_IN_BYTE - bitsInSecondByte;         shiftedMask  = UNSHIFTED_MASK << shiftBy;        shiftedValue = sectionValue << shiftBy;         oldValue = byteAt[1] & ~shiftedMask;        newValue = oldValue | shiftedValue;        byteAt[1] = newValue;    }} bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) {    if (!possibleAncestor || !possibleDescendent) {        return false;    }     int ancestorCodeLength = numberOfThreeBitSectionsInCode(possibleAncestor);    if (ancestorCodeLength == 0) {        return true; // this is the root, it's the anscestor of all    }     int descendentCodeLength = numberOfThreeBitSectionsInCode(possibleDescendent);     // if the caller also include a child, then our descendent length is actually one extra!    if (descendentsChild != CHECK_NODE_ONLY) {        descendentCodeLength++;    }     if (ancestorCodeLength > descendentCodeLength) {        return false; // if the descendent is shorter, it can't be a descendent    }     // compare the sections for the ancestor to the descendent    for (int section = 0; section < ancestorCodeLength; section++) {        char sectionValueAncestor = getOctalCodeSectionValue(possibleAncestor, section);        char sectionValueDescendent;        if (ancestorCodeLength <= descendentCodeLength) {            sectionValueDescendent = getOctalCodeSectionValue(possibleDescendent, section);        } else {            assert(descendentsChild != CHECK_NODE_ONLY);            sectionValueDescendent = descendentsChild;        }        if (sectionValueAncestor != sectionValueDescendent) {            return false; // first non-match, means they don't match        }    }     // they all match, so we are an ancestor    return true;} OctalCodePtr createOctalCodePtr(size_t size) {    return OctalCodePtr(new unsigned char[size], std::default_delete<unsigned char[]>());} OctalCodePtr hexStringToOctalCode(const QString& input) {    const int HEX_NUMBER_BASE = 16;    const int HEX_BYTE_SIZE = 2;    int stringIndex = 0;    int byteArrayIndex = 0;     // allocate byte array based on half of string length    auto bytes = createOctalCodePtr(input.length() / HEX_BYTE_SIZE);     // loop through the string - 2 bytes at a time converting    //  it to decimal equivalent and store in byte array    bool ok = false;    while (stringIndex < input.length()) {        uint value = input.mid(stringIndex, HEX_BYTE_SIZE).toUInt(&ok, HEX_NUMBER_BASE);        if (!ok) {            break;        }        bytes.get()[byteArrayIndex] = (unsigned char)value;        stringIndex += HEX_BYTE_SIZE;        byteArrayIndex++;    }     // something went wrong    if (!ok) {        return nullptr;    }    return bytes;} QString octalCodeToHexString(const unsigned char* octalCode) {    const int HEX_NUMBER_BASE = 16;    const int HEX_BYTE_SIZE = 2;    QString output;    if (!octalCode) {        output = "00";    } else {        for (size_t i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) {            output.append(QString("%1").arg(octalCode[i], HEX_BYTE_SIZE, HEX_NUMBER_BASE, QChar('0')).toUpper());        }    }    return output;}