Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vdb): add touchLeafAndCache() #31

Merged
merged 3 commits into from
Feb 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions apps/frontend/src/app/scene-viewer-container/grid.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,12 @@ export class GridService {
const end = points[1];
const endCenter = add(end, [0.5, 0.5, 0.5]);

// Set start & end to ensure leaf-nodes are created in the grid.
// Otherwise, it could happen that the start/end point is in a new leaf which
// doesn't yet exist and therefore doesn't cause any intersection.
// TODO: Maybe `touchLeaf()` would work as well?
const tempChanges = this.setVoxels(points, [newValue, newValue]);
// Set end to ensure leaf-node is created in the grid. And has at least one active voxel.
// Otherwise, it could happen that the end point is in a new leaf which doesn't yet exist
// and therefore doesn't cause any intersection (since a ray intersects only with active
// values i.e. either active voxels or tiles. The start voxel is already added when the
// drawing of the line starts (in effect).
const tempChange = this.setVoxel(end, newValue);

const ray = this.createIntersectionRay(startCenter, endCenter);

Expand All @@ -112,12 +113,10 @@ export class GridService {
return [];
}

// Restore old values
tempChanges.forEach(change =>
change.oldValue === this.grid.background
? this.removeVoxel(change.xyz)
: this.setVoxel(change.xyz, change.oldValue),
);
// Restore old value
tempChange.oldValue === this.grid.background
? this.removeVoxel(tempChange.xyz)
: this.setVoxel(tempChange.xyz, tempChange.oldValue);

return this.setVoxelsAlongRayUntilLastVoxel(ray, totalTimeSpan, end, newValue);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@ export class SceneViewerContainerComponent implements AfterViewInit {
constructor(private store: Store<fromApp.State>) {}

ngAfterViewInit(): void {
// this.initializeChessboard();

this.store.dispatch(
setVoxel({ xyz: [0, 0, 0], newValue: rgbaToInt({ r: 0, g: 255, b: 0, a: 255 }) }),
);
Expand Down
17 changes: 15 additions & 2 deletions libs/vdb/src/lib/tree/internal-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,19 @@ abstract class InternalNode<T> implements HashableNode<T> {
return child.probeLeafNodeAndCache(xyz, accessor);
}

touchLeafAndCache(xyz: Coord, accessor: ValueAccessor3<T>): LeafNode<T> {
const i: Index = this.coordToOffset(xyz);
const node = this.nodes[i];

if (this.childMask.isOff(i)) {
this.setChildNode(i, this.createChildNode(xyz, node.getValue(), this.valueMask.isOn(i)));
}

accessor.insert(xyz, node.getChild());

return node.getChild().touchLeafAndCache(xyz, accessor);
}

probeInternalNode1AndCache(
xyz: Coord,
accessor: ValueAccessor3<T>,
Expand Down Expand Up @@ -337,7 +350,7 @@ export class InternalNode1<T> extends InternalNode<T> {
static readonly NUM_VOXELS = 1 << (3 * InternalNode1.TOTAL); // total voxel count represented by this node
// tslint:enable:no-bitwise

createChildNode(xyz: [number, number, number], value?: T, active?: boolean): LeafNode<T> {
createChildNode(xyz: Coord, value?: T, active?: boolean): LeafNode<T> {
return new LeafNode(xyz, value, active);
}

Expand All @@ -364,7 +377,7 @@ export class InternalNode2<T> extends InternalNode<T> {
static readonly NUM_VOXELS = Math.pow(2, 3 * InternalNode2.TOTAL);
// tslint:enable:no-bitwise

createChildNode(xyz: [number, number, number], value?: T, active?: boolean): InternalNode1<T> {
createChildNode(xyz: Coord, value?: T, active?: boolean): InternalNode1<T> {
return new InternalNode1(xyz, value, active);
}

Expand Down
4 changes: 4 additions & 0 deletions libs/vdb/src/lib/tree/leaf-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ export class LeafNode<T> implements HashableNode<T> {
return this;
}

touchLeafAndCache(_xyz: Coord, _accessor: ValueAccessor3<T>): LeafNode<T> {
return this;
}

probeInternalNode1AndCache(
_xyz: Coord,
_accessor: ValueAccessor3<T>,
Expand Down
10 changes: 10 additions & 0 deletions libs/vdb/src/lib/tree/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ export interface HashableNode<T> extends Node<T> {
probeLeafNodeAndCache(xyz: Coord, accessor: ValueAccessor3<T>): LeafNode<T> | undefined;
probeInternalNode1AndCache(xyz: Coord, accessor: ValueAccessor3<T>): InternalNode1<T> | undefined;

/**
* Return the leaf node that contains voxel (x, y, z).
* If no such node exists, create one, but preserve the values and
* active states of all voxels.
*
* If necessary, update the given accessor with pointers to the nodes along the path
* from the root node to the node containing the coordinate.
*/
touchLeafAndCache(xyz: Coord, accessor: ValueAccessor3<T>): LeafNode<T>;

/**
* Change the value of the voxel at the given coordinates and mark it as active.
* If necessary, update the accessor with pointers to the nodes along the path
Expand Down
19 changes: 19 additions & 0 deletions libs/vdb/src/lib/tree/root-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,25 @@ export class RootNode<T> implements HashableNode<T> {
return child.probeInternalNode1AndCache(xyz, accessor);
}

touchLeafAndCache(xyz: Coord, accessor: ValueAccessor3<T>): LeafNode<T> {
let child: HashableNode<T> | undefined;
const struct = this.findCoord(xyz);

if (!struct) {
child = new InternalNode2(xyz, this._background, false);
this.table.set(RootNode.coordToKey(xyz), new NodeStruct(child));
} else if (struct.isChild()) {
child = struct.getChild();
} else {
child = new InternalNode2(xyz, struct.getTile().value, struct.isTileOn());
struct.setChild(child);
}

accessor.insert(xyz, child);

return child.touchLeafAndCache(xyz, accessor);
}

setValueOn(xyz: Coord, value: T): void {
let child: HashableNode<T> | undefined;
const struct = this.findCoord(xyz);
Expand Down
16 changes: 16 additions & 0 deletions libs/vdb/src/lib/tree/value-accessor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,4 +234,20 @@ describe('ValueAccessor', () => {
expect(isHashed1Spy.calls.count()).toEqual(0);
});
});

describe('touchLeaf()', () => {
const tree = new Tree(-1);

it('should create not existing leaf node and return it', () => {
const accessor = new ValueAccessor3(tree);

expect(accessor.probeLeafNode([0, 0, 0])).toBeUndefined();

const newLeaf = accessor.touchLeaf([0, 0, 0]);

expect(newLeaf).toBeDefined();
expect(accessor.probeLeafNode([0, 0, 0])).toBeDefined();
expect(accessor.probeLeafNode([0, 0, 0])).toBe(newLeaf);
});
});
});
12 changes: 12 additions & 0 deletions libs/vdb/src/lib/tree/value-accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,18 @@ export class ValueAccessor3<T> {
}
}

touchLeaf(xyz: Coord): LeafNode<T> {
if (this.isHashed0(xyz)) {
return this.leafNode;
} else if (this.isHashed1(xyz)) {
return this.internalNode1.touchLeafAndCache(xyz, this);
} else if (this.isHashed2(xyz)) {
return this.internalNode2.touchLeafAndCache(xyz, this);
} else {
return this.tree.root.touchLeafAndCache(xyz, this);
}
}

/**
* Return the value of the voxel at the given coordinates.
*/
Expand Down