Skip to content
Open

Dev #217

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
11 changes: 10 additions & 1 deletion modules/math/equality.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import {distanceSquared3, distanceSquaredAB3, distanceSquaredANegB3} from "math/distance";
import {
distanceAB,
distanceSquared3,
distanceSquaredAB3,
distanceSquaredANegB3
} from "math/distance";

export const TOLERANCE = 1E-6;
export const TOLERANCE_SQ = TOLERANCE * TOLERANCE;
Expand All @@ -7,6 +12,10 @@ export function areEqual(v1, v2, tolerance) {
return Math.abs(v1 - v2) < tolerance;
}

export function arePointsEqual(v1, v2, toleranceSQ) {
return areEqual(distanceAB(v1, v2), 0, toleranceSQ);
}

export function areVectorsEqual(v1, v2, toleranceSQ) {
return areEqual(distanceSquaredAB3(v1, v2), 0, toleranceSQ);
}
Expand Down
2 changes: 1 addition & 1 deletion modules/math/optim/dogleg.js
Original file line number Diff line number Diff line change
Expand Up @@ -413,4 +413,4 @@ var cg = function(A, x, b, tol, maxIt) {

var dogleg = {DEBUG_HANDLER : function() {}}; //backward compatibility

export {dog_leg, dogleg}
export {dog_leg, dogleg, lu_solve}
2 changes: 1 addition & 1 deletion modules/scene/sceneSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export default class SceneSetUp {
this.createOrthographicCamera();
this.createPerspectiveCamera();

this.camera = this.oCamera;
this.camera = this.pCamera;

this.light = new DirectionalLight( 0xffffff );
this.light.position.set( 10, 10, 10 );
Expand Down
108 changes: 102 additions & 6 deletions modules/voxels/octree.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export class Node {
constructor() {
this.nodes = null;
this.tag = 0;
this.normal = null;
}


Expand All @@ -13,15 +14,81 @@ export class Node {
}

breakDown() {
if (this.nodes) {
console.error("attempt of breaking down not a leaf node")
this.makeLeaf();
}
this.nodes = [new Node(), new Node(), new Node(), new Node(), new Node(), new Node(), new Node(), new Node()];
this.nodes.forEach(n => n.tag = this.tag);
}

makeLeaf() {
if (this.nodes) {
this.nodes.forEach(n => n.dispose());
this.nodes = null;
}
}

dispose() {}

}

const directors = [
export const directors = [
[0,0,0], [1,0,0], [0,1,0], [1,1,0],
[0,0,1], [1,0,1], [0,1,1], [1,1,1]
];

export class NDTree {

constructor(size) {
this.root = new Node();
this.size = size;
if (this.size % 2 !== 0) {
throw 'size of nd tree must be power of two'
}
this.dimension = 3;
this.directors = directors;
this.nodesCount = Math.pow(2, this.dimension);
}

traverse(handler) {
traverseOctree(this.root, this.size, handler);
}

defragment() {

function defrg(node, x,y,z, size) {

if (node.leaf) {
return;
}

const subSize = size / 2;

let allChildrenLeafsSameKind = true;

for (let i = 0; i < 8; i ++) {
const subNode = node.nodes[i];
if (subNode) {
const [dx, dy, dz] = directors[i];
defrg(subNode, x + dx*subSize, y + dy*subSize, z + dz*subSize, subSize)
if (!subNode.leaf || subNode.tag !== node.tag) {
allChildrenLeafsSameKind = false;
}
}
}

if (allChildrenLeafsSameKind) {
node.makeLeaf();
}

}

defrg(this.root, 0,0,0, this.size);
}

}

export function traverseOctree(root, baseSize, handler) {

const stack = [];
Expand All @@ -32,7 +99,7 @@ export function traverseOctree(root, baseSize, handler) {

const [node, [x,y,z], size] = stack.pop();
if (node.leaf) {
handler(x, y, z, size, node.tag);
handler(x, y, z, size, node.tag, node);
continue;
}
const subSize = size / 2;
Expand All @@ -45,12 +112,40 @@ export function traverseOctree(root, baseSize, handler) {
stack.push([subNode, subLocation, subSize]);
}
}

}
}

export function generateVoxelShape(root, baseSize, classify) {
const stack = [];

stack.push([root, [0,0,0], baseSize]);

while (stack.length !== 0) {

const [node, [x,y,z], size] = stack.pop();

node.size = size; // todo remove, debug
node.xyz = [x,y,z]; // todo remove, debug

node.tag = classify(x, y, z, size);

if (size === 1 || node.tag !== 'edge') {
continue;
}
node.breakDown();

const subSize = size / 2;

for (let i = 0; i < 8; i ++) {
const [dx, dy, dz] = directors[i];
const subLocation = [x + dx*subSize, y + dy*subSize, z + dz*subSize];
const subNode = node.nodes[i];
stack.push([subNode, subLocation, subSize]);
}
}
}

export function pushVoxel(root, baseSize, [vx, vy, vz], tag) {
export function pushVoxel(root, baseSize, [vx, vy, vz], tag, normal, semantic) {
const stack = [];

stack.push([root, [0,0,0], baseSize]);
Expand All @@ -61,6 +156,7 @@ export function pushVoxel(root, baseSize, [vx, vy, vz], tag) {

if (size === 1 && x === vx && y === vy && z === vz) {
node.tag = tag;
node.normal = normal;
return;
}
if (size === 1) {
Expand Down Expand Up @@ -110,8 +206,8 @@ export function createOctreeFromSurface(origin, sceneSize, treeSize, surface, ta
const voxel = vec.sub(pMin, origin);
vec._div(voxel, resolution);
vec.scalarOperand(voxel, voxel, v => Math.floor(v));

pushVoxel(root, treeSize, voxel, tag);
const normal = surface.normal(uMin, vMin);
pushVoxel(root, treeSize, voxel, tag, normal);
} else {
const uMid = uMin + (uMax - uMin) / 2;
const vMid = vMin + (vMax - vMin) / 2;
Expand Down
54 changes: 54 additions & 0 deletions modules/voxels/vixelViz.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {BoxGeometry, Color, Group, Mesh, MeshPhongMaterial} from "three";

const geometry = new BoxGeometry( 1, 1, 1 );

export class Cube extends Group {

material: MeshPhongMaterial;

constructor(size=1, colorTag) {

super();

let material;
if (colorTag) {
material = MaterialTable[colorTag];
} else {
material = MaterialRandomTable[Math.round(Math.random() * 100000) % MaterialRandomTable.length]
}

const mesh = new Mesh(geometry, material);
mesh.position.x = 0.5*size;
mesh.position.y = 0.5*size;
mesh.position.z = 0.5*size;
mesh.scale.x = size
mesh.scale.y = size
mesh.scale.z = size

this.add(mesh)

}
}

const randomInt = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};

const niceColor = () => {
const h = randomInt(0, 360);
const s = randomInt(42, 98);
const l = randomInt(40, 90);
return `hsl(${h},${s}%,${l}%)`;
};

const MaterialRandomTable = [];

for (let i = 0; i < 1000; i ++) {
MaterialRandomTable.push(new MeshPhongMaterial( { color: new Color(niceColor())} ));
}

const MaterialTable = {
'inside': new MeshPhongMaterial( { color: 'white'} ),
'edge': new MeshPhongMaterial( { color: 0x999999} )
};

139 changes: 139 additions & 0 deletions modules/voxels/voxelBool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import {directors, NDTree} from "voxels/octree";

export function ndTreeSubtract(a: NDTree, b: NDTree) {
mergeNDTrees(a, b, 'subtract')
}


function mergeNDTrees(aTree: NDTree, bTree: NDTree, boolSemantic) {

const stack = [];

if (aTree.size !== bTree.size) {
throw 'unsupported';
}

stack.push([
aTree.root,
bTree.root,
[0,0,0],
aTree.size
]);

let counter = 0;
while (stack.length !== 0) {
counter ++;
const [a, b, [x, y, z], size] = stack.pop();

if (a.leaf && b.leaf) {
if (boolSemantic === 'subtract') {
if (b.tag === 'inside' || b.tag === 'edge') {
a.tag = 'outside';
}
//TBD...
}
continue;
}

if (a.leaf) {
a.breakDown();
}

const subSize = size / 2;

for (let i = 0; i < aTree.nodesCount; i ++) {
const [dx, dy, dz] = aTree.directors[i];
const subLocation = [x + dx*subSize, y + dy*subSize, z + dz*subSize];
const subNode1 = a.nodes[i];
const subNode2 = b.leaf ? b : b.nodes[i];
stack.push([subNode1, subNode2, subLocation, subSize]);
}
}
console.log("!!!! =",counter)

}

export function ndTreeTransformAndSubtract(a: NDTree, b: NDTree, transformer) {
b.traverse((xo, yo, zo, size, tag, node) => {

const coord = transformer([xo, yo, zo]);

if (tag !== 'outside') {

insertNode(a.root, a.size, coord, size, tag, 'subtract');

}

});


}

function insertNode(targetNode, targetSize, [vx, vy, vz], insertSize, tag, boolSemantic) {
if (vx > targetSize || vy > targetSize || vz > targetSize) {
return;
}

const stack = [];

stack.push([targetNode, [0,0,0], targetSize]);

while (stack.length !== 0) {

const [node, [x,y,z], size] = stack.pop();


const nodeInside = isInside(x, y, z, size, vx, vy, vz, insertSize);
if (nodeInside) {
if (boolSemantic === 'subtract') {
if (node.tag === 'inside' || node.tag === 'edge') {
node.tag = 'outside';
node.makeLeaf();
}
//TBD...
}
continue;
}

if (size === 1) {
continue;
}

if (node.leaf) {
node.breakDown();
}

const subSize = size / 2;

for (let i = 0; i < 8; i ++) {
const [dx, dy, dz] = directors[i];
const subLocation = [x + dx*subSize, y + dy*subSize, z + dz*subSize];
const [sx1, sy1, sz1] = subLocation;
if (nodeInside || overlaps(vx, vy, vz, insertSize, sx1, sy1, sz1, subSize)) {
const subNode = node.nodes[i];
stack.push([subNode, subLocation, subSize]);
}
}
}
}

function isInside(tx, ty, tz, tsize, rx, ry, rz, rsize) {

return isPtInside(tx, ty, tz, rx, ry, rz, rsize) && isPtInside(tx+tsize, ty+tsize,tz+tsize, rx, ry, rz, rsize)

}
function overlaps(tx, ty, tz, tsize, rx, ry, rz, rsize) {
return overlap1d(tx, tx + tsize, rx, rx + rsize)
* overlap1d(ty, ty + tsize, ry, ry + rsize)
* overlap1d(tz, tz + tsize, rz, rz + rsize) > 0;
}

function isPtInside(x, y, z, rx, ry, rz, size) {

return (x >= rx) && (y >= ry) && (z >= rz) && (x <= rx + size) && (y <= ry+size) && (z <= rz+size);

}

function overlap1d(min1, max1, min2, max2) {
return Math.max(0, Math.min(max1, max2) - Math.max(min1, min2))
}
Loading