Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Autodrop3d/jsketcher
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: xibyte/jsketcher
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 2 commits
  • 8 files changed
  • 1 contributor

Commits on Oct 30, 2023

  1. voxel experiments

    xibyte committed Oct 30, 2023
    Copy the full SHA
    1564f24 View commit details
  2. fix tesselation

    xibyte committed Oct 30, 2023
    Copy the full SHA
    c1905c4 View commit details
8 changes: 6 additions & 2 deletions modules/geom/impl/curve/curve-tess.js
Original file line number Diff line number Diff line change
@@ -19,8 +19,12 @@ export function curveTessParams(curve, min, max, tessTol, scale) {
splits.push(max);

function refine(u1, u2, step) {
if (step < u2 - u1) {
const mid = u1 + (u2 - u1) * 0.5;
const uDist = u2 - u1;
if (uDist < 1e-3) {
return
}
if (step < uDist) {
const mid = u1 + uDist * 0.5;
refine(u1, mid, step);
out.push(mid);
refine(mid, u2, curveStep(curve, mid, tessTol, scale));
2 changes: 1 addition & 1 deletion modules/scene/sceneSetup.ts
Original file line number Diff line number Diff line change
@@ -84,7 +84,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 );
108 changes: 102 additions & 6 deletions modules/voxels/octree.js
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ export class Node {
constructor() {
this.nodes = null;
this.tag = 0;
this.normal = null;
}


@@ -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 = [];
@@ -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;
@@ -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]);
@@ -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) {
@@ -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;
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