Files
workinf_Blender_Wasm/blender-5.2.0/intern/dualcon/intern/octree.h
2026-08-12 04:47:48 -04:00

1391 lines
36 KiB
C++

/* SPDX-FileCopyrightText: 2011-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef __OCTREE_H__
#define __OCTREE_H__
#include "GeoCommon.h"
#include "MemoryAllocator.h"
#include "ModelReader.h"
#include "Projections.h"
#include "cubes.h"
#include "dualcon.h"
#include "manifold_table.h"
#include <cassert>
#include <cstdio>
#include <cstring>
/**
* Main class and structures for scan-convertion, sign-generation,
* and surface reconstruction.
*
* @author Tao Ju
*/
/* Global defines */
/* Uncomment to see debug information */
// #define IN_DEBUG_MODE
/* Uncomment to see more output messages during repair */
// #define IN_VERBOSE_MODE
/* Set scan convert params */
#define EDGE_FLOATS 4
union Node;
struct LeafNode;
struct InternalNode {
/* Initialized in Octree::BuildTable */
static int numChildrenTable[256];
static int childrenCountTable[256][8];
static int childrenIndexTable[256][8];
/* Bit N indicates whether child N exists or not */
unsigned char has_child_bitfield;
/* Bit N indicates whether child N is a leaf or not */
unsigned char child_is_leaf_bitfield;
/* Can have up to eight children */
Node *children[0];
/** Test if child is leaf */
int is_child_leaf(int index) const
{
return (child_is_leaf_bitfield >> index) & 1;
}
/** If child index exists */
int has_child(int index) const
{
return (has_child_bitfield >> index) & 1;
}
/** Get the pointer to child index */
Node *get_child(int count)
{
return children[count];
}
const Node *get_child(int count) const
{
return children[count];
}
/** Get total number of children */
int get_num_children() const
{
return numChildrenTable[has_child_bitfield];
}
/** Get the count of children */
int get_child_count(int index) const
{
return childrenCountTable[has_child_bitfield][index];
}
int get_child_index(int count)
{
return childrenIndexTable[has_child_bitfield][count];
}
const int *get_child_counts() const
{
return childrenCountTable[has_child_bitfield];
}
/** Get all children */
void fill_children(Node *children[8], int leaf[8])
{
int count = 0;
for (int i = 0; i < 8; i++) {
leaf[i] = is_child_leaf(i);
if (has_child(i)) {
children[i] = get_child(count);
count++;
}
else {
children[i] = nullptr;
leaf[i] = 0;
}
}
}
/** Sets the child pointer */
void set_child(int count, Node *chd)
{
children[count] = chd;
}
void set_internal_child(int index, int count, InternalNode *chd)
{
set_child(count, (Node *)chd);
has_child_bitfield |= (1 << index);
}
void set_leaf_child(int index, int count, LeafNode *chd)
{
set_child(count, (Node *)chd);
has_child_bitfield |= (1 << index);
child_is_leaf_bitfield |= (1 << index);
}
};
/**
* Bits order
*
* Leaf node:
* Byte 0,1(0-11): edge parity
* Byte 1(4,5,6): mask of primary edges intersections stored
* Byte 1(7): in flood fill mode, whether the cell is in process
* Byte 2(0-8): signs
* Byte 3,4: in coloring mode, the mask for edges
* Byte 5: edge intersections(4 bytes per inter, or 12 bytes if USE_HERMIT)
*/
struct LeafNode /* TODO: remove this attribute once everything is fixed */ {
unsigned short edge_parity : 12;
unsigned short primary_edge_intersections : 3;
/* XXX: maybe actually unused? */
unsigned short in_process : 1;
/* bitfield */
char signs;
int minimizer_index;
unsigned short flood_fill;
float edge_intersections[0];
};
/* Doesn't get directly allocated anywhere, just used for passing
pointers to nodes that could be internal or leaf. */
union Node {
InternalNode internal;
LeafNode leaf;
};
/* Global variables */
extern const int edgemask[3];
extern const int faceMap[6][4];
extern const int cellProcFaceMask[12][3];
extern const int cellProcEdgeMask[6][5];
extern const int faceProcFaceMask[3][4][3];
extern const int edgeProcEdgeMask[3][2][5];
extern const int faceProcEdgeMask[3][4][6];
extern const int processEdgeMask[3][4];
extern const int dirCell[3][4][3];
extern const int dirEdge[3][4];
/**
* Structures for detecting/patching open cycles on the dual surface
*/
struct PathElement {
/* Origin */
int pos[3];
/* link */
PathElement *next;
};
struct PathList {
/* Head */
PathElement *head;
PathElement *tail;
/* Length of the list */
int length;
/* Next list */
PathList *next;
};
/**
* Class for building and processing an octree
*/
class Octree {
public:
/* Public members */
/** Memory allocators */
VirtualMemoryAllocator *alloc[9];
VirtualMemoryAllocator *leafalloc[4];
/** Root node */
Node *root;
/** Model reader */
ModelReader *reader;
/** Marching cubes table */
Cubes *cubes;
/** Length of grid */
int dimen;
int mindimen, minshift;
/** Maximum depth */
int maxDepth;
/** The lower corner of the bounding box and the size */
float origin[3];
float range;
/** Counting information */
int nodeCount;
int nodeSpace;
int nodeCounts[9];
int actualQuads, actualVerts;
PathList *ringList;
int maxTrianglePerCell;
int outType; /* 0 for OFF, 1 for PLY, 2 for VOL */
/* For flood filling */
int use_flood_fill;
float thresh;
int use_manifold;
float hermite_num;
DualConMode mode;
/**
* Construtor
*/
Octree(ModelReader *mr,
DualConAllocOutput alloc_output_func,
DualConAddVert add_vert_func,
DualConAddQuad add_quad_func,
DualConFlags flags,
DualConMode dualcon_mode,
int depth,
float threshold,
float sharpness);
/**
* Destructor
*/
~Octree();
/**
* Scan convert
*/
void scanConvert();
void *getOutputMesh()
{
return output_mesh;
}
private:
/* Helper functions */
/**
* Initialize memory allocators
*/
void initMemory();
/**
* Release memory
*/
void freeMemory();
/**
* Print memory usage
*/
void printMemUsage();
/**
* Methods to set / restore minimum edges
*/
void resetMinimalEdges();
void cellProcParity(Node *node, int leaf, int depth);
void faceProcParity(Node *node[2], const int leaf[2], const int depth[2], int maxdep, int dir);
void edgeProcParity(Node *node[4], const int leaf[4], const int depth[4], int maxdep, int dir);
void processEdgeParity(LeafNode *node[4], const int depths[4], int maxdep, int dir);
/**
* Add triangles to the tree
*/
void addAllTriangles();
void addTriangle(Triangle *trian, int triind);
InternalNode *addTriangle(InternalNode *node, CubeTriangleIsect *p, int height);
/**
* Method to update minimizer in a cell: update edge intersections instead
*/
LeafNode *updateCell(LeafNode *node, CubeTriangleIsect *p);
/* Routines to detect and patch holes */
int numRings;
int totRingLengths;
int maxRingLength;
/**
* Entry routine.
*/
void trace();
/**
* Trace the given node, find patches and fill them in
*/
Node *trace(Node *node, int *st, int len, int depth, PathList *&paths);
/**
* Look for path on the face and add to paths
*/
void findPaths(Node *node[2],
const int leaf[2],
const int depth[2],
int *st[2],
int maxdep,
int dir,
PathList *&paths);
/**
* Combine two list1 and list2 into list1 using connecting paths list3,
* while closed paths are appended to rings
*/
void combinePaths(PathList *&list1, PathList *list2, PathList *paths, PathList *&rings);
/**
* Helper function: combine current paths in list1 and list2 to a single path and append to list3
*/
PathList *combineSinglePath(PathList *&head1,
PathList *pre1,
PathList *&list1,
PathList *&head2,
PathList *pre2,
PathList *&list2);
/**
* Functions to patch rings in a node
*/
Node *patch(Node *node, int st[3], int len, PathList *rings);
Node *patchSplit(Node *node,
int st[3],
int len,
PathList *rings,
int dir,
PathList *&nrings1,
PathList *&nrings2);
Node *patchSplitSingle(Node *node,
int st[3],
int len,
PathElement *head,
int dir,
PathList *&nrings1,
PathList *&nrings2);
Node *connectFace(Node *node, int st[3], int len, int dir, PathElement *f1, PathElement *f2);
Node *locateCell(InternalNode *node,
const int st[3],
int len,
int ori[3],
int dir,
int side,
Node *&rleaf,
int rst[3],
int &rlen);
void compressRing(PathElement *&ring);
void getFacePoint(PathElement *leaf, int dir, int &x, int &y, float &p, float &q);
LeafNode *patchAdjacent(InternalNode *node,
int len,
int st1[3],
LeafNode *leaf1,
int st2[3],
LeafNode *leaf2,
int walkdir,
int inc,
int dir,
int side,
float alpha);
int findPair(PathElement *head, int pos, int dir, PathElement *&pre1, PathElement *&pre2);
int getSide(PathElement *e, int pos, int dir);
int isEqual(PathElement *e1, PathElement *e2);
void preparePrimalEdgesMask(InternalNode *node);
void testFacePoint(PathElement *e1, PathElement *e2);
/**
* Path-related functions
*/
void deletePath(PathList *&head, PathList *pre, PathList *&curr);
void printPath(PathList *path);
void printPath(PathElement *path);
void printElement(PathElement *ele);
void printPaths(PathList *path);
void checkElement(PathElement *ele);
void checkPath(PathElement *path);
/**
* Routines to build signs to create a partitioned volume
*(after patching rings)
*/
void buildSigns();
void buildSigns(unsigned char table[], Node *node, int isLeaf, int sg, int rvalue[8]);
/************************************************************************/
/* To remove disconnected components */
/************************************************************************/
void floodFill();
void clearProcessBits(Node *node, int height);
int floodFill(LeafNode *leaf, const int st[3], int len, int height, int threshold);
int floodFill(Node *node, int st[3], int len, int height, int threshold);
/**
* Write out polygon file
*/
void writeOut();
void countIntersection(Node *node, int height, int &nedge, int &ncell, int &nface);
void generateMinimizer(Node *node, int st[3], int len, int height, int &offset);
void computeMinimizer(const LeafNode *leaf, int st[3], int len, float rvalue[3]) const;
/**
* Traversal functions to generate polygon model
* op: 0 for counting, 1 for writing OBJ, 2 for writing OFF, 3 for writing PLY
*/
void cellProcContour(Node *node, int leaf, int depth);
void faceProcContour(Node *node[2], const int leaf[2], const int depth[2], int maxdep, int dir);
void edgeProcContour(Node *node[4], const int leaf[4], int depth[4], int maxdep, int dir);
void processEdgeWrite(Node *node[4], int depths[4], int maxdep, int dir);
/* output callbacks/data */
DualConAllocOutput alloc_output;
DualConAddVert add_vert;
DualConAddQuad add_quad;
void *output_mesh;
/************ Operators for all nodes ************/
/** Lookup table */
int numEdgeTable[8];
int edgeCountTable[8][3];
/** Build up lookup table */
void buildTable()
{
for (int i = 0; i < 256; i++) {
InternalNode::numChildrenTable[i] = 0;
int count = 0;
for (int j = 0; j < 8; j++) {
InternalNode::numChildrenTable[i] += ((i >> j) & 1);
InternalNode::childrenCountTable[i][j] = count;
InternalNode::childrenIndexTable[i][count] = j;
count += ((i >> j) & 1);
}
}
for (int i = 0; i < 8; i++) {
numEdgeTable[i] = 0;
int count = 0;
for (int j = 0; j < 3; j++) {
numEdgeTable[i] += ((i >> j) & 1);
edgeCountTable[i][j] = count;
count += ((i >> j) & 1);
}
}
}
int getSign(Node *node, int height, int index)
{
if (height == 0) {
return getSign(&node->leaf, index);
}
if (node->internal.has_child(index)) {
return getSign(
node->internal.get_child(node->internal.get_child_count(index)), height - 1, index);
}
return getSign(node->internal.get_child(0), height - 1, 7 - node->internal.get_child_index(0));
}
/************ Operators for leaf nodes ************/
void printInfo(int st[3])
{
printf("INFO AT: %d %d %d\n", st[0] >> minshift, st[1] >> minshift, st[2] >> minshift);
LeafNode *leaf = locateLeafCheck(st);
if (leaf) {
printInfo(leaf);
}
else {
printf("Leaf not exists!\n");
}
}
void printInfo(const LeafNode *leaf)
{
/* Disable overly verbose debugging information. */
#if 0
printf("Edge mask: ");
for (int i = 0; i < 12; i++) {
printf("%d ", getEdgeParity(leaf, i));
}
printf("\n");
printf("Stored edge mask: ");
for (int i = 0; i < 3; i++) {
printf("%d ", getStoredEdgesParity(leaf, i));
}
printf("\n");
#endif
printf("Sign mask: ");
for (int i = 0; i < 8; i++) {
printf("%d ", getSign(leaf, i));
}
printf("\n");
}
/** Retrieve signs */
int getSign(const LeafNode *leaf, int index)
{
return ((leaf->signs >> index) & 1);
}
/** Set sign */
void setSign(LeafNode *leaf, int index)
{
leaf->signs |= (1 << index);
}
void setSign(LeafNode *leaf, int index, int sign)
{
leaf->signs &= (~(1 << index));
leaf->signs |= ((sign & 1) << index);
}
int getSignMask(const LeafNode *leaf) const
{
return leaf->signs;
}
void setInProcessAll(const int st[3], int dir)
{
int nst[3], eind;
for (int i = 0; i < 4; i++) {
nst[0] = st[0] + dirCell[dir][i][0] * mindimen;
nst[1] = st[1] + dirCell[dir][i][1] * mindimen;
nst[2] = st[2] + dirCell[dir][i][2] * mindimen;
eind = dirEdge[dir][i];
LeafNode *cell = locateLeafCheck(nst);
assert(cell);
setInProcess(cell, eind);
}
}
void flipParityAll(const int st[3], int dir)
{
int nst[3], eind;
for (int i = 0; i < 4; i++) {
nst[0] = st[0] + dirCell[dir][i][0] * mindimen;
nst[1] = st[1] + dirCell[dir][i][1] * mindimen;
nst[2] = st[2] + dirCell[dir][i][2] * mindimen;
eind = dirEdge[dir][i];
LeafNode *cell = locateLeaf(nst);
flipEdge(cell, eind);
}
}
void setInProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
leaf->flood_fill |= (1 << eind);
}
void setOutProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
leaf->flood_fill &= ~(1 << eind);
}
int isInProcess(LeafNode *leaf, int eind)
{
assert(eind >= 0 && eind <= 11);
return (leaf->flood_fill >> eind) & 1;
}
/** Generate signs at the corners from the edge parity */
void generateSigns(LeafNode *leaf, const unsigned char table[], int start)
{
leaf->signs = table[leaf->edge_parity];
if ((start ^ leaf->signs) & 1) {
leaf->signs = ~(leaf->signs);
}
}
/** Get edge parity */
int getEdgeParity(const LeafNode *leaf, int index) const
{
assert(index >= 0 && index <= 11);
return (leaf->edge_parity >> index) & 1;
}
/** Get edge parity on a face */
int getFaceParity(LeafNode *leaf, int index)
{
int a = getEdgeParity(leaf, faceMap[index][0]) + getEdgeParity(leaf, faceMap[index][1]) +
getEdgeParity(leaf, faceMap[index][2]) + getEdgeParity(leaf, faceMap[index][3]);
return (a & 1);
}
int getFaceEdgeNum(LeafNode *leaf, int index)
{
int a = getEdgeParity(leaf, faceMap[index][0]) + getEdgeParity(leaf, faceMap[index][1]) +
getEdgeParity(leaf, faceMap[index][2]) + getEdgeParity(leaf, faceMap[index][3]);
return a;
}
/** Set edge parity */
void flipEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity ^= (1 << index);
}
/** Set 1 */
void setEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity |= (1 << index);
}
/** Set 0 */
void resetEdge(LeafNode *leaf, int index)
{
assert(index >= 0 && index <= 11);
leaf->edge_parity &= ~(1 << index);
}
/** Flipping with a new intersection offset */
void createPrimalEdgesMask(LeafNode *leaf)
{
leaf->primary_edge_intersections = getPrimalEdgesMask2(leaf);
}
void setStoredEdgesParity(LeafNode *leaf, int pindex)
{
assert(pindex <= 2 && pindex >= 0);
leaf->primary_edge_intersections |= (1 << pindex);
}
int getStoredEdgesParity(const LeafNode *leaf, int pindex) const
{
assert(pindex <= 2 && pindex >= 0);
return (leaf->primary_edge_intersections >> pindex) & 1;
}
LeafNode *flipEdge(LeafNode *leaf, int index, float alpha)
{
flipEdge(leaf, index);
if ((index & 3) == 0) {
int ind = index / 4;
if (getEdgeParity(leaf, index) && !getStoredEdgesParity(leaf, ind)) {
/* Create a new node */
int num = getNumEdges(leaf) + 1;
setStoredEdgesParity(leaf, ind);
int count = getEdgeCount(leaf, ind);
LeafNode *nleaf = createLeaf(num);
*nleaf = *leaf;
setEdgeOffset(nleaf, alpha, count);
if (num > 1) {
float *pts = leaf->edge_intersections;
float *npts = nleaf->edge_intersections;
for (int i = 0; i < count; i++) {
for (int j = 0; j < EDGE_FLOATS; j++) {
npts[i * EDGE_FLOATS + j] = pts[i * EDGE_FLOATS + j];
}
}
for (int i = count + 1; i < num; i++) {
for (int j = 0; j < EDGE_FLOATS; j++) {
npts[i * EDGE_FLOATS + j] = pts[(i - 1) * EDGE_FLOATS + j];
}
}
}
removeLeaf(num - 1, leaf);
leaf = nleaf;
}
}
return leaf;
}
/** Update parent link */
void updateParent(InternalNode *node, int len, int st[3], LeafNode *leaf)
{
/* First, locate the parent */
int count;
InternalNode *parent = locateParent(node, len, st, count);
/* Update */
parent->set_child(count, (Node *)leaf);
}
void updateParent(InternalNode *node, int len, int st[3])
{
if (len == dimen) {
root = (Node *)node;
return;
}
/* First, locate the parent */
int count;
InternalNode *parent = locateParent(len, st, count);
/* Update */
parent->set_child(count, (Node *)node);
}
/** Find edge intersection on a given edge */
int getEdgeIntersectionByIndex(int st[3], int index, float pt[3], int check) const
{
/* First, locat the leaf */
const LeafNode *leaf;
if (check) {
leaf = locateLeafCheck(st);
}
else {
leaf = locateLeaf(st);
}
if (leaf && getStoredEdgesParity(leaf, index)) {
float off = getEdgeOffset(leaf, getEdgeCount(leaf, index));
pt[0] = (float)st[0];
pt[1] = (float)st[1];
pt[2] = (float)st[2];
pt[index] += off * mindimen;
return 1;
}
return 0;
}
/** Retrieve number of edges intersected */
int getPrimalEdgesMask(const LeafNode *leaf) const
{
return leaf->primary_edge_intersections;
}
int getPrimalEdgesMask2(LeafNode *leaf)
{
return (((leaf->edge_parity & 0x1) >> 0) | ((leaf->edge_parity & 0x10) >> 3) |
((leaf->edge_parity & 0x100) >> 6));
}
/** Get the count for a primary edge */
int getEdgeCount(const LeafNode *leaf, int index) const
{
return edgeCountTable[getPrimalEdgesMask(leaf)][index];
}
int getNumEdges(LeafNode *leaf)
{
return numEdgeTable[getPrimalEdgesMask(leaf)];
}
int getNumEdges2(LeafNode *leaf)
{
return numEdgeTable[getPrimalEdgesMask2(leaf)];
}
/** Set edge intersection */
void setEdgeOffset(LeafNode *leaf, float pt, int count)
{
float *pts = leaf->edge_intersections;
pts[EDGE_FLOATS * count] = pt;
pts[EDGE_FLOATS * count + 1] = 0;
pts[EDGE_FLOATS * count + 2] = 0;
pts[EDGE_FLOATS * count + 3] = 0;
}
/** Set multiple edge intersections */
void setEdgeOffsets(LeafNode *leaf, const float pt[3], int len)
{
float *pts = leaf->edge_intersections;
for (int i = 0; i < len; i++) {
pts[i] = pt[i];
}
}
/** Retrieve edge intersection */
float getEdgeOffset(const LeafNode *leaf, int count) const
{
return leaf->edge_intersections[4 * count];
}
/** Update method */
LeafNode *updateEdgeOffsets(LeafNode *leaf, int oldlen, int newlen, float offs[3])
{
/* First, create a new leaf node */
LeafNode *nleaf = createLeaf(newlen);
*nleaf = *leaf;
/* Next, fill in the offsets */
setEdgeOffsets(nleaf, offs, newlen);
/* Finally, delete the old leaf */
removeLeaf(oldlen, leaf);
return nleaf;
}
/** Set minimizer index */
void setMinimizerIndex(LeafNode *leaf, int index)
{
leaf->minimizer_index = index;
}
/** Get minimizer index */
int getMinimizerIndex(LeafNode *leaf)
{
return leaf->minimizer_index;
}
int getMinimizerIndex(LeafNode *leaf, int eind)
{
int add = manifold_table[getSignMask(leaf)].pairs[eind][0] - 1;
assert(add >= 0);
return leaf->minimizer_index + add;
}
void getMinimizerIndices(LeafNode *leaf, int eind, int inds[2])
{
const int *add = manifold_table[getSignMask(leaf)].pairs[eind];
inds[0] = leaf->minimizer_index + add[0] - 1;
if (add[0] == add[1]) {
inds[1] = -1;
}
else {
inds[1] = leaf->minimizer_index + add[1] - 1;
}
}
/** Set edge intersection */
void setEdgeOffsetNormal(LeafNode *leaf, float pt, float a, float b, float c, int count)
{
float *pts = leaf->edge_intersections;
pts[4 * count] = pt;
pts[4 * count + 1] = a;
pts[4 * count + 2] = b;
pts[4 * count + 3] = c;
}
float getEdgeOffsetNormal(LeafNode *leaf, int count, float &a, float &b, float &c)
{
float *pts = leaf->edge_intersections;
a = pts[4 * count + 1];
b = pts[4 * count + 2];
c = pts[4 * count + 3];
return pts[4 * count];
}
/** Set multiple edge intersections */
void setEdgeOffsetsNormals(
LeafNode *leaf, const float pt[], const float a[], const float b[], const float c[], int len)
{
float *pts = leaf->edge_intersections;
for (int i = 0; i < len; i++) {
if (pt[i] > 1 || pt[i] < 0) {
printf("\noffset: %f\n", pt[i]);
}
pts[i * 4] = pt[i];
pts[i * 4 + 1] = a[i];
pts[i * 4 + 2] = b[i];
pts[i * 4 + 3] = c[i];
}
}
/** Retrieve complete edge intersection */
void getEdgeIntersectionByIndex(
const LeafNode *leaf, int index, const int st[3], int len, float pt[3], float nm[3]) const
{
int count = getEdgeCount(leaf, index);
const float *pts = leaf->edge_intersections;
float off = pts[4 * count];
pt[0] = (float)st[0];
pt[1] = (float)st[1];
pt[2] = (float)st[2];
pt[index] += (off * len);
nm[0] = pts[4 * count + 1];
nm[1] = pts[4 * count + 2];
nm[2] = pts[4 * count + 3];
}
float getEdgeOffsetNormalByIndex(LeafNode *leaf, int index, float nm[3])
{
int count = getEdgeCount(leaf, index);
float *pts = leaf->edge_intersections;
float off = pts[4 * count];
nm[0] = pts[4 * count + 1];
nm[1] = pts[4 * count + 2];
nm[2] = pts[4 * count + 3];
return off;
}
void fillEdgeIntersections(
const LeafNode *leaf, int st[3], int len, float pts[12][3], float norms[12][3]) const
{
int i;
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getEdgeParity(leaf, pmask[i])) {
// getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
int e1 = getEdgeParity(leaf, fmask[i][0]);
int e2 = getEdgeParity(leaf, fmask[i][1]);
if (e1 || e2) {
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
const LeafNode *node = locateLeaf(nst);
if (e1) {
// getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]],
// norms[fmask[i][0]]);
getEdgeIntersectionByIndex(
node, femask[i][0], nst, len, pts[fmask[i][0]], norms[fmask[i][0]]);
}
if (e2) {
// getEdgeIntersectionByIndex(node, femask[i][1], nstt, 1, pts[fmask[i][1]],
// norms[fmask[i][1]]);
getEdgeIntersectionByIndex(
node, femask[i][1], nst, len, pts[fmask[i][1]], norms[fmask[i][1]]);
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
if (getEdgeParity(leaf, emask[i])) {
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
const LeafNode *node = locateLeaf(nst);
// getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]);
getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]);
}
}
}
void fillEdgeIntersections(const LeafNode *leaf,
int st[3],
int len,
float pts[12][3],
float norms[12][3],
int parity[12]) const
{
int i;
for (i = 0; i < 12; i++) {
parity[i] = 0;
}
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getStoredEdgesParity(leaf, i)) {
// getEdgeIntersectionByIndex(leaf, i, stt, 1, pts[pmask[i]], norms[pmask[i]]);
getEdgeIntersectionByIndex(leaf, i, st, len, pts[pmask[i]], norms[pmask[i]]);
parity[pmask[i]] = 1;
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
{
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
const LeafNode *node = locateLeafCheck(nst);
if (node == nullptr) {
continue;
}
int e1 = getStoredEdgesParity(node, femask[i][0]);
int e2 = getStoredEdgesParity(node, femask[i][1]);
if (e1) {
// getEdgeIntersectionByIndex(node, femask[i][0], nstt, 1, pts[fmask[i][0]],
// norms[fmask[i][0]]);
getEdgeIntersectionByIndex(
node, femask[i][0], nst, len, pts[fmask[i][0]], norms[fmask[i][0]]);
parity[fmask[i][0]] = 1;
}
if (e2) {
// getEdgeIntersectionByIndex(node, femask[i][1], nstt, 1, pts[fmask[i][1]],
// norms[fmask[i][1]]);
getEdgeIntersectionByIndex(
node, femask[i][1], nst, len, pts[fmask[i][1]], norms[fmask[i][1]]);
parity[fmask[i][1]] = 1;
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
// if(getEdgeParity(leaf, emask[i]))
{
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
const LeafNode *node = locateLeafCheck(nst);
if (node == nullptr) {
continue;
}
if (getStoredEdgesParity(node, eemask[i])) {
// getEdgeIntersectionByIndex(node, eemask[i], nstt, 1, pts[emask[i]], norms[emask[i]]);
getEdgeIntersectionByIndex(node, eemask[i], nst, len, pts[emask[i]], norms[emask[i]]);
parity[emask[i]] = 1;
}
}
}
}
void fillEdgeOffsetsNormals(
LeafNode *leaf, int st[3], int len, float pts[12], float norms[12][3], int parity[12])
{
int i;
for (i = 0; i < 12; i++) {
parity[i] = 0;
}
// int stt[3] = {0, 0, 0};
// The three primal edges are easy
int pmask[3] = {0, 4, 8};
for (i = 0; i < 3; i++) {
if (getStoredEdgesParity(leaf, i)) {
pts[pmask[i]] = getEdgeOffsetNormalByIndex(leaf, i, norms[pmask[i]]);
parity[pmask[i]] = 1;
}
}
// 3 face adjacent cubes
int fmask[3][2] = {{6, 10}, {2, 9}, {1, 5}};
int femask[3][2] = {{1, 2}, {0, 2}, {0, 1}};
for (i = 0; i < 3; i++) {
{
int nst[3] = {st[0], st[1], st[2]};
nst[i] += len;
// int nstt[3] = {0, 0, 0};
// nstt[i] += 1;
LeafNode *node = locateLeafCheck(nst);
if (node == nullptr) {
continue;
}
int e1 = getStoredEdgesParity(node, femask[i][0]);
int e2 = getStoredEdgesParity(node, femask[i][1]);
if (e1) {
pts[fmask[i][0]] = getEdgeOffsetNormalByIndex(node, femask[i][0], norms[fmask[i][0]]);
parity[fmask[i][0]] = 1;
}
if (e2) {
pts[fmask[i][1]] = getEdgeOffsetNormalByIndex(node, femask[i][1], norms[fmask[i][1]]);
parity[fmask[i][1]] = 1;
}
}
}
// 3 edge adjacent cubes
int emask[3] = {3, 7, 11};
int eemask[3] = {0, 1, 2};
for (i = 0; i < 3; i++) {
// if(getEdgeParity(leaf, emask[i]))
{
int nst[3] = {st[0] + len, st[1] + len, st[2] + len};
nst[i] -= len;
// int nstt[3] = {1, 1, 1};
// nstt[i] -= 1;
LeafNode *node = locateLeafCheck(nst);
if (node == nullptr) {
continue;
}
if (getStoredEdgesParity(node, eemask[i])) {
pts[emask[i]] = getEdgeOffsetNormalByIndex(node, eemask[i], norms[emask[i]]);
parity[emask[i]] = 1;
}
}
}
}
/** Update method */
LeafNode *updateEdgeOffsetsNormals(
LeafNode *leaf, int oldlen, int newlen, float offs[3], float a[3], float b[3], float c[3])
{
/* First, create a new leaf node */
LeafNode *nleaf = createLeaf(newlen);
*nleaf = *leaf;
/* Next, fill in the offsets */
setEdgeOffsetsNormals(nleaf, offs, a, b, c, newlen);
/* Finally, delete the old leaf */
removeLeaf(oldlen, leaf);
return nleaf;
}
/**
* Locate a leaf
* WARNING: assuming this leaf already exists!
*/
LeafNode *locateLeaf(const int st[3])
{
Node *node = root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
const LeafNode *locateLeaf(const int st[3]) const
{
const Node *node = root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
LeafNode *locateLeaf(InternalNode *parent, int len, const int st[3])
{
Node *node = (Node *)parent;
int index;
for (int i = len / 2; i >= mindimen; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) | ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0));
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
LeafNode *locateLeafCheck(const int st[3])
{
Node *node = root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1));
if (!node->internal.has_child(index)) {
return nullptr;
}
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
const LeafNode *locateLeafCheck(const int st[3]) const
{
const Node *node = root;
for (int i = GRID_DIMENSION - 1; i > GRID_DIMENSION - maxDepth - 1; i--) {
int index = (((st[0] >> i) & 1) << 2) | (((st[1] >> i) & 1) << 1) | (((st[2] >> i) & 1));
if (!node->internal.has_child(index)) {
return nullptr;
}
node = node->internal.get_child(node->internal.get_child_count(index));
}
return &node->leaf;
}
InternalNode *locateParent(int len, const int st[3], int &count)
{
InternalNode *node = (InternalNode *)root;
InternalNode *pre = nullptr;
int index = 0;
for (int i = dimen / 2; i >= len; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) | ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0));
pre = node;
node = &node->get_child(node->get_child_count(index))->internal;
}
count = pre->get_child_count(index);
return pre;
}
InternalNode *locateParent(InternalNode *parent, int len, const int st[3], int &count)
{
InternalNode *node = parent;
InternalNode *pre = nullptr;
int index = 0;
for (int i = len / 2; i >= mindimen; i >>= 1) {
index = (((st[0] & i) ? 4 : 0) | ((st[1] & i) ? 2 : 0) | ((st[2] & i) ? 1 : 0));
pre = node;
node = &node->get_child(node->get_child_count(index))->internal;
}
count = pre->get_child_count(index);
return pre;
}
/************ Operators for internal nodes ************/
/** Add a kid to an existing internal node */
InternalNode *addChild(InternalNode *node, int index, Node *child, int aLeaf)
{
// Create new internal node
int num = node->get_num_children();
InternalNode *rnode = createInternal(num + 1);
// Establish children
int i;
int count1 = 0, count2 = 0;
for (i = 0; i < 8; i++) {
if (i == index) {
if (aLeaf) {
rnode->set_leaf_child(i, count2, &child->leaf);
}
else {
rnode->set_internal_child(i, count2, &child->internal);
}
count2++;
}
else if (node->has_child(i)) {
if (node->is_child_leaf(i)) {
rnode->set_leaf_child(i, count2, &node->get_child(count1)->leaf);
}
else {
rnode->set_internal_child(i, count2, &node->get_child(count1)->internal);
}
count1++;
count2++;
}
}
removeInternal(num, node);
return rnode;
}
/** Allocate a node */
InternalNode *createInternal(int length)
{
InternalNode *inode = (InternalNode *)alloc[length]->allocate();
inode->has_child_bitfield = 0;
inode->child_is_leaf_bitfield = 0;
return inode;
}
LeafNode *createLeaf(int length)
{
assert(length <= 3);
LeafNode *lnode = (LeafNode *)leafalloc[length]->allocate();
lnode->edge_parity = 0;
lnode->primary_edge_intersections = 0;
lnode->signs = 0;
return lnode;
}
void removeInternal(int num, InternalNode *node)
{
alloc[num]->deallocate(node);
}
void removeLeaf(int num, LeafNode *leaf)
{
assert(num >= 0 && num <= 3);
leafalloc[num]->deallocate(leaf);
}
/** Add a leaf (by creating a new par node with the leaf added) */
InternalNode *addLeafChild(InternalNode *par, int index, int count, LeafNode *leaf)
{
int num = par->get_num_children() + 1;
InternalNode *npar = createInternal(num);
*npar = *par;
if (num == 1) {
npar->set_leaf_child(index, 0, leaf);
}
else {
int i;
for (i = 0; i < count; i++) {
npar->set_child(i, par->get_child(i));
}
npar->set_leaf_child(index, count, leaf);
for (i = count + 1; i < num; i++) {
npar->set_child(i, par->get_child(i - 1));
}
}
removeInternal(num - 1, par);
return npar;
}
InternalNode *addInternalChild(InternalNode *par, int index, int count, InternalNode *node)
{
int num = par->get_num_children() + 1;
InternalNode *npar = createInternal(num);
*npar = *par;
if (num == 1) {
npar->set_internal_child(index, 0, node);
}
else {
int i;
for (i = 0; i < count; i++) {
npar->set_child(i, par->get_child(i));
}
npar->set_internal_child(index, count, node);
for (i = count + 1; i < num; i++) {
npar->set_child(i, par->get_child(i - 1));
}
}
removeInternal(num - 1, par);
return npar;
}
MEM_CXX_CLASS_ALLOC_FUNCS("DUALCON:Octree")
};
#endif /* __OCTREE_H__ */